Guía práctica de la nueva API Illuminate\Image de Laravel
Laravel News repasa el componente Illuminate\Image incorporado en Laravel 13.20 (PR #59276): redimensionado, recorte, conversión de formato, efectos y almacenamiento mediante una API fluida e inmutable, con ejemplos para avatares y variantes de imagen responsivas.
Laravel News publicó un tutorial sobre el procesamiento de imágenes nativo añadido en Laravel 13.20 a través del componente Illuminate\Image, introducido en el Pull Request #59276 del repositorio laravel/framework. Antes de esto, los desarrolladores dependían de paquetes de terceros para tareas como redimensionar avatares o convertir archivos subidos a WebP.
Los controladores GD e Imagick se apoyan en Intervention Image v4, que se instala por separado con `composer require intervention/image:^4.0`. GD es el controlador predeterminado; Imagick puede activarse globalmente mediante la configuración `images.default` o por llamada con `usingImagick()` o `using('imagick')`. Si se llama a un controlador sin Intervention Image instalado, Laravel lanza una `ImageException` indicando el paquete que falta.
Las imágenes pueden cargarse desde muchas fuentes: `$request->image('avatar')` para archivos subidos (devuelve null si el campo falta o no es un archivo), o mediante los métodos de la fachada `Image`: `fromPath()`, `fromUrl()`, `fromStorage()`, `fromBytes()` y `fromBase64()`, además del atajo `Storage::disk('s3')->image('ruta')`.
Cada transformación devuelve una nueva instancia `Image` inmutable, y nada se procesa hasta que se solicita una salida mediante `store()`, `toBytes()` o `width()`. Esto permite construir una imagen base (por ejemplo con `orient()`, que rota automáticamente según los datos EXIF) y derivar varias variantes, como una miniatura con `cover(300, 300)` y una versión de visualización con `scale(width: 1600)`, sin que una rama afecte a la otra.
Hay cinco métodos de redimensionado disponibles: `cover($a, $h)` recorta para llenar exactamente las dimensiones (ideal para avatares); `contain($a, $h, $fondo)` ajusta la imagen completa dentro del recuadro con relleno opcional; `scale($a, $h)` redimensiona proporcionalmente y nunca amplía (internamente usa `scaleDown()` de Intervention); `resize($a, $h)` fuerza dimensiones exactas y puede distorsionar; `crop($a, $h, $x, $y)` recorta una región en un desplazamiento dado.
Otros ajustes incluyen `rotate()`, `blur()` (0 a 100, por defecto 5), `sharpen()` (0 a 100, por defecto 10), `grayscale()`, `flip()`/`flipVertically()` y `flop()`/`flipHorizontally()`. La conversión de formato se hace con `toWebp()`, `toJpg()`, `toPng()`, `toGif()`, `toAvif()` y `toBmp()`, combinada con `quality()` (1 a 100) para formatos con pérdida. El atajo `optimize()` convierte por defecto a WebP con calidad 70, pero acepta formato y calidad personalizados, por ejemplo `optimize('avif', 60)`. Los formatos de entrada admitidos son JPEG, PNG, GIF, BMP y WebP.
El almacenamiento replica la API UploadedFile de Laravel: `store()`, `storeAs()` y `storePublicly()` escriben en el disco configurado, aplicando automáticamente la extensión correcta según el formato de salida. Para obtener los datos en bruto están `toBytes()`, `toBase64()` y `toDataUri()`, junto con los métodos de inspección `width()`, `height()`, `dimensions()`, `mimeType()` y `extension()`.
Un ejemplo de controlador de avatares valida el archivo subido y luego encadena `orient()->cover(512, 512)->optimize()->storePublicly('avatars', disk: 's3')`. Otro ejemplo genera variantes responsivas iterando sobre los anchos 480, 960 y 1440 con `scale(width: $width)`; como `scale()` nunca amplía, una imagen original de 900px se mantiene en 900px incluso en la iteración de 1440.
La clase `Image` utiliza el trait `Conditionable` de Laravel, por lo que `when()` y `unless()` permiten aplicar transformaciones de forma condicional. Los puntos de extensión incluyen `Image::extend()` para registrar un controlador personalizado y `Image::transformUsing()` para sobrescribir una transformación concreta por controlador, además de implementar el contrato `Illuminate\Contracts\Image\Transformation` para transformaciones totalmente propias.
Algunas advertencias: las instancias Image no se pueden serializar, por lo que enviarlas a un job en cola lanza una `ImageException` (hay que almacenar el archivo y pasar su ruta); el procesamiento es diferido y se cachea tras la primera salida; y los fallos, como formatos no admitidos o archivos indecodificables, lanzan de forma uniforme `ImageException`.
Tribuna de lectores
Aún no hay aportaciones — abre el debate.
Inicia la conversación
Sin cuenta ni contraseña — introduce tu correo y te enviamos un enlace de acceso de un solo uso. ¿Primera vez? Todo se configura automáticamente.
Tu valoración se aplicará automáticamente al iniciar sesión.
Revisa tu bandeja de entrada
Hemos enviado un enlace de acceso a …. Ábrelo en este dispositivo — esta pestaña te conectará automáticamente.
Esperando tu clic …
·