Agrego archivos iniciales
This commit is contained in:
@@ -0,0 +1,106 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services;
|
||||
|
||||
use Illuminate\Http\UploadedFile;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
|
||||
class ImageOptimizer
|
||||
{
|
||||
/**
|
||||
* Configuracion por carpeta. Una unica fuente de verdad — usada por el
|
||||
* comando optimize:images y por los uploads de los controllers admin.
|
||||
*/
|
||||
public const FOLDERS = [
|
||||
'carousel' => ['maxWidth' => 1600, 'quality' => 82],
|
||||
'noticias' => ['maxWidth' => 1200, 'quality' => 82],
|
||||
'promos' => ['maxWidth' => 1200, 'quality' => 82],
|
||||
'clubes' => ['maxWidth' => 512, 'quality' => 85],
|
||||
'sponsors' => ['maxWidth' => 600, 'quality' => 85],
|
||||
'qr' => ['maxWidth' => 800, 'quality' => 85],
|
||||
];
|
||||
|
||||
private const MIN_RECOMPRESS_BYTES = 100 * 1024;
|
||||
|
||||
/**
|
||||
* Sube el archivo al disk 'public' y lo optimiza in-place.
|
||||
* Retorna el path relativo (ej: "carousel/abc123.jpg").
|
||||
*/
|
||||
public function storeAndOptimize(UploadedFile $file, string $folder): string
|
||||
{
|
||||
$path = $file->store($folder, 'public');
|
||||
|
||||
if (!extension_loaded('gd')) {
|
||||
return $path;
|
||||
}
|
||||
|
||||
$cfg = self::FOLDERS[$folder] ?? null;
|
||||
if (!$cfg) {
|
||||
return $path;
|
||||
}
|
||||
|
||||
$abs = Storage::disk('public')->path($path);
|
||||
$this->optimizeFile($abs, $cfg['maxWidth'], $cfg['quality']);
|
||||
|
||||
return $path;
|
||||
}
|
||||
|
||||
/**
|
||||
* Optimiza un archivo en disco (resize + recompress).
|
||||
* Devuelve [origSize, newSize, newW, newH] o null si no se modifico.
|
||||
*/
|
||||
public function optimizeFile(string $file, int $maxWidth, int $quality): ?array
|
||||
{
|
||||
if (!file_exists($file)) return null;
|
||||
|
||||
$origSize = filesize($file);
|
||||
$info = @getimagesize($file);
|
||||
if (!$info) return null;
|
||||
|
||||
[$w, $h] = $info;
|
||||
$needsResize = $w > $maxWidth;
|
||||
$needsRecomp = $origSize > self::MIN_RECOMPRESS_BYTES;
|
||||
if (!$needsResize && !$needsRecomp) return null;
|
||||
|
||||
$ext = strtolower(pathinfo($file, PATHINFO_EXTENSION));
|
||||
$img = match ($ext) {
|
||||
'jpg', 'jpeg' => @imagecreatefromjpeg($file),
|
||||
'png' => @imagecreatefrompng($file),
|
||||
'webp' => @imagecreatefromwebp($file),
|
||||
default => null,
|
||||
};
|
||||
if (!$img) return null;
|
||||
|
||||
$newW = $w; $newH = $h;
|
||||
if ($w > $maxWidth) {
|
||||
$newW = $maxWidth;
|
||||
$newH = (int) round($h * ($maxWidth / $w));
|
||||
$resized = imagecreatetruecolor($newW, $newH);
|
||||
|
||||
if (in_array($ext, ['png', 'webp'])) {
|
||||
imagealphablending($resized, false);
|
||||
imagesavealpha($resized, true);
|
||||
$transparent = imagecolorallocatealpha($resized, 0, 0, 0, 127);
|
||||
imagefilledrectangle($resized, 0, 0, $newW, $newH, $transparent);
|
||||
}
|
||||
|
||||
imagecopyresampled($resized, $img, 0, 0, 0, 0, $newW, $newH, $w, $h);
|
||||
$img = $resized;
|
||||
}
|
||||
|
||||
ob_start();
|
||||
match ($ext) {
|
||||
'jpg', 'jpeg' => imagejpeg($img, null, $quality),
|
||||
'png' => imagepng($img, null, 9),
|
||||
'webp' => imagewebp($img, null, $quality),
|
||||
};
|
||||
$bytes = ob_get_clean();
|
||||
|
||||
if (strlen($bytes) >= $origSize) {
|
||||
return null;
|
||||
}
|
||||
|
||||
file_put_contents($file, $bytes);
|
||||
return [$origSize, strlen($bytes), $newW, $newH];
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user