diff --git a/main/inc/lib/html2pdf/_LGPL.txt b/main/inc/lib/html2pdf/_LGPL.txt new file mode 100644 index 0000000000..e8bec28dfa --- /dev/null +++ b/main/inc/lib/html2pdf/_LGPL.txt @@ -0,0 +1,165 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + + This version of the GNU Lesser General Public License incorporates +the terms and conditions of version 3 of the GNU General Public +License, supplemented by the additional permissions listed below. + + 0. Additional Definitions. + + As used herein, "this License" refers to version 3 of the GNU Lesser +General Public License, and the "GNU GPL" refers to version 3 of the GNU +General Public License. + + "The Library" refers to a covered work governed by this License, +other than an Application or a Combined Work as defined below. + + An "Application" is any work that makes use of an interface provided +by the Library, but which is not otherwise based on the Library. +Defining a subclass of a class defined by the Library is deemed a mode +of using an interface provided by the Library. + + A "Combined Work" is a work produced by combining or linking an +Application with the Library. The particular version of the Library +with which the Combined Work was made is also called the "Linked +Version". + + The "Minimal Corresponding Source" for a Combined Work means the +Corresponding Source for the Combined Work, excluding any source code +for portions of the Combined Work that, considered in isolation, are +based on the Application, and not on the Linked Version. + + The "Corresponding Application Code" for a Combined Work means the +object code and/or source code for the Application, including any data +and utility programs needed for reproducing the Combined Work from the +Application, but excluding the System Libraries of the Combined Work. + + 1. Exception to Section 3 of the GNU GPL. + + You may convey a covered work under sections 3 and 4 of this License +without being bound by section 3 of the GNU GPL. + + 2. Conveying Modified Versions. + + If you modify a copy of the Library, and, in your modifications, a +facility refers to a function or data to be supplied by an Application +that uses the facility (other than as an argument passed when the +facility is invoked), then you may convey a copy of the modified +version: + + a) under this License, provided that you make a good faith effort to + ensure that, in the event an Application does not supply the + function or data, the facility still operates, and performs + whatever part of its purpose remains meaningful, or + + b) under the GNU GPL, with none of the additional permissions of + this License applicable to that copy. + + 3. Object Code Incorporating Material from Library Header Files. + + The object code form of an Application may incorporate material from +a header file that is part of the Library. You may convey such object +code under terms of your choice, provided that, if the incorporated +material is not limited to numerical parameters, data structure +layouts and accessors, or small macros, inline functions and templates +(ten or fewer lines in length), you do both of the following: + + a) Give prominent notice with each copy of the object code that the + Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the object code with a copy of the GNU GPL and this license + document. + + 4. Combined Works. + + You may convey a Combined Work under terms of your choice that, +taken together, effectively do not restrict modification of the +portions of the Library contained in the Combined Work and reverse +engineering for debugging such modifications, if you also do each of +the following: + + a) Give prominent notice with each copy of the Combined Work that + the Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the Combined Work with a copy of the GNU GPL and this license + document. + + c) For a Combined Work that displays copyright notices during + execution, include the copyright notice for the Library among + these notices, as well as a reference directing the user to the + copies of the GNU GPL and this license document. + + d) Do one of the following: + + 0) Convey the Minimal Corresponding Source under the terms of this + License, and the Corresponding Application Code in a form + suitable for, and under terms that permit, the user to + recombine or relink the Application with a modified version of + the Linked Version to produce a modified Combined Work, in the + manner specified by section 6 of the GNU GPL for conveying + Corresponding Source. + + 1) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (a) uses at run time + a copy of the Library already present on the user's computer + system, and (b) will operate properly with a modified version + of the Library that is interface-compatible with the Linked + Version. + + e) Provide Installation Information, but only if you would otherwise + be required to provide such information under section 6 of the + GNU GPL, and only to the extent that such information is + necessary to install and execute a modified version of the + Combined Work produced by recombining or relinking the + Application with a modified version of the Linked Version. (If + you use option 4d0, the Installation Information must accompany + the Minimal Corresponding Source and Corresponding Application + Code. If you use option 4d1, you must provide the Installation + Information in the manner specified by section 6 of the GNU GPL + for conveying Corresponding Source.) + + 5. Combined Libraries. + + You may place library facilities that are a work based on the +Library side by side in a single library together with other library +facilities that are not Applications and are not covered by this +License, and convey such a combined library under terms of your +choice, if you do both of the following: + + a) Accompany the combined library with a copy of the same work based + on the Library, uncombined with any other library facilities, + conveyed under the terms of this License. + + b) Give prominent notice with the combined library that part of it + is a work based on the Library, and explaining where to find the + accompanying uncombined form of the same work. + + 6. Revised Versions of the GNU Lesser General Public License. + + The Free Software Foundation may publish revised and/or new versions +of the GNU Lesser General Public License from time to time. Such new +versions will be similar in spirit to the present version, but may +differ in detail to address new problems or concerns. + + Each version is given a distinguishing version number. If the +Library as you received it specifies that a certain numbered version +of the GNU Lesser General Public License "or any later version" +applies to it, you have the option of following the terms and +conditions either of that published version or of any later version +published by the Free Software Foundation. If the Library as you +received it does not specify a version number of the GNU Lesser +General Public License, you may choose any version of the GNU Lesser +General Public License ever published by the Free Software Foundation. + + If the Library as you received it specifies that a proxy can decide +whether future versions of the GNU Lesser General Public License shall +apply, that proxy's public statement of acceptance of any version is +permanent authorization for you to choose that version for the +Library. diff --git a/main/inc/lib/html2pdf/_balises_html.xls b/main/inc/lib/html2pdf/_balises_html.xls new file mode 100644 index 0000000000..ec70bbff99 Binary files /dev/null and b/main/inc/lib/html2pdf/_balises_html.xls differ diff --git a/main/inc/lib/html2pdf/_lisez_moi.txt b/main/inc/lib/html2pdf/_lisez_moi.txt new file mode 100644 index 0000000000..fbb7b5e094 --- /dev/null +++ b/main/inc/lib/html2pdf/_lisez_moi.txt @@ -0,0 +1,181 @@ +******************************************************* +** Ce programme est distribué sous la licence LGPL, ** +** reportez-vous au fichier _LGPL.txt ou à ** +** http://www.gnu.org/licenses/lgpl.html ** +** pour en savoir plus. ** +** ** +** Copyright 2000-2009 par Laurent Minguet ** +******************************************************* +******************************** +* HTML2PDF v3.22a - 15/06/2009 * +******************************** + +Utilisation : +------------ + - regardez les exemples fournis pour voir le fonctionnement. + + - les formulaires ne marchent QUE avec ADOBE READER 8 et ADOBE READER 9.0 + + - il est TRES IMPORTANT de fournir du HTML 4.01 valide au convertisseur, + mais seulement ce que contient le + + - pour les borders : il est conseillé qu'ils soient au format "solid 1mm #000000" + + - pour les paddings : ils ne sont applicables qu'aux balises table, th, td, div, li + + - la liste des balises HTML reconnues se trouve dans le fichier "_balises_html.xls" + + - la possibilité de protégé vos PDF est présente, CF Exemple 7. Elle utilise le script + fpdf_protection de Klemen Vodopivec. + + - Certaines balises spécifiques ont été introduites : + * (CF Exemple 7) : + permet de définir l'orientation, les marges left, right, top et bottom, l'image + et la couleur de fond d'une page, sa taille et position, le footer. + Il est egalement possible de garder les header et footer des pages précédentes, + grace à l'attribue pageset="old" (CF Exemple 3) + + * (CF Exemple 3) + + * (CF Exemple 3) + + * : + permet de forcer l'affichage d'une partie sur une même page. + Si cette partie ne rentre pas dans le reste de la page, un saut de page est + effectué avant. + + * (CF Exemples 0 et 9) : + permet d'inserer des barcodes dans les pdfs, CF Exemples 0 et 9 + Les types de codebar possible sont : EAN13, UPC_A, CODE39. Ceci utilise les + scripts de The-eh et Olivier + + * (CF Exemples 7 et About) : + permet d'inserer des bookmark dans les pdfs, CF Exemple 7 et About. + Il est egalement possible de créer un index automatiquement en fin de + document, CF exemple About. + Ceci utilise les scripts d'Olivier et de Min's + +Modification : +------------- + 3.22a: redistribution de HTML2PDF sous la licence LGPL !!! (au lieu de GPL) + 3.22 : correction sur le background-color + refonte totale de la gestion de text-align. les valeurs center et right marchent maintenant meme en cas de contenu riche + 3.21 : ajout de la propriété css FLOAT pour la balise IMG + correction sur la gestion des TFOOT + correction sur le positionnement des images + 3.20 : ajout de la gestion des margins pour la balise DIV + ajout de la gestion de la propriete css LINE-HEIGHT + correction sur l'interpretation de la valeur de certains styles CSS (background-image, background-position, ...) + correction sur la reconnaissance des balises thead et tfoot + correction sur la balise select + correction sur les fichiers de langue (merci à Sinan) + 3.19 : optimisation du parseur HTML - merci à Jezelinside + ajout de la balise TFOOT + amélioration de la gestion des tableaux : les contenus des balises THEAD et TFOOT sont maintenant répétés sur chaque page. + ajout de la balise spécifique BOOKMARK afin de créer des "marques-page" + possibilité de rajouter un index automatique en fin de fichier + ajout de la langue turque TR (merci à Hidayet) + amélioration de la méthode Output. Elle est maintenant également utilisable comme celle de FPDF + 3.18 : correction sur les sauts de page automatique pour les balises TABLE, UL, OL + correction sur l'interpretation des styles pour la balise HR + correction sur l'interpretation du style border-collapse pour la balise TABLE + prise en compte de margin:auto pour les tables et les divs + les commentaires dans les CSS sont acceptés + 3.17 : ajout de la gestion des balises INPUT (text, radio, checkbox, button, hidden, ...), SELECT, OPTION, TEXTAREA (cf exemple 14) + ajout de la possibilité de mettre des scripts dans le pdf, via $html2pdf->pdf->IncludeJS(...); (cf exemples JS) + correction sur le saut de page automatique pour les images + correction sur les sauts de lignes automatiques pour certaines balises (UL, P, ...) + ajout de la langue NL (merci à Roland) + 3.16 : ajout de la gestion de list-style: none (cf exemple 13) + correction dans la gestion des fontes ajoutées à fpdf (via la méthode AddFont) + nombreuses corrections sur le calcul des largeurs des éléments table, div, hr, td, th + ajout de l'exemple about.php + (pour info, les PDF générés à partir des exemples sont maintenant dans le répertoire /exemples/pdf/, et sont supprimables) + 3.15 : correction sur l'identification des styles en cas de valeurs multiples dans la propriete class + prise en compte de border-radius pour la limite des backgrounds (color et image) + ajout des proprietes CSS border-top-*, border-right-*, border-bottom-*, border-left-* + ajout de la propriété CSS list-style-image (cf exemple 12) + pour la balise table, ajout de l'interprétation de align="center" et align="right" (cf exemple 1) + correction dans le positionnement des images + correction de quelques bugs + ajout d'une fonction d'analyse des ressources HTML2PDFgetTimerDebug (cf début du fichier html2pdf.class.php) + 3.14 : ajout d'une langue (pt : Brazilian Portuguese language) et amelioration de la methode vueHTML (merci à Rodrigo) + correction du positionnement du contenu des DIVs. gestion des proprietes valign et align + ajout de la propriete CSS border-collapse (cf exemple 0) + ajout de la propriete CSS border-radius (cf exemple 1) + correction de quelques bugs + 3.13 : reecriture de la balise hr, avec prise en compte des styles (cf exemple 0) + ajout de la propriete backcolor pour la balise page (cf exemple 9) + ajout des proprietes backleft et backright pour la balise page afin de pouvoir changer les marges des pages (cf exemple 8) + nombreuses corrections sur les balises et les styles + 3.12 : ajout des balises ol, ul, li (cf exemple 12) + correction sur le calcul de la taille des td en cas de colspan et rowspan + ajout de la méthode setTestTdInOnePage afin de pouvoir desactiver le test sur la taille des TD (cf exemple 11) + correction de quelques bugs + 3.11 : ajout des balises div, p, pre, s + gestion des styles CSS position (relative, absolute), left, top, right, bottom (cf exemple 10) + meilleur gestion des border : border-style, border-color, border-width (cf exemple 10) + possibilité d'indiquer les marges par défault, via le constructeur (cf exemple 2) + 3.10a: correction pour compatibilité php4 / php5 + 3.10 : ajout des liens internes (cf exemple 7) + gestion complete des background : image, repeat, position, color (cf exemple 1) + gestion de underline, overline, linethrough (cf exemple 2) + correction de quelques bugs + 3.09 : mise à jour vers fpdf version 1.6, ajout de barcode, correction de l'affichage de certains caractères spéciaux + correction du calcul de la hauteur de ligne de la balise br + detection en cas de contenu trop grand dans un TD + amélioration de la balise page (ajout de l'attribue pageset, avec les valeurs new et old) + ajout de FPDF_PROTECTION, accesible via $pdf->pdf->SetProtection(...) + 3.08 : version opérationnelle de page_header, ajout de page_footer, correction des borders des tableaux + 3.07 : correction de l'interpretation de cellspacing, amélioration de la balise page_header + 3.06 : première gestion de la balise page_header, correction des dimensions des tableaux + 3.05 : ajout de la propriété vertical-align, ajout de la gestion des fichiers de langue + 3.04 : correction du saut de page automatique pour les tableaux. Ajout de propriétés à la balise PAGE + 3.03 : correction de bugs au niveau de la gestion des images PHP par FPDF, meilleure gestion des erreurs + 3.02 : ajout de la gestion des noms des couleurs, correction de la gestion des images générées par php, correction de quelques bugs + 3.01 : correction de quelques bugs, ajout d'une protection pour les balises non existantes + 3.00 : refont totale du calcul des tableaux. Prise en compte des colspan et rowspan + 2.85 : ajout de la propriété cellspacing, nouvelle gestion des padding des tableaux (identique à l'html) + 2.80 : ajout des types de border dotted et dasheds + 2.75 : ajout des top, left, right, bottom pour padding et border + 2.70 : correction de la balise HR, ajout de la propriété padding pour les table, th, td + correction des dimensions, les unités px, mm, in, pt sont enfin réellement reproduites, correction de font-size, border, ... + ajout d'une propriété à la balise page : footer + correction dans l'affichage et le calcul des tables + 2.55 : vérification de la validité du code (ouverture / fermeture) - ajout des unités mm, in, pt + 2.50 : correction de nobreak, des marges, ajout de nombreuses balises + 2.40 : refonte totale de l'identification des styles CSS. Les héritages marchent. + 2.39 : corrections diverses, ajout de certaines propriétés (bgcolor, ...) + 2.38 : meilleur identification des propriétés border et color + 2.37 : nombreuses corrections : balise A, couleur de fond, retour à la ligne, gestion des images dans un texte, ... + 2.36 : ajout des balises STRONG, EM + 2.35 : amélioration de la gestion des feuilles de style + 2.31 : correction de quelques bugs + 2.30 : première version opérationnel des feuilles de style + 2.25 : ajout de la balise LINK pour le type text/css + 2.20 : premier jet de la gestion des feuilles de style, ajout de la balise STYLE + 2.15 : n'interprète plus l'HTML en commentaire + 2.10 : ajout des balises H1 -> H6 + 2.01 : correction de quelques bugs + 2.00 : première version diffusée + +Aide et Support : +---------------- + pour toutes questions et rapport de bug, merci d'utiliser exclusivement le lien de support ci-dessous. + Je ne répondrais à aucune question en dehors, afin que tout le monde puisse profiter des réponses. + +Informations : +------------- + Programmation en PHP4 + + Programmeur : Spipu + email : webmaster@spipu.net + site : http://html2pdf.fr/ + wiki : http://html2pdf.fr/wiki.php + support : http://html2pdf.fr/forum.php + +Remerciement : +------------- + * Olivier PLATHEY pour sa librairie Fpdf (http://www.fpdf.org/) + * yAronet pour l'hebergement du forum de support + * toutes les personnes qui m'ont aidé à développer cet librairie, et à traduire les différents textes diff --git a/main/inc/lib/html2pdf/_read_me.txt b/main/inc/lib/html2pdf/_read_me.txt new file mode 100644 index 0000000000..a89200403e --- /dev/null +++ b/main/inc/lib/html2pdf/_read_me.txt @@ -0,0 +1,79 @@ +********************************************************* +** This program is distributed under the LGPL License, ** +** for more information see file _LGPL.txt or ** +** http://www.gnu.org/licenses/lgpl.html ** +** ** +** Copyright 2000-2009 by Laurent Minguet ** +********************************************************* +******************************** +* HTML2PDF v3.22a - 2009-06-15 * +******************************** + +How to use : +------------ + - Look at the examples provided to see how it works. + + - forms work only with ADOBE READER 8 and 9.0 + + - It is very important to provide valid HTML 4.01 to the converter, + but only what is in the + + - for borders: it is advised that they are like "solid 1mm #000000" + + - for padding, they are applicable only on tags table, th, td, div, li + + - the list of recognized HTML tags is in the file "_balises_html.xls" + + - The possibility to protect your PDF is present, CF Example 7. It uses the script + fpdf_protection of Klemen Vodopivec. + + - Some specific tags have been introduced: + * (CF Exemple 7) : + determines the orientation, margins left, right, top and bottom, the background image + and the background color of a page, its size and position, the footer. + It is also possible to keep the header and footer of the previous pages, + through the attribut pageset="old" (see Example 3) + + * (CF Example 3) + + * (CF Example 3) + + * : + used to force the display of a section on the same page. + If this section does not fit into the rest of the page, a page break is done before. + + * (CF Examples 0 et 9) : + can insert barcodes in pdfs, CF Examples 0 and 9 + The possible types od codebar are: EAN13, UPC_A, CODE39. + This uses the scripts of The-eh and Olivier + + * (CF Examples 7 et About) : + can insert bookmark in pdfs, CF Example 7 and About. + It is also possible to automatically create an index at the end of + documentv CF Example About. + This uses the scripts of Olivier and Min's + +change log : +----------- + see the _lisez_moi.txt file, in french sorry ;) + +Help & Support : +--------------- + For questions and bug reports, thank you to use only the support link below. + I will answer to your questions only on it... + +Informations : +------------- + Programming in PHP4 + + Programmer : Spipu + email : webmaster@spipu.net + web site : http://html2pdf.fr/ + wiki : http://html2pdf.fr/wiki.php + support : http://html2pdf.fr/forum.php + +Thanks : +------- + * Olivier PLATHEY for his library Fpdf (http://www.fpdf.org/) + * yAronet for hosting support forum + * everyone who helped me to develop this library and to bring the texts diff --git a/main/inc/lib/html2pdf/html2pdf.class.php b/main/inc/lib/html2pdf/html2pdf.class.php new file mode 100644 index 0000000000..6566079a23 --- /dev/null +++ b/main/inc/lib/html2pdf/html2pdf.class.php @@ -0,0 +1,4644 @@ + PDF, utilise fpdf de Olivier PLATHEY + * Distribué sous la licence LGPL. + * + * @author Laurent MINGUET + * @version 3.22a - 15/06/2009 + */ + +if (!defined('__CLASS_HTML2PDF__')) +{ + define('__CLASS_HTML2PDF__', '3.22a'); + + // vous pouvez utiliser cette fonction de debug comme suit + // pour voir le temps et la mémoire utilisés (sous linux) pour la conversion : + // echo HTML2PDFgetTimerDebug(); + // $html2pdf->WriteHTML($content); + // echo HTML2PDFgetTimerDebug(); + function HTML2PDFgetTimerDebug($debug=false) + { + global $TIMER_ACTION_LAST; + list($usec, $sec) = explode(" ", microtime()); + $time = (float)$sec + (float)$usec; + $mem = HTML2PDFgetMem(); + + if (!$TIMER_ACTION_LAST) + { + if ($debug) $ret = null; + else $ret = 'Debug : init'."
\n"; + } + else + { + $aff_time = $time-$TIMER_ACTION_LAST[0]; + $aff_mem = $mem; + if ($debug) $ret = array($aff_time, $aff_mem); + else $ret = 'Timer : '.number_format($aff_time, 3, '.', '').'s - Memory used '.$aff_mem.' Ko'."
\n"; + } + $TIMER_ACTION_LAST = array($time, $mem); + return $ret; + } + function HTML2PDFgetMem() { return function_exists('memory_get_usage') ? floor(memory_get_usage()/1024) : 0; } + + require_once(dirname(__FILE__).'/_mypdf/mypdf.class.php'); // classe mypdf dérivé de fpdf de Olivier PLATHEY + require_once(dirname(__FILE__).'/parsingHTML.class.php'); // classe de parsing HTML + require_once(dirname(__FILE__).'/styleHTML.class.php'); // classe de gestion des styles + + global $HTML2PDF_TABLEAU; $HTML2PDF_TABLEAU = array(); // tableau global necessaire à la gestion des tables imbriquées + + class HTML2PDF + { + var $langue = 'fr'; // langue des messages + var $sens = 'P'; // sens d'affichage Portrait ou Landscape + var $format = 'A4'; // format de la page : A4, A3, ... + var $background = array(); // informations sur le background + var $testTDin1page = true; // activer le test de TD ne devant pas depasser une page + + var $style = null; // objet de style + var $parsing = null; // objet de parsing + var $parse_pos = 0; // position du parsing + var $temp_pos = 0; // position temporaire pour multi tableau + + var $sub_html = null; // sous html + var $sub_part = false; // indicateur de sous html + var $isSubPart = false; // indique que le convertisseur courant est un sous html + + var $pdf = null; // objet PDF + var $maxX = 0; // zone maxi X + var $maxY = 0; // zone maxi Y + + var $FirstPage = true; // premier page + + var $defaultLeft = 0; // marges par default de la page + var $defaultTop = 0; + var $defaultRight = 0; + var $defaultBottom = 0; + + var $margeLeft = 0; //marges réelles de la page + var $margeTop = 0; + var $margeRight = 0; + var $margeBottom = 0; + var $marges = array(); + var $Maxs = array(); + + var $maxH = 0; // plus grande hauteur dans la ligne, pour saut de ligne à corriger + var $inLink = ''; // indique si on est à l'interieur d'un lien + var $lstAncre = array(); // liste des ancres détectées ou créées + var $subHEADER = array(); // tableau des sous commandes pour faire l'HEADER + var $subFOOTER = array(); // tableau des sous commandes pour faire le FOOTER + var $subSTATES = array(); // tableau de sauvegarde de certains paramètres + var $defLIST = array(); // tableau de sauvegarde de l'etat des UL et OL + + var $lstChamps = array(); // liste des champs + var $lstSelect = array(); // options du select en cours + var $previousCall = null; // dernier appel + var $isInTfoot = false; // indique si on est dans un tfoot + var $pageMarges = array(); // marges spécifiques dues aux floats + var $isAfterFloat = false; // indique si on est apres un float + var $forOneLine = false; // indique si on est dans un sous HTML ne servant qu'a calculer la taille de la prochaine ligne + + /** + * Constructeur + * + * @param string sens portrait ou landscape + * @param string format A4, A5, ... + * @param string langue : fr, en, it... + * @param array marges par defaut, dans l'ordre (left, top, right, bottom) + * @param boolean forcer la création de la premiere page, ne pas utiliser, c'est utilisé en interne pour la gestion des tableaux + * @return null + */ + function HTML2PDF($sens = 'P', $format = 'A4', $langue='fr', $marges = array(5, 5, 5, 8), $force_page = false) + { + // sauvegarde des paramètres + $this->sens = $sens; + $this->format = $format; + $this->FirstPage = true; + $this->langue = strtolower($langue); + $this->setTestTdInOnePage(true); + + // chargement du fichier de langue + $this->textLOAD($this->langue); + + // création de l' objet PDF + $this->pdf = new MyPDF($sens, 'mm', $format); + + // initialisation des styles + $this->style = new styleHTML($this->pdf); + $this->style->FontSet(); + $this->defLIST = array(); + + // initialisation du parsing + $this->parsing = new parsingHTML(); + $this->sub_html = null; + $this->sub_part = false; + + // initialisation des marges + $this->setDefaultMargins($marges[0], $marges[1], $marges[2], $marges[3]); + $this->setMargins(); + $this->marges = array(); + + // initialisation des champs de formulaire + $this->lstChamps = array(); + + // premier page forcée + if ($force_page) $this->setNewPage($this->sens); + } + + /** + * activer ou desactiver le test de TD ne devant pas depasser une page + * + * @param boolean nouvel etat + * @return boolean ancien etat + */ + function setTestTdInOnePage($mode = true) + { + $old = $this->testTDin1page; + + $this->testTDin1page = $mode ? true : false; + + return $old; + } + + /** + * définir les marges par défault + * + * @param int en mm, marge left + * @param int en mm, marge top + * @param int en mm, marge right. si null, left=right + * @param int en mm, marge bottom. si null, bottom=8 + * @return null + */ + function setDefaultMargins($left, $top, $right = null, $bottom = null) + { + if ($right===null) $right = $left; + if ($bottom===null) $bottom = 8; + + $this->defaultLeft = $this->style->ConvertToMM($left.'mm'); + $this->defaultTop = $this->style->ConvertToMM($top.'mm'); + $this->defaultRight = $this->style->ConvertToMM($right.'mm'); + $this->defaultBottom = $this->style->ConvertToMM($bottom.'mm'); + } + + /** + * définir les marges réelles, fonctions de la balise page + * + * @return null + */ + function setMargins() + { + $this->margeLeft = $this->defaultLeft + (isset($this->background['left']) ? $this->background['left'] : 0); + $this->margeRight = $this->defaultRight + (isset($this->background['right']) ? $this->background['right'] : 0); + $this->margeTop = $this->defaultTop + (isset($this->background['top']) ? $this->background['top'] : 0); + $this->margeBottom = $this->defaultBottom + (isset($this->background['bottom']) ? $this->background['bottom'] : 0); + + $this->pdf->SetMargins($this->margeLeft, $this->margeTop, $this->margeRight); + $this->pdf->cMargin = 0; + $this->pdf->SetAutoPageBreak(false, $this->margeBottom); + } + + /** + * recuperer les positions x minimales et maximales en fonction d'une hauteur + * + * @param float y + * @return array(float, float) + */ + function getMargins($y) + { + $y = floor($y*100); + $x = array($this->pdf->lMargin, $this->pdf->w-$this->pdf->rMargin); + + foreach($this->pageMarges as $m_y => $m_x) + if ($m_y<=$y) $x = $m_x; + + return $x; + } + + /** + * ajouter une marge suite a un float + * + * @param string left ou right + * @param float x1 + * @param float y1 + * @param float x2 + * @param float y2 + * @return null + */ + function addMargins($float, $x1, $y1, $x2, $y2) + { + $old1 = $this->getMargins($y1); + $old2 = $this->getMargins($y2); + if ($float=='left') $old1[0] = $x2; + if ($float=='right') $old1[1] = $x1; + + $y1 = floor($y1*100); + $y2 = floor($y2*100); + + foreach($this->pageMarges as $m_y => $m_x) + { + if ($m_y<$y1) continue; + if ($m_y>$y2) break; + if ($float=='left' && $this->pageMarges[$m_y][0]<$x2) unset($this->pageMarges[$m_y]); + if ($float=='right' && $this->pageMarges[$m_y][1]>$x1) unset($this->pageMarges[$m_y]); + } + + $this->pageMarges[$y1] = $old1; + $this->pageMarges[$y2] = $old2; + + ksort($this->pageMarges); + + $this->isAfterFloat = true; + } + + /** + * définir des nouvelles marges et sauvegarder les anciennes + * + * @param float marge left + * @param float marge top + * @param float marge right + * @return null + */ + function saveMargin($ml, $mt, $mr) + { + $this->marges[] = array('l' => $this->pdf->lMargin, 't' => $this->pdf->tMargin, 'r' => $this->pdf->rMargin, 'page' => $this->pageMarges); + $this->pdf->SetMargins($ml, $mt, $mr); + + $this->pageMarges = array(); + $this->pageMarges[floor($mt*100)] = array($ml, $this->pdf->w-$mr); + } + + /** + * récuperer les dernières marches sauvées + * + * @return null + */ + function loadMargin() + { + $old = array_pop($this->marges); + if ($old) + { + $ml = $old['l']; + $mt = $old['t']; + $mr = $old['r']; + $mP = $old['page']; + } + else + { + $ml = $this->margeLeft; + $mt = 0; + $mr = $this->margeRight; + $mP = array($mt => array($ml, $this->pdf->w-$mr)); + } + + $this->pdf->SetMargins($ml, $mt, $mr); + $this->pageMarges = $mP; + } + + /** + * permet d'ajouter une fonte. + * + * @param string nom de la fonte + * @param string style de la fonte + * @param string fichier de la fonte + * @return null + */ + function AddFont($family, $style='', $file='') + { + $this->pdf->AddFont($family, $style, $file); + } + + /** + * sauvegarder l'état actuelle des maximums + * + * @return null + */ + function saveMax() + { + $this->Maxs[] = array($this->maxX, $this->maxY, $this->maxH); + } + + /** + * charger le dernier état sauvé des maximums + * + * @return null + */ + function loadMax() + { + $old = array_pop($this->Maxs); + + if ($old) + { + $this->maxX = $old[0]; + $this->maxY = $old[1]; + $this->maxH = $old[2]; + } + else + { + $this->maxX = 0; + $this->maxY = 0; + $this->maxH = 0; + } + } + + /** + * afficher l'header contenu dans page_header + * + * @return null + */ + function SetPageHeader() + { + if (!count($this->subHEADER)) return false; + + $OLD_parse_pos = $this->parse_pos; + $OLD_parse_code = $this->parsing->code; + + $this->parse_pos = 0; + $this->parsing->code = $this->subHEADER; + $this->MakeHTMLcode(); + + $this->parse_pos = $OLD_parse_pos; + $this->parsing->code = $OLD_parse_code; + } + + /** + * afficher le footer contenu dans page_footer + * + * @return null + */ + function SetPageFooter() + { + if (!count($this->subFOOTER)) return false; + + $OLD_parse_pos = $this->parse_pos; + $OLD_parse_code = $this->parsing->code; + + $this->parse_pos = 0; + $this->parsing->code = $this->subFOOTER; + $this->MakeHTMLcode(); + + $this->parse_pos = $OLD_parse_pos; + $this->parsing->code = $OLD_parse_code; + } + + /** + * saut de ligne avec une hauteur spécifique + * + * @param float hauteur de la ligne + * @param integer position reelle courante si saut de ligne pendant l'ecriture d'un texte + * @return null + */ + function setNewLine($h, $curr = null) + { + $this->pdf->Ln($h); + + $this->setNewPositionForNewLine($curr); + } + + /** + * création d'une nouvelle page avec une orientation particuliere + * + * @param string sens P=portrait ou L=landscape + * @param array tableau des propriétés du fond de la page + * @param integer position reelle courante si saut de ligne pendant l'ecriture d'un texte + * @return null + */ + function setNewPage($orientation = '', $background = null, $curr = null) + { +/* + if (!$this->FirstPage) + { + $info = debug_backtrace(); foreach($info as $k => $v) { unset($info[$k]['object']); unset($info[$k]['type']); unset($info[$k]['args']);} + echo '
'.print_r($info, true).'

'; + } +*/ + $this->FirstPage = false; + + $this->sens = $orientation ? $orientation : $this->sens; + $this->background = $background!==null ? $background : $this->background; + $this->maxY = 0; + $this->maxX = 0; + + $this->pdf->lMargin = $this->defaultLeft; + $this->pdf->rMargin = $this->defaultRight; + $this->pdf->tMargin = $this->defaultTop; + $this->pdf->AddPage($this->sens); + + if (!$this->sub_part && !$this->isSubPart) + { + if (is_array($this->background)) + { + if (isset($this->background['color']) && $this->background['color']) + { + $this->pdf->SetFillColor($this->background['color'][0], $this->background['color'][1], $this->background['color'][2]); + $this->pdf->Rect(0, 0, $this->pdf->w, $this->pdf->h, 'F'); + } + + if (isset($this->background['img']) && $this->background['img']) + $this->pdf->Image($this->background['img'], $this->background['posX'], $this->background['posY'], $this->background['width']); + } + + $this->SetPageHeader(); + $this->SetPageFooter(); + } + + $this->SetMargins(); + $this->pdf->y = $this->margeTop; + + $this->setNewPositionForNewLine($curr); + } + + /** + * calcul de la position de debut de la prochaine ligne en fonction de l'alignement voulu + * + * @param integer position reelle courante si saut de ligne pendant l'ecriture d'un texte + * @return null + */ + function setNewPositionForNewLine($curr = null) + { + list($lx, $rx) = $this->getMargins($this->pdf->y); + $this->pdf->x=$lx; + + if ( + $this->style->value['text-align']!='right' && + $this->style->value['text-align']!='center' + ) + return null; + + $sub = null; + $this->CreateSubHTML($sub); + $sub->saveMargin(0, 0, $sub->pdf->w-$rx+$lx); + $sub->forOneLine = true; + $sub->parse_pos = $this->parse_pos; + $sub->parsing->code = $this->parsing->code; + + if ($curr!==null && $sub->parsing->code[$this->parse_pos]['name']=='write') + $sub->parsing->code[$this->parse_pos]['param']['txt'] = substr($sub->parsing->code[$this->parse_pos]['param']['txt'], $curr); + else + $sub->parse_pos++; + + // pour chaque element identifié par le parsing + for($sub->parse_pos; $sub->parse_posparsing->code); $sub->parse_pos++) + { + $todo = $sub->parsing->code[$sub->parse_pos]; + if (!$sub->loadAction($todo)) break; + } + + $w = $sub->maxX; + + unset($sub); + if ($this->style->value['text-align']=='center') + $this->pdf->x+= ($rx-$this->pdf->x-$w)*0.5-0.01; + else + $this->pdf->x = $rx-$w-0.01; + } + + /** + * récupération du PDF + * + * @param string nom du fichier PDF + * @param boolean destination + * @return string contenu éventuel du pdf + * + * + * Destination où envoyer le document. Le paramètre peut prendre les valeurs suivantes : + * true : equivalent à I + * false : equivalent à S + * I : envoyer en inline au navigateur. Le plug-in est utilisé s'il est installé. Le nom indiqué dans name est utilisé lorsque l'on sélectionne "Enregistrer sous" sur le lien générant le PDF. + * D : envoyer au navigateur en forçant le téléchargement, avec le nom indiqué dans name. + * F : sauver dans un fichier local, avec le nom indiqué dans name (peut inclure un répertoire). + * S : renvoyer le document sous forme de chaîne. name est ignoré. + */ + function Output($name = '', $dest = false) + { + // nettoyage + global $HTML2PDF_TABLEAU; $HTML2PDF_TABLEAU = array(); + + // interpretation des paramètres + if ($dest===false) $dest = 'I'; + if ($dest===true) $dest = 'S'; + if ($dest==='') $dest = 'I'; + if ($name=='') $name='document.pdf'; + + // verification de la destination + $dest = strtoupper($dest); + if (!in_array($dest, array('I', 'D', 'F', 'S'))) $dest = 'I'; + + // verification du nom + if (strtolower(substr($name, -4))!='.pdf') + { + echo 'ERROR : The output document name "'.$name.'" is not a PDF name'; + exit; + } + + + return $this->pdf->Output($name, $dest); + } + + /** + * création d'un sous HTML2PDF pour la gestion des tableaux imbriqués + * + * @param HTML2PDF futur sous HTML2PDF passé en référence pour création + * @param integer marge eventuelle de l'objet si simulation d'un TD + * @return null + */ + function CreateSubHTML(&$sub_html, $cellmargin=0) + { + // initialisation du sous objet + $sub_html = new HTML2PDF( + $this->sens, + $this->format, + $this->langue, + array($this->defaultLeft,$this->defaultTop,$this->defaultRight,$this->defaultBottom), + true + ); + $sub_html->isSubPart = true; + $sub_html->setTestTdInOnePage($this->testTDin1page); + + $sub_html->style->css = $this->style->css; + $sub_html->style->css_keys = $this->style->css_keys; + $sub_html->style->table = $this->style->table; + $sub_html->style->value = $this->style->value; + $sub_html->style->value['text-align'] = 'left'; + $sub_html->defLIST = $this->defLIST; + $sub_html->style->onlyLeft = true; + + // initialisation de la largeur + if ($this->style->value['width']) + { + $marge = $cellmargin*2; + $marge+= $this->style->value['padding']['l'] + $this->style->value['padding']['r']; + $marge+= $this->style->value['border']['l']['width'] + $this->style->value['border']['r']['width']; + $marge = $sub_html->pdf->w - $this->style->value['width'] + $marge; + } + else + $marge = $this->margeLeft+$this->margeRight; + + $sub_html->saveMargin(0, 0, $marge); + + // initialisation des fontes + $sub_html->pdf->fonts = &$this->pdf->fonts; + $sub_html->pdf->FontFiles = &$this->pdf->FontFiles; + $sub_html->pdf->diffs = &$this->pdf->diffs; + + // initialisation des positions et autre + $sub_html->maxX = 0; + $sub_html->maxY = 0; + $sub_html->maxH = 0; + $sub_html->pdf->setX(0); + $sub_html->pdf->setY(0); + $sub_html->style->FontSet(); + } + + /** + * destruction d'un sous HTML2PDF pour la gestion des tableaux imbriqués + * + * @return null + */ + function DestroySubHTML() + { + + unset($this->sub_html); + $this->sub_html = null; + } + + /** + * Convertir un nombre arabe en nombre romain + * + * @param integer nombre à convertir + * @return string nombre converti + */ + function listeArab2Rom($nb_ar) + { + $nb_b10 = array('I','X','C','M'); + $nb_b5 = array('V','L','D'); + $nb_ro = ''; + + if ($nb_ar<1) return $nb_ar; + if ($nb_ar>3999) return $nb_ar; + + for($i=3; $i>=0 ; $i--) + { + $chiffre=floor($nb_ar/pow(10,$i)); + if($chiffre>=1) + { + $nb_ar=$nb_ar-$chiffre*pow(10,$i); + if($chiffre<=3) + { + for($j=$chiffre; $j>=1; $j--) + { + $nb_ro=$nb_ro.$nb_b10[$i]; + } + } + else if($chiffre==9) + { + $nb_ro=$nb_ro.$nb_b10[$i].$nb_b10[$i+1]; + } + elseif($chiffre==4) + { + $nb_ro=$nb_ro.$nb_b10[$i].$nb_b5[$i]; + } + else + { + $nb_ro=$nb_ro.$nb_b5[$i]; + for($j=$chiffre-5; $j>=1; $j--) + { + $nb_ro=$nb_ro.$nb_b10[$i]; + } + } + } + } + return $nb_ro; + } + + /** + * Ajouter un LI au niveau actuel + * + * @return null + */ + function listeAddLi() + { + $this->defLIST[count($this->defLIST)-1]['nb']++; + } + + function listeGetWidth() { return '7mm'; } + function listeGetPadding() { return '1mm'; } + + /** + * Recuperer le LI du niveau actuel + * + * @return string chaine à afficher + */ + function listeGetLi() + { + $im = $this->defLIST[count($this->defLIST)-1]['img']; + $st = $this->defLIST[count($this->defLIST)-1]['style']; + $nb = $this->defLIST[count($this->defLIST)-1]['nb']; + $up = (substr($st, 0, 6)=='upper-'); + + if ($im) return array(false, false, $im); + + switch($st) + { + case 'none': + return array('arial', true, ' '); + + case 'upper-alpha': + case 'lower-alpha': + $str = ''; + while($nb>26) + { + $str = chr(96+$nb%26).$str; + $nb = floor($nb/26); + } + $str = chr(96+$nb).$str; + + return array('arial', false, ($up ? strtoupper($str) : $str).'.'); + + case 'upper-roman': + case 'lower-roman': + $str = $this->listeArab2Rom($nb); + + return array('arial', false, ($up ? strtoupper($str) : $str).'.'); + + case 'decimal': + return array('arial', false, $nb.'.'); + + case 'square': + return array('zapfdingbats', true, chr(110)); + + case 'circle': + return array('zapfdingbats', true, chr(109)); + + case 'disc': + default: + return array('zapfdingbats', true, chr(108)); + } + } + + /** + * Ajouter un niveau de liste + * + * @param string type de liste : ul, ol + * @param string style de la liste + * @return null + */ + function listeAddLevel($type = 'ul', $style = '', $img = null) + { + if ($img) + { + if (preg_match('/^url\(([^)]+)\)$/isU', trim($img), $match)) + $img = $match[1]; + else + $img = null; + } + else + $img = null; + + if (!in_array($type, array('ul', 'ol'))) $type = 'ul'; + if (!in_array($style, array('lower-alpha', 'upper-alpha', 'upper-roman', 'lower-roman', 'decimal', 'square', 'circle', 'disc', 'none'))) $style = ''; + + if (!$style) + { + if ($type=='ul') $style = 'disc'; + else $style = 'decimal'; + } + $this->defLIST[count($this->defLIST)] = array('style' => $style, 'nb' => 0, 'img' => $img); + } + + /** + * Supprimer un niveau de liste + * + * @return null + */ + function listeDelLevel() + { + if (count($this->defLIST)) + { + unset($this->defLIST[count($this->defLIST)-1]); + $this->defLIST = array_values($this->defLIST); + } + } + + /** + * traitement d'un code HTML + * + * @param string code HTML à convertir + * @param boolean afficher en pdf (false) ou en html (true) + * @return null + */ + function WriteHTML($html, $vue = false) + { + $html = str_replace('[[page_nb]]', '{nb}', $html); + + $html = str_replace('[[date_y]]', date('Y'), $html); + $html = str_replace('[[date_m]]', date('m'), $html); + $html = str_replace('[[date_d]]', date('d'), $html); + + $html = str_replace('[[date_h]]', date('H'), $html); + $html = str_replace('[[date_i]]', date('i'), $html); + $html = str_replace('[[date_s]]', date('s'), $html); + + // si on veut voir le résultat en HTML => on appelle la fonction + if ($vue) $this->vueHTML($html); + + // sinon, traitement pour conversion en PDF : + // parsing + $this->sub_pdf = false; + $this->style->readStyle($html); + $this->parsing->setHTML($html); + $this->parsing->parse(); + $this->MakeHTMLcode(); + } + + function MakeHTMLcode() + { + // pour chaque element identifié par le parsing + for($this->parse_pos=0; $this->parse_posparsing->code); $this->parse_pos++) + { + // récupération de l'élément + $todo = $this->parsing->code[$this->parse_pos]; + + // si c'est une ouverture de tableau + if (in_array($todo['name'], array('table', 'ul', 'ol')) && !$todo['close']) + { + // on va créer un sous HTML, et on va travailler sur une position temporaire + $tag_open = $todo['name']; + + $this->sub_part = true; + $this->temp_pos = $this->parse_pos; + + // pour tous les éléments jusqu'à la fermeture de la table afin de préparer les dimensions + while(isset($this->parsing->code[$this->temp_pos]) && !($this->parsing->code[$this->temp_pos]['name']==$tag_open && $this->parsing->code[$this->temp_pos]['close'])) + { + $this->loadAction($this->parsing->code[$this->temp_pos]); + $this->temp_pos++; + } + if (isset($this->parsing->code[$this->temp_pos])) $this->loadAction($this->parsing->code[$this->temp_pos]); + $this->sub_part = false; + } + + // chargement de l'action correspondant à l'élément + $this->loadAction($todo); + } + } + + + + /** + * affichage en mode HTML du contenu + * + * @param string contenu + * @return null + */ + function vueHTML($content) + { + $content = preg_replace('/]*)>/isU', '
'.HTML2PDF::textGET('vue01').' : $1
', $content); + $content = preg_replace('/]*)>/isU', '
'.HTML2PDF::textGET('vue02').' : $1
', $content); + $content = preg_replace('/]*)>/isU', '
'.HTML2PDF::textGET('vue03').' : $1
', $content); + $content = preg_replace('/<\/page([^>]*)>/isU', '
', $content); + $content = preg_replace('/]*)>/isU', '
bookmark : $1
', $content); + $content = preg_replace('/<\/bookmark([^>]*)>/isU', '', $content); + + echo ' + + + '.HTML2PDF::textGET('vue04').' HTML + + + +'.$content.' + +'; + exit; + } + + /** + * chargement de l'action correspondante à un element de parsing + * + * @param array élément de parsing + * @return null + */ + function loadAction($row) + { + // nom de l'action + $fnc = ($row['close'] ? 'c_' : 'o_').strtoupper($row['name']); + + // parametres de l'action + $param = $row['param']; + + // si aucune page n'est créé, on la créé + if ($fnc!='o_PAGE' && $this->FirstPage) + { + $this->setNewPage(); + } + + // lancement de l'action + if (is_callable(array(&$this, $fnc))) + { + $res = $this->{$fnc}($param); + $this->previousCall = $fnc; + return $res; + } + else + { + HTML2PDF::makeError(1, __FILE__, __LINE__, strtoupper($row['name'])); + return false; + } + } + + /** + * balise : PAGE + * mode : OUVERTURE + * + * @param array paramètres de l'élément de parsing + * @return null + */ + function o_PAGE($param) + { + if ($this->forOneLine) return false; + + $newPageSet= (!isset($param['pageset']) || $param['pageset']!='old'); + + $this->maxH = 0; + if ($newPageSet) + { + $this->subHEADER = array(); + $this->subFOOTER = array(); + + // identification de l'orientation demandée + $orientation = ''; + if (isset($param['orientation'])) + { + $param['orientation'] = strtolower($param['orientation']); + if ($param['orientation']=='p') $orientation = 'P'; + if ($param['orientation']=='portrait') $orientation = 'P'; + + if ($param['orientation']=='l') $orientation = 'L'; + if ($param['orientation']=='paysage') $orientation = 'L'; + if ($param['orientation']=='landscape') $orientation = 'L'; + } + + // identification des propriétés du background + $background = array(); + if (isset($param['backimg'])) + { + $background['img'] = isset($param['backimg']) ? $param['backimg'] : ''; // nom de l'image + $background['posX'] = isset($param['backimgx']) ? $param['backimgx'] : 'center'; // position horizontale de l'image + $background['posY'] = isset($param['backimgy']) ? $param['backimgy'] : 'middle'; // position verticale de l'image + $background['width'] = isset($param['backimgw']) ? $param['backimgw'] : '100%'; // taille de l'image (100% = largueur de la feuille) + + // conversion du nom de l'image, en cas de paramètres en _GET + $background['img'] = str_replace('&', '&', $background['img']); + // conversion des positions + if ($background['posX']=='left') $background['posX'] = '0%'; + if ($background['posX']=='center') $background['posX'] = '50%'; + if ($background['posX']=='right') $background['posX'] = '100%'; + if ($background['posY']=='top') $background['posY'] = '0%'; + if ($background['posY']=='middle') $background['posY'] = '50%'; + if ($background['posY']=='bottom') $background['posY'] = '100%'; + + + // si il y a une image de précisé + if ($background['img']) + { + // est-ce que c'est une image ? + $infos=@GetImageSize($background['img']); + if (count($infos)>1) + { + // taille de l'image, en fonction de la taille spécifiée. + $Wi = $this->style->ConvertToMM($background['width'], $this->pdf->w); + $Hi = $Wi*$infos[1]/$infos[0]; + + // récupération des dimensions et positions de l'image + $background['width'] = $Wi; + $background['posX'] = $this->style->ConvertToMM($background['posX'], $this->pdf->w - $Wi); + $background['posY'] = $this->style->ConvertToMM($background['posY'], $this->pdf->h - $Hi); + } + else + $background = array(); + } + else + $background = array(); + } + + // marges TOP et BOTTOM pour le texte. + $background['top'] = isset($param['backtop']) ? $param['backtop'] : '0'; + $background['bottom'] = isset($param['backbottom']) ? $param['backbottom'] : '0'; + $background['left'] = isset($param['backleft']) ? $param['backleft'] : '0'; + $background['right'] = isset($param['backright']) ? $param['backright'] : '0'; + + if (preg_match('/^([0-9]*)$/isU', $background['top'])) $background['top'] .= 'mm'; + if (preg_match('/^([0-9]*)$/isU', $background['bottom'])) $background['bottom'] .= 'mm'; + if (preg_match('/^([0-9]*)$/isU', $background['left'])) $background['left'] .= 'mm'; + if (preg_match('/^([0-9]*)$/isU', $background['right'])) $background['right'] .= 'mm'; + + $background['top'] = $this->style->ConvertToMM($background['top'], $this->pdf->h); + $background['bottom'] = $this->style->ConvertToMM($background['bottom'], $this->pdf->h); + $background['left'] = $this->style->ConvertToMM($background['left'], $this->pdf->w); + $background['right'] = $this->style->ConvertToMM($background['right'], $this->pdf->w); + + $res = false; + $background['color'] = isset($param['backcolor']) ? $this->style->ConvertToRVB($param['backcolor'], $res) : null; + if (!$res) $background['color'] = null; + + $this->style->save(); + $this->style->analyse('PAGE', $param); + $this->style->setPosition($this->pdf->x, $this->pdf->y); + $this->style->FontSet(); + + // nouvelle page + $this->setNewPage($orientation, $background); + + // footer automatique + if (isset($param['footer'])) + { + $lst = explode(';', $param['footer']); + foreach($lst as $key => $val) $lst[$key] = trim(strtolower($val)); + $page = in_array('page', $lst); + $date = in_array('date', $lst); + $heure = in_array('heure', $lst); + $form = in_array('form', $lst); + } + else + { + $page = null; + $date = null; + $heure = null; + $form = null; + } + $this->pdf->SetMyFooter($page, $date, $heure, $form); + } + else + { + $this->style->save(); + $this->style->analyse('PAGE', $param); + $this->style->setPosition($this->pdf->x, $this->pdf->y); + $this->style->FontSet(); + + $this->setNewPage(); + } + + return true; + } + + /** + * balise : PAGE + * mode : FERMETURE + * + * @param array paramètres de l'élément de parsing + * @return null + */ + function c_PAGE($param) + { + if ($this->forOneLine) return false; + + $this->maxH = 0; + + $this->style->load(); + $this->style->FontSet(); + + return true; + } + + + function o_PAGE_HEADER($param) + { + if ($this->forOneLine) return false; + + $this->subHEADER = array(); + for($this->parse_pos; $this->parse_posparsing->code); $this->parse_pos++) + { + $todo = $this->parsing->code[$this->parse_pos]; + if ($todo['name']=='page_header') $todo['name']='page_header_sub'; + $this->subHEADER[] = $todo; + if (strtolower($todo['name'])=='page_header_sub' && $todo['close']) break; + } + + $this->SetPageHeader(); + + return true; + } + + function o_PAGE_FOOTER($param) + { + if ($this->forOneLine) return false; + + $this->subFOOTER = array(); + for($this->parse_pos; $this->parse_posparsing->code); $this->parse_pos++) + { + $todo = $this->parsing->code[$this->parse_pos]; + if ($todo['name']=='page_footer') $todo['name']='page_footer_sub'; + $this->subFOOTER[] = $todo; + if (strtolower($todo['name'])=='page_footer_sub' && $todo['close']) break; + } + + $this->SetPageFooter(); + + return true; + } + + function o_PAGE_HEADER_SUB($param) + { + if ($this->forOneLine) return false; + + $this->subSTATES = array(); + $this->subSTATES['x'] = $this->pdf->x; + $this->subSTATES['y'] = $this->pdf->y; + $this->subSTATES['s'] = $this->style->value; + $this->subSTATES['t'] = $this->style->table; + $this->subSTATES['ml'] = $this->pdf->lMargin; + $this->subSTATES['mr'] = $this->pdf->rMargin; + $this->subSTATES['mt'] = $this->pdf->tMargin; + $this->subSTATES['mb'] = $this->pdf->bMargin; + + $this->pdf->x = $this->defaultLeft; + $this->pdf->y = $this->defaultTop; + $this->style->initStyle(); + $this->style->resetStyle(); + $this->style->value['width'] = $this->pdf->w - $this->defaultLeft - $this->defaultRight; + $this->style->table = array(); + $this->pdf->lMargin = $this->defaultLeft; + $this->pdf->rMargin = $this->defaultRight; + $this->pdf->tMargin = $this->defaultTop; + $this->pdf->bMargin = $this->defaultBottom; + $this->pdf->PageBreakTrigger = $this->pdf->h - $this->pdf->bMargin; + + $this->style->save(); + $this->style->analyse('page_header_sub', $param); + $this->style->setPosition($this->pdf->x, $this->pdf->y); + $this->style->FontSet(); + + return true; + } + + function c_PAGE_HEADER_SUB($param) + { + if ($this->forOneLine) return false; + + $this->style->load(); + + $this->pdf->x = $this->subSTATES['x']; + $this->pdf->y = $this->subSTATES['y']; + $this->style->value = $this->subSTATES['s']; + $this->style->table = $this->subSTATES['t']; + $this->pdf->lMargin = $this->subSTATES['ml']; + $this->pdf->rMargin = $this->subSTATES['mr']; + $this->pdf->tMargin = $this->subSTATES['mt']; + $this->pdf->bMargin = $this->subSTATES['mb']; + $this->pdf->PageBreakTrigger = $this->pdf->h - $this->pdf->bMargin; + + $this->style->FontSet(); + + return true; + } + + function o_PAGE_FOOTER_SUB($param) + { + if ($this->forOneLine) return false; + + $this->subSTATES = array(); + $this->subSTATES['x'] = $this->pdf->x; + $this->subSTATES['y'] = $this->pdf->y; + $this->subSTATES['s'] = $this->style->value; + $this->subSTATES['t'] = $this->style->table; + $this->subSTATES['ml'] = $this->pdf->lMargin; + $this->subSTATES['mr'] = $this->pdf->rMargin; + $this->subSTATES['mt'] = $this->pdf->tMargin; + $this->subSTATES['mb'] = $this->pdf->bMargin; + + $this->pdf->x = $this->defaultLeft; + $this->pdf->y = $this->defaultTop; + $this->style->initStyle(); + $this->style->resetStyle(); + $this->style->value['width'] = $this->pdf->w - $this->defaultLeft - $this->defaultRight; + $this->style->table = array(); + $this->pdf->lMargin = $this->defaultLeft; + $this->pdf->rMargin = $this->defaultRight; + $this->pdf->tMargin = $this->defaultTop; + $this->pdf->bMargin = $this->defaultBottom; + $this->pdf->PageBreakTrigger = $this->pdf->h - $this->pdf->bMargin; + + // on en créé un sous HTML que l'on transforme en PDF + // pour récupérer la hauteur + // on extrait tout ce qui est contenu dans le FOOTER + $sub = null; + $res = $this->parsing->getLevel($this->parse_pos); + $this->CreateSubHTML($sub); + $sub->writeHTML($res[1]); + $this->pdf->y = $this->pdf->h - $sub->maxY - $this->defaultBottom - 0.01; + unset($sub); + + $this->style->save(); + $this->style->analyse('page_footer_sub', $param); + $this->style->setPosition($this->pdf->x, $this->pdf->y); + $this->style->FontSet(); + + return true; + } + + function c_PAGE_FOOTER_SUB($param) + { + if ($this->forOneLine) return false; + + $this->style->load(); + + $this->pdf->x = $this->subSTATES['x']; + $this->pdf->y = $this->subSTATES['y']; + $this->style->value = $this->subSTATES['s']; + $this->style->table = $this->subSTATES['t']; + $this->pdf->lMargin = $this->subSTATES['ml']; + $this->pdf->rMargin = $this->subSTATES['mr']; + $this->pdf->tMargin = $this->subSTATES['mt']; + $this->pdf->bMargin = $this->subSTATES['mb']; + $this->pdf->PageBreakTrigger = $this->pdf->h - $this->pdf->bMargin; + + $this->style->FontSet(); + + return true; + } + + /** + * balise : NOBREAK + * mode : OUVERTURE + * + * @param array paramètres de l'élément de parsing + * @return null + */ + function o_NOBREAK($param) + { + if ($this->forOneLine) return false; + + $this->maxH = 0; + // on extrait tout ce qui est contenu dans le NOBREAK + $res = $this->parsing->getLevel($this->parse_pos); + + // on en créé un sous HTML que l'on transforme en PDF + // pour analyse les dimensions + // et voir si ca rentre + $sub = null; + $this->CreateSubHTML($sub); + $sub->writeHTML($res[1]); + + $y = $this->pdf->getY(); + if ( + $sub->maxY < ($this->pdf->h - $this->pdf->tMargin-$this->pdf->bMargin) && + $y + $sub->maxY>=($this->pdf->h - $this->pdf->bMargin) + ) + $this->setNewPage(); + unset($sub); + + return true; + } + + + /** + * balise : NOBREAK + * mode : FERMETURE + * + * @param array paramètres de l'élément de parsing + * @return null + */ + function c_NOBREAK($param) + { + if ($this->forOneLine) return false; + + $this->maxH = 0; + + return true; + } + + /** + * balise : DIV + * mode : OUVERTURE + * + * @param array paramètres de l'élément de parsing + * @return null + */ + function o_DIV($param, $other = 'div') + { + if ($this->forOneLine) return false; + + $this->style->save(); + $this->style->analyse($other, $param); + $this->style->FontSet(); + + $align_object = null; + if ($this->style->value['margin-auto']) $align_object = 'center'; + + $marge = array(); + $marge['l'] = $this->style->value['border']['l']['width'] + $this->style->value['padding']['l']+0.03; + $marge['r'] = $this->style->value['border']['r']['width'] + $this->style->value['padding']['r']+0.03; + $marge['t'] = $this->style->value['border']['t']['width'] + $this->style->value['padding']['t']+0.03; + $marge['b'] = $this->style->value['border']['b']['width'] + $this->style->value['padding']['b']+0.03; + + // on extrait tout ce qui est contenu dans la DIV + $res = $this->parsing->getLevel($this->parse_pos); + + // on en créé un sous HTML que l'on transforme en PDF + // pour analyse les dimensions + $w = 0; $h = 0; + if (trim($res[1])) + { + $sub = null; + $this->CreateSubHTML($sub); + $sub->writeHTML($res[1]); + $w = $sub->maxX; + $h = $sub->maxY; + unset($sub); + } + + $w+= $marge['l']+$marge['r']; + $h+= $marge['t']+$marge['b']; + + $this->style->value['width'] = max($w, $this->style->value['width']); + $this->style->value['height'] = max($h, $this->style->value['height']); + + if (!$this->style->value['position']) + { + if ( + $this->style->value['width'] < ($this->pdf->w - $this->pdf->lMargin-$this->pdf->rMargin) && + $this->pdf->x + $this->style->value['width']>=($this->pdf->w - $this->pdf->rMargin) + ) + $this->o_BR(array()); + + if ( + $this->style->value['height'] < ($this->pdf->h - $this->pdf->tMargin-$this->pdf->bMargin) && + $this->pdf->y + $this->style->value['height']>=($this->pdf->h - $this->pdf->bMargin) + ) + $this->setNewPage(); + + // en cas d'alignement => correction + $w = $this->style->value['width']; + $old = isset($this->style->table[count($this->style->table)-1]) ? $this->style->table[count($this->style->table)-1] : $this->style->value; + $parent_w = $old['width'] ? $old['width'] : $this->pdf->w - $this->pdf->lMargin - $this->pdf->rMargin; + + if ($parent_w>$w) + { + if ($align_object=='center') $this->pdf->x = $this->pdf->x + ($parent_w-$w)*0.5; + else if ($align_object=='right') $this->pdf->x = $this->pdf->x + $parent_w-$w; + } + + $this->style->setPosition($this->pdf->x, $this->pdf->y); + } + else + { + $this->style->setPosition($this->pdf->x, $this->pdf->y); + $this->saveMax(); + $this->saveX = 0; + $this->saveY = 0; + $this->saveH = 0; + } + + // initialisation du style des bordures de la premiere partie de tableau + $this->Rectangle( + $this->style->value['x'], + $this->style->value['y'], + $this->style->value['width'], + $this->style->value['height'], + $this->style->value['border'], + $this->style->value['padding'], + 0, + $this->style->value['background'] + ); + + + $marge = array(); + $marge['l'] = $this->style->value['border']['l']['width'] + $this->style->value['padding']['l']+0.03; + $marge['r'] = $this->style->value['border']['r']['width'] + $this->style->value['padding']['r']+0.03; + $marge['t'] = $this->style->value['border']['t']['width'] + $this->style->value['padding']['t']+0.03; + $marge['b'] = $this->style->value['border']['b']['width'] + $this->style->value['padding']['b']+0.03; + + $this->style->value['width'] = $this->style->value['width']-$marge['l']-$marge['r']; + $this->style->value['height'] = $this->style->value['height']-$marge['r']-$marge['b']; + + // limitation des marges aux dimensions de la div + $mL = $this->style->value['x']+$marge['l']; + $mR = $this->pdf->w - $mL - $this->style->value['width']; + $this->saveMargin($mL, 0, $mR); + + // positionnement en fonction + $h_corr = $this->style->value['height']; + $h_reel = $h-$marge['b']-$marge['t']; + switch($this->style->value['vertical-align']) + { + case 'bottom': + $y_corr = $h_corr-$h_reel; + break; + + case 'middle': + $y_corr = ($h_corr-$h_reel)*0.5; + break; + + case 'top': + default: + $y_corr = 0; + break; + } + + $this->pdf->setX($this->style->value['x']+$marge['l']); + $this->pdf->setY($this->style->value['y']+$marge['t']+$y_corr); + + $this->setNewPositionForNewLine(); + + return true; + } + function o_BLOCKQUOTE($param) { return $this->o_DIV($param, 'blockquote'); } + + /** + * balise : DIV + * mode : FERMETURE + * + * @param array paramètres de l'élément de parsing + * @return null + */ + function c_DIV($param) + { + if ($this->forOneLine) return false; + + $marge = array(); + $marge['l'] = $this->style->value['border']['l']['width'] + $this->style->value['padding']['l']+0.03; + $marge['r'] = $this->style->value['border']['r']['width'] + $this->style->value['padding']['r']+0.03; + $marge['t'] = $this->style->value['border']['t']['width'] + $this->style->value['padding']['t']+0.03; + $marge['b'] = $this->style->value['border']['b']['width'] + $this->style->value['padding']['b']+0.03; + + $x = $this->style->value['x']; + $y = $this->style->value['y']; + $w = $this->style->value['width']+$marge['l']+$marge['r']; + $h = $this->style->value['height']+$marge['t']+$marge['b']; + + // correction pour les margins + $w+= $this->style->value['margin']['r']; + $h+= $this->style->value['margin']['b']; + + if ($this->style->value['position']!='absolute') + { + // position + $this->pdf->x = $x+$w; + $this->pdf->y = $y; + + // position MAX + $this->maxX = max($this->maxX, $x+$w); + $this->maxY = max($this->maxY, $y+$h); + $this->maxH = max($this->maxH, $h); + } + else + { + // position + $this->pdf->x = $this->style->value['xc']; + $this->pdf->y = $this->style->value['yc']; + + $this->loadMax(); + } + + $block = ($this->style->value['display']!='inline' && $this->style->value['position']!='absolute'); + + $this->style->load(); + $this->style->FontSet(); + $this->loadMargin(); + + if ($block) $this->o_BR(array()); + + return true; + } + function c_BLOCKQUOTE($param) { return $this->c_DIV($param); } + + /** + * balise : BARCODE + * mode : OUVERTURE + * + * @param array paramètres de l'élément de parsing + * @return null + */ + function o_BARCODE($param) + { + + $lst_barcode = array( + 'EAN13' => '0.35mm', + 'UPC_A' => '0.35mm', + 'CODE39' => '1.00mm', + ); + if (isset($param['type'])) $param['type'] = strtoupper($param['type']); + + if (!isset($param['type']) || !isset($lst_barcode[$param['type']])) $param['type']=='CODE39'; + if (!isset($param['value'])) $param['value'] = 0; + if (!isset($param['bar_w'])) $param['bar_w'] = $lst_barcode[$param['type']]; + if (!isset($param['bar_h'])) $param['bar_h'] = '10mm'; + + if (!isset($param['style']['color'])) $param['style']['color'] = '#000000'; + $param['style']['background-color'] = $param['style']['color']; + + $this->style->save(); + $this->style->analyse('barcode', $param); + $this->style->setPosition($this->pdf->x, $this->pdf->y); + $this->style->FontSet(); + + + $x = $this->pdf->getX(); + $y = $this->pdf->getY(); + $w = $this->style->ConvertToMM($param['bar_w']); + $h = $this->style->ConvertToMM($param['bar_h']); + + $infos = $this->pdf->{'BARCODE_'.$param['type']}($x, $y, $param['value'], $h, $w); + + // position maximale globale + $this->maxX = max($this->maxX, $x+$infos[0]); + $this->maxY = max($this->maxY, $y+$infos[1]); + $this->maxH = max($this->maxH, $infos[1]); + + $this->pdf->setX($x+$infos[0]); + + $this->style->load(); + $this->style->FontSet(); + + return true; + } + + /** + * balise : BARCODE + * mode : FERMETURE + * + * @param array paramètres de l'élément de parsing + * @return null + */ + function c_BARCODE($param) + { + // completement inutile + + return true; + } + + /** + * balise : BOOKMARK + * mode : OUVERTURE + * + * @param array paramètres de l'élément de parsing + * @return null + */ + function o_BOOKMARK($param) + { + $titre = isset($param['title']) ? trim($param['title']) : ''; + $level = isset($param['level']) ? floor($param['level']) : 0; + + if ($level<0) $level = 0; + if ($titre) $this->pdf->Bookmark($titre, $level, -1); + + return true; + } + + /** + * balise : BOOKMARK + * mode : FERMETURE + * + * @param array paramètres de l'élément de parsing + * @return null + */ + function c_BOOKMARK($param) + { + // completement inutile + + return true; + } + + /** + * balise : WRITE + * mode : OUVERTURE + * + * @param array paramètres de l'élément de parsing + * @return null + */ + function o_WRITE($param) + { + $fill = ($this->style->value['background']['color']!==null && $this->style->value['background']['image']===null); + + // récupération du texte à écrire, et conversion + $txt = $param['txt']; + $txt = str_replace('€', '€', $txt); + + if ($this->isAfterFloat) + { + $txt = preg_replace('/^([\s]*)([^\s])/isU', '$2', $txt); + $this->isAfterFloat = false; + } + + $txt = html_entity_decode($txt, ENT_QUOTES, 'ISO-8859-15'); +// $txt = utf8_decode(html_entity_decode($txt, ENT_QUOTES, 'UTF-8')); + + $txt = str_replace('[[page_cu]]', $this->pdf->PageNo(), $txt); + + // tailles du texte + $h = 1.08*$this->style->value['font-size']; + $dh = $h*$this->style->value['mini-decal']; + + $w = $this->pdf->GetStringWidth($txt); + // identification de l'alignement + $align = 'L'; + + if ($this->style->value['text-align']=='li_right') + { + $w = $this->style->value['width']; + $align = 'R'; + } + + $curr_max = strlen($txt); // taille maxi du texte + $maxX = 0; // plus grande largeur du texte apres retour à la ligne + $x = $this->pdf->getX(); // position du texte + $y = $this->pdf->getY(); + $w = $this->pdf->GetStringWidth($txt); // largeur du texte + list($left, $right) = $this->getMargins($y); // marges autorisees + $nb = 0; // nbr de lignes découpées + + // tant que ca ne rentre pas sur la ligne et qu'on a du texte => on découpe + while($x+$w>$right && $x<$right && strlen($txt)) + { + // liste des mots + $lst = explode(' ', $txt); + + // trouver une phrase qui rentre dans la largeur, en ajoutant les mots 1 à 1 + $i=0; + $old = ''; + $str = $lst[0]; + while(($x+$this->pdf->GetStringWidth($str))<$right) + { + unset($lst[$i]); + $old = $str; + + $i++; + $str.= ' '.$lst[$i]; + } + $str = $old; + + // si rien de rentre, et que le premier mot ne rentre de toute facon pas dans une ligne, on le force... + if ($i==0 && (($left+$this->pdf->GetStringWidth($lst[0]))>=$right)) + { + $str = $lst[0]; + unset($lst[0]); + } + + // récupération des mots restant, et calcul de la largeur + $txt = implode(' ', $lst); + $w = $this->pdf->GetStringWidth($str); + + // ecriture du bout de phrase extrait et qui rentre + $wc = ($align=='L' ? $w : $this->style->value['width']); + if ($right - $left<$wc) $wc = $right - $left; + if (strlen($str)) $this->pdf->Cell($wc, $h+$dh, $str, 0, 0, $align, $fill, $this->inLink); + $this->maxH = max($this->maxH, $this->style->getLineHeight()); + + // détermination de la largeur max + $maxX = max($maxX, $this->pdf->getX()); + + // nouvelle position et nouvelle largeur pour la boucle + $w = $this->pdf->GetStringWidth($txt); + $y = $this->pdf->getY(); + $x = $this->pdf->getX(); + + // si il reste du text à afficher + if (strlen($txt)) + { + if ($this->forOneLine) + { + $this->maxX = max($this->maxX, $maxX); + return false; + } + + // retour à la ligne + $this->o_BR(array('style' => ''), $curr_max - strlen($txt)); + + $y = $this->pdf->getY(); + $x = $this->pdf->getX(); + + // si la prochaine ligne ne rentre pas dans la page => nouvelle page + if ($y + $h>$this->pdf->h - $this->pdf->bMargin) $this->setNewPage('', null, $curr_max - strlen($txt)); + + // ligne suplémentaire. au bout de 1000 : trop long => erreur + $nb++; + if ($nb>1000) HTML2PDF::makeError(2, __FILE__, __LINE__, array($txt, $right-$left, $this->pdf->GetStringWidth($txt))); + + list($left, $right) = $this->getMargins($y); // marges autorisees + } + } + + // si il reste du text apres découpe, c'est qu'il rentre direct => on l'affiche + if (strlen($txt)) + { + $this->pdf->Cell(($align=='L' ? $w : $this->style->value['width']), $h+$dh, $txt, 0, 0, $align, $fill, $this->inLink); + $this->maxH = max($this->maxH, $this->style->getLineHeight()); + } + + // détermination des positions MAX + $maxX = max($maxX, $this->pdf->getX()); + $maxY = $this->pdf->getY()+$h; + + // position maximale globale + $this->maxX = max($this->maxX, $maxX); + $this->maxY = max($this->maxY, $maxY); + + return true; + } + + /** + * tracer une image + * + * @param string nom du fichier source + * @return null + */ + function Image($src, $sub_li=false) + { + // est-ce que c'est une image ? + $infos=@GetImageSize($src); + + if (count($infos)<2) + { + HTML2PDF::makeError(6, __FILE__, __LINE__, $src); + return false; + } + + // récupération des dimensions dans l'unité du PDF + $wi = $infos[0]/$this->pdf->k; + $hi = $infos[1]/$this->pdf->k; + + // détermination des dimensions d'affichage en fonction du style + if ($this->style->value['width'] && $this->style->value['height']) + { + $w = $this->style->value['width']; + $h = $this->style->value['height']; + } + else if ($this->style->value['width']) + { + $w = $this->style->value['width']; + $h = $hi*$w/$wi; + + } + else if ($this->style->value['height']) + { + $h = $this->style->value['height']; + $w = $wi*$h/$hi; + } + else + { + $w = 72./96.*$wi; + $h = 72./96.*$hi; + } + + // detection du float + $float = $this->style->getFloat(); + if ($float && $this->maxH) $this->o_BR(array()); + + // position d'affichage + $x = $this->pdf->getX(); + $y = $this->pdf->getY(); + + // si l'image ne rentre pas dans la page => nouvelle page + if ($y + $h>$this->pdf->h - $this->pdf->bMargin) + { + $this->setNewPage(); + $x = $this->pdf->getX(); + $y = $this->pdf->getY(); + } + + // correction pour l'affichage d'une puce image + $hT = 0.80*$this->style->value['font-size']; + if ($sub_li && $h<$hT) + { + $y+=($hT-$h); + } + + $yc = $y-$this->style->value['margin']['t']; + + // détermination de la position réelle d'affichage en fonction du text-align du parent + $old = isset($this->style->table[count($this->style->table)-1]) ? $this->style->table[count($this->style->table)-1] : $this->style->value; + + if ( $old['width']) + { + $parent_w = $old['width']; + $parent_x = $x; + } + else + { + $parent_w = $this->pdf->w - $this->pdf->lMargin - $this->pdf->rMargin; + $parent_x = $this->pdf->lMargin; + } + + if ($float) + { + list($lx, $rx) = $this->getMargins($yc); + $parent_x = $lx; + $parent_w = $rx-$lx; + } + + if ($parent_w>$w && $float!='left') + { + if ($float=='right' || $this->style->value['text-align']=='li_right') $x = $parent_x + $parent_w - $w-$this->style->value['margin']['r']-$this->style->value['margin']['l']; + +// if ($float=='right' || $this->style->value['text-align']=='right') $x = $parent_x + $parent_w - $w-$this->style->value['margin']['r']-$this->style->value['margin']['l']; +// else if ($this->style->value['text-align']=='center') $x = $parent_x + 0.5*($parent_w - $w); + } + + // affichage de l'image, et positionnement à la suite + if (!$this->sub_part && !$this->isSubPart) $this->pdf->Image($src, $x, $y, $w, $h, '', $this->inLink); + + $x-= $this->style->value['margin']['l']; + $y-= $this->style->value['margin']['t']; + $w+= $this->style->value['margin']['l'] + $this->style->value['margin']['r']; + $h+= $this->style->value['margin']['t'] + $this->style->value['margin']['b']; + + if ($float=='left') + { + $this->maxX = max($this->maxX, $x+$w); + $this->maxY = max($this->maxY, $y+$h); + + $this->addMargins($float, $x, $y, $x+$w, $y+$h); + + list($lx, $rx) = $this->getMargins($yc); + $this->pdf->x = $lx; + $this->pdf->y = $yc; + } + else if ($float=='right') + { +// $this->maxX = max($this->maxX, $x+$w); + $this->maxY = max($this->maxY, $y+$h); + + $this->addMargins($float, $x, $y, $x+$w, $y+$h); + + list($lx, $rx) = $this->getMargins($yc); + $this->pdf->x = $lx; + $this->pdf->y = $yc; + } + else + { + $this->pdf->SetX($x+$w); + $this->maxX = max($this->maxX, $x+$w); + $this->maxY = max($this->maxY, $y+$h); + $this->maxH = max($this->maxH, $h); + } + } + + /** + * Tracer un rectanble + * + * @param float position X + * @param float position Y + * @param float Largeur + * @param float Hauteur + * @param array Tableau de style de définition des borders + * @param float padding - marge intérieur au rectangle => non utile mais on le passe en paramètre + * @param float margin - marge exterieur au rectangle + * @param array Tableau de style de définition du background + * @return null + */ + function Rectangle($x, $y, $w, $h, $border, $padding, $margin, $background) + { + if ($this->sub_part || $this->isSubPart) return false; + if ($h===null) return false; + + $x+= $margin; + $y+= $margin; + $w-= $margin*2; + $h-= $margin*2; + + // récupération des radius + $radius_h = $border['radius'][0]; + $radius_v = $border['radius'][1]; + + // verification des coins en radius + $coin_TL = ($radius_h && $radius_v && $radius_v>$border['t']['width'] && $radius_h>$border['l']['width']) ? array($radius_h, $radius_v) : null; + $coin_TR = ($radius_h && $radius_v && $radius_v>$border['t']['width'] && $radius_h>$border['r']['width']) ? array($radius_h, $radius_v) : null; + $coin_BL = ($radius_h && $radius_v && $radius_v>$border['b']['width'] && $radius_h>$border['l']['width']) ? array($radius_h, $radius_v) : null; + $coin_BR = ($radius_h && $radius_v && $radius_v>$border['b']['width'] && $radius_h>$border['r']['width']) ? array($radius_h, $radius_v) : null; + + + + // traitement de la couleur de fond + $STYLE = ''; + if ($background['color']) + { + $this->pdf->SetFillColor($background['color'][0], $background['color'][1], $background['color'][2]); + $STYLE.= 'F'; + } + + if ($STYLE) + { + $this->pdf->clippingPathOpen($x, $y, $w, $h, $coin_TL,$coin_TR, $coin_BL, $coin_BR); + $this->pdf->Rect($x, $y, $w, $h, $STYLE); + $this->pdf->clippingPathClose(); + } + + // traitement de l'image de fond + if ($background['image']) + { + $i_name = $background['image']; + $i_position = $background['position']!==null ? $background['position'] : array(0, 0); + $i_repeat = $background['repeat']!==null ? $background['repeat'] : array(true, true); + + // taile du fond (il faut retirer les borders + $b_x = $x; + $b_y = $y; + $b_w = $w; + $b_h = $h; + + if ($border['b']['width']) { $b_h-= $border['b']['width']; } + if ($border['l']['width']) { $b_w-= $border['l']['width']; $b_x+= $border['l']['width']; } + if ($border['t']['width']) { $b_h-= $border['t']['width']; $b_y+= $border['t']['width']; } + if ($border['r']['width']) { $b_w-= $border['r']['width']; } + + // est-ce que c'est une image ? + $i_infos=@GetImageSize($i_name); + + if (count($i_infos)<2) + { + HTML2PDF::makeError(6, __FILE__, __LINE__, $i_name); + return false; + } + + // récupération des dimensions dans l'unité du PDF + $i_width = 72./96.*$i_infos[0]/$this->pdf->k; + $i_height = 72./96.*$i_infos[1]/$this->pdf->k; + + if ($i_repeat[0]) $i_position[0] = $b_x; + else if(preg_match('/^([-]?[0-9\.]+)%/isU', $i_position[0], $match)) $i_position[0] = $b_x + $match[1]*($b_w-$i_width)/100; + else $i_position[0] = $b_x+$i_position[0]; + + if ($i_repeat[1]) $i_position[1] = $b_y; + else if(preg_match('/^([-]?[0-9\.]+)%/isU', $i_position[1], $match)) $i_position[1] = $b_y + $match[1]*($b_h-$i_height)/100; + else $i_position[1] = $b_y+$i_position[1]; + + $i_x_min = $b_x; + $i_x_max = $b_x+$b_w; + $i_y_min = $b_y; + $i_y_max = $b_y+$b_h; + + if (!$i_repeat[0] && !$i_repeat[1]) + { + $i_x_min = $i_position[0]; $i_x_max = $i_position[0]+$i_width; + $i_y_min = $i_position[1]; $i_y_max = $i_position[1]+$i_height; + } + else if ($i_repeat[0] && !$i_repeat[1]) + { + $i_y_min = $i_position[1]; $i_y_max = $i_position[1]+$i_height; + } + elseif (!$i_repeat[0] && $i_repeat[1]) + { + $i_x_min = $i_position[0]; $i_x_max = $i_position[0]+$i_width; + } + + if (is_array($coin_TL)) { $coin_TL[0]-= $border['l']['width']; $coin_TL[1]-= $border['t']['width']; } + if (is_array($coin_TR)) { $coin_TR[0]-= $border['r']['width']; $coin_TR[1]-= $border['t']['width']; } + if (is_array($coin_BL)) { $coin_BL[0]-= $border['l']['width']; $coin_BL[1]-= $border['b']['width']; } + if (is_array($coin_BR)) { $coin_BR[0]-= $border['r']['width']; $coin_BR[1]-= $border['b']['width']; } + + $this->pdf->clippingPathOpen($b_x, $b_y, $b_w, $b_h, $coin_TL, $coin_TR, $coin_BL, $coin_BR); + for ($i_y=$i_y_min; $i_y<$i_y_max; $i_y+=$i_height) + { + for ($i_x=$i_x_min; $i_x<$i_x_max; $i_x+=$i_width) + { + $c_x = null; + $c_y = null; + $c_w = $i_width; + $c_h = $i_height; + if ($i_y_max-$i_y<$i_height) + { + $c_x = $i_x; + $c_y = $i_y; + $c_h = $i_y_max-$i_y; + } + if ($i_x_max-$i_x<$i_width) + { + $c_x = $i_x; + $c_y = $i_y; + $c_w = $i_x_max-$i_x; + } + + $this->pdf->Image($i_name, $i_x, $i_y, $i_width, $i_height, '', ''); + } + } + $this->pdf->clippingPathClose(); + } + + $x-= 0.01; + $y-= 0.01; + $w+= 0.02; + $h+= 0.02; + if ($border['b']['width']) $border['b']['width']+= 0.02; + if ($border['l']['width']) $border['l']['width']+= 0.02; + if ($border['t']['width']) $border['t']['width']+= 0.02; + if ($border['r']['width']) $border['r']['width']+= 0.02; + + if ($border['b']['width'] && $border['b']['color'][0]!==null) + { + $pt = array(); + $pt[] = $x+$w; $pt[] = $y+$h; + $pt[] = $x+$w-$border['r']['width']; $pt[] = $y+$h; + $pt[] = $x+$border['l']['width']; $pt[] = $y+$h; + $pt[] = $x; $pt[] = $y+$h; + $pt[] = $x+$border['l']['width']; $pt[] = $y+$h-$border['b']['width']; + $pt[] = $x+$w-$border['r']['width']; $pt[] = $y+$h-$border['b']['width']; + + $bord = 3; + if (is_array($coin_BL)) + { + $bord-=2; + $pt[4] += $radius_h-$border['l']['width']; + $pt[8] += $radius_h-$border['l']['width']; + unset($pt[6]);unset($pt[7]); + } + if (is_array($coin_BR)) + { + $courbe = array(); + $courbe[] = $x+$w; $courbe[] = $y+$h-$radius_v; + $courbe[] = $x+$w-$radius_h; $courbe[] = $y+$h; + $courbe[] = $x+$w-$border['r']['width']; $courbe[] = $y+$h-$radius_v; + $courbe[] = $x+$w-$radius_h; $courbe[] = $y+$h-$border['b']['width']; + $courbe[] = $x+$w-$radius_h; $courbe[] = $y+$h-$radius_v; + $this->Courbe($courbe, $border['b']['color']); + + $bord-=1; + $pt[2] -= $radius_h-$border['r']['width']; + $pt[10]-= $radius_h-$border['r']['width']; + unset($pt[0]);unset($pt[1]); + + } + + $pt = array_values($pt); + $this->Line($pt, $border['b']['color'], $border['b']['type'], $border['b']['width'], $bord); + } + + if ($border['l']['width'] && $border['l']['color'][0]!==null) + { + $pt = array(); + $pt[] = $x; $pt[] = $y+$h; + $pt[] = $x; $pt[] = $y+$h-$border['b']['width']; + $pt[] = $x; $pt[] = $y+$border['t']['width']; + $pt[] = $x; $pt[] = $y; + $pt[] = $x+$border['l']['width']; $pt[] = $y+$border['t']['width']; + $pt[] = $x+$border['l']['width']; $pt[] = $y+$h-$border['b']['width']; + + $bord = 3; + if (is_array($coin_BL)) + { + $courbe = array(); + $courbe[] = $x+$radius_h; $courbe[] = $y+$h; + $courbe[] = $x; $courbe[] = $y+$h-$radius_v; + $courbe[] = $x+$radius_h; $courbe[] = $y+$h-$border['b']['width']; + $courbe[] = $x+$border['l']['width']; $courbe[] = $y+$h-$radius_v; + $courbe[] = $x+$radius_h; $courbe[] = $y+$h-$radius_v; + $this->Courbe($courbe, $border['l']['color']); + + $bord-=1; + $pt[3] -= $radius_v-$border['b']['width']; + $pt[11]-= $radius_v-$border['b']['width']; + unset($pt[0]);unset($pt[1]); + } + if (is_array($coin_TL)) + { + $bord-=2; + $pt[5] += $radius_v-$border['t']['width']; + $pt[9] += $radius_v-$border['t']['width']; + unset($pt[6]);unset($pt[7]); + } + + $pt = array_values($pt); + $this->Line($pt, $border['l']['color'], $border['l']['type'], $border['l']['width'], $bord); + } + + if ($border['t']['width'] && $border['t']['color'][0]!==null) + { + $pt = array(); + $pt[] = $x; $pt[] = $y; + $pt[] = $x+$border['l']['width']; $pt[] = $y; + $pt[] = $x+$w-$border['r']['width']; $pt[] = $y; + $pt[] = $x+$w; $pt[] = $y; + $pt[] = $x+$w-$border['r']['width']; $pt[] = $y+$border['t']['width']; + $pt[] = $x+$border['l']['width']; $pt[] = $y+$border['t']['width']; + + $bord = 3; + if (is_array($coin_TL)) + { + $courbe = array(); + $courbe[] = $x; $courbe[] = $y+$radius_v; + $courbe[] = $x+$radius_h; $courbe[] = $y; + $courbe[] = $x+$border['l']['width']; $courbe[] = $y+$radius_v; + $courbe[] = $x+$radius_h; $courbe[] = $y+$border['t']['width']; + $courbe[] = $x+$radius_h; $courbe[] = $y+$radius_v; + $this->Courbe($courbe, $border['t']['color']); + + $bord-=1; + $pt[2] += $radius_h-$border['l']['width']; + $pt[10]+= $radius_h-$border['l']['width']; + unset($pt[0]);unset($pt[1]); + } + if (is_array($coin_TR)) + { + $bord-=2; + $pt[4] -= $radius_h-$border['r']['width']; + $pt[8] -= $radius_h-$border['r']['width']; + unset($pt[6]);unset($pt[7]); + } + + $pt = array_values($pt); + $this->Line($pt, $border['t']['color'], $border['t']['type'], $border['t']['width'], $bord); + } + + if ($border['r']['width'] && $border['r']['color'][0]!==null) + { + $pt = array(); + $pt[] = $x+$w; $pt[] = $y; + $pt[] = $x+$w; $pt[] = $y+$border['t']['width']; + $pt[] = $x+$w; $pt[] = $y+$h-$border['b']['width']; + $pt[] = $x+$w; $pt[] = $y+$h; + $pt[] = $x+$w-$border['r']['width']; $pt[] = $y+$h-$border['b']['width']; + $pt[] = $x+$w-$border['r']['width']; $pt[] = $y+$border['t']['width']; + + $bord = 3; + if (is_array($coin_TR)) + { + $courbe = array(); + $courbe[] = $x+$w-$radius_h; $courbe[] = $y; + $courbe[] = $x+$w; $courbe[] = $y+$radius_v; + $courbe[] = $x+$w-$radius_h; $courbe[] = $y+$border['t']['width']; + $courbe[] = $x+$w-$border['r']['width']; $courbe[] = $y+$radius_v; + $courbe[] = $x+$w-$radius_h; $courbe[] = $y+$radius_v; + $this->Courbe($courbe, $border['r']['color']); + + $bord-=1; + $pt[3] += $radius_v-$border['t']['width']; + $pt[11]+= $radius_v-$border['t']['width']; + unset($pt[0]);unset($pt[1]); + } + if (is_array($coin_BR)) + { + $bord-=2; + $pt[5] -= $radius_v-$border['b']['width']; + $pt[9] -= $radius_v-$border['b']['width']; + unset($pt[6]);unset($pt[7]); + } + + $pt = array_values($pt); + $this->Line($pt, $border['r']['color'], $border['r']['type'], $border['r']['width'], $bord); + } + + if ($background) $this->pdf->SetFillColor($background['color'][0], $background['color'][1], $background['color'][2]); + } + + function Courbe($pt, $color) + { + $this->pdf->SetFillColor($color[0], $color[1], $color[2]); + + $this->pdf->drawCourbe($pt[0], $pt[1], $pt[2], $pt[3], $pt[4], $pt[5], $pt[6], $pt[7], $pt[8], $pt[9]); + } + + /** + * Tracer une ligne epaisse défini par ses points avec des extreminites en biseau + * + * @param array liste des points definissant le tour de la ligne + * @param float couleur RVB + * @param string type de ligne + * @param float largeur de la ligne + * @return null + */ + function Line($pt, $color, $type, $width, $bord=3) + { + $this->pdf->SetFillColor($color[0], $color[1], $color[2]); + if ($type=='dashed' || $type=='dotted') + { + if ($bord==1) + { + $tmp = array(); $tmp[]=$pt[0]; $tmp[]=$pt[1]; $tmp[]=$pt[2]; $tmp[]=$pt[3]; $tmp[]=$pt[8]; $tmp[]=$pt[9]; + $this->pdf->Polygon($tmp, 'F'); + + $tmp = array(); $tmp[]=$pt[2]; $tmp[]=$pt[3]; $tmp[]=$pt[4]; $tmp[]=$pt[5]; $tmp[]=$pt[6]; $tmp[]=$pt[7]; $tmp[]=$pt[8]; $tmp[]=$pt[9]; + $pt = $tmp; + } + else if ($bord==2) + { + $tmp = array(); $tmp[]=$pt[2]; $tmp[]=$pt[3]; $tmp[]=$pt[4]; $tmp[]=$pt[5]; $tmp[]=$pt[6]; $tmp[]=$pt[7]; + $this->pdf->Polygon($tmp, 'F'); + + $tmp = array(); $tmp[]=$pt[0]; $tmp[]=$pt[1]; $tmp[]=$pt[2]; $tmp[]=$pt[3]; $tmp[]=$pt[6]; $tmp[]=$pt[7]; $tmp[]=$pt[8]; $tmp[]=$pt[9]; + $pt = $tmp; + } + else if ($bord==3) + { + $tmp = array(); $tmp[]=$pt[0]; $tmp[]=$pt[1]; $tmp[]=$pt[2]; $tmp[]=$pt[3]; $tmp[]=$pt[10]; $tmp[]=$pt[11]; + $this->pdf->Polygon($tmp, 'F'); + + $tmp = array(); $tmp[]=$pt[4]; $tmp[]=$pt[5]; $tmp[]=$pt[6]; $tmp[]=$pt[7]; $tmp[]=$pt[8]; $tmp[]=$pt[9]; + $this->pdf->Polygon($tmp, 'F'); + + $tmp = array(); $tmp[]=$pt[2]; $tmp[]=$pt[3]; $tmp[]=$pt[4]; $tmp[]=$pt[5]; $tmp[]=$pt[8]; $tmp[]=$pt[9]; $tmp[]=$pt[10]; $tmp[]=$pt[11]; + $pt = $tmp; + } + + if ($pt[2]==$pt[0]) + { + $l = abs(($pt[3]-$pt[1])*0.5); + $px = 0; + $py = $width; + $x1 = $pt[0]; $y1 = ($pt[3]+$pt[1])*0.5; + $x2 = $pt[6]; $y2 = ($pt[7]+$pt[5])*0.5; + } + else + { + $l = abs(($pt[2]-$pt[0])*0.5); + $px = $width; + $py = 0; + $x1 = ($pt[2]+$pt[0])*0.5; $y1 = $pt[1]; + $x2 = ($pt[6]+$pt[4])*0.5; $y2 = $pt[7]; + } + if ($type=='dashed') + { + $px = $px*3.; + $py = $py*3.; + } + $mode = ($l/($px+$py)<.5); + + for($i=0; $l-($px+$py)*($i-0.5)>0; $i++) + { + if (($i%2)==$mode) + { + $j = $i-0.5; + $lx1 = $px*($j); if ($lx1<-$l) $lx1 =-$l; + $ly1 = $py*($j); if ($ly1<-$l) $ly1 =-$l; + $lx2 = $px*($j+1); if ($lx2>$l) $lx2 = $l; + $ly2 = $py*($j+1); if ($ly2>$l) $ly2 = $l; + + $tmp = array(); + $tmp[] = $x1+$lx1; $tmp[] = $y1+$ly1; + $tmp[] = $x1+$lx2; $tmp[] = $y1+$ly2; + $tmp[] = $x2+$lx2; $tmp[] = $y2+$ly2; + $tmp[] = $x2+$lx1; $tmp[] = $y2+$ly1; + $this->pdf->Polygon($tmp, 'F'); + + if ($j>0) + { + $tmp = array(); + $tmp[] = $x1-$lx1; $tmp[] = $y1-$ly1; + $tmp[] = $x1-$lx2; $tmp[] = $y1-$ly2; + $tmp[] = $x2-$lx2; $tmp[] = $y2-$ly2; + $tmp[] = $x2-$lx1; $tmp[] = $y2-$ly1; + $this->pdf->Polygon($tmp, 'F'); + } + } + } + } + else if ($type=='solid') + { + $this->pdf->Polygon($pt, 'F'); + } + } + + /** + * balise : BR + * mode : OUVERTURE + * + * @param array paramètres de l'élément de parsing + * @param integer position reelle courante si saut de ligne pendant l'ecriture d'un texte + * @return null + */ + function o_BR($param, $curr = null) + { + if ($this->forOneLine) return false; + + $h = $this->style->getLineHeight(); + $h = max($this->maxH, $h); + $y = $this->pdf->getY(); + + // si la ligne est vide, la position maximale n'a pas été mise à jour => on la met à jour + if ($this->maxH==0) $this->maxY = max($this->maxY, $y+$h); + + // si le saut de ligne rentre => on le prend en compte, sinon nouvelle page + if ($y+$h<$this->pdf->h - $this->pdf->bMargin) $this->setNewLine($h, $curr); + else $this->setNewPage('', null, $curr); + + $this->maxH = 0; + + return true; + } + + /** + * balise : HR + * mode : OUVERTURE + * + * @param array paramètres de l'élément de parsing + * @return null + */ + function o_HR($param) + { + if ($this->forOneLine) return false; + $old_align = $this->style->value['text-align']; + $this->style->value['text-align'] = 'left'; + + if ($this->maxH) $this->o_BR($param); + + $f_size = $this->style->value['font-size']; + $this->style->value['font-size']=$f_size*0.5; $this->o_BR($param); + $this->style->value['font-size']=0; + + $param['style']['width'] = '100%'; + + $this->style->save(); + $this->style->value['height']=$this->style->ConvertToMM('1mm'); + + $this->style->analyse('hr', $param); + $this->style->setPosition($this->pdf->x, $this->pdf->y); + $this->style->FontSet(); + + $h = $this->style->value['height']; + if ($h) $h-= $this->style->value['border']['t']['width']+$this->style->value['border']['b']['width']; + if ($h<=0) $h = $this->style->value['border']['t']['width']+$this->style->value['border']['b']['width']; + + $this->Rectangle($this->pdf->x, $this->pdf->y, $this->style->value['width'], $h, $this->style->value['border'], 0, 0, $this->style->value['background']); + $this->maxH = $h; + + $this->style->load(); + $this->style->FontSet(); + + $this->o_BR($param); + + $this->style->value['font-size']=$f_size*0.5; $this->o_BR($param); + $this->style->value['font-size']=$f_size; + + $this->style->value['text-align'] = $old_align; + $this->setNewPositionForNewLine(); + + return true; + } + + /** + * balise : B + * mode : OUVERTURE + * + * @param array paramètres de l'élément de parsing + * @return null + */ + function o_B($param, $other = 'b') + { + $this->style->save(); + $this->style->value['font-bold'] = true; + $this->style->analyse($other, $param); + $this->style->setPosition($this->pdf->x, $this->pdf->y); + $this->style->FontSet(); + + return true; + } + function o_STRONG($param) { return $this->o_B($param, 'strong'); } + + /** + * balise : B + * mode : FERMETURE + * + * @param array paramètres de l'élément de parsing + * @return null + */ + function c_B($param) + { + $this->style->load(); + $this->style->FontSet(); + + return true; + } + function c_STRONG($param) { return $this->c_B($param); } + + /** + * balise : I + * mode : OUVERTURE + * + * @param array paramètres de l'élément de parsing + * @return null + */ + function o_I($param, $other = 'i') + { + $this->style->save(); + $this->style->value['font-italic'] = true; + $this->style->analyse($other, $param); + $this->style->setPosition($this->pdf->x, $this->pdf->y); + $this->style->FontSet(); + + return true; + } + function o_ADDRESS($param) { return $this->o_I($param, 'address'); } + function o_CITE($param) { return $this->o_I($param, 'cite'); } + function o_EM($param) { return $this->o_I($param, 'em'); } + function o_SAMP($param) { return $this->o_I($param, 'samp'); } + + /** + * balise : I + * mode : FERMETURE + * + * @param array paramètres de l'élément de parsing + * @return null + */ + function c_I($param) + { + $this->style->load(); + $this->style->FontSet(); + + return true; + } + function c_ADDRESS($param) { return $this->c_I($param); } + function c_CITE($param) { return $this->c_I($param); } + function c_EM($param) { return $this->c_I($param); } + function c_SAMP($param) { return $this->c_I($param); } + + /** + * balise : S + * mode : OUVERTURE + * + * @param array paramètres de l'élément de parsing + * @return null + */ + function o_S($param) + { + $this->style->save(); + $this->style->value['font-linethrough'] = true; + $this->style->analyse('s', $param); + $this->style->setPosition($this->pdf->x, $this->pdf->y); + $this->style->FontSet(); + + return true; + } + + /** + * balise : S + * mode : FERMETURE + * + * @param array paramètres de l'élément de parsing + * @return null + */ + function c_S($param) + { + $this->style->load(); + $this->style->FontSet(); + + return true; + } + + /** + * balise : U + * mode : OUVERTURE + * + * @param array paramètres de l'élément de parsing + * @return null + */ + function o_U($param) + { + $this->style->save(); + $this->style->value['font-underline'] = true; + $this->style->analyse('u', $param); + $this->style->setPosition($this->pdf->x, $this->pdf->y); + $this->style->FontSet(); + + return true; + } + + /** + * balise : U + * mode : FERMETURE + * + * @param array paramètres de l'élément de parsing + * @return null + */ + function c_U($param) + { + $this->style->load(); + $this->style->FontSet(); + + return true; + } + + /** + * balise : A + * mode : OUVERTURE + * + * @param array paramètres de l'élément de parsing + * @return null + */ + function o_A($param) + { + $this->inLink = str_replace('&', '&', isset($param['href']) ? $param['href'] : ''); + + if (isset($param['name'])) + { + $nom = $param['name']; + if (!isset($this->lstAncre[$nom])) $this->lstAncre[$nom] = array($this->pdf->AddLink(), false); + + if (!$this->lstAncre[$nom][1]) + { + $this->lstAncre[$nom][1] = true; + $this->pdf->SetLink($this->lstAncre[$nom][0], -1, -1); + } + } + + if (preg_match('/^#([^#]+)$/isU', $this->inLink, $match)) + { + $nom = $match[1]; + if (!isset($this->lstAncre[$nom])) $this->lstAncre[$nom] = array($this->pdf->AddLink(), false); + + $this->inLink = $this->lstAncre[$nom][0]; + } + + $this->style->save(); + $this->style->value['font-underline'] = true; + $this->style->value['color'] = array(20, 20, 250); + $this->style->analyse('a', $param); + $this->style->setPosition($this->pdf->x, $this->pdf->y); + $this->style->FontSet(); + + return true; + } + + /** + * balise : A + * mode : FERMETURE + * + * @param array paramètres de l'élément de parsing + * @return null + */ + function c_A($param) + { + $this->inLink = ''; + $this->style->load(); + $this->style->FontSet(); + + return true; + } + + /** + * balise : H1 + * mode : OUVERTURE + * + * @param array paramètres de l'élément de parsing + * @return null + */ + function o_H1($param) + { + if ($this->forOneLine) return false; + + $this->o_BR(array()); + $this->style->save(); + $this->style->value['font-bold'] = true; + $this->style->value['font-size'] = $this->style->ConvertToMM('28px'); + $this->style->analyse('h1', $param); + $this->style->setPosition($this->pdf->x, $this->pdf->y); + $this->style->FontSet(); + $this->setNewPositionForNewLine(); + + return true; + } + + /** + * balise : H1 + * mode : FERMETURE + * + * @param array paramètres de l'élément de parsing + * @return null + */ + function c_H1($param) + { + if ($this->forOneLine) return false; + + $this->o_BR(array()); + $this->style->load(); + $this->style->FontSet(); + $this->o_BR(array()); + + return true; + } + + /** + * balise : H2 + * mode : OUVERTURE + * + * @param array paramètres de l'élément de parsing + * @return null + */ + function o_H2($param) + { + if ($this->forOneLine) return false; + + $this->o_BR(array()); + $this->style->save(); + $this->style->value['font-bold'] = true; + $this->style->value['font-size'] = $this->style->ConvertToMM('24px'); + $this->style->analyse('h2', $param); + $this->style->setPosition($this->pdf->x, $this->pdf->y); + $this->style->FontSet(); + $this->setNewPositionForNewLine(); + + return true; + } + + /** + * balise : H2 + * mode : FERMETURE + * + * @param array paramètres de l'élément de parsing + * @return null + */ + function c_H2($param) + { + if ($this->forOneLine) return false; + + $this->o_BR(array()); + $this->style->load(); + $this->style->FontSet(); + $this->o_BR(array()); + + return true; + } + + /** + * balise : H3 + * mode : OUVERTURE + * + * @param array paramètres de l'élément de parsing + * @return null + */ + function o_H3($param) + { + if ($this->forOneLine) return false; + + $this->o_BR(array()); + $this->style->save(); + $this->style->value['font-bold'] = true; + $this->style->value['font-size'] = $this->style->ConvertToMM('20px'); + $this->style->analyse('h3', $param); + $this->style->setPosition($this->pdf->x, $this->pdf->y); + $this->style->FontSet(); + $this->setNewPositionForNewLine(); + + return true; + } + + /** + * balise : H3 + * mode : FERMETURE + * + * @param array paramètres de l'élément de parsing + * @return null + */ + function c_H3($param) + { + if ($this->forOneLine) return false; + + $this->o_BR(array()); + $this->style->load(); + $this->style->FontSet(); + $this->o_BR(array()); + + return true; + } + + /** + * balise : H4 + * mode : OUVERTURE + * + * @param array paramètres de l'élément de parsing + * @return null + */ + function o_H4($param) + { + if ($this->forOneLine) return false; + + $this->o_BR(array()); + $this->style->save(); + $this->style->value['font-bold'] = true; + $this->style->value['font-size'] = $this->style->ConvertToMM('16px'); + $this->style->analyse('h4', $param); + $this->style->setPosition($this->pdf->x, $this->pdf->y); + $this->style->FontSet(); + $this->setNewPositionForNewLine(); + + return true; + } + + /** + * balise : H4 + * mode : FERMETURE + * + * @param array paramètres de l'élément de parsing + * @return null + */ + function c_H4($param) + { + if ($this->forOneLine) return false; + + $this->o_BR(array()); + $this->style->load(); + $this->style->FontSet(); + $this->o_BR(array()); + + return true; + } + + /** + * balise : H5 + * mode : OUVERTURE + * + * @param array paramètres de l'élément de parsing + * @return null + */ + function o_H5($param) + { + if ($this->forOneLine) return false; + + $this->o_BR(array()); + $this->style->save(); + $this->style->value['font-bold'] = true; + $this->style->value['font-size'] = $this->style->ConvertToMM('12px'); + $this->style->analyse('h5', $param); + $this->style->setPosition($this->pdf->x, $this->pdf->y); + $this->style->FontSet(); + $this->setNewPositionForNewLine(); + + return true; + } + + /** + * balise : H5 + * mode : FERMETURE + * + * @param array paramètres de l'élément de parsing + * @return null + */ + function c_H5($param) + { + if ($this->forOneLine) return false; + + $this->o_BR(array()); + $this->style->load(); + $this->style->FontSet(); + $this->o_BR(array()); + + return true; + } + + /** + * balise : H6 + * mode : OUVERTURE + * + * @param array paramètres de l'élément de parsing + * @return null + */ + function o_H6($param) + { + if ($this->forOneLine) return false; + + $this->o_BR(array()); + $this->style->save(); + $this->style->value['font-bold'] = true; + $this->style->value['font-size'] = $this->style->ConvertToMM('9px'); + $this->style->analyse('h6', $param); + $this->style->setPosition($this->pdf->x, $this->pdf->y); + $this->style->FontSet(); + $this->setNewPositionForNewLine(); + + return true; + } + + /** + * balise : H6 + * mode : FERMETURE + * + * @param array paramètres de l'élément de parsing + * @return null + */ + function c_H6($param) + { + if ($this->forOneLine) return false; + + $this->o_BR(array()); + $this->style->load(); + $this->style->FontSet(); + $this->o_BR(array()); + + return true; + } + + /** + * balise : SPAN + * mode : OUVERTURE + * + * @param array paramètres de l'élément de parsing + * @return null + */ + function o_SPAN($param, $other = 'span') + { + $this->style->save(); + $this->style->analyse($other, $param); + $this->style->setPosition($this->pdf->x, $this->pdf->y); + $this->style->FontSet(); + + return true; + } + function o_FONT($param) { return $this->o_SPAN($param, 'font'); } + + /** + * balise : SPAN + * mode : FERMETURE + * + * @param array paramètres de l'élément de parsing + * @return null + */ + function c_SPAN($param) + { + $this->style->load(); + $this->style->FontSet(); + + return true; + } + function c_FONT($param) { return $this->c_SPAN($param); } + + + /** + * balise : P + * mode : OUVERTURE + * + * @param array paramètres de l'élément de parsing + * @return null + */ + function o_P($param) + { + if ($this->forOneLine) return false; + + if (!in_array($this->previousCall, array('c_P', 'c_UL'))) + { + if ($this->maxH) $this->o_BR(array()); + $this->o_BR(array()); + } + + $this->style->save(); + $this->style->analyse('p', $param); + $this->style->setPosition($this->pdf->x, $this->pdf->y); + $this->style->FontSet(); + + if ($this->style->value['text-indent']>0) $this->pdf->x+= $this->style->value['text-indent']; + + return true; + } + + /** + * balise : P + * mode : FERMETURE + * + * @param array paramètres de l'élément de parsing + * @return null + */ + function c_P($param) + { + if ($this->forOneLine) return false; + + if ($this->maxH) $this->o_BR(array()); + $this->o_BR(array()); + $this->style->load(); + $this->style->FontSet(); + + return true; + } + + /** + * balise : PRE + * mode : OUVERTURE + * + * @param array paramètres de l'élément de parsing + * @return null + */ + function o_PRE($param, $other = 'pre') + { + if ($other=='pre' && $this->maxH) $this->o_BR(array()); + + $this->style->save(); + $this->style->value['font-family'] = 'courier'; + $this->style->analyse($other, $param); + $this->style->setPosition($this->pdf->x, $this->pdf->y); + $this->style->FontSet(); + + if ($other=='pre') return $this->o_DIV($param, $other); + + return true; + } + function o_CODE($param) { return $this->o_PRE($param, 'code'); } + + /** + * balise : PRE + * mode : FERMETURE + * + * @param array paramètres de l'élément de parsing + * @return null + */ + function c_PRE($param, $other = 'pre') + { + if ($other=='pre') + { + if ($this->forOneLine) return false; + + $this->c_DIV($param); + $this->o_BR(array()); + } + $this->style->load(); + $this->style->FontSet(); + + return true; + } + function c_CODE($param) { return $this->c_PRE($param, 'code'); } + + /** + * balise : BIG + * mode : OUVERTURE + * + * @param array paramètres de l'élément de parsing + * @return null + */ + function o_BIG($param) + { + $this->style->save(); + $this->style->value['mini-decal']-= $this->style->value['mini-size']*0.2; + $this->style->value['mini-size'] *= 1.2; + $this->style->analyse('big', $param); + $this->style->setPosition($this->pdf->x, $this->pdf->y); + $this->style->FontSet(); + + return true; + } + + /** + * balise : BIG + * mode : FERMETURE + * + * @param array paramètres de l'élément de parsing + * @return null + */ + function c_BIG($param) + { + $this->style->load(); + $this->style->FontSet(); + + return true; + } + + /** + * balise : SMALL + * mode : OUVERTURE + * + * @param array paramètres de l'élément de parsing + * @return null + */ + function o_SMALL($param) + { + $this->style->save(); + $this->style->value['mini-decal']+= $this->style->value['mini-size']*0.18; + $this->style->value['mini-size'] *= 0.82; + $this->style->analyse('small', $param); + $this->style->setPosition($this->pdf->x, $this->pdf->y); + $this->style->FontSet(); + + return true; + } + + /** + * balise : SMALL + * mode : FERMETURE + * + * @param array paramètres de l'élément de parsing + * @return null + */ + function c_SMALL($param) + { + $this->style->load(); + $this->style->FontSet(); + + return true; + } + + + /** + * balise : SUP + * mode : OUVERTURE + * + * @param array paramètres de l'élément de parsing + * @return null + */ + function o_SUP($param) + { + $this->style->save(); + $this->style->value['mini-decal']-= $this->style->value['mini-size']*0.25; + $this->style->value['mini-size'] *= 0.75; + $this->style->analyse('sup', $param); + $this->style->setPosition($this->pdf->x, $this->pdf->y); + $this->style->FontSet(); + + return true; + } + + /** + * balise : SUP + * mode : FERMETURE + * + * @param array paramètres de l'élément de parsing + * @return null + */ + function c_SUP($param) + { + $this->style->load(); + $this->style->FontSet(); + + return true; + } + + /** + * balise : SUB + * mode : OUVERTURE + * + * @param array paramètres de l'élément de parsing + * @return null + */ + function o_SUB($param) + { + $this->style->save(); + $this->style->value['mini-decal']+= $this->style->value['mini-size']*0.25; + $this->style->value['mini-size'] *= 0.75; + $this->style->analyse('sub', $param); + $this->style->setPosition($this->pdf->x, $this->pdf->y); + $this->style->FontSet(); + $this->inSub = 1; + + return true; + } + + /** + * balise : SUB + * mode : FERMETURE + * + * @param array paramètres de l'élément de parsing + * @return null + */ + function c_SUB($param) + { + $this->style->load(); + $this->style->FontSet(); + + return true; + } + + /** + * balise : UL + * mode : OUVERTURE + * + * @param array paramètres de l'élément de parsing + * @return null + */ + function o_UL($param, $other = 'ul') + { + if ($this->forOneLine) return false; + + if (!in_array($this->previousCall, array('c_P', 'c_UL'))) + { + if ($this->maxH) $this->o_BR(array()); + if (!count($this->defLIST)) $this->o_BR(array()); + } + + if (!isset($param['style']['width'])) $param['allwidth'] = true; + $param['cellspacing'] = 0; + + // une liste est traitée comme un tableau + $this->o_TABLE($param, $other); + + // ajouter un niveau de liste + $this->listeAddLevel($other, $this->style->value['list-style-type'], $this->style->value['list-style-image']); + + return true; + } + function o_OL($param) { return $this->o_UL($param, 'ol'); } + + /** + * balise : UL + * mode : FERMETURE + * + * @param array paramètres de l'élément de parsing + * @return null + */ + function c_UL($param) + { + if ($this->forOneLine) return false; + + // fin du tableau + $this->c_TABLE($param); + + // enlever un niveau de liste + $this->listeDelLevel(); + + if (!$this->sub_part) + { + if (!count($this->defLIST)) $this->o_BR(array()); + } + + return true; + } + function c_OL($param) { return $this->c_UL($param); } + + /** + * balise : LI + * mode : OUVERTURE + * + * @param array paramètres de l'élément de parsing + * @return null + */ + function o_LI($param) + { + if ($this->forOneLine) return false; + + // ajouter une puce au niveau actuel + $this->listeAddLi(); + + if (!isset($param['style']['width'])) $param['style']['width'] = '100%'; + + // preparation du style de la puce + $paramPUCE = $param; + + $inf = $this->listeGetLi(); + if ($inf[0]) + { + $paramPUCE['style']['font-family'] = $inf[0]; + $paramPUCE['style']['text-align'] = 'li_right'; + $paramPUCE['style']['vertical-align'] = 'top'; + $paramPUCE['style']['width'] = $this->listeGetWidth(); + $paramPUCE['style']['padding-right'] = $this->listeGetPadding(); + $paramPUCE['txt'] = $inf[2]; + } + else + { + $paramPUCE['style']['text-align'] = 'li_right'; + $paramPUCE['style']['vertical-align'] = 'top'; + $paramPUCE['style']['width'] = $this->listeGetWidth(); + $paramPUCE['style']['padding-right'] = $this->listeGetPadding(); + $paramPUCE['src'] = $inf[2]; + $paramPUCE['sub_li'] = true; + } + + // nouvelle ligne + $this->o_TR($param, 'li'); + + $this->style->save(); + + if ($inf[1]) + { + $this->style->value['mini-decal']+= $this->style->value['mini-size']*0.25; + $this->style->value['mini-size'] *= 0.75; + } + + // si on est dans un sub_html => preparation, sinon affichage classique + if ($this->sub_part) + { + // TD pour la puce + $tmp_pos = $this->temp_pos; + $tmp_lst1 = $this->parsing->code[$tmp_pos+1]; + $tmp_lst2 = $this->parsing->code[$tmp_pos+2]; + $this->parsing->code[$tmp_pos+1] = array(); + $this->parsing->code[$tmp_pos+1]['name'] = (isset($paramPUCE['src'])) ? 'img' : 'write'; + $this->parsing->code[$tmp_pos+1]['param'] = $paramPUCE; unset($this->parsing->code[$tmp_pos+1]['param']['style']['width']); + $this->parsing->code[$tmp_pos+1]['close'] = 0; + $this->parsing->code[$tmp_pos+2] = array(); + $this->parsing->code[$tmp_pos+2]['name'] = 'li'; + $this->parsing->code[$tmp_pos+2]['param'] = $paramPUCE; + $this->parsing->code[$tmp_pos+2]['close'] = 1; + $this->o_TD($paramPUCE, 'li_sub'); + $this->c_TD($param); + $this->temp_pos = $tmp_pos; + $this->parsing->code[$tmp_pos+1] = $tmp_lst1; + $this->parsing->code[$tmp_pos+2] = $tmp_lst2; + } + else + { + // TD pour la puce + $this->o_TD($paramPUCE, 'li_sub'); + unset($paramPUCE['style']['width']); + if (isset($paramPUCE['src'])) $this->o_IMG($paramPUCE); + else $this->o_WRITE($paramPUCE); + $this->c_TD($paramPUCE); + } + $this->style->load(); + + + // td pour le contenu + $this->o_TD($param, 'li'); + + return true; + } + + /** + * balise : LI + * mode : FERMETURE + * + * @param array paramètres de l'élément de parsing + * @return null + */ + function c_LI($param) + { + if ($this->forOneLine) return false; + + // fin du contenu + $this->c_TD($param, 'li'); + + // fin de la ligne + $this->c_TR($param, 'li'); + + return true; + } + + /** + * balise : TBODY + * mode : OUVERTURE + * + * @param array paramètres de l'élément de parsing + * @return null + */ + function o_TBODY($param) + { + if ($this->forOneLine) return false; + + $this->style->save(); + $this->style->analyse('tbody', $param); + $this->style->setPosition($this->pdf->x, $this->pdf->y); + $this->style->FontSet(); + + return true; + } + + /** + * balise : TBODY + * mode : FERMETURE + * + * @param array paramètres de l'élément de parsing + * @return null + */ + function c_TBODY($param) + { + if ($this->forOneLine) return false; + + $this->style->load(); + $this->style->FontSet(); + + return true; + } + + /** + * balise : THEAD + * mode : OUVERTURE + * + * @param array paramètres de l'élément de parsing + * @return null + */ + function o_THEAD($param) + { + if ($this->forOneLine) return false; + + global $HTML2PDF_TABLEAU; + + $this->style->save(); + $this->style->analyse('thead', $param); + $this->style->setPosition($this->pdf->x, $this->pdf->y); + $this->style->FontSet(); + + // si on est en mode sub_html : sauvegarde du numéro du TR + if ($this->sub_part) + { + $HTML2PDF_TABLEAU[$param['num']]['thead']['tr'][0] = $HTML2PDF_TABLEAU[$param['num']]['tr_curr']; + $HTML2PDF_TABLEAU[$param['num']]['thead']['code'] = array(); + for($pos=$this->temp_pos; $posparsing->code); $pos++) + { + $todo = $this->parsing->code[$pos]; + if (strtolower($todo['name'])=='thead') $todo['name'] = 'thead_sub'; + $HTML2PDF_TABLEAU[$param['num']]['thead']['code'][] = $todo; + if (strtolower($todo['name'])=='thead_sub' && $todo['close']) break; + } + } + else + { + $res = $this->parsing->getLevel($this->parse_pos); + $this->parse_pos = $res[0]-1; + $HTML2PDF_TABLEAU[$param['num']]['tr_curr']+= count($HTML2PDF_TABLEAU[$param['num']]['thead']['tr']); + } + + return true; + } + + /** + * balise : THEAD + * mode : FERMETURE + * + * @param array paramètres de l'élément de parsing + * @return null + */ + function c_THEAD($param) + { + if ($this->forOneLine) return false; + + $this->style->load(); + $this->style->FontSet(); + + // si on est en mode sub_html : sauvegarde du numéro du TR + if ($this->sub_part) + { + global $HTML2PDF_TABLEAU; + $min = $HTML2PDF_TABLEAU[$param['num']]['thead']['tr'][0]; + $max = $HTML2PDF_TABLEAU[$param['num']]['tr_curr']-1; + $HTML2PDF_TABLEAU[$param['num']]['thead']['tr'] = range($min, $max); + } + + return true; + } + + /** + * balise : TFOOT + * mode : OUVERTURE + * + * @param array paramètres de l'élément de parsing + * @return null + */ + function o_TFOOT($param) + { + if ($this->forOneLine) return false; + + global $HTML2PDF_TABLEAU; + + $this->style->save(); + $this->style->analyse('tfoot', $param); + $this->style->setPosition($this->pdf->x, $this->pdf->y); + $this->style->FontSet(); + + // si on est en mode sub_html : sauvegarde du numéro du TR + if ($this->sub_part) + { + $HTML2PDF_TABLEAU[$param['num']]['tfoot']['tr'][0] = $HTML2PDF_TABLEAU[$param['num']]['tr_curr']; + $HTML2PDF_TABLEAU[$param['num']]['tfoot']['code'] = array(); + for($pos=$this->temp_pos; $posparsing->code); $pos++) + { + $todo = $this->parsing->code[$pos]; + if (strtolower($todo['name'])=='tfoot') $todo['name'] = 'tfoot_sub'; + $HTML2PDF_TABLEAU[$param['num']]['tfoot']['code'][] = $todo; + if (strtolower($todo['name'])=='tfoot_sub' && $todo['close']) break; + } + } + else + { + $res = $this->parsing->getLevel($this->parse_pos+1); + $this->parse_pos = $res[0]; + $HTML2PDF_TABLEAU[$param['num']]['tr_curr']+= count($HTML2PDF_TABLEAU[$param['num']]['tfoot']['tr']); + } + + return true; + } + + /** + * balise : TFOOT + * mode : FERMETURE + * + * @param array paramètres de l'élément de parsing + * @return null + */ + function c_TFOOT($param) + { + if ($this->forOneLine) return false; + + $this->style->load(); + $this->style->FontSet(); + + // si on est en mode sub_html : sauvegarde du numéro du TR + if ($this->sub_part) + { + global $HTML2PDF_TABLEAU; + + $min = $HTML2PDF_TABLEAU[$param['num']]['tfoot']['tr'][0]; + $max = $HTML2PDF_TABLEAU[$param['num']]['tr_curr']-1; + $HTML2PDF_TABLEAU[$param['num']]['tfoot']['tr'] = range($min, $max); + } + + return true; + } + + /** + * balise : THEAD_SUB + * mode : OUVERTURE + * + * @param array paramètres de l'élément de parsing + * @return null + */ + function o_THEAD_SUB($param) + { + if ($this->forOneLine) return false; + + $this->style->save(); + $this->style->analyse('thead', $param); + $this->style->setPosition($this->pdf->x, $this->pdf->y); + $this->style->FontSet(); + + return true; + } + + /** + * balise : THEAD_SUB + * mode : FERMETURE + * + * @param array paramètres de l'élément de parsing + * @return null + */ + function c_THEAD_SUB($param) + { + if ($this->forOneLine) return false; + + $this->style->load(); + $this->style->FontSet(); + + return true; + } + + /** + * balise : TFOOT_SUB + * mode : OUVERTURE + * + * @param array paramètres de l'élément de parsing + * @return null + */ + function o_TFOOT_SUB($param) + { + if ($this->forOneLine) return false; + + $this->style->save(); + $this->style->analyse('tfoot', $param); + $this->style->setPosition($this->pdf->x, $this->pdf->y); + $this->style->FontSet(); + + return true; + } + + /** + * balise : TFOOT_SUB + * mode : FERMETURE + * + * @param array paramètres de l'élément de parsing + * @return null + */ + function c_TFOOT_SUB($param) + { + if ($this->forOneLine) return false; + + $this->style->load(); + $this->style->FontSet(); + + return true; + } + + /** + * balise : FORM + * mode : OUVERTURE + * + * @param array paramètres de l'élément de parsing + * @return null + */ + function o_FORM($param) + { + $this->style->save(); + $this->style->analyse('form', $param); + $this->style->setPosition($this->pdf->x, $this->pdf->y); + $this->style->FontSet(); + + return true; + } + + /** + * balise : FORM + * mode : FERMETURE + * + * @param array paramètres de l'élément de parsing + * @return null + */ + function c_FORM($param) + { + $this->style->load(); + $this->style->FontSet(); + + return true; + } + + /** + * balise : TABLE + * mode : OUVERTURE + * + * @param array paramètres de l'élément de parsing + * @return null + */ + function o_TABLE($param, $other = 'table') + { + if ($this->forOneLine) return false; + + $this->maxH = 0; + // utilisation du tableau des paramétres des tables + global $HTML2PDF_TABLEAU; + + $align_object = isset($param['align']) ? strtolower($param['align']) : 'left'; + if (isset($param['align'])) unset($param['align']); + if (!in_array($align_object, array('left', 'center', 'right'))) $align_object = 'left'; + + // lecture et initialisation du style + $this->style->save(); + $this->style->analyse($other, $param); + $this->style->setPosition($this->pdf->x, $this->pdf->y); + $this->style->FontSet(); + + if ($this->style->value['margin-auto']) $align_object = 'center'; + + // est-on en collapse + $collapse = false; + if ($other=='table') + $collapse = isset($this->style->value['border']['collapse']) ? $this->style->value['border']['collapse'] : false; + + // si oui il faut adapté les borders + if ($collapse) + { + $param['style']['border'] = 'none'; + $param['cellspacing'] = 0; + $none = $this->style->readBorder('none'); + $this->style->value['border']['t'] = $none; + $this->style->value['border']['r'] = $none; + $this->style->value['border']['b'] = $none; + $this->style->value['border']['l'] = $none; + } + + // si on est en mode sub_html : initialisation des dimensions et autres + if ($this->sub_part) + { + $HTML2PDF_TABLEAU[$param['num']] = array(); + $HTML2PDF_TABLEAU[$param['num']]['cellpadding'] = $this->style->ConvertToMM(isset($param['cellpadding']) ? $param['cellpadding'] : '1px'); // cellpadding du tableau + $HTML2PDF_TABLEAU[$param['num']]['cellspacing'] = $this->style->ConvertToMM(isset($param['cellspacing']) ? $param['cellspacing'] : '2px'); // cellspacing du tableau + $HTML2PDF_TABLEAU[$param['num']]['cases'] = array(); // liste des propriétés des cases + $HTML2PDF_TABLEAU[$param['num']]['td_curr'] = 0; // colonne courante + $HTML2PDF_TABLEAU[$param['num']]['tr_curr'] = 0; // ligne courante + $HTML2PDF_TABLEAU[$param['num']]['curr_x'] = $this->pdf->getX(); // position courante X + $HTML2PDF_TABLEAU[$param['num']]['curr_y'] = $this->pdf->getY(); // position courante Y + $HTML2PDF_TABLEAU[$param['num']]['width'] = 0; // largeur globale + $HTML2PDF_TABLEAU[$param['num']]['height'] = 0; // hauteur globale + $HTML2PDF_TABLEAU[$param['num']]['align'] = $align_object; + $HTML2PDF_TABLEAU[$param['num']]['marge'] = array(); + $HTML2PDF_TABLEAU[$param['num']]['marge']['t'] = $this->style->value['padding']['t']+$this->style->value['border']['t']['width']+$HTML2PDF_TABLEAU[$param['num']]['cellspacing']*0.5; + $HTML2PDF_TABLEAU[$param['num']]['marge']['r'] = $this->style->value['padding']['r']+$this->style->value['border']['r']['width']+$HTML2PDF_TABLEAU[$param['num']]['cellspacing']*0.5; + $HTML2PDF_TABLEAU[$param['num']]['marge']['b'] = $this->style->value['padding']['b']+$this->style->value['border']['b']['width']+$HTML2PDF_TABLEAU[$param['num']]['cellspacing']*0.5; + $HTML2PDF_TABLEAU[$param['num']]['marge']['l'] = $this->style->value['padding']['l']+$this->style->value['border']['l']['width']+$HTML2PDF_TABLEAU[$param['num']]['cellspacing']*0.5; + $HTML2PDF_TABLEAU[$param['num']]['page'] = 0; // nombre de pages + $HTML2PDF_TABLEAU[$param['num']]['new_page'] = true; // nouvelle page pour le TR courant + $HTML2PDF_TABLEAU[$param['num']]['style_value'] = null; // style du tableau + $HTML2PDF_TABLEAU[$param['num']]['thead'] = array(); // infos sur le thead + $HTML2PDF_TABLEAU[$param['num']]['tfoot'] = array(); // infos sur le tfoot + $HTML2PDF_TABLEAU[$param['num']]['thead']['tr'] = array(); // tr du thead + $HTML2PDF_TABLEAU[$param['num']]['tfoot']['tr'] = array(); // tr du tfoot + $HTML2PDF_TABLEAU[$param['num']]['thead']['height'] = 0; // hauteur du thead + $HTML2PDF_TABLEAU[$param['num']]['tfoot']['height'] = 0; // hauteur du tfoot + $HTML2PDF_TABLEAU[$param['num']]['thead']['code'] = array(); // contenu HTML du thead + $HTML2PDF_TABLEAU[$param['num']]['tfoot']['code'] = array(); // contenu HTML du tfoot + + $this->saveMargin($this->pdf->lMargin, $this->pdf->tMargin, $this->pdf->rMargin); + + // adaptation de la largeur en fonction des marges du tableau + $this->style->value['width']-= $HTML2PDF_TABLEAU[$param['num']]['marge']['l'] + $HTML2PDF_TABLEAU[$param['num']]['marge']['r']; + } + else + { + // on repart à la premiere page du tableau et à la premiere case + $HTML2PDF_TABLEAU[$param['num']]['page'] = 0; + $HTML2PDF_TABLEAU[$param['num']]['td_curr'] = 0; + $HTML2PDF_TABLEAU[$param['num']]['tr_curr'] = 0; + $HTML2PDF_TABLEAU[$param['num']]['td_x'] = $HTML2PDF_TABLEAU[$param['num']]['marge']['l']+$HTML2PDF_TABLEAU[$param['num']]['curr_x']; + $HTML2PDF_TABLEAU[$param['num']]['td_y'] = $HTML2PDF_TABLEAU[$param['num']]['marge']['t']+$HTML2PDF_TABLEAU[$param['num']]['curr_y']; + + // initialisation du style des bordures de la premiere partie de tableau + $this->Rectangle( + $HTML2PDF_TABLEAU[$param['num']]['curr_x'], + $HTML2PDF_TABLEAU[$param['num']]['curr_y'], + $HTML2PDF_TABLEAU[$param['num']]['width'], + isset($HTML2PDF_TABLEAU[$param['num']]['height'][0]) ? $HTML2PDF_TABLEAU[$param['num']]['height'][0] : null, + $this->style->value['border'], + $this->style->value['padding'], + 0, + $this->style->value['background'] + ); + + $HTML2PDF_TABLEAU[$param['num']]['style_value'] = $this->style->value; + } + + return true; + } + + /** + * balise : TABLE + * mode : FERMETURE + * + * @param array paramètres de l'élément de parsing + * @return null + */ + function c_TABLE($param) + { + if ($this->forOneLine) return false; + + $this->maxH = 0; + global $HTML2PDF_TABLEAU; + + // restauration du style + $this->style->load(); + $this->style->FontSet(); + + // si on est en mode sub_html : initialisation des dimensions et autres + if ($this->sub_part) + { + // ajustement de la taille des cases + $this->calculTailleCases($HTML2PDF_TABLEAU[$param['num']]['cases']); + + // calcul de la hauteur du THEAD et du TFOOT + $lst = array('thead', 'tfoot'); + foreach($lst as $mode) + { + $HTML2PDF_TABLEAU[$param['num']][$mode]['height'] = 0; + foreach($HTML2PDF_TABLEAU[$param['num']][$mode]['tr'] as $tr) + { + // hauteur de la ligne tr + $h = 0; + for($i=0; $istyle->table[count($this->style->table)-1]) ? $this->style->table[count($this->style->table)-1] : $this->style->value; + $parent_w = $old['width'] ? $old['width'] : $this->pdf->w - $this->pdf->lMargin - $this->pdf->rMargin; + $x = $HTML2PDF_TABLEAU[$param['num']]['curr_x']; + $w = $HTML2PDF_TABLEAU[$param['num']]['width']; + if ($parent_w>$w) + { + if ($HTML2PDF_TABLEAU[$param['num']]['align']=='center') + $x = $x + ($parent_w-$w)*0.5; + else if ($HTML2PDF_TABLEAU[$param['num']]['align']=='right') + $x = $x + $parent_w-$w; + + $HTML2PDF_TABLEAU[$param['num']]['curr_x'] = $x; + } + + + // calcul des dimensions du tableau - hauteur du tableau sur chaque page + $HTML2PDF_TABLEAU[$param['num']]['height'] = array(); + + $h0 = $HTML2PDF_TABLEAU[$param['num']]['marge']['t'] + $HTML2PDF_TABLEAU[$param['num']]['marge']['b']; // minimum de hauteur à cause des marges + $h0+= $HTML2PDF_TABLEAU[$param['num']]['thead']['height'] + $HTML2PDF_TABLEAU[$param['num']]['tfoot']['height']; // et du tfoot et thead + $max = $this->pdf->h - $this->pdf->bMargin; // max de hauteur par page + $y = $HTML2PDF_TABLEAU[$param['num']]['curr_y']; // position Y actuelle + $height = $h0; + + // on va lire les hauteurs de chaque ligne, une à une, et voir si ca rentre sur la page. + for($k=0; $k la hauteur sur cette page est trouvée, et on passe à la page d'apres + if ($y+$h+$height>$max) + { + if ($height==$h0) $height = null; + $HTML2PDF_TABLEAU[$param['num']]['height'][] = $height; + $height = $h0; + $y = $this->margeTop; + } + $height+= $th; + } + // rajout du reste de tableau (si il existe) à la derniere page + if ($height!=$h0 || $k==0) $HTML2PDF_TABLEAU[$param['num']]['height'][] = $height; + } + else + { + if (count($HTML2PDF_TABLEAU[$param['num']]['tfoot']['code'])) + { + $tmp_tr = $HTML2PDF_TABLEAU[$param['num']]['tr_curr']; + $tmp_td = $HTML2PDF_TABLEAU[$param['num']]['td_curr']; + $OLD_parse_pos = $this->parse_pos; + $OLD_parse_code = $this->parsing->code; + + $HTML2PDF_TABLEAU[$param['num']]['tr_curr'] = $HTML2PDF_TABLEAU[$param['num']]['tfoot']['tr'][0]; + $HTML2PDF_TABLEAU[$param['num']]['td_curr'] = 0; + $this->parse_pos = 0; + $this->parsing->code = $HTML2PDF_TABLEAU[$param['num']]['tfoot']['code']; + $this->MakeHTMLcode(); + + $this->parse_pos = $OLD_parse_pos; + $this->parsing->code = $OLD_parse_code; + $HTML2PDF_TABLEAU[$param['num']]['tr_curr'] = $tmp_tr; + $HTML2PDF_TABLEAU[$param['num']]['td_curr'] = $tmp_td; + } + + // determination des coordonnées de sortie du tableau + $x = $HTML2PDF_TABLEAU[$param['num']]['curr_x'] + $HTML2PDF_TABLEAU[$param['num']]['width']; + if (count($HTML2PDF_TABLEAU[$param['num']]['height'])>1) + $y = $this->margeTop+$HTML2PDF_TABLEAU[$param['num']]['height'][count($HTML2PDF_TABLEAU[$param['num']]['height'])-1]; + else if (count($HTML2PDF_TABLEAU[$param['num']]['height'])==1) + $y = $HTML2PDF_TABLEAU[$param['num']]['curr_y']+$HTML2PDF_TABLEAU[$param['num']]['height'][count($HTML2PDF_TABLEAU[$param['num']]['height'])-1]; + else + $y = $HTML2PDF_TABLEAU[$param['num']]['curr_y']; + + // restauration des marges + $this->loadMargin(); + + // position de sortie du tableau + $this->pdf->setX($x); + $this->pdf->setY($y); + $this->maxX = max($this->maxX, $x); + $this->maxY = max($this->maxY, $y); + } + + return true; + } + + /** + * balise : TR + * mode : OUVERTURE + * + * @param array paramètres de l'élément de parsing + * @return null + */ + function o_TR($param, $other = 'tr') + { + if ($this->forOneLine) return false; + + $this->maxH = 0; + global $HTML2PDF_TABLEAU; + + // analyse du style + $this->style->save(); + $this->style->analyse($other, $param); + $this->style->setPosition($this->pdf->x, $this->pdf->y); + $this->style->FontSet(); + + // positionnement dans le tableau + $HTML2PDF_TABLEAU[$param['num']]['tr_curr']++; + $HTML2PDF_TABLEAU[$param['num']]['td_curr']= 0; + + // si on est pas dans un sub_html + if (!$this->sub_part) + { + // Y courant apres la ligne + $ty=null; + for($ii=0; $ii nouvelle page + if (!$this->isInTfoot && $HTML2PDF_TABLEAU[$param['num']]['td_y'] + $HTML2PDF_TABLEAU[$param['num']]['marge']['b'] + $ty +$hfoot> $this->pdf->h - $this->pdf->bMargin) + { + if (count($HTML2PDF_TABLEAU[$param['num']]['tfoot']['code'])) + { + $tmp_tr = $HTML2PDF_TABLEAU[$param['num']]['tr_curr']; + $tmp_td = $HTML2PDF_TABLEAU[$param['num']]['td_curr']; + $OLD_parse_pos = $this->parse_pos; + $OLD_parse_code = $this->parsing->code; + + $HTML2PDF_TABLEAU[$param['num']]['tr_curr'] = $HTML2PDF_TABLEAU[$param['num']]['tfoot']['tr'][0]; + $HTML2PDF_TABLEAU[$param['num']]['td_curr'] = 0; + $this->parse_pos = 0; + $this->parsing->code = $HTML2PDF_TABLEAU[$param['num']]['tfoot']['code']; + $this->isInTfoot = true; + $this->MakeHTMLcode(); + $this->isInTfoot = false; + + $this->parse_pos = $OLD_parse_pos; + $this->parsing->code = $OLD_parse_code; + $HTML2PDF_TABLEAU[$param['num']]['tr_curr'] = $tmp_tr; + $HTML2PDF_TABLEAU[$param['num']]['td_curr'] = $tmp_td; + } + + $HTML2PDF_TABLEAU[$param['num']]['new_page'] = true; + $this->setNewPage(); + + $HTML2PDF_TABLEAU[$param['num']]['page']++; + $HTML2PDF_TABLEAU[$param['num']]['curr_y'] = $this->pdf->getY(); + $HTML2PDF_TABLEAU[$param['num']]['td_y'] = $HTML2PDF_TABLEAU[$param['num']]['curr_y']+$HTML2PDF_TABLEAU[$param['num']]['marge']['t']; + + // si la hauteur de cette partie a bien été calculée, on trace le cadre + if (isset($HTML2PDF_TABLEAU[$param['num']]['height'][$HTML2PDF_TABLEAU[$param['num']]['page']])) + { + $old = $this->style->value; + $this->style->value = $HTML2PDF_TABLEAU[$param['num']]['style_value']; + + // initialisation du style des bordures de la premiere partie de tableau + $this->Rectangle( + $HTML2PDF_TABLEAU[$param['num']]['curr_x'], + $HTML2PDF_TABLEAU[$param['num']]['curr_y'], + $HTML2PDF_TABLEAU[$param['num']]['width'], + $HTML2PDF_TABLEAU[$param['num']]['height'][$HTML2PDF_TABLEAU[$param['num']]['page']], + $this->style->value['border'], + $this->style->value['padding'], + $HTML2PDF_TABLEAU[$param['num']]['cellspacing']*0.5, + $this->style->value['background'] + ); + + $this->style->value = $old; + } + } + + if ($HTML2PDF_TABLEAU[$param['num']]['new_page'] && count($HTML2PDF_TABLEAU[$param['num']]['thead']['code'])) + { + $HTML2PDF_TABLEAU[$param['num']]['new_page'] = false; + $tmp_tr = $HTML2PDF_TABLEAU[$param['num']]['tr_curr']; + $tmp_td = $HTML2PDF_TABLEAU[$param['num']]['td_curr']; + $OLD_parse_pos = $this->parse_pos; + $OLD_parse_code = $this->parsing->code; + + $HTML2PDF_TABLEAU[$param['num']]['tr_curr'] = $HTML2PDF_TABLEAU[$param['num']]['thead']['tr'][0]; + $HTML2PDF_TABLEAU[$param['num']]['td_curr'] = 0; + $this->parse_pos = 0; + $this->parsing->code = $HTML2PDF_TABLEAU[$param['num']]['thead']['code']; + $this->MakeHTMLcode(); + + $this->parse_pos = $OLD_parse_pos; + $this->parsing->code = $OLD_parse_code; + $HTML2PDF_TABLEAU[$param['num']]['tr_curr'] = $tmp_tr; + $HTML2PDF_TABLEAU[$param['num']]['td_curr'] = $tmp_td; + $HTML2PDF_TABLEAU[$param['num']]['new_page'] = true; + } + } + else + { + $HTML2PDF_TABLEAU[$param['num']]['cases'][$HTML2PDF_TABLEAU[$param['num']]['tr_curr']-1] = array(); + } + + return true; + } + + /** + * balise : TR + * mode : FERMETURE + * + * @param array paramètres de l'élément de parsing + * @return null + */ + function c_TR($param) + { + if ($this->forOneLine) return false; + + $this->maxH = 0; + global $HTML2PDF_TABLEAU; + + // restauration du style + $this->style->load(); + $this->style->FontSet(); + + // si on est pas dans un sub_html + if (!$this->sub_part) + { + // Y courant apres la ligne + $ty=null; + for($ii=0; $iiforOneLine) return false; + + $this->maxH = 0; + global $HTML2PDF_TABLEAU; + + $param['cellpadding'] = $HTML2PDF_TABLEAU[$param['num']]['cellpadding'].'mm'; + $param['cellspacing'] = $HTML2PDF_TABLEAU[$param['num']]['cellspacing'].'mm'; + + if ($other=='li') + { + $special_li = true; + } + else + { + $special_li = false; + if ($other=='li_sub') + { + $param['style']['border'] = 'none'; + $param['style']['background-color'] = 'transparent'; + $param['style']['background-image'] = 'none'; + $param['style']['background-position'] = ''; + $param['style']['background-repeat'] = ''; + $other = 'li'; + } + } + + // est-on en collapse + $collapse = false; + if (in_array($other, array('td', 'th'))) + $collapse = isset($this->style->value['border']['collapse']) ? $this->style->value['border']['collapse'] : false; + + + // analyse du style + $this->style->save(); + $this->style->analyse($other, $param); + + if ($special_li) + { + $this->style->value['width']-= $this->style->ConvertToMM($this->listeGetWidth()); + $this->style->value['width']-= $this->style->ConvertToMM($this->listeGetPadding()); + } + $this->style->setPosition($this->pdf->x, $this->pdf->y); + $this->style->FontSet(); + + // si on est en collapse : modification du style + if ($collapse) + { + if (!$this->sub_part) + { + if ($HTML2PDF_TABLEAU[$param['num']]['tr_curr']>1 && !$HTML2PDF_TABLEAU[$param['num']]['new_page']) + $this->style->value['border']['t'] = $this->style->readBorder('none'); + } + + if ($HTML2PDF_TABLEAU[$param['num']]['td_curr']>0) + $this->style->value['border']['l'] = $this->style->readBorder('none'); + } + + $marge = array(); + $marge['t'] = $this->style->value['padding']['t']+0.5*$HTML2PDF_TABLEAU[$param['num']]['cellspacing']+$this->style->value['border']['t']['width']; + $marge['r'] = $this->style->value['padding']['r']+0.5*$HTML2PDF_TABLEAU[$param['num']]['cellspacing']+$this->style->value['border']['r']['width']; + $marge['b'] = $this->style->value['padding']['b']+0.5*$HTML2PDF_TABLEAU[$param['num']]['cellspacing']+$this->style->value['border']['b']['width']; + $marge['l'] = $this->style->value['padding']['l']+0.5*$HTML2PDF_TABLEAU[$param['num']]['cellspacing']+$this->style->value['border']['l']['width']; + + // si on est dans un sub_html + if ($this->sub_part) + { + // on se positionne dans le tableau + $HTML2PDF_TABLEAU[$param['num']]['td_curr']++; + $HTML2PDF_TABLEAU[$param['num']]['cases'][$HTML2PDF_TABLEAU[$param['num']]['tr_curr']-1][$HTML2PDF_TABLEAU[$param['num']]['td_curr']-1] = array(); + $HTML2PDF_TABLEAU[$param['num']]['cases'][$HTML2PDF_TABLEAU[$param['num']]['tr_curr']-1][$HTML2PDF_TABLEAU[$param['num']]['td_curr']-1]['w'] = 0; + $HTML2PDF_TABLEAU[$param['num']]['cases'][$HTML2PDF_TABLEAU[$param['num']]['tr_curr']-1][$HTML2PDF_TABLEAU[$param['num']]['td_curr']-1]['h'] = 0; + $HTML2PDF_TABLEAU[$param['num']]['cases'][$HTML2PDF_TABLEAU[$param['num']]['tr_curr']-1][$HTML2PDF_TABLEAU[$param['num']]['td_curr']-1]['dw'] = 0; + $HTML2PDF_TABLEAU[$param['num']]['cases'][$HTML2PDF_TABLEAU[$param['num']]['tr_curr']-1][$HTML2PDF_TABLEAU[$param['num']]['td_curr']-1]['colspan'] = isset($param['colspan']) ? $param['colspan'] : 1; + $HTML2PDF_TABLEAU[$param['num']]['cases'][$HTML2PDF_TABLEAU[$param['num']]['tr_curr']-1][$HTML2PDF_TABLEAU[$param['num']]['td_curr']-1]['rowspan'] = isset($param['rowspan']) ? $param['rowspan'] : 1; + + // on extrait tout ce qui est contenu dans le TD + $res = $this->parsing->getLevel($this->temp_pos); + + // on en créé un sous HTML que l'on transforme en PDF + // pour analyse les dimensions + // et les récupérer dans le tableau global. + $this->CreateSubHTML($this->sub_html); + $this->sub_html->writeHTML($res[1]); + $this->temp_pos = $res[0]-2; + } + else + { + // on se positionne dans le tableau + $HTML2PDF_TABLEAU[$param['num']]['td_curr']++; + $HTML2PDF_TABLEAU[$param['num']]['td_x']+= $HTML2PDF_TABLEAU[$param['num']]['cases'][$HTML2PDF_TABLEAU[$param['num']]['tr_curr']-1][$HTML2PDF_TABLEAU[$param['num']]['td_curr']-1]['dw']; + + // initialisation du style des bordures de la premiere partie de tableau + $this->Rectangle( + $HTML2PDF_TABLEAU[$param['num']]['td_x'], + $HTML2PDF_TABLEAU[$param['num']]['td_y'], + $HTML2PDF_TABLEAU[$param['num']]['cases'][$HTML2PDF_TABLEAU[$param['num']]['tr_curr']-1][$HTML2PDF_TABLEAU[$param['num']]['td_curr']-1]['w'], + $HTML2PDF_TABLEAU[$param['num']]['cases'][$HTML2PDF_TABLEAU[$param['num']]['tr_curr']-1][$HTML2PDF_TABLEAU[$param['num']]['td_curr']-1]['h'], + $this->style->value['border'], + $this->style->value['padding'], + $HTML2PDF_TABLEAU[$param['num']]['cellspacing']*0.5, + $this->style->value['background'] + ); + + + $this->style->value['width'] = $HTML2PDF_TABLEAU[$param['num']]['cases'][$HTML2PDF_TABLEAU[$param['num']]['tr_curr']-1][$HTML2PDF_TABLEAU[$param['num']]['td_curr']-1]['w'] - $marge['l'] - $marge['r']; + + // limitation des marges aux dimensions de la case + $mL = $HTML2PDF_TABLEAU[$param['num']]['td_x']+$marge['l']; + $mR = $this->pdf->w - $mL - $this->style->value['width']; + $this->saveMargin($mL, 0, $mR); + + // positionnement en fonction + $h_corr = $HTML2PDF_TABLEAU[$param['num']]['cases'][$HTML2PDF_TABLEAU[$param['num']]['tr_curr']-1][$HTML2PDF_TABLEAU[$param['num']]['td_curr']-1]['h']; + $h_reel = $HTML2PDF_TABLEAU[$param['num']]['cases'][$HTML2PDF_TABLEAU[$param['num']]['tr_curr']-1][$HTML2PDF_TABLEAU[$param['num']]['td_curr']-1]['real_h']; + switch($this->style->value['vertical-align']) + { + case 'bottom': + $y_corr = $h_corr-$h_reel; + break; + + case 'middle': + $y_corr = ($h_corr-$h_reel)*0.5; + break; + + case 'top': + default: + $y_corr = 0; + break; + } + + $this->pdf->setX($HTML2PDF_TABLEAU[$param['num']]['td_x']+$marge['l']); + $this->pdf->setY($HTML2PDF_TABLEAU[$param['num']]['td_y']+$marge['t']+$y_corr); + $this->setNewPositionForNewLine(); + } + + return true; + } + + /** + * balise : TD + * mode : FERMETURE + * + * @param array paramètres de l'élément de parsing + * @return null + */ + function c_TD($param) + { + if ($this->forOneLine) return false; + + $this->maxH = 0; + global $HTML2PDF_TABLEAU; + + // récupération de la marge + $marge = array(); + $marge['t'] = $this->style->value['padding']['t']+0.5*$HTML2PDF_TABLEAU[$param['num']]['cellspacing']+$this->style->value['border']['t']['width']; + $marge['r'] = $this->style->value['padding']['r']+0.5*$HTML2PDF_TABLEAU[$param['num']]['cellspacing']+$this->style->value['border']['r']['width']; + $marge['b'] = $this->style->value['padding']['b']+0.5*$HTML2PDF_TABLEAU[$param['num']]['cellspacing']+$this->style->value['border']['b']['width']; + $marge['l'] = $this->style->value['padding']['l']+0.5*$HTML2PDF_TABLEAU[$param['num']]['cellspacing']+$this->style->value['border']['l']['width']; + $marge['t']+= 0.01; + $marge['r']+= 0.01; + $marge['b']+= 0.01; + $marge['l']+= 0.01; + + // si on est dans un sub_html + if ($this->sub_part) + { + if ($this->testTDin1page && $this->sub_html->pdf->page>1) HTML2PDF::makeError(7, __FILE__, __LINE__); + + // dimentions de cette case + $w0 = $this->sub_html->maxX + $marge['l'] + $marge['r']; + $h0 = $this->sub_html->maxY + $marge['t'] + $marge['b']; + + // dimensions imposées par le style + $w2 = $this->style->value['width'] + $marge['l'] + $marge['r']; + $h2 = $this->style->value['height'] + $marge['t'] + $marge['b']; + + // dimension finale de la case = max des 2 ci-dessus + $HTML2PDF_TABLEAU[$param['num']]['cases'][$HTML2PDF_TABLEAU[$param['num']]['tr_curr']-1][$HTML2PDF_TABLEAU[$param['num']]['td_curr']-1]['w'] = max(array($w0, $w2)); + $HTML2PDF_TABLEAU[$param['num']]['cases'][$HTML2PDF_TABLEAU[$param['num']]['tr_curr']-1][$HTML2PDF_TABLEAU[$param['num']]['td_curr']-1]['h'] = max(array($h0, $h2)); + + $HTML2PDF_TABLEAU[$param['num']]['cases'][$HTML2PDF_TABLEAU[$param['num']]['tr_curr']-1][$HTML2PDF_TABLEAU[$param['num']]['td_curr']-1]['real_w'] = $w0; + $HTML2PDF_TABLEAU[$param['num']]['cases'][$HTML2PDF_TABLEAU[$param['num']]['tr_curr']-1][$HTML2PDF_TABLEAU[$param['num']]['td_curr']-1]['real_h'] = $h0; + + // suppresion du sous_html + $this->DestroySubHTML(); + } + else + { + $this->loadMargin(); + //positionnement + $HTML2PDF_TABLEAU[$param['num']]['td_x']+= $HTML2PDF_TABLEAU[$param['num']]['cases'][$HTML2PDF_TABLEAU[$param['num']]['tr_curr']-1][$HTML2PDF_TABLEAU[$param['num']]['td_curr']-1]['w']; + } + + // restauration du style + $this->style->load(); + $this->style->FontSet(); + + return true; + } + + function calculTailleCases(&$cases) + { + // construction d'un tableau de correlation + $corr = array(); + + // on fait correspondre chaque case d'un tableau normé aux cases réelles, en prennant en compte les colspan et rowspan + $Yr=0; + for($y=0; $y0) ? '' : array($x, $y, $cases[$y][$x]['colspan'], $cases[$y][$x]['rowspan']); + } + } + $Xr+= $cases[$y][$x]['colspan']; + while(isset($corr[$Yr][$Xr])) $Xr++; + } + $Yr++; + } + + if (!isset($corr[0])) return true; + + // on détermine, pour les cases sans colspan, la largeur maximale de chaque colone + $sw = array(); + for($x=0; $x1) + { + // somme des colonnes correspondant au colspan + $s = 0; for($i=0; $i<$corr[$y][$x][2]; $i++) $s+= $sw[$x+$i]; + + // si la somme est inférieure à la taille necessaire => règle de 3 pour adapter + if ($s>0 && $s<$cases[$corr[$y][$x][1]][$corr[$y][$x][0]]['w']) + for($i=0; $i<$corr[$y][$x][2]; $i++) + $sw[$x+$i] = $sw[$x+$i]/$s*$cases[$corr[$y][$x][1]][$corr[$y][$x][0]]['w']; + } + } + } + + // on applique les nouvelles largeurs + for($x=0; $x1) + { + // somme des colonnes correspondant au colspan + $s = 0; for($i=0; $i<$corr[$y][$x][3]; $i++) $s+= $sh[$y+$i]; + + // si la somme est inférieure à la taille necessaire => règle de 3 pour adapter + if ($s>0 && $s<$cases[$corr[$y][$x][1]][$corr[$y][$x][0]]['h']) + for($i=0; $i<$corr[$y][$x][3]; $i++) + $sh[$y+$i] = $sh[$y+$i]/$s*$cases[$corr[$y][$x][1]][$corr[$y][$x][0]]['h']; + } + } + } + + + // on applique les nouvelles hauteurs + for($y=0; $yforOneLine) return false; + + $this->maxH = 0; + // identique à TD mais en gras + if (!isset($param['style']['font-weight'])) $param['style']['font-weight'] = 'bold'; + $this->o_TD($param, 'th'); + + return true; + } + + /** + * balise : TH + * mode : FERMETURE + * + * @param array paramètres de l'élément de parsing + * @return null + */ + function c_TH($param) + { + if ($this->forOneLine) return false; + + $this->maxH = 0; + // identique à TD + $this->c_TD($param); + + return true; + } + + /** + * balise : IMG + * mode : OUVERTURE + * + * @param array paramètres de l'élément de parsing + * @return null + */ + function o_IMG($param) + { + // analyse du style + $src = str_replace('&', '&', $param['src']); + + $this->style->save(); + $this->style->value['width'] = 0; + $this->style->value['height'] = 0; + $this->style->value['border'] = array( + 'type' => 'none', + 'width' => 0, + 'color' => array(0, 0, 0), + ); + $this->style->value['background'] = array( + 'color' => null, + 'image' => null, + 'position' => null, + 'repeat' => null + ); + $this->style->analyse('img', $param); + $this->style->setPosition($this->pdf->x, $this->pdf->y); + $this->style->FontSet(); + + // affichage de l'image + $this->Image($src, isset($param['sub_li'])); + + // restauration du style + $this->style->load(); + $this->style->FontSet(); + + return true; + } + + /** + * balise : SELECT + * mode : OUVERTURE + * + * @param array paramètres de l'élément de parsing + * @return null + */ + function o_SELECT($param) + { + // preparation du champs + if (!isset($param['name'])) $param['name'] = 'champs_pdf_'.(count($this->lstChamps)+1); + + $param['name'] = strtolower($param['name']); + + if (isset($this->champs[$param['name']])) + $this->champs[$param['name']]++; + else + $this->champs[$param['name']] = 1; + + $this->style->save(); + $this->style->analyse('select', $param); + $this->style->setPosition($this->pdf->x, $this->pdf->y); + $this->style->FontSet(); + + $this->lstSelect = array(); + $this->lstSelect['name'] = $param['name']; + $this->lstSelect['multi'] = isset($param['multiple']) ? true : false; + $this->lstSelect['size'] = isset($param['size']) ? $param['size'] : 1; + $this->lstSelect['options'] = array(); + + if ($this->lstSelect['multi'] && $this->lstSelect['size']<3) $this->lstSelect['size'] = 3; + + return true; + } + + /** + * balise : OPTION + * mode : OUVERTURE + * + * @param array paramètres de l'élément de parsing + * @return null + */ + function o_OPTION($param) + { + // on extrait tout ce qui est contenu dans l'option + $res = $this->parsing->getLevel($this->parse_pos); + $this->parse_pos = $res[0]-2; + $texte = $res[1]; + $value = isset($param['value']) ? $param['value'] : 'auto_opt_'.(count($this->lstSelect)+1); + + $this->lstSelect['options'][$value] = $texte; + + return true; + } + + /** + * balise : OPTION + * mode : FERMETURE + * + * @param array paramètres de l'élément de parsing + * @return null + */ + function c_OPTION($param) { return true; } + + /** + * balise : SELECT + * mode : FERMETURE + * + * @param array paramètres de l'élément de parsing + * @return null + */ + function c_SELECT() + { + // position d'affichage + $x = $this->pdf->getX(); + $y = $this->pdf->getY(); + $f = 1.08*$this->style->value['font-size']; + + $w = $this->style->value['width']; if (!$w) $w = 50; + $h = ($f*1.07*$this->lstSelect['size'] + 1); + $prop = array(); + if ($this->lstSelect['multi']) $prop['multipleSelection'] = true; + $this->pdf->form_Select($this->lstSelect['name'], $x, $y, $w, $h, $this->lstSelect['options'], $this->lstSelect['size']>1, $prop); + + $this->maxX = max($this->maxX, $x+$w); + $this->maxY = max($this->maxY, $y+$h); + $this->maxH = max($this->maxH, $h); + $this->pdf->setX($x+$w); + + $this->style->load(); + $this->style->FontSet(); + + $this->lstSelect = array(); + + return true; + } + + /** + * balise : TEXTAREA + * mode : OUVERTURE + * + * @param array paramètres de l'élément de parsing + * @return null + */ + function o_TEXTAREA($param) + { + // preparation du champs + if (!isset($param['name'])) $param['name'] = 'champs_pdf_'.(count($this->lstChamps)+1); + + $param['name'] = strtolower($param['name']); + + if (isset($this->champs[$param['name']])) + $this->champs[$param['name']]++; + else + $this->champs[$param['name']] = 1; + + $this->style->save(); + $this->style->analyse('textarea', $param); + $this->style->setPosition($this->pdf->x, $this->pdf->y); + $this->style->FontSet(); + + // position d'affichage + $x = $this->pdf->getX(); + $y = $this->pdf->getY(); + $fx = 0.65*$this->style->value['font-size']; + $fy = 1.08*$this->style->value['font-size']; + + // on extrait tout ce qui est contenu dans le textarea + $res = $this->parsing->getLevel($this->parse_pos); + $this->parse_pos = $res[0]-2; + $texte = $res[1]; + + $w = $fx*(isset($param['cols']) ? $param['cols'] : 22)+1; + $h = $fy*1.07*(isset($param['rows']) ? $param['rows'] : 3)+3; + +// if ($this->style->value['width']) $w = $this->style->value['width']; +// if ($this->style->value['height']) $h = $this->style->value['height']; + + $prop = array(); + $prop['value'] = $texte; + $prop['multiline'] = true; + + $this->pdf->form_InputText($param['name'], $x, $y, $w, $h, $prop); + + $this->maxX = max($this->maxX, $x+$w); + $this->maxY = max($this->maxY, $y+$h); + $this->maxH = max($this->maxH, $h); + $this->pdf->setX($x+$w); + + return true; + } + + /** + * balise : TEXTAREA + * mode : FERMETURE + * + * @param array paramètres de l'élément de parsing + * @return null + */ + function c_TEXTAREA() + { + $this->style->load(); + $this->style->FontSet(); + + return true; + } + + /** + * balise : INPUT + * mode : OUVERTURE + * + * @param array paramètres de l'élément de parsing + * @return null + */ + function o_INPUT($param) + { + // preparation du champs + if (!isset($param['name'])) $param['name'] = 'champs_pdf_'.(count($this->lstChamps)+1); + if (!isset($param['value'])) $param['value'] = ''; + if (!isset($param['type'])) $param['type'] = 'text'; + + $param['name'] = strtolower($param['name']); + $param['type'] = strtolower($param['type']); + + if (!in_array($param['type'], array('text', 'checkbox', 'radio', 'hidden', 'submit', 'reset', 'button'))) $param['type'] = 'text'; + + if (isset($this->champs[$param['name']])) + $this->champs[$param['name']]++; + else + $this->champs[$param['name']] = 1; + + $this->style->save(); + $this->style->analyse('input', $param); + $this->style->setPosition($this->pdf->x, $this->pdf->y); + $this->style->FontSet(); + + $name = $param['name']; + + // position d'affichage + $x = $this->pdf->getX(); + $y = $this->pdf->getY(); + $f = 1.08*$this->style->value['font-size']; + + switch($param['type']) + { + case 'checkbox': + $w = 3; + $h = $w; + if ($h<$f) $y+= ($f-$h)*0.5; + $this->pdf->form_InputCheckBox($name, $x, $y, $w, isset($param['checked'])); + break; + + case 'radio': + $w = 3; + $h = $w; + if ($h<$f) $y+= ($f-$h)*0.5; + $this->pdf->form_InputRadio($name, $x, $y, $w); + break; + + case 'hidden': + $w = 0; + $h = 0; + $this->pdf->form_InputHidden($name, $param['value']); + break; + + case 'text': + $w = $this->style->value['width']; if (!$w) $w = 40; + $h = $f*1.3; + $prop = array(); + $prop['value'] = $param['value']; + $this->pdf->form_InputText($name, $x, $y, $w, $h, $prop); + break; + + case 'submit': + case 'reset': + case 'button': + $action = isset($param['onclick']) ? $param['onclick'] : ''; + $w = $this->style->value['width']; if (!$w) $w = 40; + $h = $this->style->value['height']; if (!$h) $h = $f*1.3; + $prop = array(); + $this->pdf->form_InputButton($name, $x, $y, $w, $h, $param['value'], $action, $prop); + break; + + default: + $w = 0; + $h = 0; + break; + } + + $this->maxX = max($this->maxX, $x+$w); + $this->maxY = max($this->maxY, $y+$h); + $this->maxH = max($this->maxH, $h); + $this->pdf->setX($x+$w); + + $this->style->load(); + $this->style->FontSet(); + + return true; + } + + function textLOAD($langue) + { + if (!preg_match('/^([a-z0-9]+)$/isU', $langue)) + { + echo 'ERROR : language code '.$langue.' incorrect.'; + exit; + } + + $file = dirname(__FILE__).'/langues/'.strtolower($langue).'.txt'; + if (!is_file($file)) + { + echo 'ERROR : language code '.$langue.' unknown.
'; + echo 'You can create the translation file '.$file.' and send it to me in order to integrate it into a future version.'; + exit; + } + + $texte = array(); + $infos = file($file); + foreach($infos as $val) + { + $val = trim($val); + $val = explode("\t", $val); + if (count($val)<2) continue; + + $t_k = trim($val[0]); unset($val[0]); + $t_v = trim(implode(' ', $val)); + if ($t_k && $t_v) $texte[$t_k] = $t_v; + } + global $HTML2PDF_TEXTE_FILE; + $HTML2PDF_TEXTE_FILE = $texte; + } + + function textGET($key) + { + global $HTML2PDF_TEXTE_FILE; + if (!isset($HTML2PDF_TEXTE_FILE[$key])) return '######'; + + return $HTML2PDF_TEXTE_FILE[$key]; + } + + function makeError($err, $file, $line, $other = null) + { + $msg = ''; + switch($err) + { + case 1: + $msg = (HTML2PDF::textGET('err01')); + $msg = str_replace('[[OTHER]]', $other, $msg); + break; + + case 2: + $msg = (HTML2PDF::textGET('err02')); + $msg = str_replace('[[OTHER_0]]', $other[0], $msg); + $msg = str_replace('[[OTHER_1]]', $other[1], $msg); + $msg = str_replace('[[OTHER_2]]', $other[2], $msg); + break; + + case 3: + $msg = (HTML2PDF::textGET('err03')); + $msg = str_replace('[[OTHER]]', $other, $msg); + break; + + case 4: + $msg = (HTML2PDF::textGET('err04')); + $msg = str_replace('[[OTHER]]', print_r($other, true), $msg); + break; + + case 5: + $msg = (HTML2PDF::textGET('err05')); + $msg = str_replace('[[OTHER]]', print_r($other, true), $msg); + break; + + case 6: + $msg = (HTML2PDF::textGET('err06')); + $msg = str_replace('[[OTHER]]', $other, $msg); + break; + + case 7: + $msg = (HTML2PDF::textGET('err07')); + break; + } + echo ''.(HTML2PDF::textGET('txt01')).$err.'
'; + echo (HTML2PDF::textGET('txt02')).' '.$file.'
'; + echo (HTML2PDF::textGET('txt03')).' '.$line.'
'; + echo '
'; + echo $msg; + exit; + } + } +} + diff --git a/main/inc/lib/html2pdf/parsingHTML.class.php b/main/inc/lib/html2pdf/parsingHTML.class.php new file mode 100644 index 0000000000..3f0274505c --- /dev/null +++ b/main/inc/lib/html2pdf/parsingHTML.class.php @@ -0,0 +1,421 @@ + PDF, utilise fpdf de Olivier PLATHEY + * Distribué sous la licence LGPL. + * + * @author Laurent MINGUET + * @version 3.22a - 15/06/2009 + */ + +if (!defined('__CLASS_PARSINGHTML__')) +{ + define('__CLASS_PARSINGHTML__', true); + + class parsingHTML + { + var $html = ''; // code HTML à parser + var $code = array(); // code HTML parsé + var $num = 0; // numéro de table + var $level = 0; // niveaux de table + + /** + * Constructeur + * + * @return null + */ + function parsingHTML() + { + $this->num = 0; + $this->level = array($this->num); + $this->html = ''; + $this->code = array(); + } + + /** + * Définir le code HTML à parser + * + * @param string code html + * @return null + */ + function setHTML($html) + { + $html = preg_replace('//isU', '', $html); + $this->html = $html; + } + + /** + * parser le code HTML + * + * @return null + */ + function parse() + { + $parents = array(); + // récupérer le code à parser + $content = $this->html; + + // chercher les balises HTML du code + $tmp = array(); + $this->searchCode($content, $tmp); + + // identifier les balises une à une + $pre_in = false; + $pre_br = array( + 'name' => 'br', + 'close' => false, + 'param' => array( + 'style' => array(), + 'num' => 0 + ) + ); + + $todos = array(); + foreach($tmp as $part) + { + // si c'est un texte + if ($part[0]=='txt') + { + // enregistrer l'action correspondante + if (!$pre_in) + { + if (trim($part[1])!=='') + { + // remplacer tous les espaces, tabulations, saufs de ligne multiples par de simples espaces + $part[1] = preg_replace('/([\s]+)/is', ' ', $part[1]); + + $todos[] = array( + 'name' => 'write', + 'close' => false, + 'param' => array('txt' => $part[1]), + ); + } + } + else + { + $part[1] = str_replace("\r", '', $part[1]); + $part[1] = explode("\n", $part[1]); + + foreach($part[1] as $k => $txt) + { + $txt = str_replace("\t", ' ', $txt); + $txt = str_replace(' ', ' ', $txt); + if ($k>0) $todos[] = $pre_br; + + $todos[] = array( + 'name' => 'write', + 'close' => false, + 'param' => array('txt' => $txt), + ); + } + } + } + // sinon, analyser le code + else + { + $res = $this->analiseCode($part[1]); + if ($res) + { + if (!in_array($res['name'], array('br', 'hr', 'img', 'input', 'link', 'option'))) + { + if ($res['close']) + { + if (count($parents)<1) + HTML2PDF::makeError(3, __FILE__, __LINE__, $res['name']); + else if ($parents[count($parents)-1]!=$res['name']) + HTML2PDF::makeError(4, __FILE__, __LINE__, $parents); + else + unset($parents[count($parents)-1]); + } + else + { + $parents[count($parents)] = $res['name']; + } + } + if ($res['name']=='pre' || $res['name']=='code') + { + $pre_in = !$res['close']; + } + $todos[] = $res; + } + } + } + + // pour chaque action identifiée, il faut nettoyer le début et la fin des textes + // en fonction des balises qui l'entourent. + $nb = count($todos); + for($k=0; $k<$nb; $k++) + { + //si c'est un texte + if ($todos[$k]['name']=='write') + { + // et qu'une balise spécifique le précède => on nettoye les espaces du début du texte + if ($k>0 && in_array($todos[$k-1]['name'], array('table', 'tr', 'td', 'th', 'br', 'div', 'hr', 'p', 'ul', 'ol', 'li'))) + $todos[$k]['param']['txt'] = preg_replace('/^([\s]*)([^\s])/isU', '$2', $todos[$k]['param']['txt']); + + // et qu'une balise spécifique le suit => on nettoye les espaces de la fin du texte + if ($kcode = $todos; + } + + /** + * parser le code HTML + * + * @param string contenu à parser. + * @param &array tableau de retour des données + * @return null + */ + function searchCode($content, &$tmp) + { + // séparer les balises du texte + $tmp = array(); + $reg = '/(<[^>]+>)|([^<]+)+/isU'; + + // pour chaque élément trouvé : + $str = ''; + $offset = 0; + while(preg_match($reg, $content, $parse, PREG_OFFSET_CAPTURE, $offset)) + { + // si une balise a été détectée + if ($parse[1][0]) + { + // sauvegarde du texte précédent si il existe + if ($str!=='') $tmp[] = array('txt',$str); + + // sauvegarde de la balise + $tmp[] = array('code',trim($parse[1][0])); + + // initialisation du texte suivant + $str = ''; + } + else + { + // ajout du texte à la fin de celui qui est déjà détecté + $str.= $parse[2][0]; + } + // Update offset to the end of the match + $offset = $parse[0][1] + strlen($parse[0][0]); + unset($parse); + } + // si un texte est présent à la fin, on l'enregistre + if ($str!='') $tmp[] = array('txt',$str); + unset($str); + } + + /** + * analyse une balise HTML + * + * @param string code HTML à identifier + * @return array action correspondante + */ + function analiseCode($code) + { + // nom de la balise et ouverture ou fermeture + $balise = '<([\/]{0,1})([_a-z0-9]+)([\/>\s]+)'; + preg_match('/'.$balise.'/isU', $code, $match); + $close = ($match[1]=='/' ? true : false); + $name = strtolower($match[2]); + + // paramètres obligatoires en fonction du nom de la balise + $param = array(); + $param['style'] = ''; + if ($name=='img') { $param['alt'] = ''; $param['src'] = ''; } + if ($name=='a') { $param['href'] = ''; } + + // lecture des paramétres du type nom=valeur + $prop = '([a-zA-Z0-9_]+)=([^"\'\s>]+)'; + preg_match_all('/'.$prop.'/is', $code, $match); + for($k=0; $k $val) + { + $key = strtolower($key); + switch($key) + { + case 'width': + unset($param[$key]); + $param['style'] = 'width: '.$val.'px; '.$param['style']; + break; + + case 'align': + if ($name!=='table') + { + unset($param[$key]); + $param['style'] = 'text-align: '.$val.'; '.$param['style']; + } + break; + + case 'valign': + unset($param[$key]); + $param['style'] = 'vertical-align: '.$val.'; '.$param['style']; + break; + + case 'height': + unset($param[$key]); + $param['style'] = 'height: '.$val.'px; '.$param['style']; + break; + + case 'bgcolor': + unset($param[$key]); + $param['style'] = 'background: '.$val.'; '.$param['style']; + break; + + case 'bordercolor': + unset($param[$key]); + $color = $val; + break; + + case 'border': + unset($param[$key]); + if (preg_match('/^[0-9]$/isU', $val)) $val = $val.'px'; + $border = $val; + break; + + case 'cellpadding': + case 'cellspacing': + if (preg_match('/^([0-9]+)$/isU', $val)) $param[$key] = $val.'px'; + break; + + case 'colspan': + case 'rowspan': + $val = preg_replace('/[^0-9]/isU', '', $val); + if (!$val) $val = 1; + $param[$key] = $val; + break; + } + } + if ($border!==null) + { + if ($border) $param['style'] = 'border: solid '.$border.' '.$color.'; '.$param['style']; + else $param['style'] = 'border: none'; + } + + // lecture des styles - décomposition + $styles = explode(';', $param['style']); + $param['style'] = array(); + foreach($styles as $style) + { + $tmp = explode(':', $style); + if (count($tmp)>1) + { + $cod = $tmp[0]; unset($tmp[0]); $tmp = implode(':', $tmp); + $param['style'][trim(strtolower($cod))] = preg_replace('/[\s]+/isU', ' ', trim($tmp)); + } + } + + // détermination du niveau de table pour les ouverture, avec ajout d'un level + if (in_array($name, array('ul', 'ol', 'table')) && !$close) + { + $this->num++; + $this->level[count($this->level)] = $this->num; + } + + // attribution du niveau de table où se trouve l'élément + if (!isset($param['num'])) $param['num'] = $this->level[count($this->level)-1]; + + // pour les fins de table : suppression d'un level + if (in_array($name, array('ul', 'ol', 'table')) && $close) + { + unset($this->level[count($this->level)-1]); + } + + // retour de l'action identifiée + return array('name' => $name, 'close' => $close ? 1 : 0, 'param' => $param); + } + + // récupérer un niveau complet d'HTML entre une ouverture de balise et la fermeture correspondante + function getLevel($k) + { + // si le code n'existe pas : fin + if (!isset($this->code[$k])) return ''; + + // quelle balise faudra-t-il détecter + $detect = $this->code[$k]['name']; + + $level = 0; // niveau de profondeur + $end = false; // etat de fin de recherche + $code = ''; // code extrait + + // tant que c'est pas fini, on boucle + while (!$end) + { + // action courante + $row = $this->code[$k]; + + // si write => on ajoute le texte + if ($row['name']=='write') + { + $code.= $row['param']['txt']; + } + // sinon, c'est une balise html + else + { + $not = false; // indicateur de non prise en compte de la balise courante + + // si c'est la balise que l'on cherche + if ($row['name']==$detect) + { + if ($level==0) { $not = true; } // si on est à la premiere balise : on l'ignore + $level+= ($row['close'] ? -1 : 1); // modification du niveau en cours en fonction de l'ouvertre / fermeture + if ($level==0) { $not = true; $end = true; } // si on est au niveau 0 : on a fini + } + + // si on doit prendre en compte la balise courante + if (!$not) + { + // ecriture du code HTML de la balise + $code.= '<'.($row['close'] ? '/' : '').$row['name']; + foreach($row['param'] as $key => $val) + { + if ($key=='style') + { + $tmp = ''; + if (isset($val['text-align'])) unset($val['text-align']); + foreach($val as $ks => $vs) $tmp.= $ks.':'.$vs.'; '; + if (trim($tmp)) $code.= ' '.$key.'="'.$tmp.'"'; + } + else + { + $code.= ' '.$key.'="'.$val.'"'; + } + } + $code.= '>'; + } + } + + // on continue tant qu'il y a du code à analyser... + if (isset($this->code[$k+1])) + $k++; + else + $end = true; + } + + // retourne la position finale et le code HTML extrait + return array($k, $code); + } + } +} +?> \ No newline at end of file diff --git a/main/inc/lib/html2pdf/styleHTML.class.php b/main/inc/lib/html2pdf/styleHTML.class.php new file mode 100644 index 0000000000..272e6c436d --- /dev/null +++ b/main/inc/lib/html2pdf/styleHTML.class.php @@ -0,0 +1,1440 @@ + PDF, utilise fpdf de Olivier PLATHEY + * Distribué sous la licence LGPL. + * + * @author Laurent MINGUET + * @version 3.22a - 15/06/2009 + */ + +if (!defined('__CLASS_STYLEHTML__')) +{ + define('__CLASS_STYLEHTML__', true); + + class styleHTML + { + var $css = array(); // tableau des CSS + var $css_keys = array(); // tableau des clefs CSS, pour l'ordre d'execution + var $value = array(); // valeurs actuelles + var $table = array(); // tableau d'empilement pour historisation des niveaux + var $pdf = null; // référence au PDF parent + var $htmlColor = array(); // liste des couleurs HTML + var $onlyLeft = false; // indique si on est dans un sous HTML et qu'on bloque à gauche + + /** + * Constructeur + * + * @param &pdf référence à l'objet HTML2PDF parent + * @return null + */ + function styleHTML(&$pdf) + { + $this->init(); // initialisation + $this->pdf = &$pdf; + } + + /** + * Initialisation du style + * + * @return null + */ + function init() + { + $color = array(); + $color['AliceBlue'] = '#F0F8FF'; + $color['AntiqueWhite'] = '#FAEBD7'; + $color['Aqua'] = '#00FFFF'; + $color['Aquamarine'] = '#7FFFD4'; + $color['Azure'] = '#F0FFFF'; + $color['Beige'] = '#F5F5DC'; + $color['Bisque'] = '#FFE4C4'; + $color['Black'] = '#000000'; + $color['BlanchedAlmond'] = '#FFEBCD'; + $color['Blue'] = '#0000FF'; + $color['BlueViolet'] = '#8A2BE2'; + $color['Brown'] = '#A52A2A'; + $color['BurlyWood'] = '#DEB887'; + $color['CadetBlue'] = '#5F9EA0'; + $color['Chartreuse'] = '#7FFF00'; + $color['Chocolate'] = '#D2691E'; + $color['Coral'] = '#FF7F50'; + $color['CornflowerBlue'] = '#6495ED'; + $color['Cornsilk'] = '#FFF8DC'; + $color['Crimson'] = '#DC143C'; + $color['Cyan'] = '#00FFFF'; + $color['DarkBlue'] = '#00008B'; + $color['DarkCyan'] = '#008B8B'; + $color['DarkGoldenRod'] = '#B8860B'; + $color['DarkGray'] = '#A9A9A9'; + $color['DarkGrey'] = '#A9A9A9'; + $color['DarkGreen'] = '#006400'; + $color['DarkKhaki'] = '#BDB76B'; + $color['DarkMagenta'] = '#8B008B'; + $color['DarkOliveGreen'] = '#556B2F'; + $color['Darkorange'] = '#FF8C00'; + $color['DarkOrchid'] = '#9932CC'; + $color['DarkRed'] = '#8B0000'; + $color['DarkSalmon'] = '#E9967A'; + $color['DarkSeaGreen'] = '#8FBC8F'; + $color['DarkSlateBlue'] = '#483D8B'; + $color['DarkSlateGray'] = '#2F4F4F'; + $color['DarkSlateGrey'] = '#2F4F4F'; + $color['DarkTurquoise'] = '#00CED1'; + $color['DarkViolet'] = '#9400D3'; + $color['DeepPink'] = '#FF1493'; + $color['DeepSkyBlue'] = '#00BFFF'; + $color['DimGray'] = '#696969'; + $color['DimGrey'] = '#696969'; + $color['DodgerBlue'] = '#1E90FF'; + $color['FireBrick'] = '#B22222'; + $color['FloralWhite'] = '#FFFAF0'; + $color['ForestGreen'] = '#228B22'; + $color['Fuchsia'] = '#FF00FF'; + $color['Gainsboro'] = '#DCDCDC'; + $color['GhostWhite'] = '#F8F8FF'; + $color['Gold'] = '#FFD700'; + $color['GoldenRod'] = '#DAA520'; + $color['Gray'] = '#808080'; + $color['Grey'] = '#808080'; + $color['Green'] = '#008000'; + $color['GreenYellow'] = '#ADFF2F'; + $color['HoneyDew'] = '#F0FFF0'; + $color['HotPink'] = '#FF69B4'; + $color['IndianRed'] = '#CD5C5C'; + $color['Indigo'] = '#4B0082'; + $color['Ivory'] = '#FFFFF0'; + $color['Khaki'] = '#F0E68C'; + $color['Lavender'] = '#E6E6FA'; + $color['LavenderBlush'] = '#FFF0F5'; + $color['LawnGreen'] = '#7CFC00'; + $color['LemonChiffon'] = '#FFFACD'; + $color['LightBlue'] = '#ADD8E6'; + $color['LightCoral'] = '#F08080'; + $color['LightCyan'] = '#E0FFFF'; + $color['LightGoldenRodYellow'] = '#FAFAD2'; + $color['LightGray'] = '#D3D3D3'; + $color['LightGrey'] = '#D3D3D3'; + $color['LightGreen'] = '#90EE90'; + $color['LightPink'] = '#FFB6C1'; + $color['LightSalmon'] = '#FFA07A'; + $color['LightSeaGreen'] = '#20B2AA'; + $color['LightSkyBlue'] = '#87CEFA'; + $color['LightSlateGray'] = '#778899'; + $color['LightSlateGrey'] = '#778899'; + $color['LightSteelBlue'] = '#B0C4DE'; + $color['LightYellow'] = '#FFFFE0'; + $color['Lime'] = '#00FF00'; + $color['LimeGreen'] = '#32CD32'; + $color['Linen'] = '#FAF0E6'; + $color['Magenta'] = '#FF00FF'; + $color['Maroon'] = '#800000'; + $color['MediumAquaMarine'] = '#66CDAA'; + $color['MediumBlue'] = '#0000CD'; + $color['MediumOrchid'] = '#BA55D3'; + $color['MediumPurple'] = '#9370D8'; + $color['MediumSeaGreen'] = '#3CB371'; + $color['MediumSlateBlue'] = '#7B68EE'; + $color['MediumSpringGreen'] = '#00FA9A'; + $color['MediumTurquoise'] = '#48D1CC'; + $color['MediumVioletRed'] = '#C71585'; + $color['MidnightBlue'] = '#191970'; + $color['MintCream'] = '#F5FFFA'; + $color['MistyRose'] = '#FFE4E1'; + $color['Moccasin'] = '#FFE4B5'; + $color['NavajoWhite'] = '#FFDEAD'; + $color['Navy'] = '#000080'; + $color['OldLace'] = '#FDF5E6'; + $color['Olive'] = '#808000'; + $color['OliveDrab'] = '#6B8E23'; + $color['Orange'] = '#FFA500'; + $color['OrangeRed'] = '#FF4500'; + $color['Orchid'] = '#DA70D6'; + $color['PaleGoldenRod'] = '#EEE8AA'; + $color['PaleGreen'] = '#98FB98'; + $color['PaleTurquoise'] = '#AFEEEE'; + $color['PaleVioletRed'] = '#D87093'; + $color['PapayaWhip'] = '#FFEFD5'; + $color['PeachPuff'] = '#FFDAB9'; + $color['Peru'] = '#CD853F'; + $color['Pink'] = '#FFC0CB'; + $color['Plum'] = '#DDA0DD'; + $color['PowderBlue'] = '#B0E0E6'; + $color['Purple'] = '#800080'; + $color['Red'] = '#FF0000'; + $color['RosyBrown'] = '#BC8F8F'; + $color['RoyalBlue'] = '#4169E1'; + $color['SaddleBrown'] = '#8B4513'; + $color['Salmon'] = '#FA8072'; + $color['SandyBrown'] = '#F4A460'; + $color['SeaGreen'] = '#2E8B57'; + $color['SeaShell'] = '#FFF5EE'; + $color['Sienna'] = '#A0522D'; + $color['Silver'] = '#C0C0C0'; + $color['SkyBlue'] = '#87CEEB'; + $color['SlateBlue'] = '#6A5ACD'; + $color['SlateGray'] = '#708090'; + $color['SlateGrey'] = '#708090'; + $color['Snow'] = '#FFFAFA'; + $color['SpringGreen'] = '#00FF7F'; + $color['SteelBlue'] = '#4682B4'; + $color['Tan'] = '#D2B48C'; + $color['Teal'] = '#008080'; + $color['Thistle'] = '#D8BFD8'; + $color['Tomato'] = '#FF6347'; + $color['Turquoise'] = '#40E0D0'; + $color['Violet'] = '#EE82EE'; + $color['Wheat'] = '#F5DEB3'; + $color['White'] = '#FFFFFF'; + $color['WhiteSmoke'] = '#F5F5F5'; + $color['Yellow'] = '#FFFF00'; + $color['YellowGreen'] = '#9ACD32'; + + $this->htmlColor = array(); + foreach($color as $key => $val) $this->htmlColor[strtolower($key)] = $val; + unset($color); + + $this->table = array(); + + $this->value = array(); + $this->initStyle(); + + // initialisation des styles sans héritages + $this->resetStyle(); + } + + function initStyle() + { + $this->value['id_balise'] = 'body'; // balise + $this->value['id_name'] = null; // name + $this->value['id_id'] = null; // id + $this->value['id_class'] = null; // class + $this->value['id_lst'] = array('*'); // lst de dependance + $this->value['mini-size'] = 1.; // rapport de taille spécifique aux sup, sub + $this->value['mini-decal'] = 0; // rapport de position spécifique aux sup, sub + $this->value['font-family'] = 'Arial'; + $this->value['font-bold'] = false; + $this->value['font-italic'] = false; + $this->value['font-underline'] = false; + $this->value['font-overline'] = false; + $this->value['font-linethrough'] = false; + $this->value['font-size'] = $this->ConvertToMM('10pt'); + $this->value['text-indent'] = 0; + $this->value['text-align'] = 'left'; + $this->value['vertical-align'] = 'middle'; + $this->value['line-height'] = 'normal'; + + $this->value['position'] = null; + $this->value['x'] = null; + $this->value['y'] = null; + $this->value['width'] = 0; + $this->value['height'] = 0; + $this->value['top'] = null; + $this->value['right'] = null; + $this->value['bottom'] = null; + $this->value['left'] = null; + $this->value['float'] = null; + $this->value['display'] = null; + + $this->value['color'] = array(0, 0, 0); + $this->value['background'] = array('color' => null, 'image' => null, 'position' => null, 'repeat' => null); + $this->value['border'] = array(); + $this->value['padding'] = array(); + $this->value['margin'] = array(); + $this->value['margin-auto'] = false; + + $this->value['list-style-type'] = ''; + $this->value['list-style-image'] = ''; + + $this->value['xc'] = null; + $this->value['yc'] = null; + } + + /** + * Initialisation des styles sans héritages + * + * @param string balise HTML + * @return null + */ + function resetStyle($balise = '') + { + $collapse = isset($this->value['border']['collapse']) ? $this->value['border']['collapse'] : false; + if (!in_array($balise, array('tr', 'td', 'th'))) $collapse = false; + + $this->value['position'] = null; + $this->value['x'] = null; + $this->value['y'] = null; + $this->value['width'] = 0; + $this->value['height'] = 0; + $this->value['top'] = null; + $this->value['right'] = null; + $this->value['bottom'] = null; + $this->value['left'] = null; + $this->value['float'] = null; + $this->value['display'] = null; + $this->value['background'] = array('color' => null, 'image' => null, 'position' => null, 'repeat' => null); + $this->value['border'] = array( + 't' => $this->readBorder('none'), + 'r' => $this->readBorder('none'), + 'b' => $this->readBorder('none'), + 'l' => $this->readBorder('none'), + 'radius' => array(0, 0), + 'collapse' => $collapse, + ); + + $this->value['margin'] = array( + 't' => 0, + 'r' => 0, + 'b' => 0, + 'l' => 0 + ); + $this->value['margin-auto'] = false; + + if (in_array($balise, array('div'))) + $this->value['vertical-align'] = 'top'; + + if (in_array($balise, array('ul', 'li'))) + { + $this->value['list-style-type'] = ''; + $this->value['list-style-image'] = ''; + } + + if (!in_array($balise, array('tr', 'td'))) + { + $this->value['padding'] = array( + 't' => 0, + 'r' => 0, + 'b' => 0, + 'l' => 0 + ); + } + else + { + $this->value['padding'] = array( + 't' => $this->ConvertToMM('1px'), + 'r' => $this->ConvertToMM('1px'), + 'b' => $this->ConvertToMM('1px'), + 'l' => $this->ConvertToMM('1px') + ); + } + + if ($balise=='hr') + { + $this->value['border'] = array( + 't' => $this->readBorder('solid 1px #000000'), + 'r' => $this->readBorder('solid 1px #000000'), + 'b' => $this->readBorder('solid 1px #000000'), + 'l' => $this->readBorder('solid 1px #000000'), + 'radius' => array(0, 0), + 'collapse' => false, + ); + $this->ConvertBackground('#FFFFFF', $this->value['background']); + } + + $this->value['xc'] = null; + $this->value['yc'] = null; + } + + /** + * Initialisation de la font PDF + * + * @return null + */ + function FontSet() + { + $b = ($this->value['font-bold'] ? 'B' : ''); + $i = ($this->value['font-italic'] ? 'I' : ''); + $u = ($this->value['font-underline'] ? 'U' : ''); + + // taille en mm, à ramener en pt + $size = $this->value['font-size']; + $size = 72 * $size / 25.4; + + $this->pdf->setOverline($this->value['font-overline']); + $this->pdf->setLinethrough($this->value['font-linethrough']); + + // application de la fonte + $this->pdf->SetFont($this->value['font-family'], $b.$i.$u, $this->value['mini-size']*$size); + $this->pdf->SetTextColor($this->value['color'][0],$this->value['color'][1], $this->value['color'][2]); + if ($this->value['background']['color']) + $this->pdf->SetFillColor($this->value['background']['color'][0],$this->value['background']['color'][1], $this->value['background']['color'][2]); + else + $this->pdf->SetFillColor(255); + } + + /** + * Monter d'un niveau dans l'historisation + * + * @return null + */ + function save() + { + $this->table[count($this->table)] = $this->value; + } + + /** + * Descendre d'un niveau dans l'historisation + * + * @return null + */ + function load() + { + if (count($this->table)) + { + $this->value = $this->table[count($this->table)-1]; + unset($this->table[count($this->table)-1]); + } + } + + function setPosition(&$current_x, &$current_y) + { + $this->value['xc'] = $current_x; + $this->value['yc'] = $current_y; + + if ($this->value['position']=='relative' || $this->value['position']=='absolute') + { + if ($this->value['right']!==null) + { + $x = $this->getLastWidth(true) - $this->value['right'] - $this->value['width']; + if ($this->value['margin']['r']) $x-= $this->value['margin']['r']; + } + else + { + $x = $this->value['left']; + if ($this->value['margin']['l']) $x+= $this->value['margin']['l']; + } + + if ($this->value['bottom']!==null) + { + $y = $this->getLastHeight(true) - $this->value['bottom'] - $this->value['height']; + if ($this->value['margin']['b']) $y-= $this->value['margin']['b']; + } + else + { + $y = $this->value['top']; + if ($this->value['margin']['t']) $y+= $this->value['margin']['t']; + } + + if ($this->value['position']=='relative') + { + $this->value['x'] = $current_x + $x; + $this->value['y'] = $current_y + $y; + } + else + { + $this->value['x'] = $this->getLastAbsoluteX()+$x; + $this->value['y'] = $this->getLastAbsoluteY()+$y; + } + } + else + { + $this->value['x'] = $current_x; + $this->value['y'] = $current_y; + if ($this->value['margin']['l']) $this->value['x']+= $this->value['margin']['l']; + if ($this->value['margin']['t']) $this->value['y']+= $this->value['margin']['t']; + } + + $current_x = $this->value['x']; + $current_y = $this->value['y']; + } + + /** + * Analyse un tableau de style provenant du parseurHTML + * + * @param string nom de la balise + * @param array tableau de style + * @return null + */ + function analyse($balise, &$param) + { + // preparation + $balise = strtolower($balise); + $id = isset($param['id']) ? strtolower(trim($param['id'])) : null; if (!$id) $id = null; + $name = isset($param['name']) ? strtolower(trim($param['name'])) : null; if (!$name) $name = null; + + // lecture de la propriete classe + $class = array(); + $tmp = isset($param['class']) ? preg_replace('/[\s]+/', ' ', strtolower($param['class'])) : ''; + $tmp = explode(' ', $tmp); + foreach($tmp as $k => $v) + { + $v = trim($v); + if ($v) $class[] = $v; + } + + // identification de la balise et des styles direct qui pourraient lui être appliqués + $this->value['id_balise'] = $balise; + $this->value['id_name'] = $name; + $this->value['id_id'] = $id; + $this->value['id_class'] = $class; + $this->value['id_lst'] = array(); + $this->value['id_lst'][] = '*'; + $this->value['id_lst'][] = $balise; + if (count($class)) + { + foreach($class as $v) + { + $this->value['id_lst'][] = '*.'.$v; + $this->value['id_lst'][] = '.'.$v; + $this->value['id_lst'][] = $balise.'.'.$v; + } + } + if ($id) + { + $this->value['id_lst'][] = '*#'.$id; + $this->value['id_lst'][] = '#'.$id; + $this->value['id_lst'][] = $id.'#'.$id; + } + + // style CSS + $styles = $this->getFromCSS(); + + // on ajoute le style propre à la balise + $styles = array_merge($styles, $param['style']); + if (isset($param['allwidth']) && !isset($styles['width'])) $styles['width'] = '100%'; + + // mise à zero des styles non hérités + $this->resetStyle($balise); + + // interpreration des nouvelles valeurs + $correct_width = false; + foreach($styles as $nom => $val) + { + switch($nom) + { + case 'font-family': + $val = explode(',', $val); + $val = trim($val[0]); + + if ($val) $this->value['font-family'] = $val; + break; + + case 'font-weight': + $this->value['font-bold'] = ($val=='bold'); + break; + + case 'font-style': + $this->value['font-italic'] = ($val=='italic'); + break; + + case 'text-decoration': + $val = explode(' ', $val); + $this->value['font-underline'] = (in_array('underline', $val)); + $this->value['font-overline'] = (in_array('overline', $val)); + $this->value['font-linethrough'] = (in_array('line-through', $val)); + break; + + case 'text-indent': + $this->value['text-indent'] = $this->ConvertToMM($val); + break; + + case 'font-size': + $val = $this->ConvertToMM($val, $this->value['font-size']); + if ($val) $this->value['font-size'] = $val; + break; + + case 'color': + $res = null; + $this->value['color'] = $this->ConvertToRVB($val, $res); + + if ($balise=='hr') + { + $this->value['border']['l']['color'] = $this->value['color']; + $this->value['border']['t']['color'] = $this->value['color']; + $this->value['border']['r']['color'] = $this->value['color']; + $this->value['border']['b']['color'] = $this->value['color']; + } + break; + + case 'text-align': + $this->value['text-align'] = $val; + break; + + case 'vertical-align': + $this->value['vertical-align'] = $val; + break; + + case 'width': + $this->value['width'] = $this->ConvertToMM($val, $this->getLastWidth()); + if ($this->value['width'] && substr($val, -1)=='%') $correct_width=true; + break; + + case 'height': + $this->value['height'] = $this->ConvertToMM($val, $this->getLastHeight()); + break; + + case 'line-height': + if (preg_match('/^[0-9\.]+$/isU', $val)) $val = floor($val*100).'%'; + $this->value['line-height'] = $val; + break; + + case 'padding': + $val = explode(' ', $val); + foreach($val as $k => $v) + { + $v = trim($v); + if ($v!='') $val[$k] = $v; + else unset($val[$k]); + } + $val = array_values($val); + if (count($val)!=4) + { + $val = $this->ConvertToMM($val[0], 0); + $this->value['padding']['t'] = $val; + $this->value['padding']['r'] = $val; + $this->value['padding']['b'] = $val; + $this->value['padding']['l'] = $val; + } + else + { + $this->value['padding']['t'] = $this->ConvertToMM($val[0], 0); + $this->value['padding']['r'] = $this->ConvertToMM($val[1], 0); + $this->value['padding']['b'] = $this->ConvertToMM($val[2], 0); + $this->value['padding']['l'] = $this->ConvertToMM($val[3], 0); + } + break; + + case 'padding-top': + $this->value['padding']['t'] = $this->ConvertToMM($val, 0); + break; + + case 'padding-right': + $this->value['padding']['r'] = $this->ConvertToMM($val, 0); + break; + + case 'padding-bottom': + $this->value['padding']['b'] = $this->ConvertToMM($val, 0); + break; + + case 'padding-left': + $this->value['padding']['l'] = $this->ConvertToMM($val, 0); + break; + + case 'margin': + if ($val=='auto') + { + $this->value['margin-auto'] = true; + break; + } + $val = explode(' ', $val); + foreach($val as $k => $v) + { + $v = trim($v); + if ($v!='') $val[$k] = $v; + else unset($val[$k]); + } + $val = array_values($val); + if (count($val)!=4) + { + $val = $this->ConvertToMM($val[0], 0); + $this->value['margin']['t'] = $val; + $this->value['margin']['r'] = $val; + $this->value['margin']['b'] = $val; + $this->value['margin']['l'] = $val; + } + else + { + $this->value['margin']['t'] = $this->ConvertToMM($val[0], 0); + $this->value['margin']['r'] = $this->ConvertToMM($val[1], 0); + $this->value['margin']['b'] = $this->ConvertToMM($val[2], 0); + $this->value['margin']['l'] = $this->ConvertToMM($val[3], 0); + } + break; + + case 'margin-top': + $this->value['margin']['t'] = $this->ConvertToMM($val, 0); + break; + + case 'margin-right': + $this->value['margin']['r'] = $this->ConvertToMM($val, 0); + break; + + case 'margin-bottom': + $this->value['margin']['b'] = $this->ConvertToMM($val, 0); + break; + + case 'margin-left': + $this->value['margin']['l'] = $this->ConvertToMM($val, 0); + break; + + case 'border': + $val = $this->readBorder($val); + $this->value['border']['t'] = $val; + $this->value['border']['r'] = $val; + $this->value['border']['b'] = $val; + $this->value['border']['l'] = $val; + break; + + case 'border-style': + $val = explode(' ', $val); + foreach($val as $val_k => $val_v) + if (!in_array($val_v, array('solid', 'dotted', 'dashed'))) + $val[$val_k] = null; + $this->duplicateBorder($val); + + if ($val[0]) $this->value['border']['t']['type'] = $val[0]; + if ($val[1]) $this->value['border']['r']['type'] = $val[1]; + if ($val[2]) $this->value['border']['b']['type'] = $val[2]; + if ($val[3]) $this->value['border']['l']['type'] = $val[3]; + break; + + case 'border-top-style': + if (in_array($val, array('solid', 'dotted', 'dashed'))) + $this->value['border']['t']['type'] = $val; + break; + + case 'border-right-style': + if (in_array($val, array('solid', 'dotted', 'dashed'))) + $this->value['border']['r']['type'] = $val; + break; + + case 'border-bottom-style': + if (in_array($val, array('solid', 'dotted', 'dashed'))) + $this->value['border']['b']['type'] = $val; + break; + + case 'border-left-style': + if (in_array($val, array('solid', 'dotted', 'dashed'))) + $this->value['border']['l']['type'] = $val; + break; + + case 'border-color': + $res = false; + $val = preg_replace('/,[\s]+/', ',', $val); + $val = explode(' ', $val); + + foreach($val as $val_k => $val_v) + { + $val[$val_k] = $this->ConvertToRVB($val_v, $res); + if (!$res) $val[$val_k] = null; + } + $this->duplicateBorder($val); + + if (is_array($val[0])) $this->value['border']['t']['color'] = $val[0]; + if (is_array($val[1])) $this->value['border']['r']['color'] = $val[1]; + if (is_array($val[2])) $this->value['border']['b']['color'] = $val[2]; + if (is_array($val[3])) $this->value['border']['l']['color'] = $val[3]; + + break; + + case 'border-top-color': + $res = false; + $val = $this->ConvertToRVB($val, $res); + if ($res) $this->value['border']['t']['color'] = $val; + break; + + case 'border-right-color': + $res = false; + $val = $this->ConvertToRVB($val, $res); + if ($res) $this->value['border']['r']['color'] = $val; + break; + + case 'border-bottom-color': + $res = false; + $val = $this->ConvertToRVB($val, $res); + if ($res) $this->value['border']['b']['color'] = $val; + break; + + case 'border-left-color': + $res = false; + $val = $this->ConvertToRVB($val, $res); + if ($res) $this->value['border']['l']['color'] = $val; + break; + + case 'border-width': + $val = explode(' ', $val); + foreach($val as $val_k => $val_v) + { + $val[$val_k] = $this->ConvertToMM($val_v, 0); + } + $this->duplicateBorder($val); + + if ($val[0]) $this->value['border']['t']['width'] = $val[0]; + if ($val[1]) $this->value['border']['r']['width'] = $val[1]; + if ($val[2]) $this->value['border']['b']['width'] = $val[2]; + if ($val[3]) $this->value['border']['l']['width'] = $val[3]; + break; + + case 'border-top-width': + $val = $this->ConvertToMM($val, 0);; + if ($val) $this->value['border']['t']['width'] = $val; + break; + + case 'border-right-width': + $val = $this->ConvertToMM($val, 0);; + if ($val) $this->value['border']['r']['width'] = $val; + break; + + case 'border-bottom-width': + $val = $this->ConvertToMM($val, 0);; + if ($val) $this->value['border']['b']['width'] = $val; + break; + + case 'border-left-width': + $val = $this->ConvertToMM($val, 0);; + if ($val) $this->value['border']['l']['width'] = $val; + break; + + case 'border-collapse': + if ($balise=='table') $this->value['border']['collapse'] = ($val=='collapse'); + break; + + case 'border-radius': + // nettoyage des valeurs + $val = explode(' ', $val); + foreach($val as $k => $v) + { + $v = trim($v); + if ($v) + { + $v = $this->ConvertToMM($v, 0); + if ($v) $val[$k] = $v; + else unset($val[$k]); + } + else unset($val[$k]); + } + $val = array_values($val); + + if (!isset($val[1]) && isset($val[0])) $val[1] = $val[0]; + if (count($val)==2) + $this->value['border']['radius'] = array($val[0], $val[1]); + + break; + + case 'border-top': + $this->value['border']['t'] = $this->readBorder($val); + break; + + case 'border-right': + $this->value['border']['r'] = $this->readBorder($val); + break; + + case 'border-bottom': + $this->value['border']['b'] = $this->readBorder($val); + break; + + case 'border-left': + $this->value['border']['l'] = $this->readBorder($val); + break; + + case 'background-color': + $this->value['background']['color'] = $this->ConvertBackgroundColor($val); + break; + + case 'background-image': + $this->value['background']['image'] = $this->ConvertBackgroundImage($val); + break; + + case 'background-position': + $res = null; + $this->value['background']['position'] = $this->ConvertBackgroundPosition($val, $res); + break; + + case 'background-repeat': + $this->value['background']['repeat'] = $this->ConvertBackgroundRepeat($val); + break; + + case 'background': + $this->ConvertBackground($val, $this->value['background']); + break; + + case 'position': + if ($val=='absolute') $this->value['position'] = 'absolute'; + else if ($val=='relative') $this->value['position'] = 'relative'; + else $this->value['position'] = null; + break; + + case 'float': + if ($val=='left') $this->value['float'] = 'left'; + else if ($val=='right') $this->value['float'] = 'right'; + else $this->value['float'] = null; + break; + + case 'display': + if ($val=='inline') $this->value['display'] = 'inline'; + else if ($val=='block') $this->value['display'] = 'block'; + else if ($val=='none') $this->value['display'] = 'none'; + else $this->value['display'] = null; + break; + + case 'top': + case 'bottom': + case 'left': + case 'right': + $this->value[$nom] = $val; + break; + + case 'list-style': + case 'list-style-type': + case 'list-style-image': + if ($nom=='list-style') $nom = 'list-style-type'; + $this->value[$nom] = $val; + break; + + default: + break; + } + } + + if ($this->onlyLeft) $this->value['text-align'] = 'left'; + + // correction de la largeur pour correspondre au modèle de boite quick + if ($correct_width) + { + if (!in_array($balise, array('table', 'div', 'hr'))) + { + $this->value['width']-= $this->value['padding']['l'] + $this->value['padding']['r']; + $this->value['width']-= $this->value['border']['l']['width'] + $this->value['border']['r']['width']; + } + if (in_array($balise, array('th', 'td'))) + { + $this->value['width']-= $this->ConvertToMM(isset($param['cellspacing']) ? $param['cellspacing'] : '2px'); + } + if ($this->value['width']<0) $this->value['width']=0; + } + else + { + if ($this->value['width']) + { + if ($this->value['border']['l']['width']) $this->value['width'] += $this->value['border']['l']['width']; + if ($this->value['border']['r']['width']) $this->value['width'] += $this->value['border']['r']['width']; + if ($this->value['padding']['l']) $this->value['width'] += $this->value['padding']['l']; + if ($this->value['padding']['r']) $this->value['width'] += $this->value['padding']['r']; + } + } + if ($this->value['height']) + { + if ($this->value['border']['b']['width']) { $this->value['height'] += $this->value['border']['b']['width']; } + if ($this->value['border']['t']['width']) { $this->value['height'] += $this->value['border']['t']['width']; } + if ($this->value['padding']['b']) $this->value['height'] += $this->value['padding']['b']; + if ($this->value['padding']['t']) $this->value['height'] += $this->value['padding']['t']; + } + + if ($this->value['top']!=null) $this->value['top'] = $this->ConvertToMM($this->value['top'], $this->getLastHeight(true)); + if ($this->value['bottom']!=null) $this->value['bottom'] = $this->ConvertToMM($this->value['bottom'], $this->getLastHeight(true)); + if ($this->value['left']!=null) $this->value['left'] = $this->ConvertToMM($this->value['left'], $this->getLastWidth(true)); + if ($this->value['right']!=null) $this->value['right'] = $this->ConvertToMM($this->value['right'], $this->getLastWidth(true)); + + if ($this->value['top'] && $this->value['bottom'] && $this->value['height']) $this->value['bottom'] = null; + if ($this->value['left'] && $this->value['right'] && $this->value['width']) $this->value['right'] = null; + } + + /** + * Récupération de la hauteur de ligne courante + * + * @return float hauteur en mm + */ + function getLineHeight() + { + $val = $this->value['line-height']; + if ($val=='normal') $val = '108%'; + return $this->ConvertToMM($val, $this->value['font-size']); + } + + /** + * Récupération de la largeur de l'objet parent + * + * @return float largeur + */ + function getLastWidth($mode = false) + { + for($k=count($this->table); $k>0; $k--) + { + if ($this->table[$k-1]['width']) + { + $w = $this->table[$k-1]['width']; + if ($mode) + { + $w+= $this->table[$k-1]['border']['l']['width'] + $this->table[$k-1]['padding']['l']+0.02; + $w+= $this->table[$k-1]['border']['r']['width'] + $this->table[$k-1]['padding']['r']+0.02; + } + return $w; + } + } + return $this->pdf->w - $this->pdf->lMargin - $this->pdf->rMargin; + } + + /** + * Récupération de la hauteur de l'objet parent + * + * @return float hauteur + */ + function getLastHeight($mode = false) + { + for($k=count($this->table); $k>0; $k--) + { + if ($this->table[$k-1]['height']) + { + $h = $this->table[$k-1]['height']; + if ($mode) + { + $h+= $this->table[$k-1]['border']['t']['width'] + $this->table[$k-1]['padding']['t']+0.02; + $h+= $this->table[$k-1]['border']['b']['width'] + $this->table[$k-1]['padding']['b']+0.02; + } + return $h; + } + } + return $this->pdf->h - $this->pdf->tMargin - $this->pdf->bMargin; + } + + function getFloat() + { + if ($this->value['float']=='left') return 'left'; + if ($this->value['float']=='right') return 'right'; + return null; + } + + function getLastAbsoluteX() + { + for($k=count($this->table); $k>0; $k--) + { + if ($this->table[$k-1]['x'] && $this->table[$k-1]['position']) return $this->table[$k-1]['x']; + } + return $this->pdf->lMargin; + } + + function getLastAbsoluteY() + { + for($k=count($this->table); $k>0; $k--) + { + if ($this->table[$k-1]['y'] && $this->table[$k-1]['position']) return $this->table[$k-1]['y']; + } + return $this->pdf->tMargin; + } + + /** + * Récupération des propriétés CSS de la balise en cours + * + * @return array() tableau des propriétés CSS + */ + function getFromCSS() + { + $styles = array(); // style à appliquer + $getit = array(); // styles à récuperer + + // identification des styles direct, et ceux des parents + $lst = array(); + $lst[] = $this->value['id_lst']; + for($i=count($this->table)-1; $i>=0; $i--) $lst[] = $this->table[$i]['id_lst']; + + // identification des styles à récuperer + foreach($this->css_keys as $key => $num) + if ($this->getReccursiveStyle($key, $lst)) + $getit[$key] = $num; + + // si des styles sont à recuperer + if (count($getit)) + { + // on les récupère, mais dans l'odre de définition, afin de garder les priorités + asort($getit); + foreach($getit as $key => $val) $styles = array_merge($styles, $this->css[$key]); + } + + return $styles; + } + + /** + * Identification des styles à récuperer, en fonction de la balise et de ses parents + * + * @param string clef CSS à analyser + * @param array() tableau des styles direct, et ceux des parents + * @param string prochaine etape + * @return boolean clef autorisée ou non + */ + function getReccursiveStyle($key, $lst, $next = null) + { + // si propchaine etape, on construit les valeurs + if ($next!==null) + { + if ($next) $key = trim(substr($key, 0, -strlen($next))); // on elève cette etape + unset($lst[0]); + if (!count($lst)) return false; // pas d'etape possible + $lst = array_values($lst); + } + + // pour chaque style direct possible de l'etape en cours + foreach($lst[0] as $nom) + { + if ($key==$nom) return true; // si la clef conrrespond => ok + if (substr($key, -strlen(' '.$nom))==' '.$nom && $this->getReccursiveStyle($key, $lst, $nom)) return true; // si la clef est la fin, on analyse ce qui précède + } + + // si on est pas à la premiere etape, on doit analyse toutes les sous etapes + if ($next!==null && $this->getReccursiveStyle($key, $lst, '')) return true; + + // aucun style trouvé + return false; + } + + /** + * Analyse d'une propriété Border + * + * @param string propriété border + * @return array() propriété décodée + */ + function readBorder($val) + { + $none = array('type' => 'none', 'width' => 0, 'color' => array(0, 0, 0)); + + // valeurs par défault + $type = 'solid'; + $width = $this->ConvertToMM('1pt'); + $color = array(0, 0, 0); + + // nettoyage des valeurs + $val = explode(' ', $val); + foreach($val as $k => $v) + { + $v = trim($v); + if ($v) $val[$k] = $v; + else unset($val[$k]); + } + $val = array_values($val); + // identification des valeurs + $res = null; + foreach($val as $key) + { + if ($key=='none' || $key=='hidden') return $none; + + if ($this->ConvertToMM($key)!==null) $width = $this->ConvertToMM($key); + else if (in_array($key, array('solid', 'dotted', 'dashed'))) $type = $key; + else + { + $tmp = $this->ConvertToRVB($key, $res); + if ($res) $color = $tmp; + } + } + if (!$width) return $none; + return array('type' => $type, 'width' => $width, 'color' => $color); + } + + function duplicateBorder(&$val) + { + if (count($val)==1) + { + $val[1] = $val[0]; + $val[2] = $val[0]; + $val[3] = $val[0]; + } + else if (count($val)==2) + { + $val[2] = $val[0]; + $val[3] = $val[1]; + } + else if (count($val)==3) + { + $val[3] = $val[1]; + } + } + + function ConvertBackground($stl, &$res) + { + // Image + $text = '/url\(([^)]*)\)/isU'; + if (preg_match($text, $stl, $match)) + { + $res['image'] = $this->ConvertBackgroundImage($match[0]); + $stl = preg_replace($text, '', $stl); + $stl = preg_replace('/[\s]+/', ' ', $stl); + } + + // protection des espaces + $stl = preg_replace('/,[\s]+/', ',', $stl); + $lst = explode(' ', $stl); + + $pos = ''; + foreach($lst as $val) + { + $ok = false; + $color = $this->ConvertToRVB($val, $ok); + + if ($ok) + { + $res['color'] = $color; + } + else if ($val=='transparent') + { + $res['color'] = null; + } + else + { + $repeat = $this->ConvertBackgroundRepeat($val); + if ($repeat) + { + $res['repeat'] = $repeat; + } + else + { + $pos.= ($pos ? ' ' : '').$val; + } + } + } + if ($pos) + { + $pos = $this->ConvertBackgroundPosition($pos, $ok); + if ($ok) $res['position'] = $pos; + } + } + + function ConvertBackgroundColor($val) + { + $res = null; + if ($val=='transparent') return null; + else return $this->ConvertToRVB($val, $res); + } + + function ConvertBackgroundImage($val) + { + if ($val=='none') + return null; + else if (preg_match('/^url\(([^)]*)\)$/isU', $val, $match)) + return $match[1]; + else + return null; + } + + function ConvertBackgroundPosition($val, &$res) + { + $val = explode(' ', $val); + if (count($val)<2) + { + if (!$val[0]) return null; + $val[1] = 'center'; + } + if (count($val)>2) return null; + + $x = 0; + $y = 0; + $res = true; + + if ($val[0]=='left') $x = '0%'; + else if ($val[0]=='center') $x = '50%'; + else if ($val[0]=='right') $x = '100%'; + else if ($val[0]=='top') $y = '0%'; + else if ($val[0]=='bottom') $y = '100%'; + else if (preg_match('/^[-]?[0-9\.]+%$/isU', $val[0])) $x = $val[0]; + else if ($this->ConvertToMM($val[0])) $x = $this->ConvertToMM($val[0]); + else $res = false; + + if ($val[1]=='left') $x = '0%'; + else if ($val[1]=='right') $x = '100%'; + else if ($val[1]=='top') $y = '0%'; + else if ($val[1]=='center') $y = '50%'; + else if ($val[1]=='bottom') $y = '100%'; + else if (preg_match('/^[-]?[0-9\.]+%$/isU', $val[1])) $y = $val[1]; + else if ($this->ConvertToMM($val[1])) $y = $this->ConvertToMM($val[1]); + else $res = false; + + $val[0] = $x; + $val[1] = $y; + + return $val; + } + + function ConvertBackgroundRepeat($val) + { + switch($val) + { + case 'repeat': + return array(true, true); + case 'repeat-x': + return array(true, false); + case 'repeat-y': + return array(false, true); + case 'no-repeat': + return array(false, false); + } + return null; + } + /** + * Convertir une longueur en mm + * + * @param string longueur, avec unité, à convertir + * @param float longueur du parent + * @return float longueur exprimée en mm + */ + function ConvertToMM($val, $old=0.) + { + $val = trim($val); + if (preg_match('/^[0-9\.\-]+$/isU', $val)) $val.= 'px'; + if (preg_match('/^[0-9\.\-]+px$/isU', $val)) $val = 25.4/96. * str_replace('px', '', $val); + else if (preg_match('/^[0-9\.\-]+pt$/isU', $val)) $val = 25.4/72. * str_replace('pt', '', $val); + else if (preg_match('/^[0-9\.\-]+in$/isU', $val)) $val = 25.4 * str_replace('in', '', $val); + else if (preg_match('/^[0-9\.\-]+mm$/isU', $val)) $val = 1.*str_replace('mm', '', $val); + else if (preg_match('/^[0-9\.\-]+%$/isU', $val)) $val = 1.*$old*str_replace('%', '', $val)/100.; + else $val = null; + + return $val; + } + + /** + * Décomposition d'un code couleur HTML + * + * @param string couleur au format CSS + * @return array(r, v, b) couleur exprimé par ses comporantes R, V, B, de 0 à 255. + */ + function ConvertToRVB($val, &$res) + { + $val = trim($val); + $res = true; + + if (strtolower($val)=='transparent') return array(null, null, null); + if (isset($this->htmlColor[strtolower($val)])) $val = $this->htmlColor[strtolower($val)]; + + if (preg_match('/rgb\([\s]*([0-9%]+)[\s]*,[\s]*([0-9%]+)[\s]*,[\s]*([0-9%]+)[\s]*\)/isU', $val, $match)) + { + $r =$match[1]; if (substr($r, -1)=='%') $r = floor(255*substr($r, 0, -1)/100); + $v =$match[2]; if (substr($v, -1)=='%') $v = floor(255*substr($v, 0, -1)/100); + $b =$match[3]; if (substr($b, -1)=='%') $b = floor(255*substr($b, 0, -1)/100); + } + else if (strlen($val)==7 && substr($val, 0, 1)=='#') + { + $r = hexdec(substr($val, 1, 2)); + $v = hexdec(substr($val, 3, 2)); + $b = hexdec(substr($val, 5, 2)); + } + else if (strlen($val)==4 && substr($val, 0, 1)=='#') + { + $r = hexdec(substr($val, 1, 1).substr($val, 1, 1)); + $v = hexdec(substr($val, 2, 1).substr($val, 2, 1)); + $b = hexdec(substr($val, 3, 1).substr($val, 3, 1)); + } + else + { + $r=0; + $v=0; + $b=0; + $res = false; + } + return array(floor($r), floor($v), floor($b)); + } + + /** + * Analyser une feuille de style + * + * @param string code CSS + * @return null + */ + function analyseStyle(&$code) + { + // on remplace tous les espaces, tab, \r, \n, par des espaces uniques + $code = preg_replace('/[\s]+/', ' ', $code); + + // on enlève les commentaires + $code = preg_replace('/\/\*.*?\*\//s', '', $code); + + // on analyse chaque style + preg_match_all('/([^{}]+){([^}]*)}/isU', $code, $match); + for($k=0; $k on remplie le tableau correspondant + $styles = trim($match[2][$k]); + $styles = explode(';', $styles); + $stl = array(); + foreach($styles as $style) + { + $tmp = explode(':', $style); + if (count($tmp)>1) + { + $cod = $tmp[0]; unset($tmp[0]); $tmp = implode(':', $tmp); + $stl[trim(strtolower($cod))] = trim($tmp); + } + } + + // décomposition des noms par les , + $noms = explode(',', $noms); + foreach($noms as $nom) + { + $nom = trim($nom); + // Si il a une fonction spécifique, comme :hover => on zap + if (strpos($nom, ':')!==false) continue; + if (!isset($this->css[$nom])) + $this->css[$nom] = $stl; + else + $this->css[$nom] = array_merge($this->css[$nom], $stl); + + } + } + + $this->css_keys = array_flip(array_keys($this->css)); + } + + /** + * Extraction des feuille de style du code HTML + * + * @param string code HTML + * @return null + */ + function readStyle(&$html) + { + $style = ' '; + + // extraction des balises link, et suppression de celles-ci dans le code HTML + preg_match_all('/]*)>/isU', $html, $match); + $html = preg_replace('/]*>/isU', '', $html); + $html = preg_replace('/<\/link[^>]*>/isU', '', $html); + + // analyse de chaque balise + foreach($match[1] as $code) + { + $tmp = array(); + // lecture des paramétres du type nom=valeur + $prop = '([a-zA-Z0-9_]+)=([^"\'\s>]+)'; + preg_match_all('/'.$prop.'/is', $code, $match); + for($k=0; $k on garde + if (isset($tmp['type']) && strtolower($tmp['type'])=='text/css' && isset($tmp['href'])) + { + $content = @file_get_contents($tmp['href']); + $url = $tmp['href']; + if (strpos($url, 'http://')!==false) + { + $url = str_replace('http://', '', $url); + $url = explode('/', $url); + $url_main = 'http://'.$url[0].'/'; + $url_self = $url; unset($url_self[count($url_self)-1]); $url_self = 'http://'.implode('/', $url_self).'/'; + + $content = preg_replace('/url\(([^\\\\][^)]*)\)/isU', 'url('.$url_self.'$1)', $content); + $content = preg_replace('/url\((\\\\[^)]*)\)/isU', 'url('.$url_main.'$1)', $content); + } + + $style.= $content."\n"; + } + } + + + // extraction des balises style, et suppression de celles-ci dans le code HTML + preg_match_all('/]*>(.*)<\/style[^>]*>/isU', $html, $match); + $html = preg_replace('/]*>(.*)<\/style[^>]*>/isU', '', $html); + + // analyse de chaque balise + foreach($match[1] as $code) + { + $code = str_replace('', '', $code); + $style.= $code."\n"; + } + + $this->analyseStyle($style); + } + } +} +?> \ No newline at end of file