Laravel News a publié un tutoriel sur le traitement d'images intégré nativement à Laravel 13.20 via le composant Illuminate\Image, introduit dans la Pull Request #59276 du dépôt laravel/framework. Auparavant, les développeurs devaient recourir à des paquets tiers pour redimensionner un avatar ou convertir un fichier téléchargé en WebP.

Les pilotes GD et Imagick s'appuient sur Intervention Image v4, à installer séparément avec `composer require intervention/image:^4.0`. GD est le pilote par défaut ; Imagick peut être défini globalement via la configuration `images.default` ou par appel avec `usingImagick()` ou `using('imagick')`. Sans Intervention Image installé, Laravel lève une `ImageException` indiquant le paquet manquant.

Les images peuvent provenir de nombreuses sources : `$request->image('avatar')` pour les fichiers téléchargés (retourne null si le champ est absent ou n'est pas un fichier), ou via les méthodes de la façade `Image` : `fromPath()`, `fromUrl()`, `fromStorage()`, `fromBytes()`, `fromBase64()`, ainsi que le raccourci `Storage::disk('s3')->image('chemin')`.

Chaque transformation renvoie une nouvelle instance `Image` immuable, et rien n'est traité tant qu'une sortie n'est pas demandée via `store()`, `toBytes()` ou `width()`. Cela permet de construire une image de base (par exemple avec `orient()`, qui pivote automatiquement selon les données EXIF) puis de créer plusieurs variantes, comme une miniature via `cover(300, 300)` et une version d'affichage via `scale(width: 1600)`, sans que les branches ne s'influencent mutuellement.

Cinq méthodes de redimensionnement sont disponibles : `cover($l, $h)` recadre pour remplir exactement les dimensions (idéal pour les avatars) ; `contain($l, $h, $fond)` insère l'image entière avec un remplissage optionnel ; `scale($l, $h)` redimensionne proportionnellement sans jamais agrandir (utilise en interne `scaleDown()` d'Intervention) ; `resize($l, $h)` impose des dimensions exactes au risque de déformer l'image ; `crop($l, $h, $x, $y)` découpe une zone à un décalage donné.

D'autres ajustements incluent `rotate()`, `blur()` (0 à 100, par défaut 5), `sharpen()` (0 à 100, par défaut 10), `grayscale()`, `flip()`/`flipVertically()` et `flop()`/`flipHorizontally()`. La conversion de format passe par `toWebp()`, `toJpg()`, `toPng()`, `toGif()`, `toAvif()` et `toBmp()`, combinée à `quality()` (1 à 100) pour les formats avec perte. Le raccourci `optimize()` convertit par défaut en WebP à une qualité de 70, mais accepte aussi un format et une qualité personnalisés, par exemple `optimize('avif', 60)`. Les formats d'entrée pris en charge sont JPEG, PNG, GIF, BMP et WebP.

Le stockage reprend l'API UploadedFile de Laravel : `store()`, `storeAs()` et `storePublicly()` écrivent sur un disque configuré, avec l'extension correcte appliquée automatiquement selon le format de sortie. Pour obtenir les données brutes, on dispose de `toBytes()`, `toBase64()` et `toDataUri()`, ainsi que des méthodes d'inspection `width()`, `height()`, `dimensions()`, `mimeType()` et `extension()`.

Un exemple de contrôleur pour les avatars valide le fichier téléchargé puis enchaîne `orient()->cover(512, 512)->optimize()->storePublicly('avatars', disk: 's3')`. Un autre exemple génère des variantes responsives en itérant sur les largeurs 480, 960 et 1440 avec `scale(width: $width)` — comme `scale()` n'agrandit jamais, une image originale de 900px reste à 900px même lors de l'itération à 1440.

La classe `Image` utilise le trait `Conditionable` de Laravel, permettant à `when()` et `unless()` d'appliquer des transformations de façon conditionnelle. Les points d'extension incluent `Image::extend()` pour enregistrer un pilote personnalisé et `Image::transformUsing()` pour surcharger une transformation donnée par pilote, en complément de l'implémentation du contrat `Illuminate\Contracts\Image\Transformation` pour des transformations entièrement sur mesure.

Quelques précautions à noter : les instances Image ne peuvent pas être sérialisées, donc en envoyer une à un job en file d'attente lève une `ImageException` (il faut stocker le fichier et transmettre son chemin) ; le traitement est différé et mis en cache après la première sortie ; les échecs, comme un format non pris en charge ou un fichier indécodable, lèvent systématiquement une `ImageException`.