Les PDF c’est chouette pour transmettre des documents non-modifiables. Mais parfois, c’est aussi pratique de pouvoir en suggérer leur contenu. C’est d’autant plus pertinent si vous en proposez à télécharger et que la couverture alléchante dispose d’un fort pouvoir de conviction.
Par chance, nous n’avons pas besoin de faire le sale travail à la main. Du genre prendre une capture d’écran de la première page du PDF ou je ne sais quelle autre astuce impliquant travail et effort. Image Magick est là pour nous aider et à plus forte raison, Imagick. Il s’agit d’une librairie native à PHP se basant sur l’API d’Image Magick.
Vous me direz : oui mais Image Magick c’est fait pour manipuler des images. Certes mais un PDF, c’est un peu comme une image.
Convertir un PDF mono-page
Partons d’un cas simple : votre PDF ne contient qu’une page. Le code est d’une grande simplicité :
<?php
$im = new Imagick('/chemin/vers/pdf-mono-page.pdf');
$im->writeImage('/chemin/vers/couverture.png');
2 lignes ont suffit à créer notre prévisualisation. Cette manipulation enregistre une image au format PNG sans aucune compression. Nous pourrions l’activer et régler le taux de compression avec 2 lignes supplémentaires :
$im->setCompression(Imagick::COMPRESSION_LZW);
$im->setCompressionQuality(90);
LZW est un algorithme de compression sans perte utilisé entre autre par PNG et GIF. On aurait pu choisir du JPEG sans perte ou une autre constante de compression d’Image Magick.
Convertir un PDF multi-pages
Que se passerait-il si notre code précédent était utilisé sur un PDF contenant plus d’une page ? Et bien seule la dernière page du document serait enregistrée. En fait, toutes les pages seraient enregistrées jusqu’à la dernière (pas terrible côté performances donc).
L’API d’Image Magick nous permet toutefois de connaître le nombre d’images impliquées et d’en définir l’index. Depuis PHP5, Imagick fournit des méthodes propres aux interfaces Iterator et Traversable.
Notre code bouge … mais pas tant que ça. Disons que nous souhaitons prévisualiser la 6ème page du document (donc l’index 5) :
$im = new Imagick('/chemin/vers/pdf-multi-pages.pdf');
$im->setIteratorIndex(5);
$im->setCompression(Imagick::COMPRESSION_LZW);
$im->setCompressionQuality(90);
$im->writeImage('/chemin/vers/couverture.png');
Une petite ligne de plus fait l’affaire. Pour compter le nombre d’images contenues dans le document ouvert, un appel à la méthode getNumberImages fera l’affaire.
Convertir directement avec Image Magick : convert
Pour les amateurs du shell ou les détracteurs de PHP, on peut arriver aux mêmes résultats en 1 ligne de commande. L’outil de conversion est fourni par convert. Sa documentation et ses options sont particulièrement riches. On peut tout faire … ou presque !
convert /chemin/vers/pdf-mono-page.pdf /chemin/vers/couverture.png
convert /chemin/vers/pdf-multi-pages.pdf[5] /chemin/vers/couverture.png
La seule différence réside dans les crochets suivant le nom du fichier d’entrée. Vous avez bien sûr deviné qu’il s’agit de l’index du document PDF que l’on convertit. Si on ne précise rien, convert convertira toutes les pages du document mais cette fois, en les exportant dans des fichiers uniques (pas de réécriture qui tienne).
Conclusion
Image Magick est vraiment une application sympathique. Les possibilités de manipulation offertes surpassent à mes yeux largement celles de la librairie GD (qui est toujours mieux que rien).
Cette manipulation permettrait aussi de décomposer les multiples images composant un GIF animé ou un APNG. Ou inversement, nous pourrions créer une animation à partir de plusieurs images. Ou encore créer une vignette carrée et centrée. Les possibilités ne manquent pas.
C’était également une autre façon de teaser le projet le plus chronophage qui m’ait été donné de connaître mais bon, en septembre c’est dans les bacs. Toujours pas d’idées sur le sujet couvert ?



















Commentaires & rétroliens
les blogs ?
Mis à part ça excellent article.
Je ne connaissais pas cette librairie, et pour exploiter les possibilités d’image magick, c’est excellent
Bonjour,
La simple conversion avec la commande convert ne me satisfaisant pas (basse qualité) je passe d’abord par la conversion du PDF en image haute résolution avec la commande pdftoppm (disponible après installation de XPDF), qui permet de choisir la résolution de sortie.
Un coup de convert ensuite pour passer à un format compressé.
Même avec le paramètre « resample » ça ne te convient pas ? Je ne m’en étais pas rendu compte car j’ai toujours cherché à réduire la résolution (pour des vignettes).
C’est bon à savoir.
L’option resample marche assez sur les bitmaps du PDF mais le problème avec un convert directement à partir d’un PDF c’est que ça pixellise très mal le texte vectorisé.
Voilà deux exemples, la première conversion avec Image Magick, on peut observer un aliasing trop important sur le texte et même sur la conversion des bitmaps :
http://img3.imageshack.us/img3/5483/imimg.jpg
Le deuxième expemple, plus convaicant en passant d’abord par pdftoppm :
http://img37.imageshack.us/img37/873/xpdfimg.jpg
En effet, c’est flagrant !
Bonjour !
je suis tombe sur cet article en cherchant a faire des vignettes des pdfs de mon site. c’est assez formidable imagemagick, je l’utilise pour d’autres usages et je ne savais pas qu’il gerait des pdfs, ca fait de cette lib un truc encore plus parfait !
neanmoins je l’utilise dans des shell scripts, et je n’avais utilise imagick.
et je me trouve confronte a un probleme : imagick lis *tout* le pdf. donc j’ai des temps de traitement parfois long.
exemple :
$im->setIteratorIndex(0);
permet effectivement d’avoir l’apercu de la premiere page, mais n’empeche pas le chargement complet du pdf, j’ai teste en ligne de commande :
- 7 secondes pour faire ca (pdf de 4 pages) :
convert monpdf.pdf image.jpg
- ~1 seconde pour faire ca :
convert monpdf.pdf[0] image.jpg
mon script php met aussi ~7 secondes pour faire la vignette de la premiere page. je suis a deux doigts de faire un « convert monpdf.pdf[0] -resize blah blah image.jpg » dans un popen ;p
parce que ca commence a me fatiguer de pas pouvoir
L’exemple que tu donnes est du shell ? Car d’après ce que j’ai lu, l’interface ImageMagick en PHP est moins performante car elle charge TOUT le fichier en mémoire, ce que ne fait visiblement pas
convert.Chez moi ça mettait un peu de temps (pareil, peut-être entre 7 et 10 secondes) mais c’était sur un PDF de 300 pages donc c’est compréhensible.
Donc tes temps de traitement me paraissent bien longs.
Le
popenc’est cool mais t’as pas la main sur le retour, non ? (jamais utilisé) Autrement dit ça foire, t’auras pas moyen de le savoir.Selon tes besoins, passer par une approche de file d’attente (job queue) pourrait être bien, si tu n’as pas besoin d’un traitement du fichier en temps réel.
C’est un peu plus lourd mais tu n’as plus la contrainte du temps passé à attendre que la génération se fasse.
avec popen il est possible d’avoir la sortie, c’en est meme principe : ouvrir un pipe sur une commande.
sinon effectivement apres test, des l’instantiation, ca prend 7 secondes.
($im = new Imagick(‘monpdf.pdf’); prends 7 secondes). j’ai fouille l’incomplete documentation pendant un moment et rien ne semble me permettre de faire ca. je fais donc un popen.
sinon mon pdf est une plaquette de pub bourree d’images, ce qui doit expliquer la lenteur de traitement. et le document comporte 6 pages en fait.
du coup, je fais juste la conversion page 0 => jpg en shell, et le reste en php.
Répondre