91 lines
3.1 KiB
PHP
91 lines
3.1 KiB
PHP
<?php
|
|
|
|
namespace App\Support;
|
|
|
|
use Illuminate\Http\UploadedFile;
|
|
use Illuminate\Support\Facades\Storage;
|
|
use Illuminate\Support\Str;
|
|
|
|
class ImageOptimizer
|
|
{
|
|
private const PRESETS = [
|
|
'cover' => ['w' => 600, 'h' => 900, 'quality' => 92],
|
|
'banner' => ['w' => 1920, 'h' => 1080, 'quality' => 90],
|
|
'thumbnail' => ['w' => 854, 'h' => 480, 'quality' => 88],
|
|
'site_banner'=> ['w' => 1920, 'h' => 600, 'quality' => 90],
|
|
'avatar' => ['w' => 400, 'h' => 400, 'quality' => 92],
|
|
'default' => ['w' => 1920, 'h' => 1920, 'quality' => 92],
|
|
];
|
|
|
|
public static function store(UploadedFile $file, string $folder, string $preset = 'default'): string
|
|
{
|
|
if (!extension_loaded('gd')) {
|
|
return $file->store($folder, 'public');
|
|
}
|
|
|
|
try {
|
|
$cfg = self::PRESETS[$preset] ?? self::PRESETS['default'];
|
|
$path = $file->getRealPath();
|
|
$mime = mime_content_type($path);
|
|
|
|
$src = match (true) {
|
|
str_contains($mime, 'jpeg'), str_contains($mime, 'jpg') => @imagecreatefromjpeg($path),
|
|
str_contains($mime, 'png') => @imagecreatefrompng($path),
|
|
str_contains($mime, 'webp') => @imagecreatefromwebp($path),
|
|
str_contains($mime, 'gif') => @imagecreatefromgif($path),
|
|
default => false,
|
|
};
|
|
|
|
if (!$src) {
|
|
return $file->store($folder, 'public');
|
|
}
|
|
|
|
[$origW, $origH] = [imagesx($src), imagesy($src)];
|
|
|
|
// Scale down only — never upscale
|
|
$ratio = min(1.0, $cfg['w'] / $origW, $cfg['h'] / $origH);
|
|
$newW = (int) round($origW * $ratio);
|
|
$newH = (int) round($origH * $ratio);
|
|
|
|
$dst = imagecreatetruecolor($newW, $newH);
|
|
|
|
// Preserve transparency for PNG
|
|
if (str_contains($mime, 'png')) {
|
|
imagealphablending($dst, false);
|
|
imagesavealpha($dst, true);
|
|
$transparent = imagecolorallocatealpha($dst, 0, 0, 0, 127);
|
|
imagefilledrectangle($dst, 0, 0, $newW, $newH, $transparent);
|
|
}
|
|
|
|
imagecopyresampled($dst, $src, 0, 0, 0, 0, $newW, $newH, $origW, $origH);
|
|
imagedestroy($src);
|
|
|
|
// Output as WebP if supported, else JPEG
|
|
$ext = function_exists('imagewebp') ? 'webp' : 'jpg';
|
|
$filename = $folder . '/' . Str::uuid() . '.' . $ext;
|
|
|
|
ob_start();
|
|
if ($ext === 'webp') {
|
|
imagewebp($dst, null, $cfg['quality']);
|
|
} else {
|
|
imagejpeg($dst, null, $cfg['quality']);
|
|
}
|
|
$bytes = ob_get_clean();
|
|
imagedestroy($dst);
|
|
|
|
Storage::disk('public')->put($filename, $bytes);
|
|
|
|
return $filename;
|
|
} catch (\Throwable) {
|
|
return $file->store($folder, 'public');
|
|
}
|
|
}
|
|
|
|
public static function delete(?string $path): void
|
|
{
|
|
if ($path && !MediaUrl::isExternal($path)) {
|
|
Storage::disk('public')->delete($path);
|
|
}
|
|
}
|
|
}
|