La Case de l'Oncle Tom

Développement Web, bonnes pratiques et performances

Créer une vignette d’un PDF avec Image Magick

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.

Exemple de couverture PDF

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 ? ;-)

Votre lecture de l'article Créer une vignette d’un PDF avec Image Magick est terminée. Il y a encore plein de choses à lire ici ... vous voulez des idées ?

Commentaires & rétroliens

  1. nicolas dit :

    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

  2. n3ox dit :

    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é.

  3. fleur dit :

    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

    • Oncle Tom dit :

      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 popen c’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.

  4. fleur dit :

    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.

  5. piouPiouM dit :

    Par curiosité, le chargement d’un PDF via Imagegick entraîne-t-il également le chargement de tout le document PDF si tu précises directement l’index de la page à traiter ?

    $im = new Imagick(‘/chemin/vers/pdf-multi-pages.pdf[5]‘);

Répondre

Balises HTML autorisées : <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>



Thème graphique par LeslyG, intégré par Oncle Tom.
Propulsé par WordPress, Blueprint et WP-LESS.