GD, ImageMagick, libvips : le moteur d’images, cette décision qu’on prend par défaut
Il y a des choix d’infrastructure qu’on ne fait jamais vraiment, on les subit. Le moteur de traitement d’images en fait partie. La plupart des développeurs PHP n’ont jamais choisi GD : il était là, compilé dans PHP, alors ils l’ont utilisé, et la question s’est arrêtée là. C’est compréhensible, et c’est une erreur, parce que ce composant invisible décide en réalité de la vitesse de votre back-office, de la facture mémoire de votre serveur, et de la qualité des images que voient vos visiteurs.
La question devient brûlante dès qu’on quitte le site vitrine pour un vrai pipeline : une médiathèque e-commerce où des marchands téléversent des lots de photos lourdes, qu’il faut décliner en plusieurs tailles responsives et plusieurs formats modernes. Là, le choix du moteur ne se voit plus en millisecondes, il se voit en minutes d’attente, en serveur qui sue, et parfois en serveur qui tombe. Regardons donc sérieusement les prétendants, et pourquoi l’un d’eux mérite, le plus souvent, de devenir votre défaut conscient.
Les prétendants, et ceux qu’on oublie
Trois bibliothèques dominent le paysage PHP, et il faut en nommer une quatrième que tout le monde oublie.
GD est le défaut historique, livré avec la plupart des installations PHP. Il fait le travail de base (redimensionner, recadrer, convertir) et s’arrête là. Ses limites sont réelles : pas de gestion des espaces colorimétriques, et il jette les métadonnées EXIF à l’encodage. C’est l’outil du dépannage, pas de la production exigeante.
ImageMagick, accessible en PHP via l’extension Imagick, est le couteau suisse. Il sait à peu près tout faire : composition, dessin, effets, des centaines d’opérations. C’est l’arsenal complet, et il rend généralement de meilleurs résultats que GD. Sa puissance est aussi son défaut, on y reviendra.
libvips est le prétendant moderne, et le héros de cet article. Conçu pour la vitesse et la frugalité mémoire, il vise non pas l’exhaustivité mais le pipeline de traitement en lot : décoder, redimensionner, convertir, réencoder, vite et sans gaspiller.
Et celui qu’on oublie systématiquement : GraphicsMagick, un fork d’ImageMagick né il y a près de vingt-cinq ans pour être plus léger, plus stable d’API et plus rapide sur certaines opérations. Il existe encore, il est solide, mais sa communauté s’est étiolée et son support des formats récents accuse le retard. Le citer, c’est honnête ; le recommander aujourd’hui, rarement.
La différence d’architecture qui explique tout le reste
Si libvips écrase la concurrence sur la performance, ce n’est pas un détail d’optimisation, c’est une différence de conception fondamentale.
GD et ImageMagick, dans leur fonctionnement classique, chargent l’image entière en mémoire avant de la traiter. Un JPEG de 6000 par 4000 pixels, ce sont 24 millions de pixels décompressés et posés en RAM, qu’on manipule ensuite. C’est simple, c’est intuitif, et ça explose en charge.
libvips fonctionne autrement : en flux et à la demande. Il traite l’image par régions, en bandes, sans jamais la charger entièrement, et il parallélise automatiquement sur plusieurs cœurs. La conséquence est spectaculaire et mesurable : sur du redimensionnement, libvips est typiquement plusieurs fois plus rapide qu’ImageMagick et consomme une fraction de la mémoire, l’écart se creusant à mesure que les images grossissent. La documentation d’Intervention Image, la bibliothèque PHP qui les abstrait tous, le dit sans détour : libvips surpasse les extensions standard que sont GD et Imagick.
Cette architecture en flux est exactement ce qui fait tenir un serveur quand un marchand téléverse vingt photos de 60 mégapixels d’affilée. Là où GD voudrait charger 250 Mo en RAM par image, libvips traite en flux à empreinte quasi constante. La différence n’est pas confort contre inconfort, c’est tenir contre tomber.
Vitesse et mémoire : la vérité contre-intuitive
Il faut tordre le cou à une idée fausse : le temps de génération d’une vignette dépend d’abord de l’image source, pas des dimensions de la vignette à produire. Générer une vignette, c’est décoder la source, rééchantillonner, réencoder. Le décodage traite tous les pixels d’entrée ; le rééchantillonnage les lit pour l’essentiel ; seule la dernière étape, l’encodage de la sortie, dépend de la taille cible, et elle est négligeable. Produire une vignette de 150 ou de 400 pixels depuis la même source coûte donc presque pareil. Ce qui change tout, c’est la source : une vignette tirée d’un 60 mégapixels coûte des dizaines de fois plus qu’une tirée d’un 2 mégapixels.
Là-dessus se greffe une optimisation décisive que GD ignore : le décodage réduit à la lecture. Le format JPEG permet de décoder directement à la moitié, au quart ou au huitième de sa taille, sans jamais matérialiser l’image pleine résolution. libvips et ImageMagick exploitent ce shrink-on-load ; pour une grande source vers une petite cible, le coût d’entrée s’effondre. GD, lui, décode tout à pleine résolution avant de réduire. C’est précisément pourquoi il s’écroule sur les grandes images là où libvips reste léger.
Assez de qualitatif, passons aux chiffres, parce qu’ils sont éloquents. Le benchmark de l’auteur de libvips lui-même, sur une grande image, mesure un pic mémoire de l’ordre de 200 Mo pour libvips contre environ 3 Go pour ImageMagick, soit un facteur 15. Un benchmark plus récent et reproductible, mené sous PHP 8.4 par le module d’images libvips de Drupal sur une source JPEG de 8000 par 5333 pixels, donne des ordres de grandeur convergents : libvips environ trois fois plus rapide que GD pour produire une vignette, et radicalement plus rapide qu’ImageMagick qui décode toujours l’image entière d’abord, avec deux à quatre fois moins de RAM de pic que ce dernier. L’effet le plus parlant est cumulatif : sur un upload de 20 mégapixels avec dix tailles à générer, libvips produit les dix dans le temps qu’ImageMagick met à en produire une. En production réelle, l’équipe de Criteo a documenté un traitement d’images en moyenne 230 % plus rapide, soit environ 3,3 fois plus vite, après migration d’ImageMagick vers libvips.
Que ce benchmark vienne de l’écosystème Drupal n’est d’ailleurs pas anodin. Précisons-le, car la nuance compte : le toolkit par défaut de Drupal core reste GD, et libvips n’y est pas intégré au cœur. Mais il existe désormais un module libvips dédié et soutenu, qui se branche directement sur le système d’images de Drupal core comme une alternative de premier plan à GD et ImageMagick. Quand un CMS aussi installé dans le PHP historique se dote d’un toolkit libvips de première classe, c’est un signal de plus que le monde PHP bascule, doucement mais sûrement.
Voici le récapitulatif, en gardant à l’esprit qu’un benchmark dépend toujours de la machine, de la version et du format :
| Critère | GD | ImageMagick | libvips |
|---|---|---|---|
| Livré avec PHP | Oui | Non (extension Imagick) | Non (dépendance système) |
| Empreinte mémoire | Élevée | Très élevée | Faible (flux) |
| Vitesse sur grande source | Faible | Faible (décode tout) | Excellente |
| Qualité de rééchantillonnage | Médiocre | Bonne | Bonne (Lanczos) |
| Gestion colorimétrique ICC | Non | Oui | Oui |
| AVIF / WebP natifs | Partiel | Oui | Oui |
| Étendue fonctionnelle | Minimale | Maximale | Ciblée pipeline |
| Terrain de prédilection | Dépannage | Manipulation créative | Génération en masse |
Précision sur le « partiel » de GD : son support WebP est complet, c’est l’AVIF qui n’est disponible que depuis PHP 8.1, et seulement si PHP a été compilé avec libavif.
Une honnêteté s’impose pour ne pas survendre : l’avantage de libvips n’est pas universel. Sur de très petites images, son architecture en flux et son ordonnancement de threads introduisent un surcoût qui ne se rentabilise pas, et il peut alors être plus lent et plus gourmand qu’ImageMagick. Des utilisateurs l’ont mesuré : sur une vignette générée depuis une source de quelques centaines de kilooctets, ImageMagick peut le devancer. Le gain de libvips se manifeste sur les grandes sources et à l’échelle, exactement le terrain d’une médiathèque e-commerce, pas sur la miniature isolée d’un avatar. Choisir libvips pour redimensionner trois petites icônes, c’est se tromper de problème ; le choisir pour ingérer des lots de photos lourdes, c’est viser juste.
La qualité, ce critère qu’on néglige
On parle souvent de vitesse, rarement de qualité de sortie, et c’est dommage parce que l’écart est visible à l’œil. libvips offre par défaut un rééchantillonnage de très bonne facture (noyau Lanczos), une gestion correcte des profils colorimétriques ICC, et il sait redimensionner en lumière linéaire, ce qui évite l’assombrissement des dégradés que produisent les moteurs naïfs. Il gère nativement WebP et AVIF, les formats que vous voulez servir en e-commerce pour alléger vos pages.
GD est nettement en retrait sur tous ces points : pas de gestion des espaces colorimétriques, rééchantillonnage plus grossier, et il ne conserve pas les métadonnées EXIF à l’encodage. Sur ce dernier point, une précision pour les pinailleurs : ce n’est pas que GD soit incapable de lire l’EXIF (la fonction exif_read_data existe en PHP), c’est qu’il ne le préserve pas tout seul dans l’image rééchantillonnée ; conserver l’orientation ou les droits d’auteur suppose de relire les données puis de les réinjecter à la main, là où libvips et ImageMagick gèrent la chose nativement. Sur des aplats, des dégradés, des photos produit où la fidélité compte, la différence se voit. Passer de GD à libvips, ce n’est donc pas qu’un gain de vitesse, c’est une meilleure image en sortie.
Le revers honnête : quand ImageMagick garde l’avantage
Soyons justes, parce qu’un panégyrique aveugle ne vaut rien. libvips fait moins de choses qu’ImageMagick, et c’est assumé. Si vous voulez composer dynamiquement, incruster un filigrane complexe, dessiner, faire du montage élaboré ou appliquer des effets exotiques, ImageMagick dispose d’un répertoire bien plus vaste. Pour le pipeline e-commerce standard (redimensionner, recadrer, convertir, optimiser), libvips couvre tout. Pour la manipulation créative, ImageMagick reste plus complet.
La conclusion raisonnable n’est donc pas « libvips partout, jetez le reste ». C’est libvips pour le gros du travail quotidien, la génération de vignettes à la volée ou en lot, et ImageMagick gardé sous le coude pour les cas rares et complexes. GraphicsMagick, lui, ne se justifie que dans des contextes très particuliers où sa légèreté historique compte plus que son retard sur les formats modernes.
libvips déborde largement le monde PHP
Un signe ne trompe pas sur la valeur d’une bibliothèque : ce que les autres écosystèmes en font. Et là, libvips a déjà gagné une bataille que beaucoup de développeurs PHP ignorent.
Dans le monde Node.js, la bibliothèque de traitement d’images de référence, celle que tout le monde recommande, s’appelle Sharp. Or Sharp n’est rien d’autre que libvips habillé en JavaScript : c’est le même moteur C qui tourne dessous. Le meilleur outil d’un écosystème concurrent est donc votre option PHP. Côté Python, l’équivalent dominant est Pillow, héritier de PIL, comparable à ImageMagick en philosophie. Et les services de génération d’images à la demande qui font référence, comme imgproxy ou imaginary, sont eux aussi bâtis sur libvips, tandis que Thumbor s’appuie sur Pillow. Quand un moteur devient le socle des outils de référence de trois écosystèmes, ce n’est plus une mode, c’est un consensus d’ingénierie.
Le cas concret : une médiathèque e-commerce
Descendons dans le réel, parce que c’est là que la théorie se paie ou se rentabilise. Imaginez une médiathèque qui doit ingérer des lots de photos marchandes, en tirer plusieurs tailles responsives et plusieurs formats, sans faire ramer l’upload ni saturer le serveur.
Le bon pipeline ne génère pas dix vignettes par fichier de façon synchrone après chaque envoi : c’est la recette du blocage, ce cauchemar des uploads massifs que connaît tout marchand. Il stocke l’original, en dérive une fois une image de travail à résolution raisonnable (disons 2500 pixels sur le grand côté), et génère ensuite chaque dérivé à la demande, depuis cette image de travail et jamais depuis l’original lourd. Cette règle découle directement de la vérité énoncée plus haut : le coût est dans les pixels source lus, donc on lit une source légère.
Dans ce pipeline, libvips est le bon moteur pour trois raisons cumulées. Sa frugalité mémoire encaisse les uploads lourds sans faire exploser la RAM. Son support natif d’AVIF et de WebP sert directement votre stratégie d’images légères. Et sa qualité de rééchantillonnage produit des vignettes nettes là où GD baverait. Une nuance utile au passage : l’encodage AVIF est coûteux en CPU, donc multiplier les minuscules vignettes en AVIF peut devenir votre vrai goulot, bien plus que la lecture de la source. C’est un arbitrage à surveiller, indépendant du moteur choisi.
En PHP, concrètement
Deux voies s’offrent à vous. La voie directe : la bibliothèque jcupitt/vips, le binding officiel qui s’appuie sur FFI (un composer require jcupitt/vips une fois libvips installé et l’extension FFI activée), vous donne l’accès direct à l’API, c’est le plus performant. Ou, plus confortable, vous passez par une couche d’abstraction : Intervention Image, en version 3, propose un driver libvips officiel. Attention au nom du paquet, c’est exactement le genre de détail qu’on rate : le cœur reste intervention/image, et le driver s’ajoute via composer require intervention/image-driver-vips, à côté des drivers GD et Imagick déjà inclus. Insistons, parce que c’est le vrai tournant : ce driver est désormais officiel et mature, maintenu par le projet lui-même, et c’est probablement le facteur qui va démocratiser libvips dans le monde PHP. Beaucoup de développeurs l’ignorent encore et continuent de croire que le choix se limite à GD ou Imagick, parce que c’était vrai jusqu’à la version 3. Aujourd’hui, vous écrivez votre code de traitement une fois, contre l’abstraction, et vous changez de moteur par une ligne de configuration. Élégant : GD en développement local si l’installation de libvips vous rebute, libvips en production pour la performance, sans toucher au reste de votre code.
Une friction à anticiper, la seule vraie : libvips est une dépendance système, la bibliothèque C qu’il faut installer sur la machine, pas un simple paquet Composer. Sur une infrastructure que vous maîtrisez, c’est une installation triviale, mais c’est une brique de plus à provisionner et à documenter, là où GD est souvent déjà compilé.
Et il y a un piège précis qui mérite un avertissement, parce qu’il fait perdre des heures : les paquets libvips fournis par défaut par les distributions, surtout en environnement conteneurisé (Docker sur base Alpine, ou Ubuntu LTS un peu ancienne), sont fréquemment compilés sans le support AVIF et HEIC. Vous installez libvips, tout semble fonctionner, et vous découvrez en production que la conversion AVIF échoue silencieusement parce que le délégué d’encodage manque. Concrètement, l’écriture de l’AVIF dépend du greffon d’encodage de libheif (le plugin AOM), qui n’est pas toujours embarqué dans le paquet de base. Le module Drupal le documente d’ailleurs sans détour : toutes ses tailles d’images par défaut incluant une étape AVIF, la génération échoue tout court si ce greffon manque. La parade : vérifier les délégués réellement compilés (un vips --vips-config vous le dira), utiliser une image de base récente où le support est présent, ou compiler libvips vous-même avec les bons délégués. Pensez au même contrôle pour libheif si vous voulez accepter les photos HEIC des iPhones, qui constitueront une part énorme des uploads mobiles : son support n’est pas automatique, il dépend de la compilation. C’est le genre de vérification à inscrire dans votre checklist de provisioning, à plus forte raison si vous redéployez la même stack de client en client.
Pourquoi on est passé à côté pendant des années
Je dois une confession : j’ai côtoyé GD et ImageMagick pendant des années sans jamais tomber sur libvips, même en cherchant activement une alternative. Et en y regardant de près, ce n’était pas une faute d’inattention, mais le produit de plusieurs facteurs convergents qui méritent d’être nommés, parce qu’ils expliquent pourquoi un outil excellent peut rester invisible si longtemps.
Premier paradoxe : libvips n’est pas jeune, il est ancien. Né dans les années 1990 dans le contexte très particulier du traitement d’images du patrimoine, l’analyse de peintures et de manuscrits dans des projets de musées, il a vécu deux décennies dans une niche scientifique, totalement hors du radar du développement web. Son ancienneté n’a jamais été une ancienneté grand public. On ne l’a pas raté parce qu’il était immature, on l’a raté parce qu’il était dans une autre pièce de la maison.
Deuxième facteur, le plus déterminant : le pont vers PHP a longtemps été le maillon faible. Le cœur C était excellent depuis longtemps, mais l’accès confortable depuis PHP est récent. Le binding php-vips moderne et maintenu est relativement récent, et surtout son intégration dans l’outil que la majorité des développeurs PHP utilise réellement pour manipuler des images, à savoir le driver libvips officiel d’Intervention Image, n’est arrivée qu’avec la version 3. Avant cela, quand on cherchait une alternative par les canaux normaux, libvips n’apparaissait littéralement pas dans le menu de l’outil qu’on avait sous la main. On ne cherchait pas mal, l’outil ne le référençait pas.
Troisième facteur, le biais d’antériorité du contenu. Tapez « PHP image resize » depuis quinze ans et le web vous renvoie un océan de tutoriels GD, puis ImageMagick, qui ont une empreinte pédagogique massive. libvips, confiné à sa niche, n’a quasiment aucune présence dans ce corpus généraliste. Même une recherche honnête vous ramène toujours aux deux mêmes noms. L’alternative existait, mais elle n’était pas indexée dans la conversation des développeurs web.
Quatrième facteur, et le plus humble à reconnaître : GD et ImageMagick suffisaient. L’avantage de libvips n’est pas fonctionnel, il fait à peu près les mêmes opérations de base, il est dans la performance et la mémoire. Or un avantage qu’on ne voit qu’en charge se vend infiniment moins bien qu’un manque fonctionnel visible. Tant qu’on redimensionne une poignée d’images sur un site classique, GD fait le travail et la question ne se pose pas. libvips ne devient décisif qu’à l’échelle : lots d’uploads, sources de 60 mégapixels, génération massive de dérivés. C’est exactement le contexte qu’on rencontre en bâtissant un vrai moteur e-commerce, et pas avant. La douleur qui rend libvips indispensable est récente dans le parcours de beaucoup d’entre nous. On ne le découvre pas trop tard, on le découvre au moment précis où le projet nous donne enfin la raison de le chercher.
Conclusion : choisir, plutôt que subir
Le verdict est sobre. Pour les traitements qui tournent tous les jours et en volume sur un site sérieux, la génération de vignettes et la conversion de formats, libvips devrait être votre défaut, pour sa vitesse, sa frugalité mémoire et sa qualité de sortie. ImageMagick reste précieux pour les traitements créatifs complexes qui sortent du pipeline standard. GD ne se justifie que pour le dépannage, le développement local, ou un héritage qu’on ne veut pas toucher.
Reste l’argument qu’on entend toujours en faveur de GD : il est universellement installé. Cet argument ne vaut que si vous ne maîtrisez pas votre infrastructure. Or maîtriser sa pile, c’est précisément refuser de laisser un défaut historique décider à votre place. Sur un serveur que vous administrez, provisionner libvips n’est pas un obstacle, c’est une décision. Et une décision d’ingénierie prise consciemment, en pesant l’architecture, la performance et la qualité, vaut toujours mieux qu’un choix subi parce qu’il se trouvait déjà là. Le moteur d’images n’est pas un détail : c’est l’occasion de reprendre la main sur une brique que trop de gens laissent leur outil choisir pour eux.