begin process at 2008 07 25 13:00:29
1 216 226 membres
190 nouveaux aujourd'hui
14 180 membres club

Vous ne trouvez pas de réponse à votre problème ? Alors posez la question dans le forum.
Souvenez-vous qu'il n'y a jamais de question bête, mais rester dans l'ignorance parce que l'on n'ose pas poser une question, ça c'est une erreur !

EXTRACTION DU CONTENU D'UN DOCUMENT PDF (PDF-1.4)


Information sur le tutorial

Catégorie :Tutoriaux Date de création : 30/12/2007 16:11:13 Vu : 9 351 fois

Note :
Aucune note

Commentaire sur cette source (18)
Ajouter un commentaire et/ou une note

Description

Il s'agit d'une méthode permettant d'extraire les données d'un document PDF (pour une recherche dans des documents par exemple).

Cette dernière est basique, dans le sens où elle ne fonctionnera qu'avec des PDFs de la version 1.4, non cryptés et contenant seulement du texte. Le but est de présenter la méthode, ceci dit libre à vous de l'augmenter pour traiter les images, liens, etc...

Pas tout à fait une source, je vous la propose en tutorial.

Tutorial

Suite à une question du forum ( http://www.phpcs.com/infomsg_PDF-BASE-DONNEE_1053006.asp ) je me suis demandé comment est-ce que fonctionnait un fichier PDF...

Si on regarde la source d'un fichier PDF dans un éditeur du type notepad++, on y trouvera différentes informations. La première étant la version du fichier.

Exemple:

%PDF-1.4
%Çì¢
5 0 obj
<</Length 6 0...

Plus loin, on trouve énormément de signes bizarres, il s'agit du contenu du PDF compressé et, en bas de fichier on trouvera des lignes comme:

/CreationDate(D:20071230102921+01'00')
/ModDate(D:20071230102923)
/Title(\376\377\000P\000D\000F\000 \000d\000e\000 \000t\000e\000s\000t)
...

Il n'est pas difficile de se rendre compte que nous avons là les propriétés du PDF, écritent lettre par lettre, chacune commençant par \000. Nous pouvons donc déjà récupérer les propriétés CreationDate,  ModDate, Title, Creator, Author, Keywords et Subject en faisant quelques manipulations (cf code plus bas).

Pour récupérer le texte, il faut d'abord l'isoler: il est entouré des balises stream et endstream:

stream
xo­UËN[1...-~xô!OÓ>oiô­>ûÑw,Rúî«endstream

Une fois isolé, il faut le décompresser. Dans le cas présent la compression est standard (on trouve une balise Filter en regardant le contenu du PDF, cette dernière indique la compression utilisée)

<</Length 6 0 R/Filter /FlateDecode>> (cf http://en.wikipedia.org/wiki/DEFLATE_%28algorithm%29 )

Après l'avoir décompressée en utilisant gzuncompress, le contenu du fichier PDF apparaît au format PS. Si on y regarde de plus près, on y voit des lignes comme celle-ci:

[(A)-2.7801(u)-2.7801( )-2.77991(p)-2.77991(l)-2.77991(a)-2.77954(i)-2.77991(s)-2.78065(i)-2.77991(r)-2.77991(,)600]TJ

En observant cette ligne, on remarque entre parenthèses des lettres qui, une fois isolées, font la phrase "Au plaisir".
En systématisant ce principe, on récupère tout le texte du PDF!

 

Voici un essai que j'ai fait chez moi. J'ai cherché à extraire les données du PDF suivant:

En exécutant le bout de code en fin de page, j'ai obtenu ceci:

Date de création: Sunday, 30 December 2007 10:29:21
Date de modification: Sunday, 30 December 2007 10:29:23
Titre du fichier: PDF de test
Création du fichier: PDFCreator Version 0.9.3
Auteur: Malik7934
Mots clés: (non renseigné)
Sujet: Un petit bonjour

Contenu textuel:
new 2 dimanche, 30. décembre 2007 10:28 Bonjour, Voici un fichier PDF tout simple Au plaisir, Malik7934

 

Et voici le code:


<?php

function openPDF($filename){
    $handle = fopen($filename,"rb");
    $content = fread($handle, filesize($filename));
    fclose($handle);
    return $content;
}

function versionPDF($content){
    $p1 = strpos($content,'%')+1;
    $p2 = strpos($content,'%',$p1)-2;      
    $version=substr($content,$p1,$p2);
    return strcmp(trim($version),'PDF-1.4');
}

function getPDFDate($type){
    if (strcmp($type,'cre')==0)    $input = '/CreationDate';
    if (strcmp($type,'mod')==0)    $input = '/ModDate';
    global $content;
    $p1 = strpos($content,$input)+1;
    $p2 = strpos($content,0x2F,$p1);
    $line = substr($content,strlen($input)+$p1,$p2-$p1-2-strlen($input));
    $row = substr($line,2,14);
    $date = date('l, d F Y H:i:s',mktime(substr($row,8,2),substr($row,10,2),substr($row,12,2),substr($row,4,2),substr($row,6,2),substr($row,0,4)));
      
    return $date;
}

function getPDFInfo($type){
    if (strcmp($type,'tit')==0)    $input = '/Title';
    if (strcmp($type,'cre')==0)    $input = '/Creator';
    if (strcmp($type,'aut')==0)    $input = '/Author';
    if (strcmp($type,'key')==0)    $input = '/Keywords';
    if (strcmp($type,'sub')==0)    $input = '/Subject';
    global $content;
    $p1 = strpos($content,$input)+1;
    if (strcmp($type,'sub')==0){ $s1 = '>>';$s2 = 1;}
    else{ $s1 = 0x2F; $s2 = 2;}
    $p2 = strpos($content,$s1,$p1);
    $line = substr($content,strlen($input)+$p1,$p2-$p1-$s2-strlen($input));
    $line = preg_replace("/\\\[0-9]{3}/",'',$line);
    if (trim($line)=='') $line = '(non renseigné)';
  
    return $line;
  
}
  
function getPDFContent($content,$start,$end){
    $s1 = 0;
    $e1 = 0;
    $objc = array();
  
    while ($s1 !== false && $e1 !== false){
        $s1 = strpos($content,$start,$e1)+(strlen($start)+1);
        if ($s1 !== false){
            $e1 = strpos($content,$end,$s1);
            if ($e1 !== false)
                $objc[] = substr($content,$s1,$e1-$s1);
        }
    }
  
    return $objc;
}

function extractText($content){
    $obj = array();
    $ret = array();
    $mots = array();
  
    preg_match_all('`\[([^\]]+)\]TJ`', $content, $obj);

    for ($i=0;$i<count($obj[0])-1;$i++){
        preg_match_all('`\((.){1}\)`', $obj[1][$i], $mots[$i]);
      
        $ret[] = implode('',$mots[$i][1]);
    }

    $ret = implode(' ',$ret);
  
    return $ret;

}

function getPDFText($content){
    $gc = getPDFContent($content,'obj','endobj');
    $gc_size = count($gc);
    $streams = array();
    for ($i=0;$i<$gc_size;$i++){
        $sc = getPDFContent($gc[$i],'stream','endstream');
        if (!empty($sc)){
            $streams[] = $sc;
        }
    }
    if (count($streams)>0){
        return extractText(gzuncompress(trim($streams[0][0])));
    }
  
}
/************************************/

// 1. Ouverture du PDF

$filename = 'test.pdf';
$content = openPDF($filename);

// 2. Vérification de la version du PDF - seule 1.4 est supportée

if (versionPDF($content)!=0)
    echo 'Cette source n\'est pas été conçue/testée pour d\'autres versions que la version PDF-1.4.<br />Votre fichier a la version '.$version.', désolé';
else{

    // 3. Récupération des propriétés CreationDate,  ModDate, Title, Creator, Author, Keywords et Subject

    $creDate     = getPDFDate('cre'); echo 'Date de création: '.$creDate.'<br />';
    $modDate     = getPDFDate('mod'); echo 'Date de modification: '.$modDate.'<br />';
    $title         = getPDFInfo('tit'); echo 'Titre du fichier: '.$title.'<br />';
    $creator     = getPDFInfo('cre'); echo 'Création du fichier: '.$creator.'<br />';
    $author     = getPDFInfo('aut'); echo 'Auteur: '.$author.'<br />';
    $keywords     = getPDFInfo('key'); echo 'Mots clés: '.$keywords.'<br />';
    $sujet         = getPDFInfo('sub'); echo 'Sujet: '.$sujet.'<br /><br />';
  
    //4. Récupération du contenu du PDF  

    $contenu    = getPDFText($content); echo 'Contenu textuel:<br />'.$contenu;
}
?>

 

Remarque importante:
Ne croyez pas pouvoir utiliser ce code tel quel pour par exemple parser vos fichiers PDFs lors de recherches sur votre site. Plusieurs raisons vont l'empêcher: ce code ne fonctionne que avec PDF-1.4, il ne traite pas les cas cryptés et ne gère que du texte pur.

Le but de ce code est de mettre sur la voie ceux qui seraient intéressés d'aller plus loin en observant le contenu des PDFs et en lisant la doc proposée par Adobe :-)

En espérant que ce petit code/tutoriel serve à quelqu'un!!!

Au plaisir,
Malik7934

30 décembre 2007 16:15:32 :
mise en page
  • signaler à un administrateur
    Commentaire de malik7934 le 30/12/2007 20:08:47

    Ne pouvant plus éditer mon tuto (?!?!?) je passe par les commentaires pour une petite correction:

    FAUX:
    if (versionPDF($content)!=0)
        echo 'Cette source n\'est pas été conçue/testée pour d\'autres versions que la version PDF-1.4.<br />Votre fichier a la version '.$version.', désolé';

    JUSTE:
    if (versionPDF($content)!=0)
        echo 'Cette source n\'est pas été conçue/testée pour d\'autres versions que la version PDF-1.4.<br />Votre fichier a la version '.(versionPDF($content)).', désolé';

  • signaler à un administrateur
    Commentaire de malalam le 30/12/2007 21:59:10 administrateur CS

    Hello,

    très sympa et très instructif ton tuto, Malik, merci beaucoup :-)
    J'espère que ça donnera à d'autres l'envie de creuser un peu! Il est très intéressant de s'attaquer aux applicatifs courants via PHP et le web en général. PDF, EXCEL, RTF etc... :-)

  • signaler à un administrateur
    Commentaire de malalam le 30/12/2007 22:00:23 administrateur CS

    Ah, oui, les tuto ont de petits ratés aujourd'hui en effet. Tu devrais pouvoir éditer ton tuto plus tard.
    Moi par exemple, je n'arrive plus à voter sur les tutos, aujourd'hui ! Je réessaye quand même, et te donne ma note de toute manière : 10.

  • signaler à un administrateur
    Commentaire de malik7934 le 31/12/2007 14:49:07

    Merci!

    En plus le post pour une correction que j'ai fait est faux! Honte à moi! Anyway, c'est juste du custom...

  • signaler à un administrateur
    Commentaire de Arnotic le 03/01/2008 14:03:44 administrateur CS

    Les données entre les "balises" "stream" et "endstream" ne représentent pas forcément du texte. Ce peut être une image, une font, des dessins, des sons, des videos, ... De plus entre c'est balises il y a toute les commandes de PDF qui sont présente Tj, Tw, ... Les différentes cadres etc...

    Si tu veux plus d'info sur le format PDF : http://www.adobe.com/devnet/acrobat/pdfs/pdf_reference.pdf

    En fait il te faudrait lire le "xref" du fichier PDF et qui te permettrai ensuite de remonter jusqu'a lobjet de la page qui lui contient les données de la page. Et après parser un mininum le format PDF.

    Je travail sur le PDF depuis plusieurs mois pour le développement d'une librairie permettant de créer des fichiers dans ce format. Je poserai bientôt une source exemple d'utilisation de la librairie sur CPPFrance.com

    Ceci dis c'est un bon début. A creuser.

  • signaler à un administrateur
    Commentaire de malik7934 le 03/01/2008 17:02:44

    Salut Arnotic,

    Tes remarques sont justes et je suis passé par la référence que tu proposes. Ceci dit, dans ce petit tuto je précise bien que je m'intéresse uniquement à des PDFs contenant que du texte et que mon but et de récupérer que le texte, aucune autre info.

    Je me réjouis de voir ta librairie car j'ai hésité à me lancer dans cette aventure, mais au vu des spécifications du PDF je me suis dit que je n'avais pas des mois de dispo pour ça :-)

  • signaler à un administrateur
    Commentaire de Arnotic le 05/01/2008 02:01:18 administrateur CS

    Une première version que je vous livre : http://www.cppfrance.com/codes/CREATION-FICHIER-PDF_45309.aspx

  • signaler à un administrateur
    Commentaire de webmasters62 le 09/01/2008 09:46:08

    Bonjour,

    dite moi serait -il possible de faire la même chose sous windev ?
    Et aussi pouvez vous me dire quel est le langage utilisé pour un pdf car quand j'ouvre un pdf avec notepad++ j'ai pareil que vous, quelque chose identique à ceci :
    stream xo­UËN[1...-~xô!OÓ>oiô­>ûÑw,Rúî« endstream

    donc je voudrais savoir la table de codage utilisé ( ASCII,ISO,ect... ) pour ensuite la convertir en ANSI ( windows ) ou si windev a déjà une commande toute faite, pouvez vous me la donner s'il vous plait.

    J'avais pensé aussi à intégrer le code php ci dessus dans une page php et créer un champ html sous windev ( le php marche même si c'est un champ html sous windev ) et mettre la page php dans le champ html.

  • signaler à un administrateur
    Commentaire de malik7934 le 09/01/2008 09:49:49

    Je ne connais pas Windev, désolé.

    Les specs du format PDF sont dispo ici: http://www.adobe.com/devnet/acrobat/pdfs/pdf_reference.pdf

    Le contenu des PDFs est du PS compressé

  • signaler à un administrateur
    Commentaire de Arnotic le 09/01/2008 23:10:33 administrateur CS

    Windev permet bien de créer ou lire des fichiers, alors oui tout est possible. Et j'ai entendu dire que Windev possède des libs pour gérer le PDF.

  • signaler à un administrateur
    Commentaire de Ruthay le 21/01/2008 18:11:47

    il n y a qu'a ouvrire le document pdf sur adobe illustrator et le tour est joué

  • signaler à un administrateur
    Commentaire de Chgro le 06/03/2008 20:48:45

    Bonjour,

    J'ai un petit souci. J'ai voulu utiliser le bout de code et la partie suivante : [[ if (strcmp($type,'sub')==0){ $s1 = ">>";$s2 = 1;} ]] dans la fonction getPDFInfo pose problème.

    Surtout au niveau du '>>'. A partir du deuxième '>' ça affiche le code directement dans la page. J'utilise Wamp et j'ai aussi essayé avec Xampp et c'est la même chose. Y'a-t-il un caractère d'échappement ou autre chose qu'il faudrait ajouter ?

    A bientôt.

  • signaler à un administrateur
    Commentaire de Chgro le 06/03/2008 21:15:29

    J'ai trouvé. Erreur bête. J'ai crée mon fichier en index.htm au lieu de index.php

    Rien à voir avec le sujet. Désolé pour le dérangement.

    Bye.

  • signaler à un administrateur
    Commentaire de TheWeasel47 le 30/03/2008 21:05:30

    Pas mal du tout, je pense que ton tuto peux faire la paire avec mon code de décomposition des fichiers pdf!
    Bon Courage
    TheWeasel47

  • signaler à un administrateur
    Commentaire de boulika le 03/04/2008 11:54:52

    Tres bonne source mais ne marche pas à tous les coups surtout quand c'est une version supérieur à 1.4.
    Par exemple moi j'ai la source non décompressé qui donne ca et on peut rien faire :

    "x°?]????y???+??l??|#?JV?s??pH?M?&q?yI?7?Oi?? $?????°???????\?"

    Comment faire avec une 1.5 ?

    merci

  • signaler à un administrateur
    Commentaire de marmuriel le 20/05/2008 10:18:18

    Bonjour, ce code m'a beaucoup servi et est tr?s bien fait. Par contre j'ai un petit souci lorsqu'il extrait le contenu du pdf il n'extrait pas tout le texte du pdf. J'ai donc ?tudi? le code pour voir s'il se limitait ? un certain nombre de caract?res mais je n'ai pas trouv?.
    Est-ce que quelqu'un saurait m'aider pour r?soudre ce probl?me car je fais un moteur de recherche donc il faut que mon pdf soit extrait en entier pour chercher dedans ensuite.

    Merci d'avance

  • signaler à un administrateur
    Commentaire de psgkiki le 06/06/2008 09:26:23

    Merci beaucoup pour ce code qui peut servir. J'aimerais vous demander quels sont les changements à faire pour pouvoir lire un PDF 1.6 ? Car en fait, j'ai un PDF avec un formulaire et j'aimerais récupérer les données de ce formulaire.

    Cordialement

  • signaler à un administrateur
    Commentaire de mamro2ter le 04/07/2008 12:48:48

    bonjour,
    ce code est intéressant pour moi pour faire des recherches sur un document.
    Par contre après le test le contenu ne s'affiche pas, juste la premiere partie.
    Voici le contenu de mon fichier:
    test.txt
    page de test pdf. le test a réussi.
    Page
    Voici le resultat:
    Date de création: Monday, 07 April 2008 11:11:45
    Date de modification: Monday, 07 April 2008 11:11:45
    Titre du fichier: lien.txt - Bloc-notes
    Création du fichier: PDFCreator Version 0.9.1
    Auteur: jeanmardelbv@yahoo.fr
    Mots clés: test
    Sujet: test du pdf

    Contenu textuel:


Ajouter un commentaire

Pub



Appels d'offres

Animation Flash alimen...
Budget : 6 000€
Creation portail video
Budget : 3 000€
Site de e-commerce
Budget : 5 000€

CalendriCode

Juillet 2008
LMMJVSD
 123456
78910111213
14151617181920
21222324252627
28293031   

VS Express FR Gratuit !

VS Express en français et 100% gratuit !

Boutique

Boutique de goodies CodeS-SourceS