From: <dai...@us...> - 2012-05-04 21:56:03
|
Revision: 5315 http://web-erp.svn.sourceforge.net/web-erp/?rev=5315&view=rev Author: daintree Date: 2012-05-04 21:55:53 +0000 (Fri, 04 May 2012) Log Message: ----------- update to 5.9.160 tcpdf Modified Paths: -------------- trunk/doc/Change.log trunk/includes/tcpdf/2dbarcodes.php trunk/includes/tcpdf/CHANGELOG.TXT trunk/includes/tcpdf/README.TXT trunk/includes/tcpdf/barcodes.php trunk/includes/tcpdf/tcpdf.php trunk/sql/mysql/upgrade4.07-4.08.sql Modified: trunk/doc/Change.log =================================================================== --- trunk/doc/Change.log 2012-05-04 02:48:41 UTC (rev 5314) +++ trunk/doc/Change.log 2012-05-04 21:55:53 UTC (rev 5315) @@ -1,6 +1,8 @@ webERP Change Log -1/5/2012 MTPubRadio: Measurement unit in FormDesigner.php should be points instead of millimeters. -1/5/2012 MTPubRadio: Fixed Purch Order PDF file text of Order Total- Excl tax does not align with amount horizontally. + +4/5/12 Phil: Default lastcostupdate to 0000-00-00 to avoid issues inserting new items. +1/5/12 MTPubRadio: Measurement unit in FormDesigner.php should be points instead of millimeters. +1/5/12 MTPubRadio: Fixed Purch Order PDF file text of Order Total- Excl tax does not align with amount horizontally. 29/4/12 Opto/Klaus: SelectWorkOrder.php added start date for the work order to the work orders displayed for selection 29/4/12 David Short: Added EDISendInvoices_Reece.php to send Reece format EDI invoices - approved by Reece (Australian Plumbing retailer) 28/4/2012 Exson: Fixed bugs in MRPCalendar.php which caused working days cannot be calculated correctly. Modified: trunk/includes/tcpdf/2dbarcodes.php =================================================================== --- trunk/includes/tcpdf/2dbarcodes.php 2012-05-04 02:48:41 UTC (rev 5314) +++ trunk/includes/tcpdf/2dbarcodes.php 2012-05-04 21:55:53 UTC (rev 5315) @@ -1,9 +1,9 @@ <?php //============================================================+ // File name : 2dbarcodes.php -// Version : 1.0.013 +// Version : 1.0.014 // Begin : 2009-04-07 -// Last Update : 2012-01-12 +// Last Update : 2012-04-30 // Author : Nicola Asuni - Tecnick.com LTD - Manor Coach House, Church Hill, Aldershot, Hants, GU12 4RQ, UK - www.tecnick.com - in...@te... // License : GNU-LGPL v3 (http://www.gnu.org/copyleft/lesser.html) // ------------------------------------------------------------------- @@ -37,14 +37,14 @@ * PHP class to creates array representations for 2D barcodes to be used with TCPDF. * @package com.tecnick.tcpdf * @author Nicola Asuni - * @version 1.0.013 + * @version 1.0.014 */ /** * @class TCPDF2DBarcode * PHP class to creates array representations for 2D barcodes to be used with TCPDF (http://www.tcpdf.org). * @package com.tecnick.tcpdf - * @version 1.0.013 + * @version 1.0.014 * @author Nicola Asuni */ class TCPDF2DBarcode { @@ -202,9 +202,9 @@ if ($this->barcode_array['bcode'][$r][$c] == 1) { // draw a single barcode cell if ($imagick) { - $bar->rectangle($x, $y, ($x + $w), ($y + $h)); + $bar->rectangle($x, $y, ($x + $w - 1), ($y + $h - 1)); } else { - imagefilledrectangle($png, $x, $y, ($x + $w), ($y + $h), $fgcol); + imagefilledrectangle($png, $x, $y, ($x + $w - 1), ($y + $h - 1), $fgcol); } } $x += $w; Modified: trunk/includes/tcpdf/CHANGELOG.TXT =================================================================== --- trunk/includes/tcpdf/CHANGELOG.TXT 2012-05-04 02:48:41 UTC (rev 5314) +++ trunk/includes/tcpdf/CHANGELOG.TXT 2012-05-04 21:55:53 UTC (rev 5315) @@ -1,3 +1,55 @@ +5.9.160 (2012-05-03) + - A bug on tcpdf_parser.php was fixed. + +5.9.159 (2012-04-30) + - Barcode classes were updated to fix PNG export Bug (ID: 3522291). + +5.9.158 (2012-04-22) + - Some SVG-related bugs were fixed. + +5.9.157 (2012-04-16) + - Some SVG-related bugs were fixed. + +5.9.156 (2012-04-10) + - Bug item #3515885 "TOC and booklet: left and right page exchanged". + - SetAutoPageBreak(false) now works also in multicolumn mode. + +5.9.155 (2012-04-02) + - Bug item #3512596 "font import problems" was fixed. + - Method addTTFfont() was modified to extract only specified Platform ID and Encoding ID (check the source code documentation). + - All fonts were updated. + - Bug item #3513867 "booklet and setHeaderTemplateAutoreset: header shifted left" was fixed. + - Bug item #3513749 "TCPDF Superscript/Subscript" was fixed. + +5.9.154 (2012-03-29) + - A debug echo was removed. + +5.9.153 (2012-03-28) + - A bug on font conversion was fixed. + - All fonts were updated. + - Method isCharDefined() was added to find if a character is defined on the selected font. + - Method replaceMissingChars() was added to automatically replace missing chars on selected font. + - SetFont() method was fixed. + +5.9.152 (2012-03-23) + - The following overprint methods were added: setOverprint(), getOverprint(). + - Signature of setAlpha() method was changed and method getAlpha() was added. + - stroke-opacity support was added on SVG. + - The following date methods were added: setDocCreationTimestamp(), setDocModificationTimestamp(), getDocCreationTimestamp(), getDocModificationTimestamp(), getFormattedDate(), getTimestamp(). + - Signature of _datestring() method was changed. + - Method getFontBBox() was added. + - Method setPageBoxTypes() was aded. + +5.9.151 (2012-03-22) + - Bug item #3509889 "Transform() distorts PDF" was fixed. + - Precision of real number were extended. + - ComboBox and ListBox methods were fixed. + - Bulgarian language file was added. + - addTOC() method was improved to include bookmark color and font style. + +5.9.150 (2012-03-16) + - A bug related to form fields in PDF/A mode was fixed. + 5.9.149 (2012-02-21) - Bug item #3489933 "SVG Parser treats tspan like text" was fixed. Modified: trunk/includes/tcpdf/README.TXT =================================================================== --- trunk/includes/tcpdf/README.TXT 2012-05-04 02:48:41 UTC (rev 5314) +++ trunk/includes/tcpdf/README.TXT 2012-05-04 21:55:53 UTC (rev 5315) @@ -8,8 +8,8 @@ ------------------------------------------------------------ Name: TCPDF -Version: 5.9.149 -Release date: 2012-02-21 +Version: 5.9.160 +Release date: 2012-05-03 Author: Nicola Asuni Copyright (c) 2002-2012: @@ -93,5 +93,5 @@ To get the original distribution archives please check the information on fonts subfolders: - DejaVu fonts 2.33 (Bitstream) - Copyright, License and other info: fonts/dejavu-fonts-ttf-2.33 - GNU FreeFont (GNU-GPLv3) - Copyright, License and other info: fonts/freefont-20100919 - + ============================================================ Modified: trunk/includes/tcpdf/barcodes.php =================================================================== --- trunk/includes/tcpdf/barcodes.php 2012-05-04 02:48:41 UTC (rev 5314) +++ trunk/includes/tcpdf/barcodes.php 2012-05-04 21:55:53 UTC (rev 5315) @@ -1,9 +1,9 @@ <?php //============================================================+ // File name : barcodes.php -// Version : 1.0.023 +// Version : 1.0.024 // Begin : 2008-06-09 -// Last Update : 2012-01-14 +// Last Update : 2012-04-30 // Author : Nicola Asuni - Tecnick.com LTD - Manor Coach House, Church Hill, Aldershot, Hants, GU12 4RQ, UK - www.tecnick.com - in...@te... // License : GNU-LGPL v3 (http://www.gnu.org/copyleft/lesser.html) // ------------------------------------------------------------------- @@ -37,14 +37,14 @@ * PHP class to creates array representations for common 1D barcodes to be used with TCPDF. * @package com.tecnick.tcpdf * @author Nicola Asuni - * @version 1.0.023 + * @version 1.0.024 */ /** * @class TCPDFBarcode * PHP class to creates array representations for common 1D barcodes to be used with TCPDF (http://www.tcpdf.org).<br> * @package com.tecnick.tcpdf - * @version 1.0.023 + * @version 1.0.024 * @author Nicola Asuni */ class TCPDFBarcode { @@ -201,9 +201,9 @@ $y = round(($v['p'] * $h / $this->barcode_array['maxh']), 3); // draw a vertical bar if ($imagick) { - $bar->rectangle($x, $y, ($x + $bw), ($y + $bh)); + $bar->rectangle($x, $y, ($x + $bw - 1), ($y + $bh - 1)); } else { - imagefilledrectangle($png, $x, $y, ($x + $bw), ($y + $bh), $fgcol); + imagefilledrectangle($png, $x, $y, ($x + $bw - 1), ($y + $bh - 1), $fgcol); } } $x += $bw; Modified: trunk/includes/tcpdf/tcpdf.php =================================================================== --- trunk/includes/tcpdf/tcpdf.php 2012-05-04 02:48:41 UTC (rev 5314) +++ trunk/includes/tcpdf/tcpdf.php 2012-05-04 21:55:53 UTC (rev 5315) @@ -1,9 +1,9 @@ <?php //============================================================+ // File name : tcpdf.php -// Version : 5.9.149 +// Version : 5.9.160 // Begin : 2002-08-03 -// Last Update : 2012-02-21 +// Last Update : 2012-05-03 // Author : Nicola Asuni - Tecnick.com LTD - Manor Coach House, Church Hill, Aldershot, Hants, GU12 4RQ, UK - www.tecnick.com - in...@te... // License : http://www.tecnick.com/pagefiles/tcpdf/LICENSE.TXT GNU-LGPLv3 // ------------------------------------------------------------------- @@ -137,7 +137,7 @@ * Tools to encode your unicode fonts are on fonts/utils directory.</p> * @package com.tecnick.tcpdf * @author Nicola Asuni - * @version 5.9.149 + * @version 5.9.160 */ // Main configuration file. Define the K_TCPDF_EXTERNAL_CONFIG constant to skip this file. @@ -149,7 +149,7 @@ * TCPDF project (http://www.tcpdf.org) has been originally derived in 2002 from the Public Domain FPDF class by Olivier Plathey (http://www.fpdf.org), but now is almost entirely rewritten.<br> * @package com.tecnick.tcpdf * @brief PHP class for generating PDF documents without requiring external extensions. - * @version 5.9.149 + * @version 5.9.160 * @author Nicola Asuni - in...@te... */ class TCPDF { @@ -160,7 +160,7 @@ * Current TCPDF version. * @private */ - private $tcpdf_version = '5.9.149'; + private $tcpdf_version = '5.9.160'; // Protected properties @@ -1816,19 +1816,63 @@ protected $pdfa_mode = false; /** - * Document creation date + * Document creation date-time * @protected - * @since 5.9.121 (2011-09-28) + * @since 5.9.152 (2012-03-22) */ - protected $doc_date; + protected $doc_creation_timestamp; /** + * Document modification date-time + * @protected + * @since 5.9.152 (2012-03-22) + */ + protected $doc_modification_timestamp; + + /** * Custom XMP data. * @protected * @since 5.9.128 (2011-10-06) */ protected $custom_xmp = ''; + /** + * Overprint mode array. + * (Check the "Entries in a Graphics State Parameter Dictionary" on PDF 32000-1:2008). + * @protected + * @since 5.9.152 (2012-03-23) + */ + protected $overprint = array('OP' => false, 'op' => false, 'OPM' => 0); + + /** + * Alpha mode array. + * (Check the "Entries in a Graphics State Parameter Dictionary" on PDF 32000-1:2008). + * @protected + * @since 5.9.152 (2012-03-23) + */ + protected $alpha = array('CA' => 1, 'ca' => 1, 'BM' => '/Normal', 'AIS' => false); + + /** + * Define the page boundaries boxes to be set on document. + * @protected + * @since 5.9.152 (2012-03-23) + */ + protected $page_boxes = array('MediaBox', 'CropBox', 'BleedBox', 'TrimBox', 'ArtBox'); + + /** + * Set the document producer metadata. + * @protected + * @since 5.9.152 (2012-03-23) + */ + protected $pdfproducer; + + /** + * If true print TCPDF meta link. + * @protected + * @since 5.9.152 (2012-03-23) + */ + protected $tcpdflink = true; + //------------------------------------------------------------ // METHODS //------------------------------------------------------------ @@ -1941,7 +1985,7 @@ $this->setCellMargins(0, 0, 0, 0); // line width (0.2 mm) $this->LineWidth = 0.57 / $this->k; - $this->linestyleWidth = sprintf('%.2F w', ($this->LineWidth * $this->k)); + $this->linestyleWidth = sprintf('%F w', ($this->LineWidth * $this->k)); $this->linestyleCap = '0 J'; $this->linestyleJoin = '0 j'; $this->linestyleDash = '[] 0 d'; @@ -1953,6 +1997,8 @@ $this->SetCompression(); // set default PDF version number $this->setPDFVersion(); + $this->pdfproducer = "\x54\x43\x50\x44\x46\x20".$this->tcpdf_version."\x20\x28\x68\x74\x74\x70\x3a\x2f\x2f\x77\x77\x77\x2e\x74\x63\x70\x64\x66\x2e\x6f\x72\x67\x29"; + $this->tcpdflink = true; $this->encoding = $encoding; $this->HREF = array(); $this->getFontsList(); @@ -1992,8 +2038,9 @@ $this->default_form_prop = array('lineWidth'=>1, 'borderStyle'=>'solid', 'fillColor'=>array(255, 255, 255), 'strokeColor'=>array(128, 128, 128)); // set file ID for trailer $this->file_id = md5($this->getRandomSeed('TCPDF'.$orientation.$unit.$format.$encoding)); - // set document date - $this->doc_date = substr_replace(date('YmdHisO'), '\'', (0 - 2), 0).'\''; + // set document creation and modification timestamp + $this->doc_creation_timestamp = time(); + $this->doc_modification_timestamp = $this->doc_creation_timestamp; // get default graphic vars $this->default_graphic_vars = $this->getGraphicVars(); $this->header_xobj_autoreset = false; @@ -3742,24 +3789,26 @@ $this->AddPage(); } $this->endLayer(); - // save current graphic settings - $gvars = $this->getGraphicVars(); - $this->setEqualColumns(); - $this->lastpage(true); - $this->SetAutoPageBreak(false); - $this->x = 0; - $this->y = $this->h - (1 / $this->k); - $this->lMargin = 0; - $this->_out('q'); - $font = defined('PDF_FONT_NAME_MAIN')?PDF_FONT_NAME_MAIN:'helvetica'; - $this->SetFont($font, '', 1); - $this->setTextRenderingMode(0, false, false); - $msg = "\x50\x6f\x77\x65\x72\x65\x64\x20\x62\x79\x20\x54\x43\x50\x44\x46\x20\x28\x77\x77\x77\x2e\x74\x63\x70\x64\x66\x2e\x6f\x72\x67\x29"; - $lnk = "\x68\x74\x74\x70\x3a\x2f\x2f\x77\x77\x77\x2e\x74\x63\x70\x64\x66\x2e\x6f\x72\x67"; - $this->Cell(0, 0, $msg, 0, 0, 'L', 0, $lnk, 0, false, 'D', 'B'); - $this->_out('Q'); - // restore graphic settings - $this->setGraphicVars($gvars); + if ($this->tcpdflink) { + // save current graphic settings + $gvars = $this->getGraphicVars(); + $this->setEqualColumns(); + $this->lastpage(true); + $this->SetAutoPageBreak(false); + $this->x = 0; + $this->y = $this->h - (1 / $this->k); + $this->lMargin = 0; + $this->_out('q'); + $font = defined('PDF_FONT_NAME_MAIN')?PDF_FONT_NAME_MAIN:'helvetica'; + $this->SetFont($font, '', 1); + $this->setTextRenderingMode(0, false, false); + $msg = "\x50\x6f\x77\x65\x72\x65\x64\x20\x62\x79\x20\x54\x43\x50\x44\x46\x20\x28\x77\x77\x77\x2e\x74\x63\x70\x64\x66\x2e\x6f\x72\x67\x29"; + $lnk = "\x68\x74\x74\x70\x3a\x2f\x2f\x77\x77\x77\x2e\x74\x63\x70\x64\x66\x2e\x6f\x72\x67"; + $this->Cell(0, 0, $msg, 0, 0, 'L', 0, $lnk, 0, false, 'D', 'B'); + $this->_out('Q'); + // restore graphic settings + $this->setGraphicVars($gvars); + } // close page $this->endPage(); // close document @@ -4212,7 +4261,7 @@ // print header template $x = 0; $dx = 0; - if ($this->booklet AND (($this->page % 2) == 0)) { + if (!$this->header_xobj_autoreset AND $this->booklet AND (($this->page % 2) == 0)) { // adjust margins for booklet mode $dx = ($this->original_lMargin - $this->original_rMargin); } @@ -4503,19 +4552,19 @@ $pdfcolor = sprintf('/CS%d ', $this->spot_colors[$name]['i']); switch ($type) { case 'draw': { - $pdfcolor .= sprintf('CS %.3F SCN', $tint); + $pdfcolor .= sprintf('CS %F SCN', $tint); $this->DrawColor = $pdfcolor; $this->strokecolor = $spotcolor; break; } case 'fill': { - $pdfcolor .= sprintf('cs %.3F scn', $tint); + $pdfcolor .= sprintf('cs %F scn', $tint); $this->FillColor = $pdfcolor; $this->bgcolor = $spotcolor; break; } case 'text': { - $pdfcolor .= sprintf('cs %.3F scn', $tint); + $pdfcolor .= sprintf('cs %F scn', $tint); $this->TextColor = $pdfcolor; $this->fgcolor = $spotcolor; break; @@ -4674,7 +4723,7 @@ // Grey scale $col1 = max(0, min(255, $col1)); $intcolor = array('G' => $col1); - $pdfcolor = sprintf('%.3F ', ($col1 / 255)); + $pdfcolor = sprintf('%F ', ($col1 / 255)); $suffix = 'g'; } elseif ($col4 == -1) { // RGB @@ -4682,7 +4731,7 @@ $col2 = max(0, min(255, $col2)); $col3 = max(0, min(255, $col3)); $intcolor = array('R' => $col1, 'G' => $col2, 'B' => $col3); - $pdfcolor = sprintf('%.3F %.3F %.3F ', ($col1 / 255), ($col2 / 255), ($col3 / 255)); + $pdfcolor = sprintf('%F %F %F ', ($col1 / 255), ($col2 / 255), ($col3 / 255)); $suffix = 'rg'; } else { $col1 = max(0, min(100, $col1)); @@ -4692,7 +4741,7 @@ if (empty($name)) { // CMYK $intcolor = array('C' => $col1, 'M' => $col2, 'Y' => $col3, 'K' => $col4); - $pdfcolor = sprintf('%.3F %.3F %.3F %.3F ', ($col1 / 100), ($col2 / 100), ($col3 / 100), ($col4 / 100)); + $pdfcolor = sprintf('%F %F %F %F ', ($col1 / 100), ($col2 / 100), ($col3 / 100), ($col4 / 100)); $suffix = 'k'; } else { // SPOT COLOR @@ -4744,17 +4793,17 @@ switch (count($c)) { case 4: { // CMYK - $color .= sprintf('%.3F %.3F %.3F %.3F', (max(0, min(100, floatval($c[0]))) / 100), (max(0, min(100, floatval($c[1]))) / 100), (max(0, min(100, floatval($c[2]))) / 100), (max(0, min(100, floatval($c[3]))) / 100)); + $color .= sprintf('%F %F %F %F', (max(0, min(100, floatval($c[0]))) / 100), (max(0, min(100, floatval($c[1]))) / 100), (max(0, min(100, floatval($c[2]))) / 100), (max(0, min(100, floatval($c[3]))) / 100)); break; } case 3: { // RGB - $color .= sprintf('%.3F %.3F %.3F', (max(0, min(255, floatval($c[0]))) / 255), (max(0, min(255, floatval($c[1]))) / 255), (max(0, min(255, floatval($c[2]))) / 255)); + $color .= sprintf('%F %F %F', (max(0, min(255, floatval($c[0]))) / 255), (max(0, min(255, floatval($c[1]))) / 255), (max(0, min(255, floatval($c[2]))) / 255)); break; } case 1: { // grayscale - $color .= sprintf('%.3F', (max(0, min(255, floatval($c[0]))) / 255)); + $color .= sprintf('%F', (max(0, min(255, floatval($c[0]))) / 255)); break; } } @@ -5230,11 +5279,14 @@ * @since 1.0 * @see AddFont(), SetFontSize() */ - public function SetFont($family, $style='', $size=0, $fontfile='', $subset='default', $out=true) { + public function SetFont($family, $style='', $size=null, $fontfile='', $subset='default', $out=true) { //Select a font; size given in points - if ($size == 0) { + if ($size === null) { $size = $this->FontSizePt; } + if ($size < 0) { + $size = 0; + } // try to add font (if not already added) $fontdata = $this->AddFont($family, $style, $fontfile, $subset); $this->FontFamily = $fontdata['family']; @@ -5281,11 +5333,52 @@ $this->FontAscent = ($font_ascent / $this->k); $this->FontDescent = ($font_descent / $this->k); if ($out AND ($this->page > 0) AND (isset($this->CurrentFont['i']))) { - $this->_out(sprintf('BT /F%d %.2F Tf ET', $this->CurrentFont['i'], $this->FontSizePt)); + $this->_out(sprintf('BT /F%d %F Tf ET', $this->CurrentFont['i'], $this->FontSizePt)); } } /** + * Returns the bounding box of the current font in user units. + * @return array + * @public + * @since 5.9.152 (2012-03-23) + */ + public function getFontBBox() { + $result = array(); + if (isset($this->CurrentFont['desc']['FontBBox'])) { + $bbox = explode(' ', substr($this->CurrentFont['desc']['FontBBox'], 1, -1)); + foreach ($bbox as $v) { + $result[] = (intval($v) * $this->FontSize / 1000); + } + } else { + // Find max width + if (isset($this->CurrentFont['desc']['MaxWidth'])) { + $maxw = (intval($this->CurrentFont['desc']['MaxWidth']) * $this->FontSize / 1000); + } else { + $maxw = 0; + if (isset($this->CurrentFont['desc']['MissingWidth'])) { + $maxw = max($maxw, $this->CurrentFont['desc']['MissingWidth']); + } + if (isset($this->CurrentFont['desc']['AvgWidth'])) { + $maxw = max($maxw, $this->CurrentFont['desc']['AvgWidth']); + } + if (isset($this->CurrentFont['dw'])) { + $maxw = max($maxw, $this->CurrentFont['dw']); + } + foreach ($this->CurrentFont['cw'] as $char => $w) { + $maxw = max($maxw, $w); + } + if ($maxw == 0) { + $maxw = 600; + } + $maxw = ($maxw * $this->FontSize / 1000); + } + $result = array(0, -$this->FontDescent, $maxw, $this->FontAscent); + } + return $result; + } + + /** * Return the font descent value * @param $font (string) font name * @param $style (string) font style @@ -5328,6 +5421,70 @@ } /** + * Return the font descent value + * @param $char (mixed) Character to check (integer value or string) + * @param $font (string) Font name (family name). + * @param $style (string) Font style. + * @return (boolean) true if the char is defined, false otherwise. + * @public + * @since 5.9.153 (2012-03-28) + */ + public function isCharDefined($char, $font='', $style='') { + if (is_string($char)) { + // get character code + $char = $this->UTF8StringToArray($char); + $char = $char[0]; + } + if ($this->empty_string($font)) { + $font = $this->FontFamily; + } + $fontdata = $this->AddFont($font, $style); + $fontinfo = $this->getFontBuffer($fontdata['fontkey']); + return (isset($fontinfo['cw'][intval($char)])); + } + + /** + * Replace missing font characters on selected font with specified substitutions. + * @param $text (string) Text to process. + * @param $font (string) Font name (family name). + * @param $style (string) Font style. + * @param $subs (array) Array of possible character substitutions. The key is the character to check (integer value) and the value is a single intege value or an array of possible substitutes. + * @return (string) Processed text. + * @public + * @since 5.9.153 (2012-03-28) + */ + public function replaceMissingChars($text, $font='', $style='', $subs=array()) { + if (empty($subs)) { + return $text; + } + if ($this->empty_string($font)) { + $font = $this->FontFamily; + } + $fontdata = $this->AddFont($font, $style); + $fontinfo = $this->getFontBuffer($fontdata['fontkey']); + $uniarr = $this->UTF8StringToArray($text); + foreach ($uniarr as $k => $chr) { + if (!isset($fontinfo['cw'][$chr])) { + // this character is missing on the selected font + if (isset($subs[$chr])) { + // we have available substitutions + if (is_array($subs[$chr])) { + foreach($subs[$chr] as $s) { + if (isset($fontinfo['cw'][$s])) { + $uniarr[$k] = $s; + break; + } + } + } elseif (isset($fontinfo['cw'][$subs[$chr]])) { + $uniarr[$k] = $subs[$chr]; + } + } + } + } + return $this->UniArrSubString($this->UTF8ArrayToUniArray($uniarr)); + } + + /** * Defines the default monospaced font. * @param $font (string) Font name. * @public @@ -5561,7 +5718,7 @@ if ($this->current_column < ($this->num_columns - 1)) { // go to next column $this->selectColumn($this->current_column + 1); - } else { + } elseif ($this->AutoPageBreak) { // add a new page $this->AddPage(); // set first column @@ -5854,7 +6011,7 @@ } else { $xk = ($x * $k); } - $s .= sprintf('%.2F %.2F %.2F %.2F re %s ', $xk, (($this->h - $y) * $k), ($w * $k), (-$h * $k), $op); + $s .= sprintf('%F %F %F %F re %s ', $xk, (($this->h - $y) * $k), ($w * $k), (-$h * $k), $op); } // draw borders $s .= $this->getCellBorder($x, $y, $w, $h, $border); @@ -5927,17 +6084,17 @@ } if ($this->font_stretching != 100) { // apply font stretching - $rs .= sprintf('BT %.2F Tz ET ', $this->font_stretching); + $rs .= sprintf('BT %F Tz ET ', $this->font_stretching); } if ($this->font_spacing != 0) { // increase/decrease font spacing - $rs .= sprintf('BT %.2F Tc ET ', ($this->font_spacing * $this->k)); + $rs .= sprintf('BT %F Tc ET ', ($this->font_spacing * $this->k)); } if ($this->ColorFlag AND ($this->textrendermode < 4)) { $s .= 'q '.$this->TextColor.' '; } // rendering mode - $s .= sprintf('BT %d Tr %.2F w ET ', $this->textrendermode, $this->textstrokewidth); + $s .= sprintf('BT %d Tr %F w ET ', $this->textrendermode, $this->textstrokewidth); // count number of spaces $ns = substr_count($txt, chr(32)); // Justification @@ -5953,7 +6110,7 @@ $spacewidth /= ($this->font_stretching / 100); } // set word position to be used with TJ operator - $txt2 = str_replace(chr(0).chr(32), ') '.sprintf('%.3F', $spacewidth).' (', $txt2); + $txt2 = str_replace(chr(0).chr(32), ') '.sprintf('%F', $spacewidth).' (', $txt2); $unicode_justification = true; } else { // get string width @@ -5965,7 +6122,7 @@ $spacewidth /= ($this->font_stretching / 100); } // set word spacing - $rs .= sprintf('BT %.3F Tw ET ', $spacewidth); + $rs .= sprintf('BT %F Tw ET ', $spacewidth); } $width = $w - $this->cell_padding['L'] - $this->cell_padding['R']; } @@ -6009,7 +6166,7 @@ } $xdk = $xdx * $k; // print text - $s .= sprintf('BT %.2F %.2F Td [(%s)] TJ ET', $xdk, (($this->h - $basefonty) * $k), $txt2); + $s .= sprintf('BT %F %F Td [(%s)] TJ ET', $xdk, (($this->h - $basefonty) * $k), $txt2); if (isset($uniblock)) { // print overlapping characters as separate string $xshift = 0; // horizontal shift @@ -6027,7 +6184,7 @@ // character to print $topchr = $this->arrUTF8ToUTF16BE($uniarr, false); $topchr = $this->_escape($topchr); - $s .= sprintf(' BT %.2F %.2F Td [(%s)] TJ ET', ($xdk + ($xshift * $k)), $ty, $topchr); + $s .= sprintf(' BT %F %F Td [(%s)] TJ ET', ($xdk + ($xshift * $k)), $ty, $topchr); } } } @@ -6193,85 +6350,85 @@ } // draw borders by case if (strlen($border) == 4) { - $s .= sprintf('%.2F %.2F %.2F %.2F re S ', $xT, $yT, ($w * $k), (-$h * $k)); + $s .= sprintf('%F %F %F %F re S ', $xT, $yT, ($w * $k), (-$h * $k)); } elseif (strlen($border) == 3) { if (strpos($border,'B') === false) { // LTR - $s .= sprintf('%.2F %.2F m ', $xL, $yL); - $s .= sprintf('%.2F %.2F l ', $xT, $yT); - $s .= sprintf('%.2F %.2F l ', $xR, $yR); - $s .= sprintf('%.2F %.2F l ', $xB, $yB); + $s .= sprintf('%F %F m ', $xL, $yL); + $s .= sprintf('%F %F l ', $xT, $yT); + $s .= sprintf('%F %F l ', $xR, $yR); + $s .= sprintf('%F %F l ', $xB, $yB); $s .= 'S '; } elseif (strpos($border,'L') === false) { // TRB - $s .= sprintf('%.2F %.2F m ', $xT, $yT); - $s .= sprintf('%.2F %.2F l ', $xR, $yR); - $s .= sprintf('%.2F %.2F l ', $xB, $yB); - $s .= sprintf('%.2F %.2F l ', $xL, $yL); + $s .= sprintf('%F %F m ', $xT, $yT); + $s .= sprintf('%F %F l ', $xR, $yR); + $s .= sprintf('%F %F l ', $xB, $yB); + $s .= sprintf('%F %F l ', $xL, $yL); $s .= 'S '; } elseif (strpos($border,'T') === false) { // RBL - $s .= sprintf('%.2F %.2F m ', $xR, $yR); - $s .= sprintf('%.2F %.2F l ', $xB, $yB); - $s .= sprintf('%.2F %.2F l ', $xL, $yL); - $s .= sprintf('%.2F %.2F l ', $xT, $yT); + $s .= sprintf('%F %F m ', $xR, $yR); + $s .= sprintf('%F %F l ', $xB, $yB); + $s .= sprintf('%F %F l ', $xL, $yL); + $s .= sprintf('%F %F l ', $xT, $yT); $s .= 'S '; } elseif (strpos($border,'R') === false) { // BLT - $s .= sprintf('%.2F %.2F m ', $xB, $yB); - $s .= sprintf('%.2F %.2F l ', $xL, $yL); - $s .= sprintf('%.2F %.2F l ', $xT, $yT); - $s .= sprintf('%.2F %.2F l ', $xR, $yR); + $s .= sprintf('%F %F m ', $xB, $yB); + $s .= sprintf('%F %F l ', $xL, $yL); + $s .= sprintf('%F %F l ', $xT, $yT); + $s .= sprintf('%F %F l ', $xR, $yR); $s .= 'S '; } } elseif (strlen($border) == 2) { if ((strpos($border,'L') !== false) AND (strpos($border,'T') !== false)) { // LT - $s .= sprintf('%.2F %.2F m ', $xL, $yL); - $s .= sprintf('%.2F %.2F l ', $xT, $yT); - $s .= sprintf('%.2F %.2F l ', $xR, $yR); + $s .= sprintf('%F %F m ', $xL, $yL); + $s .= sprintf('%F %F l ', $xT, $yT); + $s .= sprintf('%F %F l ', $xR, $yR); $s .= 'S '; } elseif ((strpos($border,'T') !== false) AND (strpos($border,'R') !== false)) { // TR - $s .= sprintf('%.2F %.2F m ', $xT, $yT); - $s .= sprintf('%.2F %.2F l ', $xR, $yR); - $s .= sprintf('%.2F %.2F l ', $xB, $yB); + $s .= sprintf('%F %F m ', $xT, $yT); + $s .= sprintf('%F %F l ', $xR, $yR); + $s .= sprintf('%F %F l ', $xB, $yB); $s .= 'S '; } elseif ((strpos($border,'R') !== false) AND (strpos($border,'B') !== false)) { // RB - $s .= sprintf('%.2F %.2F m ', $xR, $yR); - $s .= sprintf('%.2F %.2F l ', $xB, $yB); - $s .= sprintf('%.2F %.2F l ', $xL, $yL); + $s .= sprintf('%F %F m ', $xR, $yR); + $s .= sprintf('%F %F l ', $xB, $yB); + $s .= sprintf('%F %F l ', $xL, $yL); $s .= 'S '; } elseif ((strpos($border,'B') !== false) AND (strpos($border,'L') !== false)) { // BL - $s .= sprintf('%.2F %.2F m ', $xB, $yB); - $s .= sprintf('%.2F %.2F l ', $xL, $yL); - $s .= sprintf('%.2F %.2F l ', $xT, $yT); + $s .= sprintf('%F %F m ', $xB, $yB); + $s .= sprintf('%F %F l ', $xL, $yL); + $s .= sprintf('%F %F l ', $xT, $yT); $s .= 'S '; } elseif ((strpos($border,'L') !== false) AND (strpos($border,'R') !== false)) { // LR - $s .= sprintf('%.2F %.2F m ', $xL, $yL); - $s .= sprintf('%.2F %.2F l ', $xT, $yT); + $s .= sprintf('%F %F m ', $xL, $yL); + $s .= sprintf('%F %F l ', $xT, $yT); $s .= 'S '; - $s .= sprintf('%.2F %.2F m ', $xR, $yR); - $s .= sprintf('%.2F %.2F l ', $xB, $yB); + $s .= sprintf('%F %F m ', $xR, $yR); + $s .= sprintf('%F %F l ', $xB, $yB); $s .= 'S '; } elseif ((strpos($border,'T') !== false) AND (strpos($border,'B') !== false)) { // TB - $s .= sprintf('%.2F %.2F m ', $xT, $yT); - $s .= sprintf('%.2F %.2F l ', $xR, $yR); + $s .= sprintf('%F %F m ', $xT, $yT); + $s .= sprintf('%F %F l ', $xR, $yR); $s .= 'S '; - $s .= sprintf('%.2F %.2F m ', $xB, $yB); - $s .= sprintf('%.2F %.2F l ', $xL, $yL); + $s .= sprintf('%F %F m ', $xB, $yB); + $s .= sprintf('%F %F l ', $xL, $yL); $s .= 'S '; } } else { // strlen($border) == 1 if (strpos($border,'L') !== false) { // L - $s .= sprintf('%.2F %.2F m ', $xL, $yL); - $s .= sprintf('%.2F %.2F l ', $xT, $yT); + $s .= sprintf('%F %F m ', $xL, $yL); + $s .= sprintf('%F %F l ', $xT, $yT); $s .= 'S '; } elseif (strpos($border,'T') !== false) { // T - $s .= sprintf('%.2F %.2F m ', $xT, $yT); - $s .= sprintf('%.2F %.2F l ', $xR, $yR); + $s .= sprintf('%F %F m ', $xT, $yT); + $s .= sprintf('%F %F l ', $xR, $yR); $s .= 'S '; } elseif (strpos($border,'R') !== false) { // R - $s .= sprintf('%.2F %.2F m ', $xR, $yR); - $s .= sprintf('%.2F %.2F l ', $xB, $yB); + $s .= sprintf('%F %F m ', $xR, $yR); + $s .= sprintf('%F %F l ', $xB, $yB); $s .= 'S '; } elseif (strpos($border,'B') !== false) { // B - $s .= sprintf('%.2F %.2F m ', $xB, $yB); - $s .= sprintf('%.2F %.2F l ', $xL, $yL); + $s .= sprintf('%F %F m ', $xB, $yB); + $s .= sprintf('%F %F l ', $xL, $yL); $s .= 'S '; } } @@ -7755,7 +7912,7 @@ $tmp = array(); if (preg_match('/[\s]+width[\s]*=[\s]*"([^"]*)"/si', $svgtag, $tmp)) { $ow = $this->getHTMLUnitToUnits($tmp[1], 1, $this->svgunit, false); - $owu = sprintf('%.3F', ($ow * $dpi / 72)).$this->pdfunit; + $owu = sprintf('%F', ($ow * $dpi / 72)).$this->pdfunit; $svgtag = preg_replace('/[\s]+width[\s]*=[\s]*"[^"]*"/si', ' width="'.$owu.'"', $svgtag, 1); } else { $ow = $w; @@ -7763,7 +7920,7 @@ $tmp = array(); if (preg_match('/[\s]+height[\s]*=[\s]*"([^"]*)"/si', $svgtag, $tmp)) { $oh = $this->getHTMLUnitToUnits($tmp[1], 1, $this->svgunit, false); - $ohu = sprintf('%.3F', ($oh * $dpi / 72)).$this->pdfunit; + $ohu = sprintf('%F', ($oh * $dpi / 72)).$this->pdfunit; $svgtag = preg_replace('/[\s]+height[\s]*=[\s]*"[^"]*"/si', ' height="'.$ohu.'"', $svgtag, 1); } else { $oh = $h; @@ -7772,7 +7929,7 @@ if (!preg_match('/[\s]+viewBox[\s]*=[\s]*"[\s]*([0-9\.]+)[\s]+([0-9\.]+)[\s]+([0-9\.]+)[\s]+([0-9\.]+)[\s]*"/si', $svgtag, $tmp)) { $vbw = ($ow * $this->imgscale * $this->k); $vbh = ($oh * $this->imgscale * $this->k); - $vbox = sprintf(' viewBox="0 0 %.3F %.3F" ', $vbw, $vbh); + $vbox = sprintf(' viewBox="0 0 %F %F" ', $vbw, $vbh); $svgtag = $vbox.$svgtag; } $svgimg = preg_replace('/<svg([^\>]*)>/si', '<svg'.$svgtag.'>', $svgimg, 1); @@ -7856,7 +8013,7 @@ $xkimg = $ximg * $this->k; if (!$alt) { // only non-alternative immages will be set - $this->_out(sprintf('q %.2F 0 0 %.2F %.2F %.2F cm /I%u Do Q', ($w * $this->k), ($h * $this->k), $xkimg, (($this->h - ($y + $h)) * $this->k), $info['i'])); + $this->_out(sprintf('q %F 0 0 %F %F %F cm /I%u Do Q', ($w * $this->k), ($h * $this->k), $xkimg, (($this->h - ($y + $h)) * $this->k), $info['i'])); } if (!empty($border)) { $bx = $this->x; @@ -8843,6 +9000,21 @@ } /** + * Set page boxes to be included on page descriptions. + * @param $boxes (array) Array of page boxes to set on document: ('MediaBox', 'CropBox', 'BleedBox', 'TrimBox', 'ArtBox'). + * @protected + */ + protected function setPageBoxTypes($boxes) { + $validboxes = array('MediaBox', 'CropBox', 'BleedBox', 'TrimBox', 'ArtBox'); + $this->page_boxes = array(); + foreach ($boxes as $box) { + if (in_array($box, $validboxes)) { + $this->page_boxes[] = $box; + } + } + } + + /** * Output pages (and replace page number aliases). * @protected */ @@ -8904,22 +9076,21 @@ $out = '<<'; $out .= ' /Type /Page'; $out .= ' /Parent 1 0 R'; - $out .= ' /LastModified '.$this->_datestring(); + $out .= ' /LastModified '.$this->_datestring(0, $this->doc_modification_timestamp); $out .= ' /Resources 2 0 R'; - $boxes = array('MediaBox', 'CropBox', 'BleedBox', 'TrimBox', 'ArtBox'); - foreach ($boxes as $box) { + foreach ($this->page_boxes as $box) { $out .= ' /'.$box; - $out .= sprintf(' [%.2F %.2F %.2F %.2F]', $this->pagedim[$n][$box]['llx'], $this->pagedim[$n][$box]['lly'], $this->pagedim[$n][$box]['urx'], $this->pagedim[$n][$box]['ury']); + $out .= sprintf(' [%F %F %F %F]', $this->pagedim[$n][$box]['llx'], $this->pagedim[$n][$box]['lly'], $this->pagedim[$n][$box]['urx'], $this->pagedim[$n][$box]['ury']); } if (isset($this->pagedim[$n]['BoxColorInfo']) AND !empty($this->pagedim[$n]['BoxColorInfo'])) { $out .= ' /BoxColorInfo <<'; - foreach ($boxes as $box) { + foreach ($this->page_boxes as $box) { if (isset($this->pagedim[$n]['BoxColorInfo'][$box])) { $out .= ' /'.$box.' <<'; if (isset($this->pagedim[$n]['BoxColorInfo'][$box]['C'])) { $color = $this->pagedim[$n]['BoxColorInfo'][$box]['C']; $out .= ' /C ['; - $out .= sprintf(' %.3F %.3F %.3F', $color[0]/255, $color[1]/255, $color[2]/255); + $out .= sprintf(' %F %F %F', ($color[0] / 255), ($color[1] / 255), ($color[2] / 255)); $out .= ' ]'; } if (isset($this->pagedim[$n]['BoxColorInfo'][$box]['W'])) { @@ -8932,7 +9103,7 @@ $dashes = $this->pagedim[$n]['BoxColorInfo'][$box]['D']; $out .= ' /D ['; foreach ($dashes as $dash) { - $out .= sprintf(' %.3F', ($dash * $this->k)); + $out .= sprintf(' %F', ($dash * $this->k)); } $out .= ' ]'; } @@ -9116,7 +9287,7 @@ $b = $this->pagedim[$n]['h'] - (($pl['y'] + $pl['h']) * $this->k); $c = $pl['w'] * $this->k; $d = $pl['h'] * $this->k; - $rect = sprintf('%.2F %.2F %.2F %.2F', $a, $b, $a+$c, $b+$d); + $rect = sprintf('%F %F %F %F', $a, $b, $a+$c, $b+$d); // create new annotation object $annots = '<</Type /Annot'; $annots .= ' /Subtype /'.$pl['opt']['subtype']; @@ -9129,7 +9300,7 @@ $annots .= ' /Contents '.$this->_textstring($pl['txt'], $annot_obj_id); $annots .= ' /P '.$this->page_obj_id[$n].' 0 R'; $annots .= ' /NM '.$this->_datastring(sprintf('%04u-%04u', $n, $key), $annot_obj_id); - $annots .= ' /M '.$this->_datestring($annot_obj_id); + $annots .= ' /M '.$this->_datestring($annot_obj_id, $this->doc_modification_timestamp); if (isset($pl['opt']['f'])) { $fval = 0; if (is_array($pl['opt']['f'])) { @@ -9265,7 +9436,7 @@ $annots .= ' /S /S'; } if (isset($pl['opt']['be']['i']) AND ($pl['opt']['be']['i'] >= 0) AND ($pl['opt']['be']['i'] <= 2)) { - $annots .= ' /I '.sprintf(' %.4F', $pl['opt']['be']['i']); + $annots .= ' /I '.sprintf(' %F', $pl['opt']['be']['i']); } $annots .= '>>'; } @@ -9282,12 +9453,12 @@ } //$annots .= ' /Popup '; if (isset($pl['opt']['ca'])) { - $annots .= ' /CA '.sprintf('%.4F', floatval($pl['opt']['ca'])); + $annots .= ' /CA '.sprintf('%F', floatval($pl['opt']['ca'])); } if (isset($pl['opt']['rc'])) { $annots .= ' /RC '.$this->_textstring($pl['opt']['rc'], $annot_obj_id); } - $annots .= ' /CreationDate '.$this->_datestring($annot_obj_id); + $annots .= ' /CreationDate '.$this->_datestring($annot_obj_id, $this->doc_creation_timestamp); //$annots .= ' /IRT '; if (isset($pl['opt']['subj'])) { $annots .= ' /Subj '.$this->_textstring($pl['opt']['subj'], $annot_obj_id); @@ -9340,7 +9511,7 @@ // internal link $l = $this->links[$pl['txt']]; if (isset($this->page_obj_id[($l[0])])) { - $annots .= sprintf(' /Dest [%u 0 R /XYZ 0 %.2F null]', $this->page_obj_id[($l[0])], ($this->pagedim[$l[0]]['h'] - ($l[1] * $this->k))); + $annots .= sprintf(' /Dest [%u 0 R /XYZ 0 %F null]', $this->page_obj_id[($l[0])], ($this->pagedim[$l[0]]['h'] - ($l[1] * $this->k))); } } $hmodes = array('N', 'I', 'O', 'P'); @@ -9369,7 +9540,7 @@ if (isset($pl['opt']['cl']) AND is_array($pl['opt']['cl'])) { $annots .= ' /CL ['; foreach ($pl['opt']['cl'] as $cl) { - $annots .= sprintf('%.4F ', $cl * $this->k); + $annots .= sprintf('%F ', $cl * $this->k); } $annots .= ']'; } @@ -9382,7 +9553,7 @@ $r = $pl['opt']['rd'][1] * $this->k; $t = $pl['opt']['rd'][2] * $this->k; $b = $pl['opt']['rd'][3] * $this->k; - $annots .= ' /RD ['.sprintf('%.2F %.2F %.2F %.2F', $l, $r, $t, $b).']'; + $annots .= ' /RD ['.sprintf('%F %F %F %F', $l, $r, $t, $b).']'; } if (isset($pl['opt']['le']) AND in_array($pl['opt']['le'], $lineendings)) { $annots .= ' /LE /'.$pl['opt']['le']; @@ -9523,7 +9694,7 @@ $annots .= ' /S /'.$pl['opt']['mk']['if']['s']; } if (isset($pl['opt']['mk']['if']['a']) AND (is_array($pl['opt']['mk']['if']['a'])) AND !empty($pl['opt']['mk']['if']['a'])) { - $annots .= sprintf(' /A [%.2F %.2F]', $pl['opt']['mk']['if']['a'][0], $pl['opt']['mk']['if']['a'][1]); + $annots .= sprintf(' /A [%F %F]', $pl['opt']['mk']['if']['a'][0], $pl['opt']['mk']['if']['a'][1]); } if (isset($pl['opt']['mk']['if']['fb']) AND ($pl['opt']['mk']['if']['fb'])) { $annots .= ' /FB true'; @@ -9569,7 +9740,7 @@ if (is_array($pl['opt']['v'])) { foreach ($pl['opt']['v'] AS $optval) { if (is_float($optval)) { - $optval = sprintf('%.2F', $optval); + $optval = sprintf('%F', $optval); } $annots .= ' '.$optval; } @@ -9582,7 +9753,7 @@ if (is_array($pl['opt']['dv'])) { foreach ($pl['opt']['dv'] AS $optval) { if (is_float($optval)) { - $optval = sprintf('%.2F', $optval); + $optval = sprintf('%F', $optval); } $annots .= ' '.$optval; } @@ -9595,7 +9766,7 @@ if (is_array($pl['opt']['rv'])) { foreach ($pl['opt']['rv'] AS $optval) { if (is_float($optval)) { - $optval = sprintf('%.2F', $optval); + $optval = sprintf('%F', $optval); } $annots .= ' '.$optval; } @@ -9690,7 +9861,7 @@ $stream = gzcompress($stream); $out .= ' /Filter /FlateDecode'; } - $rect = sprintf('%.2F %.2F', $w, $h); + $rect = sprintf('%F %F', $w, $h); $out .= ' /BBox [0 0 '.$rect.']'; $out .= ' /Matrix [1 0 0 1 0 0]'; $out .= ' /Resources 2 0 R'; @@ -9733,8 +9904,8 @@ /** * Get SHORT from string (Big Endian 16-bit signed integer). - * @param $str (string) string from where to extract value - * @param $offset (int) point from where to read the data + * @param $str (string) String from where to extract value. + * @param $offset (int) Point from where to read the data. * @return int 16 bit value * @author Nicola Asuni * @protected @@ -9747,8 +9918,8 @@ /** * Get FWORD from string (Big Endian 16-bit signed integer). - * @param $str (string) string from where to extract value - * @param $offset (int) point from where to read the data + * @param $str (string) String from where to extract value. + * @param $offset (int) Point from where to read the data. * @return int 16 bit value * @author Nicola Asuni * @protected @@ -9830,17 +10001,19 @@ /** * Convert and add the selected TrueType or Type1 font to the fonts folder (that must be writeable). - * @param $fontfile (string) TrueType or Type1 font file (full path). + * @param $fontfile (string) Font file (full path). * @param $fonttype (string) Font type. Leave empty for autodetect mode. Valid values are: TrueTypeUnicode, TrueType, Type1, CID0JP = CID-0 Japanese, CID0KR = CID-0 Korean, CID0CS = CID-0 Chinese Simplified, CID0CT = CID-0 Chinese Traditional. * @param $enc (string) Name of the encoding table to use. Leave empty for default mode. Omit this parameter for TrueType Unicode and symbolic fonts like Symbol or ZapfDingBats. * @param $flags (int) Unsigned 32-bit integer containing flags specifying various characteristics of the font (PDF32000:2008 - 9.8.2 Font Descriptor Flags): +1 for fixed font; +4 for symbol or +32 for non-symbol; +64 for italic. Fixed and Italic mode are generally autodetected so you have to set it to 32 = non-symbolic font (default) or 4 = symbolic font. * @param $outpath (string) Output path for generated font files (must be writeable by the web server). Leave empty for default font folder. + * @param $platid (int) Platform ID for CMAP table to extract (when building a Unicode font for Windows this value should be 3, for Macintosh should be 1). + * @param $encid (int) Encoding ID for CMAP table to extract (when building a Unicode font for Windows this value should be 1, for Macintosh should be 0). When Platform ID is 3, legal values for Encoding ID are: 0=Symbol, 1=Unicode, 2=ShiftJIS, 3=PRC, 4=Big5, 5=Wansung, 6=Johab, 7=Reserved, 8=Reserved, 9=Reserved, 10=UCS-4. * @return (string) TCPDF font name. * @author Nicola Asuni * @public * @since 5.9.123 (2010-09-30) */ - public function addTTFfont($fontfile, $fonttype='', $enc='', $flags=32, $outpath='') { + public function addTTFfont($fontfile, $fonttype='', $enc='', $flags=32, $outpath='', $platid=3, $encid=1) { if (!file_exists($fontfile)) { $this->Error('Could not find file: '.$fontfile.''); } @@ -10309,220 +10482,216 @@ // ---------- get CIDToGIDMap ---------- $ctg = array(); foreach ($encodingTables as $enctable) { - if (($enctable['platformID'] == 3) AND ($enctable['encodingID'] == 0)) { - $modesymbol = true; - } else { - $modesymbol = false; - } - $offset = $table['cmap']['offset'] + $enctable['offset']; - $format = $this->_getUSHORT($font, $offset); - $offset += 2; - switch ($format) { - case 0: { // Format 0: Byte encoding table - $offset += 4; // skip length and version/language - for ($c = 0; $c < 256; ++$c) { - $g = $this->_getBYTE($font, $offset); - $ctg[$c] = $g; - ++$offset; + // get only specified Platform ID and Encoding ID + if (($enctable['platformID'] == $platid) AND ($enctable['encodingID'] == $encid)) { + $offset = $table['cmap']['offset'] + $enctable['offset']; + $format = $this->_getUSHORT($font, $offset); + $offset += 2; + switch ($format) { + case 0: { // Format 0: Byte encoding table + $offset += 4; // skip length and version/language + for ($c = 0; $c < 256; ++$c) { + $g = $this->_getBYTE($font, $offset); + $ctg[$c] = $g; + ++$offset; + } + break; } - break; - } - case 2: { // Format 2: High-byte mapping through table - $offset += 4; // skip length and version/language - $numSubHeaders = 0; - for ($i = 0; $i < 256; ++$i) { - // Array that maps high bytes to subHeaders: value is subHeader index * 8. - $subHeaderKeys[$i] = ($this->_getUSHORT($font, $offset) / 8); - $offset += 2; - if ($numSubHeaders < $subHeaderKeys[$i]) { - $numSubHeaders = $subHeaderKeys[$i]; + case 2: { // Format 2: High-byte mapping through table + $offset += 4; // skip length and version/language + $numSubHeaders = 0; + for ($i = 0; $i < 256; ++$i) { + // Array that maps high bytes to subHeaders: value is subHeader index * 8. + $subHeaderKeys[$i] = ($this->_getUSHORT($font, $offset) / 8); + $offset += 2; + if ($numSubHeaders < $subHeaderKeys[$i]) { + $numSubHeaders = $subHeaderKeys[$i]; + } } + // the number of subHeaders is equal to the max of subHeaderKeys + 1 + ++$numSubHeaders; + // read subHeader structures + $subHeaders = array(); + $numGlyphIndexArray = 0; + for ($k = 0; $k < $numSubHeaders; ++$k) { + $subHeaders[$k]['firstCode'] = $this->_getUSHORT($font, $offset); + $offset += 2; + $subHeaders[$k]['entryCount'] = $this->_getUSHORT($font, $offset); + $offset += 2; + $subHeaders[$k]['idDelta'] = $this->_getUSHORT($font, $offset); + $offset += 2; + $subHeaders[$k]['idRangeOffset'] = $this->_getUSHORT($font, $offset); + $offset += 2; + $subHeaders[$k]['idRangeOffset'] -= (2 + (($numSubHeaders - $k - 1) * 8)); + $subHeaders[$k]['idRangeOffset'] /= 2; + $numGlyphIndexArray += $subHeaders[$k]['entryCount']; + } + for ($k = 0; $k < $numGlyphIndexArray; ++$k) { + $glyphIndexArray[$k] = $this->_getUSHORT($font, $offset); + $offset += 2; + } + for ($i = 0; $i < 256; ++$i) { + $k = $subHeaderKeys[$i]; + if ($k == 0) { + // one byte code + $c = $i; + $g = $glyphIndexArray[0]; + $ctg[$c] = $g; + } else { + // two bytes code + $start_byte = $subHeaders[$k]['firstCode']; + $end_byte = $start_byte + $subHeaders[$k]['entryCount']; + for ($j = $start_byte; $j < $end_byte; ++$j) { + // combine high and low bytes + $c = (($i << 8) + $j); + $idRangeOffset = ($subHeaders[$k]['idRangeOffset'] + $j - $subHeaders[$k]['firstCode']); + $g = ($glyphIndexArray[$idRangeOffset] + $idDelta[$k]) % 65536; + if ($g < 0) { + $g = 0; + } + $ctg[$c] = $g; + } + } + } + break; } - // the number of subHeaders is equal to the max of subHeaderKeys + 1 - ++$numSubHeaders; - // read subHeader structures - $subHeaders = array(); - $numGlyphIndexArray = 0; - for ($k = 0; $k < $numSubHeaders; ++$k) { - $subHeaders[$k]['firstCode'] = $this->_getUSHORT($font, $offset); + case 4: { // Format 4: Segment mapping to delta values + $length = $this->_getUSHORT($font, $offset); $offset += 2; - $subHeaders[$k]['entryCount'] = $this->_getUSHORT($font, $offset); + $offset += 2; // skip version/language + $segCount = ($this->_getUSHORT($font, $offset) / 2); $offset += 2; - $subHeaders[$k]['idDelta'] = $this->_getSHORT($font, $offset); - $offset += 2; - $subHeaders[$k]['idRangeOffset'] = $this->_getUSHORT($font, $offset); - $offset += 2; - $subHeaders[$k]['idRangeOffset'] -= (2 + (($numSubHeaders - $k - 1) * 8)); - $subHeaders[$k]['idRangeOffset'] /= 2; - $numGlyphIndexArray += $subHeaders[$k]['entryCount']; - } - for ($k = 0; $k < $numGlyphIndexArray; ++$k) { - $glyphIndexArray[$k] = $this->_getUSHORT($font, $offset); - $offset += 2; - } - for ($i = 0; $i < 256; ++$i) { - $k = $subHeaderKeys[$i]; - if ($k == 0) { - // one byte code - $c = $i; - $g = $glyphIndexArray[0]; - $ctg[$c] = $g; - } else { - // two bytes code - $start_byte = $subHeaders[$k]['firstCode']; - $end_byte = $start_byte + $subHeaders[$k]['entryCount']; - for ($j = $start_byte; $j < $end_byte; ++$j) { - // combine high and low bytes - $c = (($i << 8) + $j); - $idRangeOffset = ($subHeaders[$k]['idRangeOffset'] + $j - $subHeaders[$k]['firstCode']); - $g = $glyphIndexArray[$idRangeOffset]; - $g += ($idDelta[$k] - 65536); + $offset += 6; // skip searchRange, entrySelector, rangeShift + $endCount = array(); // array of end character codes for each segment + for ($k = 0; $k < $segCount; ++$k) { + $endCount[$k] = $this->_getUSHORT($font, $offset); + $offset += 2; + } + $offset += 2; // skip reservedPad + $startCount = array(); // array of start character codes for each segment + for ($k = 0; $k < $segCount; ++$k) { + $startCount[$k] = $this->_getUSHORT($font, $offset); + $offset += 2; + } + $idDelta = array(); // delta for all character codes in segment + for ($k = 0; $k < $segCount; ++$k) { + $idDelta[$k] = $this->_getUSHORT($font, $offset); + $offset += 2; + } + $idRangeOffset = array(); // Offsets into glyphIdArray or 0 + for ($k = 0; $k < $segCount; ++$k) { + $idRangeOffset[$k] = $this->_getUSHORT($font, $offset); + $offset += 2; + } + $gidlen = ($length / 2) - 8 - (4 * $segCount); + $glyphIdArray = array(); // glyph index array + for ($k = 0; $k < $gidlen; ++$k) { + $glyphIdArray[$k] = $this->_getUSHORT($font, $offset); + $offset += 2; + } + for ($k = 0; $k < $segCount; ++$k) { + for ($c = $startCount[$k]; $c <= $endCount[$k]; ++$c) { + if ($idRangeOffset[$k] == 0) { + $g = ($idDelta[$k] + $c) % 65536; + } else { + $gid = (($idRangeOffset[$k] / 2) + ($c - $startCount[$k]) - ($segCount - $k)); + $g = ($glyphIdArray[$gid] + $idDelta[$k]) % 65536; + } if ($g < 0) { $g = 0; } $ctg[$c] = $g; } } + break; } - break; - } - case 4: { // Format 4: Segment mapping to delta values - $length = $this->_getUSHORT($font, $offset); - $offset += 2; - $offset += 2; // skip version/language - $segCount = ($this->_getUSHORT($font, $offset) / 2); - $offset += 2; - $offset += 6; // skip searchRange, entrySelector, rangeShift - $endCount = array(); // array of end character codes for each segment - for ($k = 0; $k < $segCount; ++$k) { - $endCount[$k] = $this->_getUSHORT($font, $offset); + case 6: { // Format 6: Trimmed table mapping + $offset += 4; // skip length and version/language + $firstCode = $this->_getUSHORT($font, $offset); $offset += 2; - } - $offset += 2; // skip reservedPad - $startCount = array(); // array of start character codes for each segment - for ($k = 0; $k < $segCount; ++$k) { - $startCount[$k] = $this->_getUSHORT($font, $offset); + $entryCount = $this->_getUSHORT($font, $offset); $offset += 2; + for ($k = 0; $k < $entryCount; ++$k) { + $c = ($k + $firstCode); + $g = $this->_getUSHORT($font, $offset); + $offset += 2; + $ctg[$c] = $g; + } + break; } - $idDelta = array(); // delta for all character codes in segment - for ($k = 0; $k < $segCount; ++$k) { - $idDelta[$k] = $this->_getUSHORT($font, $offset); - $offset += 2; - } - $idRangeOffset = array(); // Offsets into glyphIdArray or 0 - for ($k = 0; $k < $segCount; ++$k) { - $idRangeOffset[$k] = $this->_getUSHORT($font, $offset); - $offset += 2; - } - $gidlen = ($length / 2) - 8 - (4 * $segCount); - $glyphIdArray = array(); // glyph index array - for ($k = 0; $k < $gidlen; ++$k) { - $glyphIdArray[$k] = $this->_getUSHORT($font, $offset); - $offset += 2; - } - for ($k = 0; $k < $segCount; ++$k) { - for ($c = $startCount[$k]; $c <= $endCount[$k]; ++$c) { - if ($idRangeOffset[$k] == 0) { - $g = $c; - } else { - $gid = (($idRangeOffset[$k] / 2) + ($c - $startCount[$k]) - ($segCount - $k)); - $g = $glyphIdArray[$gid]; + case 8: { // Format 8: Mixed 16-bit and 32-bit coverage + $offset += 10; // skip reserved, length and version/language + for ($k = 0; $k < 8192; ++$k) { + $is32[$k] = $this->_getBYTE($font, $offset); + ++$offset; + } + $nGroups = $this->_getULONG($font, $offset); + $offset += 4; + for ($i = 0; $i < $nGroups; ++$i) { + $startCharCode = $this->_getULONG($font, $offset); + $offset += 4; + $endCharCode = $this->_getULONG($font, $offset); + $offset += 4; + $startGlyphID = $this->_getULONG($font, $offset); + $offset += 4; + for ($k = $startCharCode; $k <= $endCharCode; ++$k) { + $is32idx = floor($c / 8); + if ((isset($is32[$is32idx])) AND (($is32[$is32idx] & (1 << (7 - ($c % 8)))) == 0)) { + $c = $k; + } else { + // 32 bit format + // convert to decimal (http://www.unicode.org/faq//utf_bom.html#utf16-4) + //LEAD_OFFSET = (0xD800 - (0x10000 >> 10)) = 55232 + //SURROGATE_OFFSET = (0x10000 - (0xD800 << 10) - 0xDC00) = -56613888 + $c = ((55232 + ($k >> 10)) << 10) + (0xDC00 + ($k & 0x3FF)) -56613888; + } + $ctg[$c] = 0; + ++$startGlyphID; } - $g += ($idDelta[$k] - 65536); - if ($g < 0) { - $g = 0; - } - $ctg[$c] = $g; } + break; } - break; - } - case 6: { // Format 6: Trimmed table mapping - $offset += 4; // skip length and version/language - $firstCode = $this->_getUSHORT($font, $offset); - $offset += 2; - $entryCount = $this->_getUSHORT($font, $offset); - $offset += 2; - for ($k = 0; $k < $entryCount; ++$k) { - $c = ($k + $firstCode); - $g = $this->_getUSHORT($font, $offset); - $ctg[$c] = $g; - $offset += 2; - } - break; - } - case 8: { // Format 8: Mixed 16-bit and 32-bit coverage - $offset += 10; // skip reserved, length and version/language - for ($k = 0; $k < 8192; ++$k) { - $is32[$k] = $this->_getBYTE($font, $offset); - ++$offset; - } - $nGroups = $this->_getULONG($font, $offset); - $offset += 4; - for ($i = 0; $i < $nGroups; ++$i) { + case 10: { // Format 10: Trimmed array + $offset += 10; // skip reserved, length and version/language $startCharCode = $this->_getULONG($font, $offset); $offset += 4; - $endCharCode = $this->_getULONG($font, $offset); + $numChars = $this->_getULONG($font, $offset); $offset += 4; - $startGlyphID = $this->_getULONG($font, $offset); - $offset += 4; - for ($k = $startCharCode; $k <= $endCharCode; ++$k) { - $is32idx = floor($c / 8); - if ((isset($is32[$is32idx])) AND (($is32[$is32idx] & (1 << (7 - ($c % 8)))) == 0)) { - $c = $k; - } else { - // 32 bit format - // convert to decimal (http://www.unicode.org/faq//utf_bom.html#utf16-4) - //LEAD_OFFSET = (0xD800 - (0x10000 >> 10)) = 55232 - //SURROGATE_OFFSET = (0x10000 - (0xD800 << 10) - 0xDC00) = -56613888 - $c = ((55232 + ($k >> 10)) << 10) + (0xDC00 + ($k & 0x3FF)) -56613888; - } + for ($k = 0; $k < $numChars; ++$k) { + $c = ($k + $startCharCode); + $g = $this->_getUSHORT($font, $offset); $ctg[$c] = $g; - ++$startGlyphID; + $offset += 2; } + break; } - break; - } - case 10: { // Format 10: Trimmed array - $offset += 10; // skip reserved, length and version/language - $startCharCode = $this->_getULONG($font, $offset); - $offset += 4; - $numChars = $this->_getULONG($font, $offset); - $offset += 4; - for ($k = 0; $k < $numChars; ++$k) { - $c = ($k + $startCharCode); - $g = $this->_getUSHORT($font, $offset); - $ctg[$c] = $g; - $offset += 2; - } - break; - } - case 12: { // Format 12: Segmented coverage - $offset += 10; // skip length and version/language - $nGroups = $this->_getULONG($font, $offset); - $offset += 4; - for ($k = 0; $k < $nGroups; ++$k) { - $startCharCode = $this->_getULONG($font, $offset); + case 12: { // Format 12: Segmented coverage + $offset += 10; // skip length and version/language + $nGroups = $this->_getULONG($font, $offset); $offset += 4; - $endCharCode = $this->_getULONG($font, $offset); - $offset += 4; - $startGlyphCode = $this->_getULONG($font, $offset); - $offset += 4; - for ($c = $startCharCode; $c <= $endCharCode; ++$c) { - $ctg[$c] = $startGlyphCode; - ++$startGlyphCode; + for ($k = 0; $k < $nGroups; ++$k) { + $startCharCode = $this->_getULONG($font, $offset); + $offset += 4; + $endCharCode = $this->_getULONG($font, $offset); + $offset += 4; + $startGlyphCode = $this->_getULONG($font, $offset); + $offset += 4; + for ($c = $startCharCode; $c <= $endCharCode; ++$c) { + $ctg[$c] = $startGlyphCode; + ++$startGlyphCode; + } } + break; } - break; + case 13: { // Format 13: Many-to-one range mappings + // to be implemented ... + break; + } + case 14: { // Format 14: Unicode Variation Sequences + // to be implemented ... + break; + } } - case 13: { // Format 13: Many-to-one range mappings - // to be implemented ... - break; - } - case 14: { // Format 14: Unicode Variation Sequences - // to be implemented ... - break; - } } } if (!isset($ctg[0])) { @@ -10741,11 +10910,7 @@ $offset += 4; } foreach ($encodingTables as $enctable) { - if (($enctable['platformID'] == 3) AND ($enctable['encodingID'] == 0)) { - $modesymbol = true; - } else { - $modesymbol = false; - } + // get all platforms and encodings $offset = $table['cmap']['offset'] + $enctable['offset']; $format = $this->_getUSHORT($font, $offset); $offset += 2; @@ -10782,7 +10947,7 @@ $offset += 2; $subHeaders[$k]['entryCount'] = $this->_getUSHORT($font, $offset); $offset += 2; - $subHeaders[$k]['idDelta'] = $this->_getSHORT($font, $offset); + $subHeaders[$k]['idDelta'] = $this->_getUSHORT($font, $offset); $offset += 2; $subHeaders[$k]['idRangeOffset'] = $this->_getUSHORT($font, $offset); $offset += 2; @@ -10812,8 +10977,7 @@ $c = (($i << 8) + $j); if (isset($subsetchars[$c])) { $idRangeOffset = ($subHeaders[$k]['idRangeOffset'] + $j - $subHeaders[$k]['firstCode']); - $g = $glyphIndexArray[$idRangeOffset]; - $g += ($idDelta[$k] - 65536); + $g = ($glyphIndexArray[$idRangeOffset] + $idDelta[$k]) % 65536; if ($g < 0) { $g = 0; } @@ -10862,12 +11026,11 @@... [truncated message content] |