Récupérer les dimensions d’un fichier PDF en PHP

Stockage de l’information de dimension

Les dimensions d’un fichier PDF sont stockées dans une unité nommé le « point pica » ou DTP .
Pour résumer, un point pica correspond à 1/72 de pouce. Pour plus d’information, lire ce lien

Conversion de la taille de point pica en millimètre

Un pouce correspond à 25,4 mm

La conversion en millimètre s’obtient donc en multipliant la taille en point pica par 25,4/72
donc, par exemple, si dans un fichier PDF on trouve une taille de 595×842

cela donnera:
595×25,4/72 = 209,90 mm
842×25,4/72 = 297,04 mm

=> Ce qui correspond a un format A4 portrait.

On observera que selon le logiciel utilisé pour la génération du fichier, on aura un variation dans la précision de cette mesure. de même, certains logiciels ajoute derrière ces mesures le format normé (A4 ou autre) correspondant et d’autres non. D’où la difficulté de l’opération.

D’autre part un fichier PDF peut comporter des pages de différentes tailles et/ou orientations.

Récupération de ces information depuis PHP

PHP peut récupérer ces informations via différents outils Linux. Certains donnent une dimension globale, bien souvent la taille de la 1ère page, d’autres au contraire sont capable de vous donner la taille page par page.
Dans presque tout les cas, il faudra filtrer le résultat pour récupérer les informations de hauteur et de largeur.

Plusieurs solutions sont possibles, j’ai choisi pdfinfo pour sa vélocité et ses fonctionnalités.

pdfinfo s’installe avec la commande

sudo apt-get install poppler-utils

ce logiciel, lancé sans parametre renvoi par défaut la taille de la 1ère page ainsi que d’autres informations dont le nombre de pages.
exemple:

pdfinfo test.pdf

nous renvoi:

Title: fichier de test
Subject:
Keywords:
Author: D.FERET
Creator: PDFCreator Version 0.9.9
Producer: GPL Ghostscript 8.70
CreationDate: Fri Sep 27 14:24:08 2013
ModDate: Fri Sep 27 14:24:08 2013
Tagged: no
Form: none
Pages: 3
Encrypted: no
Page size: 595 x 842 pts (A4)
Page rot: 0
File size: 33923 bytes Optimized: no PDF version: 1.4

Ce qui est insuffisant car on récupère que la taille de la 1ère page. Pour demander des informations plus détaillées, on spécifiera la plage de pages a analyser ( donc de 1 à -1 puisque, normalement, on ne connait pas a l’avance le nombre de pages du fichier ):

pdfinfo test.pdf -f 1 -l -1

nous renvoi:

Title: fichier de test
Subject:
Keywords:
Author: D.FERET
Creator:        PDFCreator Version 0.9.9
Producer:       GPL Ghostscript 8.70
CreationDate:   Fri Sep 27 14:24:08 2013
ModDate:        Fri Sep 27 14:24:08 2013
Tagged:         no
Form:           none
Pages:          3
Encrypted:      no
Page    1 size: 595 x 842 pts (A4)
Page    1 rot:  0
Page    2 size: 595 x 842 pts (A4)
Page    2 rot:  0
Page    3 size: 595 x 842 pts (A4)
Page    3 rot:  0
File size: 33923 bytes
Optimized: no
PDF version: 1.4

On observe que les résultats utiles sont noyés dans le texte et il va devoir les extraire grâce a des expressions régulières pour garantir le résultat.

Le script PHP

Au début du script, on lancera la commande avec la commande exec qui permet de récupérer le résultat dans un tableau $lignes:

// série de constante pour constituer plus facilement nos expressions régulières.
CONST ER_SEP = '.*?'; // Séparateur (espace et autre)
CONST ER_FLOAT = '([+-]?\\d*\\.?\\d+)(?![-+0-9\\.])';  // chiffre a virgule ou entier
CONST ER_ENTIER = '(\\d+)';  //nombre entier
CONST ER_ENTIERSIGNE = '([+-]?\\d+)'; //nombre entier avec ou sans signe + ou -

function getDimensionsPDF($nom_du_fichier_pdf){
   $commande = escapeshellcmd('pdfinfo "' . $nom_du_fichier_pdf . '" -f 1 -l -1');
   $lignes = array(); exec($commande,$lignes);

Ensuite 3 cas seront possibles:
La ligne comportant la dimension ET la taille normé
La ligne comportant la dimension SANS la taille normé
La ligne comportant l’information de rotation.

On aura donc besoin de 3 expressions régulières pour récupérer les informations. On passera en revu chaque ligne pour savoir si elle répondent à l’une des 3 expressions.

    // composition des 3 expressions régulières permettant de récupérer les lignes utiles.
    $expRegLigneAvecFormatNorme = "/^Page " . ER_SEP . ER_ENTIER . ER_SEP ."size:" . ER_SEP . ER_FLOAT . ER_SEP . ER_FLOAT . ER_SEP . "pts". ER_SEP . $Format . "$/";
    $expRegLigneSansNorme = "/^Page " . ER_SEP . ER_ENTIER . ER_SEP . "size:" . ER_SEP . ER_FLOAT . ER_SEP . ER_FLOAT . ER_SEP . "pts$/";
    $expRegLigneRotation = "/^Page " .  ER_SEP . ER_ENTIER . ER_SEP . "rot:" . ER_SEP . ER_ENTIERSIGNE . "$/";$pages = [];
    foreach ($lignes as $ligne) {

        if (preg_match($expRegLigneAvecFormatNorme, $ligne, $resultats)) { // ligne avec format normé en bout de ligne
        list(,$numeroPage,$largeur,$hauteur,$format)=$resultats;
        $pages[$numeroPage]["Largeur"] = $this->pts2mm($largeur);
        $pages[$numeroPage]["Hauteur"] = $this->pts2mm($hauteur);
        $pages[$numeroPage]["Format"] = trim($format, '()');

    } elseif (preg_match($expRegLigneSansNorme, $ligne, $resultats)) { // ligne sans format normé
        list(,$numeroPage,$largeur,$hauteur)=$resultats;
        $pages[$numeroPage]["Largeur"] = $this->pts2mm($largeur);
        $pages[$numeroPage]["Hauteur"] = $this->pts2mm($hauteur);

    } elseif (preg_match($expRegLigneRotation, $ligne, $resultats)) { // ligne contenant le numéro de page et la rotation
        list(,$numeroPage,$rotation)=$resultats;
        $pages[$numeroPage]["Rotation"] = $rotation;
    }    
 }
 return $pages;
}

function pts2mm($valeur)
{ //petite fonction qui converti un taille de pts pica en mm
    if (is_numeric($valeur)) {
        return round((float)$valeur * 25.4 / 72);
    }
    return 0;
}

Voila, j’espère que cette méthode pourra vous être utile. A bientôt.

Compter pages couleurs et noires d’un PDF

Voici une routine qui devrait être utile à tout les développeurs d’applications pré-presse. Le principe peut-être retranscrit dans n’importe quel langage et s’appuie sur l’outil ghostscript.

<?php
/**
 * Created by Dominique FERET.
 * Date: 26/08/2014
 * Time: 09:56
 */
/**
 * Fonction qui analyse la nature des pages d'un pdf.
 * @param $nomfichier   => chemin et nom du fichier.
 * @return $this        => retourne un tableau encodé en JSON contenant la liste des pages de chaque type et leur comptes
 */
function analysepdf($nomfichier)
{
    header('content-type: application/json');
    mb_internal_encoding("UTF-8");

    $o = new stdClass();
    if (file_exists($nomfichier)){
        $commande = 'gs  -o - -q -sDEVICE=inkcov "' . $nomfichier . '"';
        $lignes = array();
        exec($commande, $lignes);
        $noir = 0;
        $couleur = 0;
        $blanche = 0;
        $pagesblanches=array();
        $pagesnoires=array();
        $pagescouleurs=array();
        $numeropage=0;
        foreach ($lignes as $ligne) {

            $cyan = substr($ligne, 1, 7);
            $magenta = substr($ligne, 10, 7);
            $yellow = substr($ligne, 19, 7);
            $black = substr($ligne, 28, 7);
            if (is_numeric($cyan)&& is_numeric($magenta) && is_numeric($yellow) && is_numeric($black)){ // si la ligne contient bien une ligne de valeurs
                $numeropage++; // on ajoute 1 a la ligne en cours
                if((($cyan+$magenta+$yellow)==0)){
                    $noir++;
                    if($black==0) {
                        $pagesblanches[]=$numeropage;
                        $blanche++;
                    }
                    $pagesnoires[]=$numeropage;
                }else{
                    $couleur++;
                    $pagescouleurs[]=$numeropage;
                }
            }

        }
        $o->listepagescouleurs=implode(",",$pagescouleurs);
        $o->listepagesnoires=implode(",",$pagesnoires);
        $o->listepagesblanches=implode(",",$pagesblanches);
        $o->totalpages = $numeropage;
        $o->pagesnoires = $noir;
        $o->pagescouleurs = $couleur;
        $o->pagesblanches = $blanche;
    }
    return json_encode($o);
}