|
@@ -3,22 +3,27 @@
|
|
namespace App\Util\Media;
|
|
namespace App\Util\Media;
|
|
|
|
|
|
use App\Media;
|
|
use App\Media;
|
|
-use Intervention\Image\ImageManager;
|
|
|
|
|
|
+use App\Services\StatusService;
|
|
|
|
+use Cache;
|
|
use Intervention\Image\Encoders\JpegEncoder;
|
|
use Intervention\Image\Encoders\JpegEncoder;
|
|
-use Intervention\Image\Encoders\WebpEncoder;
|
|
|
|
-use Intervention\Image\Encoders\AvifEncoder;
|
|
|
|
use Intervention\Image\Encoders\PngEncoder;
|
|
use Intervention\Image\Encoders\PngEncoder;
|
|
-use Cache, Log, Storage;
|
|
|
|
-use App\Util\Media\Blurhash;
|
|
|
|
-use App\Services\StatusService;
|
|
|
|
|
|
+use Intervention\Image\Encoders\WebpEncoder;
|
|
|
|
+use Intervention\Image\ImageManager;
|
|
|
|
+use Log;
|
|
|
|
+use Storage;
|
|
|
|
|
|
class Image
|
|
class Image
|
|
{
|
|
{
|
|
public $square;
|
|
public $square;
|
|
|
|
+
|
|
public $landscape;
|
|
public $landscape;
|
|
|
|
+
|
|
public $portrait;
|
|
public $portrait;
|
|
|
|
+
|
|
public $thumbnail;
|
|
public $thumbnail;
|
|
|
|
+
|
|
public $orientation;
|
|
public $orientation;
|
|
|
|
+
|
|
public $acceptedMimes = [
|
|
public $acceptedMimes = [
|
|
'image/png',
|
|
'image/png',
|
|
'image/jpeg',
|
|
'image/jpeg',
|
|
@@ -30,6 +35,8 @@ class Image
|
|
|
|
|
|
protected $imageManager;
|
|
protected $imageManager;
|
|
|
|
|
|
|
|
+ protected $defaultDisk;
|
|
|
|
+
|
|
public function __construct()
|
|
public function __construct()
|
|
{
|
|
{
|
|
ini_set('memory_limit', config('pixelfed.memory_limit', '1024M'));
|
|
ini_set('memory_limit', config('pixelfed.memory_limit', '1024M'));
|
|
@@ -38,12 +45,14 @@ class Image
|
|
$this->landscape = $this->orientations()['landscape'];
|
|
$this->landscape = $this->orientations()['landscape'];
|
|
$this->portrait = $this->orientations()['portrait'];
|
|
$this->portrait = $this->orientations()['portrait'];
|
|
$this->thumbnail = [
|
|
$this->thumbnail = [
|
|
- 'width' => 640,
|
|
|
|
|
|
+ 'width' => 640,
|
|
'height' => 640,
|
|
'height' => 640,
|
|
];
|
|
];
|
|
$this->orientation = null;
|
|
$this->orientation = null;
|
|
|
|
|
|
- $driver = match(config('image.driver')) {
|
|
|
|
|
|
+ $this->defaultDisk = config('filesystems.default');
|
|
|
|
+
|
|
|
|
+ $driver = match (config('image.driver')) {
|
|
'imagick' => \Intervention\Image\Drivers\Imagick\Driver::class,
|
|
'imagick' => \Intervention\Image\Drivers\Imagick\Driver::class,
|
|
'vips' => \Intervention\Image\Drivers\Vips\Driver::class,
|
|
'vips' => \Intervention\Image\Drivers\Vips\Driver::class,
|
|
default => \Intervention\Image\Drivers\Gd\Driver::class
|
|
default => \Intervention\Image\Drivers\Gd\Driver::class
|
|
@@ -62,15 +71,15 @@ class Image
|
|
{
|
|
{
|
|
return [
|
|
return [
|
|
'square' => [
|
|
'square' => [
|
|
- 'width' => 1080,
|
|
|
|
|
|
+ 'width' => 1080,
|
|
'height' => 1080,
|
|
'height' => 1080,
|
|
],
|
|
],
|
|
'landscape' => [
|
|
'landscape' => [
|
|
- 'width' => 1920,
|
|
|
|
|
|
+ 'width' => 1920,
|
|
'height' => 1080,
|
|
'height' => 1080,
|
|
],
|
|
],
|
|
'portrait' => [
|
|
'portrait' => [
|
|
- 'width' => 1080,
|
|
|
|
|
|
+ 'width' => 1080,
|
|
'height' => 1350,
|
|
'height' => 1350,
|
|
],
|
|
],
|
|
];
|
|
];
|
|
@@ -80,7 +89,7 @@ class Image
|
|
{
|
|
{
|
|
if ($isThumbnail) {
|
|
if ($isThumbnail) {
|
|
return [
|
|
return [
|
|
- 'dimensions' => $this->thumbnail,
|
|
|
|
|
|
+ 'dimensions' => $this->thumbnail,
|
|
'orientation' => 'thumbnail',
|
|
'orientation' => 'thumbnail',
|
|
];
|
|
];
|
|
}
|
|
}
|
|
@@ -91,7 +100,7 @@ class Image
|
|
$this->orientation = $orientation;
|
|
$this->orientation = $orientation;
|
|
|
|
|
|
return [
|
|
return [
|
|
- 'dimensions' => $this->orientations()[$orientation],
|
|
|
|
|
|
+ 'dimensions' => $this->orientations()[$orientation],
|
|
'orientation' => $orientation,
|
|
'orientation' => $orientation,
|
|
'width_original' => $width,
|
|
'width_original' => $width,
|
|
'height_original' => $height,
|
|
'height_original' => $height,
|
|
@@ -121,48 +130,68 @@ class Image
|
|
public function handleImageTransform(Media $media, $thumbnail = false)
|
|
public function handleImageTransform(Media $media, $thumbnail = false)
|
|
{
|
|
{
|
|
$path = $media->media_path;
|
|
$path = $media->media_path;
|
|
- $file = storage_path('app/'.$path);
|
|
|
|
- if (!in_array($media->mime, $this->acceptedMimes)) {
|
|
|
|
|
|
+ $localFs = config('filesystems.default') === 'local';
|
|
|
|
+
|
|
|
|
+ if (! in_array($media->mime, $this->acceptedMimes)) {
|
|
return;
|
|
return;
|
|
}
|
|
}
|
|
|
|
|
|
try {
|
|
try {
|
|
- $fileInfo = pathinfo($file);
|
|
|
|
|
|
+ $fileContents = null;
|
|
|
|
+ $tempFile = null;
|
|
|
|
+
|
|
|
|
+ if ($this->defaultDisk === 'local') {
|
|
|
|
+ $filePath = storage_path('app/'.$path);
|
|
|
|
+ $fileContents = file_get_contents($filePath);
|
|
|
|
+ } else {
|
|
|
|
+ $fileContents = Storage::disk($this->defaultDisk)->get($path);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ $fileInfo = pathinfo($path);
|
|
$extension = strtolower($fileInfo['extension'] ?? 'jpg');
|
|
$extension = strtolower($fileInfo['extension'] ?? 'jpg');
|
|
$outputExtension = $extension;
|
|
$outputExtension = $extension;
|
|
|
|
|
|
$metadata = null;
|
|
$metadata = null;
|
|
- if (!$thumbnail && config('media.exif.database', false) == true) {
|
|
|
|
|
|
+ if (! $thumbnail && config('media.exif.database', false) == true) {
|
|
try {
|
|
try {
|
|
- $exif = @exif_read_data($file);
|
|
|
|
|
|
+ if ($this->defaultDisk !== 'local') {
|
|
|
|
+ $tempFile = tempnam(sys_get_temp_dir(), 'exif_');
|
|
|
|
+ file_put_contents($tempFile, $fileContents);
|
|
|
|
+ $exifPath = $tempFile;
|
|
|
|
+ } else {
|
|
|
|
+ $exifPath = storage_path('app/'.$path);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ $exif = @exif_read_data($exifPath);
|
|
|
|
+
|
|
if ($exif) {
|
|
if ($exif) {
|
|
$meta = [];
|
|
$meta = [];
|
|
$keys = [
|
|
$keys = [
|
|
- "FileName",
|
|
|
|
- "FileSize",
|
|
|
|
- "FileType",
|
|
|
|
- "Make",
|
|
|
|
- "Model",
|
|
|
|
- "MimeType",
|
|
|
|
- "ColorSpace",
|
|
|
|
- "ExifVersion",
|
|
|
|
- "Orientation",
|
|
|
|
- "UserComment",
|
|
|
|
- "XResolution",
|
|
|
|
- "YResolution",
|
|
|
|
- "FileDateTime",
|
|
|
|
- "SectionsFound",
|
|
|
|
- "ExifImageWidth",
|
|
|
|
- "ResolutionUnit",
|
|
|
|
- "ExifImageLength",
|
|
|
|
- "FlashPixVersion",
|
|
|
|
- "Exif_IFD_Pointer",
|
|
|
|
- "YCbCrPositioning",
|
|
|
|
- "ComponentsConfiguration",
|
|
|
|
- "ExposureTime",
|
|
|
|
- "FNumber",
|
|
|
|
- "ISOSpeedRatings",
|
|
|
|
- "ShutterSpeedValue"
|
|
|
|
|
|
+ 'FileName',
|
|
|
|
+ 'FileSize',
|
|
|
|
+ 'FileType',
|
|
|
|
+ 'Make',
|
|
|
|
+ 'Model',
|
|
|
|
+ 'MimeType',
|
|
|
|
+ 'ColorSpace',
|
|
|
|
+ 'ExifVersion',
|
|
|
|
+ 'Orientation',
|
|
|
|
+ 'UserComment',
|
|
|
|
+ 'XResolution',
|
|
|
|
+ 'YResolution',
|
|
|
|
+ 'FileDateTime',
|
|
|
|
+ 'SectionsFound',
|
|
|
|
+ 'ExifImageWidth',
|
|
|
|
+ 'ResolutionUnit',
|
|
|
|
+ 'ExifImageLength',
|
|
|
|
+ 'FlashPixVersion',
|
|
|
|
+ 'Exif_IFD_Pointer',
|
|
|
|
+ 'YCbCrPositioning',
|
|
|
|
+ 'ComponentsConfiguration',
|
|
|
|
+ 'ExposureTime',
|
|
|
|
+ 'FNumber',
|
|
|
|
+ 'ISOSpeedRatings',
|
|
|
|
+ 'ShutterSpeedValue',
|
|
];
|
|
];
|
|
foreach ($exif as $k => $v) {
|
|
foreach ($exif as $k => $v) {
|
|
if (in_array($k, $keys)) {
|
|
if (in_array($k, $keys)) {
|
|
@@ -171,12 +200,22 @@ class Image
|
|
}
|
|
}
|
|
$media->metadata = json_encode($meta);
|
|
$media->metadata = json_encode($meta);
|
|
}
|
|
}
|
|
|
|
+
|
|
|
|
+ if ($tempFile && file_exists($tempFile)) {
|
|
|
|
+ unlink($tempFile);
|
|
|
|
+ $tempFile = null;
|
|
|
|
+ }
|
|
} catch (\Exception $e) {
|
|
} catch (\Exception $e) {
|
|
- Log::info('EXIF extraction failed: ' . $e->getMessage());
|
|
|
|
|
|
+ if ($tempFile && file_exists($tempFile)) {
|
|
|
|
+ unlink($tempFile);
|
|
|
|
+ }
|
|
|
|
+ if (config('app.dev_log')) {
|
|
|
|
+ Log::info('EXIF extraction failed: '.$e->getMessage());
|
|
|
|
+ }
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
- $img = $this->imageManager->read($file);
|
|
|
|
|
|
+ $img = $this->imageManager->read($fileContents);
|
|
|
|
|
|
$ratio = $this->getAspect($img->width(), $img->height(), $thumbnail);
|
|
$ratio = $this->getAspect($img->width(), $img->height(), $thumbnail);
|
|
$aspect = $ratio['dimensions'];
|
|
$aspect = $ratio['dimensions'];
|
|
@@ -209,7 +248,7 @@ class Image
|
|
$outputExtension = 'jpg';
|
|
$outputExtension = 'jpg';
|
|
break;
|
|
break;
|
|
case 'png':
|
|
case 'png':
|
|
- $encoder = new PngEncoder();
|
|
|
|
|
|
+ $encoder = new PngEncoder;
|
|
$outputExtension = 'png';
|
|
$outputExtension = 'png';
|
|
break;
|
|
break;
|
|
case 'webp':
|
|
case 'webp':
|
|
@@ -230,11 +269,17 @@ class Image
|
|
}
|
|
}
|
|
|
|
|
|
$converted = $this->setBaseName($path, $thumbnail, $outputExtension);
|
|
$converted = $this->setBaseName($path, $thumbnail, $outputExtension);
|
|
- $newPath = storage_path('app/'.$converted['path']);
|
|
|
|
-
|
|
|
|
$encoded = $encoder->encode($img);
|
|
$encoded = $encoder->encode($img);
|
|
|
|
|
|
- file_put_contents($newPath, $encoded->toString());
|
|
|
|
|
|
+ if ($localFs) {
|
|
|
|
+ $newPath = storage_path('app/'.$converted['path']);
|
|
|
|
+ file_put_contents($newPath, $encoded->toString());
|
|
|
|
+ } else {
|
|
|
|
+ Storage::disk($this->defaultDisk)->put(
|
|
|
|
+ $converted['path'],
|
|
|
|
+ $encoded->toString()
|
|
|
|
+ );
|
|
|
|
+ }
|
|
|
|
|
|
if ($thumbnail == true) {
|
|
if ($thumbnail == true) {
|
|
$media->thumbnail_path = $converted['path'];
|
|
$media->thumbnail_path = $converted['path'];
|
|
@@ -244,7 +289,7 @@ class Image
|
|
$media->height = $img->height();
|
|
$media->height = $img->height();
|
|
$media->orientation = $orientation;
|
|
$media->orientation = $orientation;
|
|
$media->media_path = $converted['path'];
|
|
$media->media_path = $converted['path'];
|
|
- $media->mime = 'image/' . $outputExtension;
|
|
|
|
|
|
+ $media->mime = 'image/'.$outputExtension;
|
|
}
|
|
}
|
|
|
|
|
|
$media->save();
|
|
$media->save();
|
|
@@ -253,7 +298,7 @@ class Image
|
|
$this->generateBlurhash($media);
|
|
$this->generateBlurhash($media);
|
|
}
|
|
}
|
|
|
|
|
|
- if($media->status_id) {
|
|
|
|
|
|
+ if ($media->status_id) {
|
|
Cache::forget('status:transformer:media:attachments:'.$media->status_id);
|
|
Cache::forget('status:transformer:media:attachments:'.$media->status_id);
|
|
Cache::forget('status:thumb:'.$media->status_id);
|
|
Cache::forget('status:thumb:'.$media->status_id);
|
|
StatusService::del($media->status_id);
|
|
StatusService::del($media->status_id);
|
|
@@ -262,7 +307,9 @@ class Image
|
|
} catch (\Exception $e) {
|
|
} catch (\Exception $e) {
|
|
$media->processed_at = now();
|
|
$media->processed_at = now();
|
|
$media->save();
|
|
$media->save();
|
|
- Log::info('MediaResizeException: ' . $e->getMessage() . ' | Could not process media id: ' . $media->id);
|
|
|
|
|
|
+ if (config('app.dev_log')) {
|
|
|
|
+ Log::info('MediaResizeException: '.$e->getMessage().' | Could not process media id: '.$media->id);
|
|
|
|
+ }
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
@@ -277,10 +324,28 @@ class Image
|
|
|
|
|
|
protected function generateBlurhash($media)
|
|
protected function generateBlurhash($media)
|
|
{
|
|
{
|
|
- $blurhash = Blurhash::generate($media);
|
|
|
|
- if ($blurhash) {
|
|
|
|
- $media->blurhash = $blurhash;
|
|
|
|
- $media->save();
|
|
|
|
|
|
+ try {
|
|
|
|
+ if ($this->defaultDisk === 'local') {
|
|
|
|
+ $thumbnailPath = storage_path('app/'.$media->thumbnail_path);
|
|
|
|
+ $blurhash = Blurhash::generate($media, $thumbnailPath);
|
|
|
|
+ } else {
|
|
|
|
+ $tempFile = tempnam(sys_get_temp_dir(), 'blurhash_');
|
|
|
|
+ $contents = Storage::disk($this->defaultDisk)->get($media->thumbnail_path);
|
|
|
|
+ file_put_contents($tempFile, $contents);
|
|
|
|
+
|
|
|
|
+ $blurhash = Blurhash::generate($media, $tempFile);
|
|
|
|
+
|
|
|
|
+ unlink($tempFile);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if ($blurhash) {
|
|
|
|
+ $media->blurhash = $blurhash;
|
|
|
|
+ $media->save();
|
|
|
|
+ }
|
|
|
|
+ } catch (\Exception $e) {
|
|
|
|
+ if (config('app.dev_log')) {
|
|
|
|
+ Log::info('Blurhash generation failed: '.$e->getMessage());
|
|
|
|
+ }
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|