Fix heic, avif, webp support and add libvips driver

pull/5983/head
Daniel Supernault 5 months ago
parent 86bb81d1a9
commit 4e938a8ffa
No known key found for this signature in database
GPG Key ID: 23740873EE6F76A1

@ -1911,6 +1911,7 @@ class ApiV1Controller extends Controller
case 'image/jpeg':
case 'image/png':
case 'image/webp':
case 'image/heic':
case 'image/avif':
ImageOptimize::dispatch($media)->onQueue('mmo');
break;
@ -2142,6 +2143,7 @@ class ApiV1Controller extends Controller
case 'image/jpeg':
case 'image/png':
case 'image/webp':
case 'image/heic':
case 'image/avif':
ImageOptimize::dispatch($media)->onQueue('mmo');
break;

@ -1310,6 +1310,9 @@ class ApiV1Dot1Controller extends Controller
case 'image/jpg':
case 'image/jpeg':
case 'image/png':
case 'image/webp':
case 'image/heic':
case 'image/avif':
ImageOptimize::dispatch($media)->onQueue('mmo');
break;

@ -309,9 +309,12 @@ class ApiV2Controller extends Controller
$media->save();
switch ($media->mime) {
case 'image/jpeg':
case 'image/jpg':
case 'image/jpeg':
case 'image/png':
case 'image/webp':
case 'image/heic':
case 'image/avif':
ImageOptimize::dispatch($media)->onQueue('mmo');
break;

@ -132,6 +132,7 @@ class ComposeController extends Controller
case 'image/jpeg':
case 'image/png':
case 'image/webp':
case 'image/heic':
case 'image/avif':
ImageOptimize::dispatch($media)->onQueue('mmo');
break;

@ -10,6 +10,7 @@ use Intervention\Image\Encoders\AvifEncoder;
use Intervention\Image\Encoders\PngEncoder;
use Cache, Log, Storage;
use App\Util\Media\Blurhash;
use App\Services\StatusService;
class Image
{
@ -75,20 +76,15 @@ class Image
];
}
public function getAspectRatio($mediaPath, $thumbnail = false)
public function getAspect($width, $height, $isThumbnail)
{
if ($thumbnail) {
if ($isThumbnail) {
return [
'dimensions' => $this->thumbnail,
'orientation' => 'thumbnail',
];
}
if (!is_file($mediaPath)) {
throw new \Exception('Invalid Media Path');
}
list($width, $height) = getimagesize($mediaPath);
$aspect = $width / $height;
$orientation = $aspect === 1 ? 'square' :
($aspect > 1 ? 'landscape' : 'portrait');
@ -129,13 +125,11 @@ class Image
if (!in_array($media->mime, $this->acceptedMimes)) {
return;
}
$ratio = $this->getAspectRatio($file, $thumbnail);
$aspect = $ratio['dimensions'];
$orientation = $ratio['orientation'];
try {
$fileInfo = pathinfo($file);
$extension = strtolower($fileInfo['extension'] ?? 'jpg');
$outputExtension = $extension;
$metadata = null;
if (!$thumbnail && config('media.exif.database', false) == true) {
@ -184,6 +178,10 @@ class Image
$img = $this->imageManager->read($file);
$ratio = $this->getAspect($img->width(), $img->height(), $thumbnail);
$aspect = $ratio['dimensions'];
$orientation = $ratio['orientation'];
if ($thumbnail) {
$img = $img->coverDown(
$aspect['width'],
@ -201,9 +199,6 @@ class Image
}
}
$converted = $this->setBaseName($path, $thumbnail, $extension);
$newPath = storage_path('app/'.$converted['path']);
$quality = config_cache('pixelfed.image_quality');
$encoder = null;
@ -211,25 +206,32 @@ class Image
case 'jpeg':
case 'jpg':
$encoder = new JpegEncoder($quality);
$outputExtension = 'jpg';
break;
case 'png':
$encoder = new PngEncoder();
$outputExtension = 'png';
break;
case 'webp':
$encoder = new WebpEncoder($quality);
$outputExtension = 'webp';
break;
case 'avif':
$encoder = new AvifEncoder($quality);
$encoder = new JpegEncoder($quality);
$outputExtension = 'jpg';
break;
case 'heic':
$encoder = new JpegEncoder($quality);
$extension = 'jpg';
$outputExtension = 'jpg';
break;
default:
$encoder = new JpegEncoder($quality);
$extension = 'jpg';
$outputExtension = 'jpg';
}
$converted = $this->setBaseName($path, $thumbnail, $outputExtension);
$newPath = storage_path('app/'.$converted['path']);
$encoded = $encoder->encode($img);
file_put_contents($newPath, $encoded->toString());
@ -242,7 +244,7 @@ class Image
$media->height = $img->height();
$media->orientation = $orientation;
$media->media_path = $converted['path'];
$media->mime = 'image/' . $extension;
$media->mime = 'image/' . $outputExtension;
}
$media->save();
@ -251,8 +253,11 @@ class Image
$this->generateBlurhash($media);
}
Cache::forget('status:transformer:media:attachments:'.$media->status_id);
Cache::forget('status:thumb:'.$media->status_id);
if($media->status_id) {
Cache::forget('status:transformer:media:attachments:'.$media->status_id);
Cache::forget('status:thumb:'.$media->status_id);
StatusService::del($media->status_id);
}
} catch (\Exception $e) {
$media->processed_at = now();
@ -263,13 +268,11 @@ class Image
public function setBaseName($basePath, $thumbnail, $extension)
{
$png = false;
$path = explode('.', $basePath);
$name = ($thumbnail == true) ? $path[0].'_thumb' : $path[0];
$ext = last($path);
$basePath = "{$name}.{$ext}";
$basePath = "{$name}.{$extension}";
return ['path' => $basePath, 'png' => $png];
return ['path' => $basePath, 'png' => false];
}
protected function generateBlurhash($media)

@ -19,6 +19,7 @@
"doctrine/dbal": "^3.0",
"endroid/qr-code": "^6.0",
"intervention/image": "^3.11.2",
"intervention/image-driver-vips": "^1.0",
"jenssegers/agent": "^2.6",
"laravel-notification-channels/expo": "^2.0.0",
"laravel-notification-channels/webpush": "^10.2",

137
composer.lock generated

@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "fc7f320209f9bd3f731d3de6e6f1755f",
"content-hash": "80e41279435abaff339524fb0a150bc6",
"packages": [
{
"name": "aws/aws-crt-php",
@ -2216,6 +2216,80 @@
],
"time": "2025-02-27T13:08:55+00:00"
},
{
"name": "intervention/image-driver-vips",
"version": "1.0.5",
"source": {
"type": "git",
"url": "https://github.com/Intervention/image-driver-vips.git",
"reference": "080de0e638bcf508b5e79c2d88e82b0fd91b12b0"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/Intervention/image-driver-vips/zipball/080de0e638bcf508b5e79c2d88e82b0fd91b12b0",
"reference": "080de0e638bcf508b5e79c2d88e82b0fd91b12b0",
"shasum": ""
},
"require": {
"intervention/image": "^3.11.0",
"jcupitt/vips": "^2.4",
"php": "^8.1"
},
"require-dev": {
"ext-fileinfo": "*",
"phpstan/phpstan": "^2",
"phpunit/phpunit": "^10.0 || ^11.0 || ^12.0",
"slevomat/coding-standard": "~8.0",
"squizlabs/php_codesniffer": "^3.8"
},
"type": "library",
"autoload": {
"psr-4": {
"Intervention\\Image\\Drivers\\Vips\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Oliver Vogel",
"email": "oliver@intervention.io",
"homepage": "https://intervention.io/"
},
{
"name": "Thomas Picquet",
"email": "thomas@sctr.net"
}
],
"description": "libvips driver for Intervention Image",
"homepage": "https://image.intervention.io/",
"keywords": [
"image",
"libvips",
"vips"
],
"support": {
"issues": "https://github.com/Intervention/image-driver-vips/issues",
"source": "https://github.com/Intervention/image-driver-vips/tree/1.0.5"
},
"funding": [
{
"url": "https://paypal.me/interventionio",
"type": "custom"
},
{
"url": "https://github.com/Intervention",
"type": "github"
},
{
"url": "https://ko-fi.com/interventionphp",
"type": "ko_fi"
}
],
"time": "2025-05-05T13:53:52+00:00"
},
{
"name": "jaybizzle/crawler-detect",
"version": "v1.3.4",
@ -2268,6 +2342,67 @@
},
"time": "2025-03-05T23:12:10+00:00"
},
{
"name": "jcupitt/vips",
"version": "v2.5.0",
"source": {
"type": "git",
"url": "https://github.com/libvips/php-vips.git",
"reference": "a54c1cceea581b592a199edd61a7c06f44a24c08"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/libvips/php-vips/zipball/a54c1cceea581b592a199edd61a7c06f44a24c08",
"reference": "a54c1cceea581b592a199edd61a7c06f44a24c08",
"shasum": ""
},
"require": {
"ext-ffi": "*",
"php": ">=7.4",
"psr/log": "^1.1.3|^2.0|^3.0"
},
"require-dev": {
"php-parallel-lint/php-parallel-lint": "^1.3",
"phpdocumentor/shim": "^3.3",
"phpunit/phpunit": "^9.5",
"squizlabs/php_codesniffer": "^3.7"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.0.x-dev"
}
},
"autoload": {
"psr-4": {
"Jcupitt\\Vips\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "John Cupitt",
"email": "jcupitt@gmail.com",
"homepage": "https://github.com/jcupitt",
"role": "Developer"
}
],
"description": "A high-level interface to the libvips image processing library.",
"homepage": "https://github.com/libvips/php-vips",
"keywords": [
"image",
"libvips",
"processing"
],
"support": {
"issues": "https://github.com/libvips/php-vips/issues",
"source": "https://github.com/libvips/php-vips/tree/v2.5.0"
},
"time": "2025-04-04T17:10:13+00:00"
},
{
"name": "jenssegers/agent",
"version": "v2.6.4",

@ -5,6 +5,7 @@ use Spatie\ImageOptimizer\Optimizers\Jpegoptim;
use Spatie\ImageOptimizer\Optimizers\Optipng;
use Spatie\ImageOptimizer\Optimizers\Pngquant;
use Spatie\ImageOptimizer\Optimizers\Svgo;
use Spatie\ImageOptimizer\Optimizers\Cwebp;
return [
/*
@ -15,7 +16,7 @@ return [
Jpegoptim::class => [
'-m' . (int) env('IMAGE_QUALITY', 80),
'--strip-all', // this strips out all text information such as comments and EXIF data
'--strip-exif', // this strips out EXIF data
'--all-progressive', // this will make sure the resulting image is a progressive one
],
@ -38,6 +39,13 @@ return [
'-b', // required parameter for this package
'-O3', // this produces the slowest but best results
],
Cwebp::class => [
'-m 6', // for the slowest compression method in order to get the best compression.
'-pass 10', // for maximizing the amount of analysis pass.
'-mt', // multithreading for some speed improvements.
'-q 90', // quality factor that brings the least noticeable changes.
],
],
/*

Loading…
Cancel
Save