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 : 21 169 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



Nos sponsors

Sondage...

CalendriCode

Juillet 2009
LMMJVSD
  12345
6789101112
13141516171819
20212223242526
2728293031  

Consulter la suite du CalendriCode

Comparez les prix Nouvelle version

Photothèque Nouveau !



Développement réalisé par Nicolas SOREL (Nix) avec l'aide de : Cyril DURAND et Emmanuel (EBArtSoft), Merci à Vincent pour ses précieux conseils
CodeS-SourceS.com© Toute reproduction même partielle est interdite sauf accord écrit du Webmaster
CodeS-SourceS.com© est une marque déposée tous droits réservés
Temps d'éxécution de la page : 0,250 sec

Google Coop CodeS-SourceS Google Coop CodeS-SourceS


Certaines images présentes sur le site (notament certains avatars) sont issues des collections IconShock, donc si vous souhaitez utiliser ces icons vous devez les acheter, ne les copiez pas et ne utilisez pas dans vos sites et applications sans les avoir commandé.