From 54860ef304f279d22ad97314674651363ae3a6b9 Mon Sep 17 00:00:00 2001
From: Regis Houssin
Date: Wed, 29 Aug 2012 09:55:32 +0200
Subject: [PATCH] Fix: upgrade tcpdf and fpdi
---
COPYRIGHT | 6 +-
htdocs/core/lib/pdf.lib.php | 8 +-
.../modules/propale/doc/pdf_azur.modules.php | 16 +-
.../includes/fpdfi/filters/FilterASCII85.php | 4 +-
.../fpdfi/filters/FilterASCII85_FPDI.php | 64 +-
htdocs/includes/fpdfi/filters/FilterLZW.php | 4 +-
.../includes/fpdfi/filters/FilterLZW_FPDI.php | 64 +-
htdocs/includes/fpdfi/fpdf_tpl.php | 898 +++++-----
htdocs/includes/fpdfi/fpdi.php | 1111 ++++++-------
htdocs/includes/fpdfi/fpdi2tcpdf_bridge.php | 12 +-
htdocs/includes/fpdfi/fpdi_pdf_parser.php | 815 +++++-----
htdocs/includes/fpdfi/pdf_context.php | 206 +--
htdocs/includes/fpdfi/pdf_parser.php | 1438 ++++++++---------
htdocs/includes/tcpdf/2dbarcodes.php | 12 +-
htdocs/includes/tcpdf/CHANGELOG.TXT | 93 +-
htdocs/includes/tcpdf/README.TXT | 6 +-
htdocs/includes/tcpdf/barcodes.php | 12 +-
htdocs/includes/tcpdf/config/lang/bul.php | 94 +-
htdocs/includes/tcpdf/config/lang/rus.php | 4 +-
htdocs/includes/tcpdf/config/lang/ukr.php | 47 +
htdocs/includes/tcpdf/config/tcpdf_config.php | 8 +-
htdocs/includes/tcpdf/qrcode.php | 22 +-
htdocs/includes/tcpdf/tcpdf.php | 705 ++++++--
htdocs/includes/tcpdf/tcpdf_parser.php | 35 +-
24 files changed, 3121 insertions(+), 2563 deletions(-)
create mode 100644 htdocs/includes/tcpdf/config/lang/ukr.php
diff --git a/COPYRIGHT b/COPYRIGHT
index 384fab6fd5c..c8e162b848d 100644
--- a/COPYRIGHT
+++ b/COPYRIGHT
@@ -13,12 +13,12 @@ Composant Version License Compatible GPL Usage
PHP libraries:
AdoDb-Date 0.21 Modified BSD License Yes Date convertion (not into rpm package)
CKEditor 3.6.2 GPL or LGPL 2.1 or MPL 1.1 Yes Editor WYSIWYG
-FPDI 1.4.1 Apache Software License 2.0 ? PDF templates management
+FPDI 1.4.2 Apache Software License 2.0 No (GPLv3 only) PDF templates management (with FPDF_TPL 1.2)
GeoIP 2004 LGPL 2.1 Yes Sample code to make geoip convert (not into deb package)
NuSoap 0.9.5 LGPL 2.1 Yes Library to develop SOAP Web services (not into rpm and deb package)
OdtPHP 1.0.1 GPL 2.0 Yes Library to build/edit ODT files
PHPExcel 1.7.6 LGPL 2.1 Yes Read/Write XLS files, read ODS files
-TCPDF 5.9.156 LGPL 3.0 Yes PDF generation
+TCPDF 5.9.180 LGPL 3.0 Yes PDF generation
JS libraries:
jQuery 1.7.2 GPL and MIT Licence Yes JS library
@@ -29,7 +29,7 @@ jQuery Flot 0.7 MIT Licence Yes JS library to build graph
jQuery FileUpload 5.0.3 GPL and MIT Licence Yes JS library to upload files
jQuery JCrop 0.9.8 GPL and MIT Licence Yes JS library plugin Crop (to crop images)
jQuery jeditable 1.7.1 GPL and MIT Licence Yes JS library plugin jeditable (to edit in place)
-jQuery jNotify 1.1.00 Apache Software License 2.0 ? JS library plugin jNotify (to use ajax popups)
+jQuery jNotify 1.1.00 Apache Software License 2.0 No (GPLv3 only) JS library plugin jNotify (to use ajax popups)
jQuery jPicker 1.1.00 GPL and MIT Licence Yes JS library for color picker with not defined list of colors
jQuery Layout 1.3.0 GPL and MIT Licence Yes JS library plugin Layout (RC-29.15)
jQuery TableDnD 0.5 GPL and MIT Licence Yes JS library plugin TableDnD (to reorder table rows)
diff --git a/htdocs/core/lib/pdf.lib.php b/htdocs/core/lib/pdf.lib.php
index 33bc91637a3..3be9c1b03f9 100644
--- a/htdocs/core/lib/pdf.lib.php
+++ b/htdocs/core/lib/pdf.lib.php
@@ -1046,9 +1046,9 @@ function pdf_getlineupexcltax($object,$i,$outputlangs,$hidedetails=0,$hookmanage
global $conf;
$sign=1;
- if ($object->type == 2 && ! empty($conf->global->INVOICE_POSITIVE_CREDIT_NOTE)) $sign=-1;
+ if (isset($object->type) && $object->type == 2 && ! empty($conf->global->INVOICE_POSITIVE_CREDIT_NOTE)) $sign=-1;
- if (is_object($hookmanager) && ( ($object->lines[$i]->product_type == 9 && !empty($object->lines[$i]->special_code) ) || ! empty($object->lines[$i]->fk_parent_line) ) )
+ if (is_object($hookmanager) && (($object->lines[$i]->product_type == 9 && !empty($object->lines[$i]->special_code)) || ! empty($object->lines[$i]->fk_parent_line)))
{
$special_code = $object->lines[$i]->special_code;
if (! empty($object->lines[$i]->fk_parent_line)) $special_code = $object->getSpecialCode($object->lines[$i]->fk_parent_line);
@@ -1250,7 +1250,7 @@ function pdf_getlinetotalexcltax($object,$i,$outputlangs,$hidedetails=0,$hookman
global $conf;
$sign=1;
- if ($object->type == 2 && ! empty($conf->global->INVOICE_POSITIVE_CREDIT_NOTE)) $sign=-1;
+ if (isset($object->type) && $object->type == 2 && ! empty($conf->global->INVOICE_POSITIVE_CREDIT_NOTE)) $sign=-1;
if ($object->lines[$i]->special_code == 3)
{
@@ -1258,7 +1258,7 @@ function pdf_getlinetotalexcltax($object,$i,$outputlangs,$hidedetails=0,$hookman
}
else
{
- if (is_object($hookmanager) && ( ($object->lines[$i]->product_type == 9 && ! empty($object->lines[$i]->special_code) ) || ! empty($object->lines[$i]->fk_parent_line) ) )
+ if (is_object($hookmanager) && (($object->lines[$i]->product_type == 9 && ! empty($object->lines[$i]->special_code)) || ! empty($object->lines[$i]->fk_parent_line)))
{
$special_code = $object->lines[$i]->special_code;
if (! empty($object->lines[$i]->fk_parent_line)) $special_code = $object->getSpecialCode($object->lines[$i]->fk_parent_line);
diff --git a/htdocs/core/modules/propale/doc/pdf_azur.modules.php b/htdocs/core/modules/propale/doc/pdf_azur.modules.php
index 4a24f74c2a0..8aacca212b1 100644
--- a/htdocs/core/modules/propale/doc/pdf_azur.modules.php
+++ b/htdocs/core/modules/propale/doc/pdf_azur.modules.php
@@ -311,6 +311,10 @@ class pdf_azur extends ModelePDFPropales
if (($object->lines[$i]->info_bits & 0x01) == 0x01) $vatrate.='*';
+ if (! isset($this->tva[$vatrate])) $this->tva[$vatrate]=0;
+ if (! isset($this->localtax1[$localtax1rate])) $this->localtax1[$localtax1rate]=0;
+ if (! isset($this->localtax2[$localtax2rate])) $this->localtax2[$localtax2rate]=0;
+
$this->tva[$vatrate] += $tvaligne;
$this->localtax1[$localtax1rate]+=$localtax1ligne;
$this->localtax2[$localtax2rate]+=$localtax2ligne;
@@ -455,7 +459,7 @@ class pdf_azur extends ModelePDFPropales
}
// Show shipping date
- if ($object->type != 2 && $object->date_livraison)
+ if (isset($object->type) && $object->type != 2 && $object->date_livraison)
{
$outputlangs->load("sendings");
$pdf->SetFont('','B', $default_font_size - 2);
@@ -469,7 +473,7 @@ class pdf_azur extends ModelePDFPropales
$posy=$pdf->GetY()+1;
}
- elseif ($object->type != 2 && ($object->availability_code || $object->availability)) // Show availability conditions
+ elseif (isset($object->type) && $object->type != 2 && ($object->availability_code || $object->availability)) // Show availability conditions
{
$pdf->SetFont('','B', $default_font_size - 2);
$pdf->SetXY($this->marge_gauche, $posy);
@@ -486,7 +490,7 @@ class pdf_azur extends ModelePDFPropales
}
// Show payments conditions
- if ($object->type != 2 && ($object->cond_reglement_code || $object->cond_reglement))
+ if (isset($object->type) && $object->type != 2 && ($object->cond_reglement_code || $object->cond_reglement))
{
$pdf->SetFont('','B', $default_font_size - 2);
$pdf->SetXY($this->marge_gauche, $posy);
@@ -503,7 +507,7 @@ class pdf_azur extends ModelePDFPropales
}
- if ($object->type != 2)
+ if (isset($object->type) && $object->type != 2)
{
// Check a payment mode is defined
if (empty($object->mode_reglement_code)
@@ -632,7 +636,7 @@ class pdf_azur extends ModelePDFPropales
$this->atleastoneratenotnull=0;
if (empty($conf->global->MAIN_GENERATE_DOCUMENTS_WITHOUT_VAT))
{
- $tvaisnull=((! empty($this->tva) && count($this->tva) == 1 && is_float($this->tva['0.000'])) ? true : false);
+ $tvaisnull=((! empty($this->tva) && count($this->tva) == 1 && isset($this->tva['0.000']) && is_float($this->tva['0.000'])) ? true : false);
if (! empty($conf->global->MAIN_GENERATE_DOCUMENTS_WITHOUT_VAT_ISNULL) && $tvaisnull)
{
// Nothing to do
@@ -1049,7 +1053,7 @@ class pdf_azur extends ModelePDFPropales
$carac_client_name=$outputlangs->convToOutputCharset($object->client->nom);
}
- $carac_client=pdf_build_address($outputlangs,$this->emetteur,$object->client,$object->contact,$usecontact,'target');
+ $carac_client=pdf_build_address($outputlangs,$this->emetteur,$object->client,(! empty($object->contact)?$object->contact:''),$usecontact,'target');
// Show recipient
$posy=42;
diff --git a/htdocs/includes/fpdfi/filters/FilterASCII85.php b/htdocs/includes/fpdfi/filters/FilterASCII85.php
index 092f3299b64..01402ba1dc6 100755
--- a/htdocs/includes/fpdfi/filters/FilterASCII85.php
+++ b/htdocs/includes/fpdfi/filters/FilterASCII85.php
@@ -1,6 +1,6 @@
ORD_u) {
diff --git a/htdocs/includes/fpdfi/filters/FilterASCII85_FPDI.php b/htdocs/includes/fpdfi/filters/FilterASCII85_FPDI.php
index d4687ee88f2..fb5600116bc 100755
--- a/htdocs/includes/fpdfi/filters/FilterASCII85_FPDI.php
+++ b/htdocs/includes/fpdfi/filters/FilterASCII85_FPDI.php
@@ -1,33 +1,33 @@
-fpdi =& $fpdi;
- }
-
- function error($msg) {
- $this->fpdi->error($msg);
- }
+fpdi =& $fpdi;
+ }
+
+ function error($msg) {
+ $this->fpdi->error($msg);
+ }
}
\ No newline at end of file
diff --git a/htdocs/includes/fpdfi/filters/FilterLZW.php b/htdocs/includes/fpdfi/filters/FilterLZW.php
index 76d303d3803..292461d248d 100755
--- a/htdocs/includes/fpdfi/filters/FilterLZW.php
+++ b/htdocs/includes/fpdfi/filters/FilterLZW.php
@@ -1,6 +1,6 @@
sTable[$oldCode];
- $string = $string.$string[0];
+ $string = $string . $string[0];
$uncompData .= $string;
$this->addStringToTable($string);
diff --git a/htdocs/includes/fpdfi/filters/FilterLZW_FPDI.php b/htdocs/includes/fpdfi/filters/FilterLZW_FPDI.php
index fd9451e214f..e7a88119ff9 100755
--- a/htdocs/includes/fpdfi/filters/FilterLZW_FPDI.php
+++ b/htdocs/includes/fpdfi/filters/FilterLZW_FPDI.php
@@ -1,33 +1,33 @@
-fpdi =& $fpdi;
- }
-
- function error($msg) {
- $this->fpdi->error($msg);
- }
+fpdi =& $fpdi;
+ }
+
+ function error($msg) {
+ $this->fpdi->error($msg);
+ }
}
\ No newline at end of file
diff --git a/htdocs/includes/fpdfi/fpdf_tpl.php b/htdocs/includes/fpdfi/fpdf_tpl.php
index 6e234bf9321..d21743e6374 100755
--- a/htdocs/includes/fpdfi/fpdf_tpl.php
+++ b/htdocs/includes/fpdfi/fpdf_tpl.php
@@ -1,449 +1,449 @@
-Error('This method is only usable with FPDF. Use TCPDF methods startTemplate() instead.');
- return;
- }
-
- if ($this->page <= 0)
- $this->error("You have to add a page to fpdf first!");
-
- if ($x == null)
- $x = 0;
- if ($y == null)
- $y = 0;
- if ($w == null)
- $w = $this->w;
- if ($h == null)
- $h = $this->h;
-
- // Save settings
- $this->tpl++;
- $tpl =& $this->tpls[$this->tpl];
- $tpl = array(
- 'o_x' => $this->x,
- 'o_y' => $this->y,
- 'o_AutoPageBreak' => $this->AutoPageBreak,
- 'o_bMargin' => $this->bMargin,
- 'o_tMargin' => $this->tMargin,
- 'o_lMargin' => $this->lMargin,
- 'o_rMargin' => $this->rMargin,
- 'o_h' => $this->h,
- 'o_w' => $this->w,
- 'buffer' => '',
- 'x' => $x,
- 'y' => $y,
- 'w' => $w,
- 'h' => $h
- );
-
- $this->SetAutoPageBreak(false);
-
- // Define own high and width to calculate possitions correct
- $this->h = $h;
- $this->w = $w;
-
- $this->_intpl = true;
- $this->SetXY($x + $this->lMargin, $y + $this->tMargin);
- $this->SetRightMargin($this->w - $w + $this->rMargin);
-
- return $this->tpl;
- }
-
- /**
- * End Template
- *
- * This method ends a template and reset initiated variables on beginTemplate.
- *
- * @return mixed If a template is opened, the ID is returned. If not a false is returned.
- */
- function endTemplate() {
- if (is_subclass_of($this, 'TCPDF')) {
- $args = func_get_args();
- return call_user_func_array(array($this, 'TCPDF::endTemplate'), $args);
- }
-
- if ($this->_intpl) {
- $this->_intpl = false;
- $tpl =& $this->tpls[$this->tpl];
- $this->SetXY($tpl['o_x'], $tpl['o_y']);
- $this->tMargin = $tpl['o_tMargin'];
- $this->lMargin = $tpl['o_lMargin'];
- $this->rMargin = $tpl['o_rMargin'];
- $this->h = $tpl['o_h'];
- $this->w = $tpl['o_w'];
- $this->SetAutoPageBreak($tpl['o_AutoPageBreak'], $tpl['o_bMargin']);
-
- return $this->tpl;
- } else {
- return false;
- }
- }
-
- /**
- * Use a Template in current Page or other Template
- *
- * You can use a template in a page or in another template.
- * You can give the used template a new size like you use the Image()-method.
- * All parameters are optional. The width or height is calculated automaticaly
- * if one is given. If no parameter is given the origin size as defined in
- * beginTemplate() is used.
- * The calculated or used width and height are returned as an array.
- *
- * @param int $tplidx A valid template-Id
- * @param int $_x The x-position
- * @param int $_y The y-position
- * @param int $_w The new width of the template
- * @param int $_h The new height of the template
- * @retrun array The height and width of the template
- */
- function useTemplate($tplidx, $_x = null, $_y = null, $_w = 0, $_h = 0) {
- if ($this->page <= 0)
- $this->error('You have to add a page first!');
-
- if (!isset($this->tpls[$tplidx]))
- $this->error('Template does not exist!');
-
- if ($this->_intpl) {
- $this->_res['tpl'][$this->tpl]['tpls'][$tplidx] =& $this->tpls[$tplidx];
- }
-
- $tpl =& $this->tpls[$tplidx];
- $w = $tpl['w'];
- $h = $tpl['h'];
-
- if ($_x == null)
- $_x = 0;
- if ($_y == null)
- $_y = 0;
-
- $_x += $tpl['x'];
- $_y += $tpl['y'];
-
- $wh = $this->getTemplateSize($tplidx, $_w, $_h);
- $_w = $wh['w'];
- $_h = $wh['h'];
-
- $tData = array(
- 'x' => $this->x,
- 'y' => $this->y,
- 'w' => $_w,
- 'h' => $_h,
- 'scaleX' => ($_w / $w),
- 'scaleY' => ($_h / $h),
- 'tx' => $_x,
- 'ty' => ($this->h - $_y - $_h),
- 'lty' => ($this->h - $_y - $_h) - ($this->h - $h) * ($_h / $h)
- );
-
- $this->_out(sprintf('q %.4F 0 0 %.4F %.4F %.4F cm', $tData['scaleX'], $tData['scaleY'], $tData['tx'] * $this->k, $tData['ty'] * $this->k)); // Translate
- $this->_out(sprintf('%s%d Do Q', $this->tplprefix, $tplidx));
-
- // reset font in the outer graphic state
- if ($this->FontFamily) {
- $family = $this->FontFamily;
- $this->FontFamily = '';
- $this->SetFont($family);
- }
-
- $this->lastUsedTemplateData = $tData;
-
- return array('w' => $_w, 'h' => $_h);
- }
-
- /**
- * Get The calculated Size of a Template
- *
- * If one size is given, this method calculates the other one.
- *
- * @param int $tplidx A valid template-Id
- * @param int $_w The width of the template
- * @param int $_h The height of the template
- * @return array The height and width of the template
- */
- function getTemplateSize($tplidx, $_w = 0, $_h = 0) {
- if (!$this->tpls[$tplidx])
- return false;
-
- $tpl =& $this->tpls[$tplidx];
- $w = $tpl['w'];
- $h = $tpl['h'];
-
- if ($_w == 0 and $_h == 0) {
- $_w = $w;
- $_h = $h;
- }
-
- if($_w == 0)
- $_w = $_h * $w / $h;
- if($_h == 0)
- $_h = $_w * $h / $w;
-
- return array("w" => $_w, "h" => $_h);
- }
-
- /**
- * See FPDF/TCPDF-Documentation ;-)
- */
- public function SetFont($family, $style = '', $size = 0) {
- if (is_subclass_of($this, 'TCPDF')) {
- $args = func_get_args();
- return call_user_func_array(array($this, 'TCPDF::SetFont'), $args);
- }
-
- /**
- * force the resetting of font changes in a template
- */
- if ($this->_intpl)
- $this->FontFamily = '';
-
- parent::SetFont($family, $style, $size);
-
- $fontkey = $this->FontFamily . $this->FontStyle;
-
- if ($this->_intpl) {
- $this->_res['tpl'][$this->tpl]['fonts'][$fontkey] =& $this->fonts[$fontkey];
- } else {
- $this->_res['page'][$this->page]['fonts'][$fontkey] =& $this->fonts[$fontkey];
- }
- }
-
- /**
- * See FPDF/TCPDF-Documentation ;-)
- */
- function Image($file, $x = null, $y = null, $w = 0, $h = 0, $type = '', $link = '') {
- if (is_subclass_of($this, 'TCPDF')) {
- $args = func_get_args();
- return call_user_func_array(array($this, 'TCPDF::Image'), $args);
- }
-
- $ret = parent::Image($file, $x, $y, $w, $h, $type, $link);
- if ($this->_intpl) {
- $this->_res['tpl'][$this->tpl]['images'][$file] =& $this->images[$file];
- } else {
- $this->_res['page'][$this->page]['images'][$file] =& $this->images[$file];
- }
-
- return $ret;
- }
-
- /**
- * See FPDF-Documentation ;-)
- *
- * AddPage is not available when you're "in" a template.
- */
- function AddPage($orientation = '', $format = '') {
- if (is_subclass_of($this, 'TCPDF')) {
- $args = func_get_args();
- return call_user_func_array(array($this, 'TCPDF::AddPage'), $args);
- }
-
- if ($this->_intpl)
- $this->Error('Adding pages in templates isn\'t possible!');
-
- parent::AddPage($orientation, $format);
- }
-
- /**
- * Preserve adding Links in Templates ...won't work
- */
- function Link($x, $y, $w, $h, $link) {
- if (is_subclass_of($this, 'TCPDF')) {
- $args = func_get_args();
- return call_user_func_array(array($this, 'TCPDF::Link'), $args);
- }
-
- if ($this->_intpl)
- $this->Error('Using links in templates aren\'t possible!');
-
- parent::Link($x, $y, $w, $h, $link);
- }
-
- function AddLink() {
- if (is_subclass_of($this, 'TCPDF')) {
- $args = func_get_args();
- return call_user_func_array(array($this, 'TCPDF::AddLink'), $args);
- }
-
- if ($this->_intpl)
- $this->Error('Adding links in templates aren\'t possible!');
- return parent::AddLink();
- }
-
- function SetLink($link, $y = 0, $page = -1) {
- if (is_subclass_of($this, 'TCPDF')) {
- $args = func_get_args();
- return call_user_func_array(array($this, 'TCPDF::SetLink'), $args);
- }
-
- if ($this->_intpl)
- $this->Error('Setting links in templates aren\'t possible!');
- parent::SetLink($link, $y, $page);
- }
-
- /**
- * Private Method that writes the form xobjects
- */
- function _putformxobjects() {
- $filter=($this->compress) ? '/Filter /FlateDecode ' : '';
- reset($this->tpls);
- foreach($this->tpls AS $tplidx => $tpl) {
-
- $p=($this->compress) ? gzcompress($tpl['buffer']) : $tpl['buffer'];
- $this->_newobj();
- $this->tpls[$tplidx]['n'] = $this->n;
- $this->_out('<<'.$filter.'/Type /XObject');
- $this->_out('/Subtype /Form');
- $this->_out('/FormType 1');
- $this->_out(sprintf('/BBox [%.2F %.2F %.2F %.2F]',
- // llx
- $tpl['x'] * $this->k,
- // lly
- -$tpl['y'] * $this->k,
- // urx
- ($tpl['w'] + $tpl['x']) * $this->k,
- // ury
- ($tpl['h'] - $tpl['y']) * $this->k
- ));
-
- if ($tpl['x'] != 0 || $tpl['y'] != 0) {
- $this->_out(sprintf('/Matrix [1 0 0 1 %.5F %.5F]',
- -$tpl['x'] * $this->k * 2, $tpl['y'] * $this->k * 2
- ));
- }
-
- $this->_out('/Resources ');
-
- $this->_out('<_res['tpl'][$tplidx]['fonts']) && count($this->_res['tpl'][$tplidx]['fonts'])) {
- $this->_out('/Font <<');
- foreach($this->_res['tpl'][$tplidx]['fonts'] as $font)
- $this->_out('/F' . $font['i'] . ' ' . $font['n'] . ' 0 R');
- $this->_out('>>');
- }
- if(isset($this->_res['tpl'][$tplidx]['images']) && count($this->_res['tpl'][$tplidx]['images']) ||
- isset($this->_res['tpl'][$tplidx]['tpls']) && count($this->_res['tpl'][$tplidx]['tpls']))
- {
- $this->_out('/XObject <<');
- if (isset($this->_res['tpl'][$tplidx]['images']) && count($this->_res['tpl'][$tplidx]['images'])) {
- foreach($this->_res['tpl'][$tplidx]['images'] as $image)
- $this->_out('/I' . $image['i'] . ' ' . $image['n'] . ' 0 R');
- }
- if (isset($this->_res['tpl'][$tplidx]['tpls']) && count($this->_res['tpl'][$tplidx]['tpls'])) {
- foreach($this->_res['tpl'][$tplidx]['tpls'] as $i => $tpl)
- $this->_out($this->tplprefix . $i . ' ' . $tpl['n'] . ' 0 R');
- }
- $this->_out('>>');
- }
- $this->_out('>>');
-
- $this->_out('/Length ' . strlen($p) . ' >>');
- $this->_putstream($p);
- $this->_out('endobj');
- }
- }
-
- /**
- * Overwritten to add _putformxobjects() after _putimages()
- *
- */
- function _putimages() {
- parent::_putimages();
- $this->_putformxobjects();
- }
-
- function _putxobjectdict() {
- parent::_putxobjectdict();
-
- if (count($this->tpls)) {
- foreach($this->tpls as $tplidx => $tpl) {
- $this->_out(sprintf('%s%d %d 0 R', $this->tplprefix, $tplidx, $tpl['n']));
- }
- }
- }
-
- /**
- * Private Method
- */
- function _out($s) {
- if ($this->state == 2 && $this->_intpl) {
- $this->tpls[$this->tpl]['buffer'] .= $s . "\n";
- } else {
- parent::_out($s);
- }
- }
-}
+Error('This method is only usable with FPDF. Use TCPDF methods startTemplate() instead.');
+ return;
+ }
+
+ if ($this->page <= 0)
+ $this->error("You have to add a page to fpdf first!");
+
+ if ($x == null)
+ $x = 0;
+ if ($y == null)
+ $y = 0;
+ if ($w == null)
+ $w = $this->w;
+ if ($h == null)
+ $h = $this->h;
+
+ // Save settings
+ $this->tpl++;
+ $tpl =& $this->tpls[$this->tpl];
+ $tpl = array(
+ 'o_x' => $this->x,
+ 'o_y' => $this->y,
+ 'o_AutoPageBreak' => $this->AutoPageBreak,
+ 'o_bMargin' => $this->bMargin,
+ 'o_tMargin' => $this->tMargin,
+ 'o_lMargin' => $this->lMargin,
+ 'o_rMargin' => $this->rMargin,
+ 'o_h' => $this->h,
+ 'o_w' => $this->w,
+ 'buffer' => '',
+ 'x' => $x,
+ 'y' => $y,
+ 'w' => $w,
+ 'h' => $h
+ );
+
+ $this->SetAutoPageBreak(false);
+
+ // Define own high and width to calculate possitions correct
+ $this->h = $h;
+ $this->w = $w;
+
+ $this->_intpl = true;
+ $this->SetXY($x + $this->lMargin, $y + $this->tMargin);
+ $this->SetRightMargin($this->w - $w + $this->rMargin);
+
+ return $this->tpl;
+ }
+
+ /**
+ * End Template
+ *
+ * This method ends a template and reset initiated variables on beginTemplate.
+ *
+ * @return mixed If a template is opened, the ID is returned. If not a false is returned.
+ */
+ function endTemplate() {
+ if (is_subclass_of($this, 'TCPDF')) {
+ $args = func_get_args();
+ return call_user_func_array(array($this, 'TCPDF::endTemplate'), $args);
+ }
+
+ if ($this->_intpl) {
+ $this->_intpl = false;
+ $tpl =& $this->tpls[$this->tpl];
+ $this->SetXY($tpl['o_x'], $tpl['o_y']);
+ $this->tMargin = $tpl['o_tMargin'];
+ $this->lMargin = $tpl['o_lMargin'];
+ $this->rMargin = $tpl['o_rMargin'];
+ $this->h = $tpl['o_h'];
+ $this->w = $tpl['o_w'];
+ $this->SetAutoPageBreak($tpl['o_AutoPageBreak'], $tpl['o_bMargin']);
+
+ return $this->tpl;
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * Use a Template in current Page or other Template
+ *
+ * You can use a template in a page or in another template.
+ * You can give the used template a new size like you use the Image()-method.
+ * All parameters are optional. The width or height is calculated automaticaly
+ * if one is given. If no parameter is given the origin size as defined in
+ * beginTemplate() is used.
+ * The calculated or used width and height are returned as an array.
+ *
+ * @param int $tplidx A valid template-Id
+ * @param int $_x The x-position
+ * @param int $_y The y-position
+ * @param int $_w The new width of the template
+ * @param int $_h The new height of the template
+ * @retrun array The height and width of the template
+ */
+ function useTemplate($tplidx, $_x = null, $_y = null, $_w = 0, $_h = 0) {
+ if ($this->page <= 0)
+ $this->error('You have to add a page first!');
+
+ if (!isset($this->tpls[$tplidx]))
+ $this->error('Template does not exist!');
+
+ if ($this->_intpl) {
+ $this->_res['tpl'][$this->tpl]['tpls'][$tplidx] =& $this->tpls[$tplidx];
+ }
+
+ $tpl =& $this->tpls[$tplidx];
+ $w = $tpl['w'];
+ $h = $tpl['h'];
+
+ if ($_x == null)
+ $_x = 0;
+ if ($_y == null)
+ $_y = 0;
+
+ $_x += $tpl['x'];
+ $_y += $tpl['y'];
+
+ $wh = $this->getTemplateSize($tplidx, $_w, $_h);
+ $_w = $wh['w'];
+ $_h = $wh['h'];
+
+ $tData = array(
+ 'x' => $this->x,
+ 'y' => $this->y,
+ 'w' => $_w,
+ 'h' => $_h,
+ 'scaleX' => ($_w / $w),
+ 'scaleY' => ($_h / $h),
+ 'tx' => $_x,
+ 'ty' => ($this->h - $_y - $_h),
+ 'lty' => ($this->h - $_y - $_h) - ($this->h - $h) * ($_h / $h)
+ );
+
+ $this->_out(sprintf('q %.4F 0 0 %.4F %.4F %.4F cm', $tData['scaleX'], $tData['scaleY'], $tData['tx'] * $this->k, $tData['ty'] * $this->k)); // Translate
+ $this->_out(sprintf('%s%d Do Q', $this->tplprefix, $tplidx));
+
+ // reset font in the outer graphic state
+ if ($this->FontFamily) {
+ $family = $this->FontFamily;
+ $this->FontFamily = '';
+ $this->SetFont($family);
+ }
+
+ $this->lastUsedTemplateData = $tData;
+
+ return array('w' => $_w, 'h' => $_h);
+ }
+
+ /**
+ * Get The calculated Size of a Template
+ *
+ * If one size is given, this method calculates the other one.
+ *
+ * @param int $tplidx A valid template-Id
+ * @param int $_w The width of the template
+ * @param int $_h The height of the template
+ * @return array The height and width of the template
+ */
+ function getTemplateSize($tplidx, $_w = 0, $_h = 0) {
+ if (!$this->tpls[$tplidx])
+ return false;
+
+ $tpl =& $this->tpls[$tplidx];
+ $w = $tpl['w'];
+ $h = $tpl['h'];
+
+ if ($_w == 0 and $_h == 0) {
+ $_w = $w;
+ $_h = $h;
+ }
+
+ if($_w == 0)
+ $_w = $_h * $w / $h;
+ if($_h == 0)
+ $_h = $_w * $h / $w;
+
+ return array("w" => $_w, "h" => $_h);
+ }
+
+ /**
+ * See FPDF/TCPDF-Documentation ;-)
+ */
+ public function SetFont($family, $style = '', $size = 0) {
+ if (is_subclass_of($this, 'TCPDF')) {
+ $args = func_get_args();
+ return call_user_func_array(array($this, 'TCPDF::SetFont'), $args);
+ }
+
+ /**
+ * force the resetting of font changes in a template
+ */
+ if ($this->_intpl)
+ $this->FontFamily = '';
+
+ parent::SetFont($family, $style, $size);
+
+ $fontkey = $this->FontFamily . $this->FontStyle;
+
+ if ($this->_intpl) {
+ $this->_res['tpl'][$this->tpl]['fonts'][$fontkey] =& $this->fonts[$fontkey];
+ } else {
+ $this->_res['page'][$this->page]['fonts'][$fontkey] =& $this->fonts[$fontkey];
+ }
+ }
+
+ /**
+ * See FPDF/TCPDF-Documentation ;-)
+ */
+ function Image($file, $x = null, $y = null, $w = 0, $h = 0, $type = '', $link = '') {
+ if (is_subclass_of($this, 'TCPDF')) {
+ $args = func_get_args();
+ return call_user_func_array(array($this, 'TCPDF::Image'), $args);
+ }
+
+ $ret = parent::Image($file, $x, $y, $w, $h, $type, $link);
+ if ($this->_intpl) {
+ $this->_res['tpl'][$this->tpl]['images'][$file] =& $this->images[$file];
+ } else {
+ $this->_res['page'][$this->page]['images'][$file] =& $this->images[$file];
+ }
+
+ return $ret;
+ }
+
+ /**
+ * See FPDF-Documentation ;-)
+ *
+ * AddPage is not available when you're "in" a template.
+ */
+ function AddPage($orientation = '', $format = '') {
+ if (is_subclass_of($this, 'TCPDF')) {
+ $args = func_get_args();
+ return call_user_func_array(array($this, 'TCPDF::AddPage'), $args);
+ }
+
+ if ($this->_intpl)
+ $this->Error('Adding pages in templates isn\'t possible!');
+
+ parent::AddPage($orientation, $format);
+ }
+
+ /**
+ * Preserve adding Links in Templates ...won't work
+ */
+ function Link($x, $y, $w, $h, $link) {
+ if (is_subclass_of($this, 'TCPDF')) {
+ $args = func_get_args();
+ return call_user_func_array(array($this, 'TCPDF::Link'), $args);
+ }
+
+ if ($this->_intpl)
+ $this->Error('Using links in templates aren\'t possible!');
+
+ parent::Link($x, $y, $w, $h, $link);
+ }
+
+ function AddLink() {
+ if (is_subclass_of($this, 'TCPDF')) {
+ $args = func_get_args();
+ return call_user_func_array(array($this, 'TCPDF::AddLink'), $args);
+ }
+
+ if ($this->_intpl)
+ $this->Error('Adding links in templates aren\'t possible!');
+ return parent::AddLink();
+ }
+
+ function SetLink($link, $y = 0, $page = -1) {
+ if (is_subclass_of($this, 'TCPDF')) {
+ $args = func_get_args();
+ return call_user_func_array(array($this, 'TCPDF::SetLink'), $args);
+ }
+
+ if ($this->_intpl)
+ $this->Error('Setting links in templates aren\'t possible!');
+ parent::SetLink($link, $y, $page);
+ }
+
+ /**
+ * Private Method that writes the form xobjects
+ */
+ function _putformxobjects() {
+ $filter=($this->compress) ? '/Filter /FlateDecode ' : '';
+ reset($this->tpls);
+ foreach($this->tpls AS $tplidx => $tpl) {
+
+ $p=($this->compress) ? gzcompress($tpl['buffer']) : $tpl['buffer'];
+ $this->_newobj();
+ $this->tpls[$tplidx]['n'] = $this->n;
+ $this->_out('<<'.$filter.'/Type /XObject');
+ $this->_out('/Subtype /Form');
+ $this->_out('/FormType 1');
+ $this->_out(sprintf('/BBox [%.2F %.2F %.2F %.2F]',
+ // llx
+ $tpl['x'] * $this->k,
+ // lly
+ -$tpl['y'] * $this->k,
+ // urx
+ ($tpl['w'] + $tpl['x']) * $this->k,
+ // ury
+ ($tpl['h'] - $tpl['y']) * $this->k
+ ));
+
+ if ($tpl['x'] != 0 || $tpl['y'] != 0) {
+ $this->_out(sprintf('/Matrix [1 0 0 1 %.5F %.5F]',
+ -$tpl['x'] * $this->k * 2, $tpl['y'] * $this->k * 2
+ ));
+ }
+
+ $this->_out('/Resources ');
+
+ $this->_out('<_res['tpl'][$tplidx]['fonts']) && count($this->_res['tpl'][$tplidx]['fonts'])) {
+ $this->_out('/Font <<');
+ foreach($this->_res['tpl'][$tplidx]['fonts'] as $font)
+ $this->_out('/F' . $font['i'] . ' ' . $font['n'] . ' 0 R');
+ $this->_out('>>');
+ }
+ if(isset($this->_res['tpl'][$tplidx]['images']) && count($this->_res['tpl'][$tplidx]['images']) ||
+ isset($this->_res['tpl'][$tplidx]['tpls']) && count($this->_res['tpl'][$tplidx]['tpls']))
+ {
+ $this->_out('/XObject <<');
+ if (isset($this->_res['tpl'][$tplidx]['images']) && count($this->_res['tpl'][$tplidx]['images'])) {
+ foreach($this->_res['tpl'][$tplidx]['images'] as $image)
+ $this->_out('/I' . $image['i'] . ' ' . $image['n'] . ' 0 R');
+ }
+ if (isset($this->_res['tpl'][$tplidx]['tpls']) && count($this->_res['tpl'][$tplidx]['tpls'])) {
+ foreach($this->_res['tpl'][$tplidx]['tpls'] as $i => $tpl)
+ $this->_out($this->tplprefix . $i . ' ' . $tpl['n'] . ' 0 R');
+ }
+ $this->_out('>>');
+ }
+ $this->_out('>>');
+
+ $this->_out('/Length ' . strlen($p) . ' >>');
+ $this->_putstream($p);
+ $this->_out('endobj');
+ }
+ }
+
+ /**
+ * Overwritten to add _putformxobjects() after _putimages()
+ *
+ */
+ function _putimages() {
+ parent::_putimages();
+ $this->_putformxobjects();
+ }
+
+ function _putxobjectdict() {
+ parent::_putxobjectdict();
+
+ if (count($this->tpls)) {
+ foreach($this->tpls as $tplidx => $tpl) {
+ $this->_out(sprintf('%s%d %d 0 R', $this->tplprefix, $tplidx, $tpl['n']));
+ }
+ }
+ }
+
+ /**
+ * Private Method
+ */
+ function _out($s) {
+ if ($this->state == 2 && $this->_intpl) {
+ $this->tpls[$this->tpl]['buffer'] .= $s . "\n";
+ } else {
+ parent::_out($s);
+ }
+ }
+}
diff --git a/htdocs/includes/fpdfi/fpdi.php b/htdocs/includes/fpdfi/fpdi.php
index faa1abe0f0d..0ae2c63741c 100755
--- a/htdocs/includes/fpdfi/fpdi.php
+++ b/htdocs/includes/fpdfi/fpdi.php
@@ -1,542 +1,571 @@
-current_filename = $filename;
-
- if (!isset($this->parsers[$filename]))
- $this->parsers[$filename] = $this->_getPdfParser($filename);
- $this->current_parser =& $this->parsers[$filename];
-
- return $this->parsers[$filename]->getPageCount();
- }
-
- /**
- * Returns a PDF parser object
- *
- * @param string $filename
- * @return fpdi_pdf_parser
- */
- function _getPdfParser($filename) {
- return new fpdi_pdf_parser($filename, $this);
- }
-
- /**
- * Get the current PDF version
- *
- * @return string
- */
- function getPDFVersion() {
- return $this->PDFVersion;
- }
-
- /**
- * Set the PDF version
- *
- * @return string
- */
- function setPDFVersion($version = '1.3') {
- $this->PDFVersion = $version;
- }
-
- /**
- * Import a page
- *
- * @param int $pageno pagenumber
- * @return int Index of imported page - to use with fpdf_tpl::useTemplate()
- */
- function importPage($pageno, $boxName = '/CropBox') {
- if ($this->_intpl) {
- return $this->error('Please import the desired pages before creating a new template.');
- }
-
- $fn = $this->current_filename;
-
- // check if page already imported
- $pageKey = $fn . '-' . ((int)$pageno) . $boxName;
- if (isset($this->_importedPages[$pageKey]))
- return $this->_importedPages[$pageKey];
-
- $parser =& $this->parsers[$fn];
- $parser->setPageno($pageno);
-
- if (!in_array($boxName, $parser->availableBoxes))
- return $this->Error(sprintf('Unknown box: %s', $boxName));
- $pageboxes = $parser->getPageBoxes($pageno, $this->k);
-
- /**
- * MediaBox
- * CropBox: Default -> MediaBox
- * BleedBox: Default -> CropBox
- * TrimBox: Default -> CropBox
- * ArtBox: Default -> CropBox
- */
- if (!isset($pageboxes[$boxName]) && ($boxName == '/BleedBox' || $boxName == '/TrimBox' || $boxName == '/ArtBox'))
- $boxName = '/CropBox';
- if (!isset($pageboxes[$boxName]) && $boxName == '/CropBox')
- $boxName = '/MediaBox';
-
- if (!isset($pageboxes[$boxName]))
- return false;
- $this->lastUsedPageBox = $boxName;
-
- $box = $pageboxes[$boxName];
-
- $this->tpl++;
- $this->tpls[$this->tpl] = array();
- $tpl =& $this->tpls[$this->tpl];
- $tpl['parser'] =& $parser;
- $tpl['resources'] = $parser->getPageResources();
- $tpl['buffer'] = $parser->getContent();
- $tpl['box'] = $box;
-
- // To build an array that can be used by PDF_TPL::useTemplate()
- $this->tpls[$this->tpl] = array_merge($this->tpls[$this->tpl], $box);
-
- // An imported page will start at 0,0 everytime. Translation will be set in _putformxobjects()
- $tpl['x'] = 0;
- $tpl['y'] = 0;
-
- // handle rotated pages
- $rotation = $parser->getPageRotation($pageno);
- $tpl['_rotationAngle'] = 0;
- if (isset($rotation[1]) && ($angle = $rotation[1] % 360) != 0) {
- $steps = $angle / 90;
-
- $_w = $tpl['w'];
- $_h = $tpl['h'];
- $tpl['w'] = $steps % 2 == 0 ? $_w : $_h;
- $tpl['h'] = $steps % 2 == 0 ? $_h : $_w;
-
- if ($angle < 0)
- $angle += 360;
-
- $tpl['_rotationAngle'] = $angle * -1;
- }
-
- $this->_importedPages[$pageKey] = $this->tpl;
-
- return $this->tpl;
- }
-
- function getLastUsedPageBox() {
- return $this->lastUsedPageBox;
- }
-
- function useTemplate($tplidx, $_x = null, $_y = null, $_w = 0, $_h = 0, $adjustPageSize = false) {
- if ($adjustPageSize == true && is_null($_x) && is_null($_y)) {
- $size = $this->getTemplateSize($tplidx, $_w, $_h);
- $format = array($size['w'], $size['h']);
- if (is_subclass_of($this, 'TCPDF')) {
- $this->setPageFormat($format, $format[0] > $format[1] ? 'L' : 'P');
- } else {
- if ($format[0] != $this->CurPageFormat[0] || $format[1] != $this->CurPageFormat[1]) {
- $this->w = $format[0];
- $this->h = $format[1];
- $this->wPt = $this->w * $this->k;
- $this->hPt = $this->h * $this->k;
- $this->PageBreakTrigger = $this->h - $this->bMargin;
- $this->CurPageFormat = $format;
- $this->PageSizes[$this->page] = array($this->wPt, $this->hPt);
- }
- }
- }
-
- $this->_out('q 0 J 1 w 0 j 0 G 0 g'); // reset standard values
- $s = parent::useTemplate($tplidx, $_x, $_y, $_w, $_h);
- $this->_out('Q');
-
- return $s;
- }
-
- /**
- * Private method, that rebuilds all needed objects of source files
- */
- function _putimportedobjects() {
- if (is_array($this->parsers) && count($this->parsers) > 0) {
- foreach($this->parsers AS $filename => $p) {
- $this->current_parser =& $this->parsers[$filename];
- if (isset($this->_obj_stack[$filename]) && is_array($this->_obj_stack[$filename])) {
- while(($n = key($this->_obj_stack[$filename])) !== null) {
- $nObj = $this->current_parser->pdf_resolve_object($this->current_parser->c, $this->_obj_stack[$filename][$n][1]);
-
- $this->_newobj($this->_obj_stack[$filename][$n][0]);
-
- if ($nObj[0] == PDF_TYPE_STREAM) {
- $this->pdf_write_value($nObj);
- } else {
- $this->pdf_write_value($nObj[1]);
- }
-
- $this->_out('endobj');
- $this->_obj_stack[$filename][$n] = null; // free memory
- unset($this->_obj_stack[$filename][$n]);
- reset($this->_obj_stack[$filename]);
- }
- }
- }
- }
- }
-
-
- /**
- * Private Method that writes the form xobjects
- */
- function _putformxobjects() {
- $filter=($this->compress) ? '/Filter /FlateDecode ' : '';
- reset($this->tpls);
- foreach($this->tpls AS $tplidx => $tpl) {
- $p=($this->compress) ? gzcompress($tpl['buffer']) : $tpl['buffer'];
- $this->_newobj();
- $cN = $this->n; // TCPDF/Protection: rem current "n"
-
- $this->tpls[$tplidx]['n'] = $this->n;
- $this->_out('<<' . $filter . '/Type /XObject');
- $this->_out('/Subtype /Form');
- $this->_out('/FormType 1');
-
- $this->_out(sprintf('/BBox [%.2F %.2F %.2F %.2F]',
- (isset($tpl['box']['llx']) ? $tpl['box']['llx'] : $tpl['x']) * $this->k,
- (isset($tpl['box']['lly']) ? $tpl['box']['lly'] : -$tpl['y']) * $this->k,
- (isset($tpl['box']['urx']) ? $tpl['box']['urx'] : $tpl['w'] + $tpl['x']) * $this->k,
- (isset($tpl['box']['ury']) ? $tpl['box']['ury'] : $tpl['h'] - $tpl['y']) * $this->k
- ));
-
- $c = 1;
- $s = 0;
- $tx = 0;
- $ty = 0;
-
- if (isset($tpl['box'])) {
- $tx = -$tpl['box']['llx'];
- $ty = -$tpl['box']['lly'];
-
- if ($tpl['_rotationAngle'] <> 0) {
- $angle = $tpl['_rotationAngle'] * M_PI/180;
- $c=cos($angle);
- $s=sin($angle);
-
- switch($tpl['_rotationAngle']) {
- case -90:
- $tx = -$tpl['box']['lly'];
- $ty = $tpl['box']['urx'];
- break;
- case -180:
- $tx = $tpl['box']['urx'];
- $ty = $tpl['box']['ury'];
- break;
- case -270:
- $tx = $tpl['box']['ury'];
- $ty = -$tpl['box']['llx'];
- break;
- }
- }
- } else if ($tpl['x'] != 0 || $tpl['y'] != 0) {
- $tx = -$tpl['x']*2;
- $ty = $tpl['y']*2;
- }
-
- $tx *= $this->k;
- $ty *= $this->k;
-
- if ($c != 1 || $s != 0 || $tx != 0 || $ty != 0) {
- $this->_out(sprintf('/Matrix [%.5F %.5F %.5F %.5F %.5F %.5F]',
- $c, $s, -$s, $c, $tx, $ty
- ));
- }
-
- $this->_out('/Resources ');
-
- if (isset($tpl['resources'])) {
- $this->current_parser =& $tpl['parser'];
- $this->pdf_write_value($tpl['resources']); // "n" will be changed
- } else {
- $this->_out('<_res['tpl'][$tplidx]['fonts']) && count($this->_res['tpl'][$tplidx]['fonts'])) {
- $this->_out('/Font <<');
- foreach($this->_res['tpl'][$tplidx]['fonts'] as $font)
- $this->_out('/F' . $font['i'] . ' ' . $font['n'] . ' 0 R');
- $this->_out('>>');
- }
- if(isset($this->_res['tpl'][$tplidx]['images']) && count($this->_res['tpl'][$tplidx]['images']) ||
- isset($this->_res['tpl'][$tplidx]['tpls']) && count($this->_res['tpl'][$tplidx]['tpls']))
- {
- $this->_out('/XObject <<');
- if (isset($this->_res['tpl'][$tplidx]['images']) && count($this->_res['tpl'][$tplidx]['images'])) {
- foreach($this->_res['tpl'][$tplidx]['images'] as $image)
- $this->_out('/I' . $image['i'] . ' ' . $image['n'] . ' 0 R');
- }
- if (isset($this->_res['tpl'][$tplidx]['tpls']) && count($this->_res['tpl'][$tplidx]['tpls'])) {
- foreach($this->_res['tpl'][$tplidx]['tpls'] as $i => $tpl)
- $this->_out($this->tplprefix . $i . ' ' . $tpl['n'] . ' 0 R');
- }
- $this->_out('>>');
- }
- $this->_out('>>');
- }
-
- $nN = $this->n; // TCPDF: rem new "n"
- $this->n = $cN; // TCPDF: reset to current "n"
- $this->_out('/Length ' . strlen($p) . ' >>');
- $this->_putstream($p);
- $this->_out('endobj');
- $this->n = $nN; // TCPDF: reset to new "n"
- }
-
- $this->_putimportedobjects();
- }
-
- /**
- * Rewritten to handle existing own defined objects
- */
- function _newobj($obj_id = false, $onlynewobj = false) {
- if (!$obj_id) {
- $obj_id = ++$this->n;
- }
-
- //Begin a new object
- if (!$onlynewobj) {
- $this->offsets[$obj_id] = is_subclass_of($this, 'TCPDF') ? $this->bufferlen : strlen($this->buffer);
- $this->_out($obj_id . ' 0 obj');
- $this->_current_obj_id = $obj_id; // for later use with encryption
- }
-
- return $obj_id;
- }
-
- /**
- * Writes a value
- * Needed to rebuild the source document
- *
- * @param mixed $value A PDF-Value. Structure of values see cases in this method
- */
- function pdf_write_value(&$value)
- {
- if (is_subclass_of($this, 'TCPDF')) {
- parent::pdf_write_value($value);
- }
-
- switch ($value[0]) {
-
- case PDF_TYPE_TOKEN:
- $this->_straightOut($value[1] . ' ');
- break;
- case PDF_TYPE_NUMERIC:
- case PDF_TYPE_REAL:
- if (is_float($value[1]) && $value[1] != 0) {
- $this->_straightOut(rtrim(rtrim(sprintf('%F', $value[1]), '0'), '.') . ' ');
- } else {
- $this->_straightOut($value[1] . ' ');
- }
- break;
-
- case PDF_TYPE_ARRAY:
-
- // An array. Output the proper
- // structure and move on.
-
- $this->_straightOut('[');
- for ($i = 0; $i < count($value[1]); $i++) {
- $this->pdf_write_value($value[1][$i]);
- }
-
- $this->_out(']');
- break;
-
- case PDF_TYPE_DICTIONARY:
-
- // A dictionary.
- $this->_straightOut('<<');
-
- reset ($value[1]);
-
- while (list($k, $v) = each($value[1])) {
- $this->_straightOut($k . ' ');
- $this->pdf_write_value($v);
- }
-
- $this->_straightOut('>>');
- break;
-
- case PDF_TYPE_OBJREF:
-
- // An indirect object reference
- // Fill the object stack if needed
- $cpfn =& $this->current_parser->filename;
-
- if (!isset($this->_don_obj_stack[$cpfn][$value[1]])) {
- $this->_newobj(false, true);
- $this->_obj_stack[$cpfn][$value[1]] = array($this->n, $value);
- $this->_don_obj_stack[$cpfn][$value[1]] = array($this->n, $value); // Value is maybee obsolete!!!
- }
- $objid = $this->_don_obj_stack[$cpfn][$value[1]][0];
-
- $this->_out($objid . ' 0 R');
- break;
-
- case PDF_TYPE_STRING:
-
- // A string.
- $this->_straightOut('(' . $value[1] . ')');
-
- break;
-
- case PDF_TYPE_STREAM:
-
- // A stream. First, output the
- // stream dictionary, then the
- // stream data itself.
- $this->pdf_write_value($value[1]);
- $this->_out('stream');
- $this->_out($value[2][1]);
- $this->_out('endstream');
- break;
-
- case PDF_TYPE_HEX:
- $this->_straightOut('<' . $value[1] . '>');
- break;
-
- case PDF_TYPE_BOOLEAN:
- $this->_straightOut($value[1] ? 'true ' : 'false ');
- break;
-
- case PDF_TYPE_NULL:
- // The null object.
-
- $this->_straightOut('null ');
- break;
- }
- }
-
-
- /**
- * Modified so not each call will add a newline to the output.
- */
- function _straightOut($s) {
- if (!is_subclass_of($this, 'TCPDF')) {
- if($this->state==2)
- $this->pages[$this->page] .= $s;
- else
- $this->buffer .= $s;
- } else {
- if ($this->state == 2) {
- if (isset($this->footerlen[$this->page]) AND ($this->footerlen[$this->page] > 0)) {
- // puts data before page footer
- $page = substr($this->getPageBuffer($this->page), 0, -$this->footerlen[$this->page]);
- $footer = substr($this->getPageBuffer($this->page), -$this->footerlen[$this->page]);
- $this->setPageBuffer($this->page, $page . ' ' . $s . "\n" . $footer);
- } else {
- $this->setPageBuffer($this->page, $s, true);
- }
- } else {
- $this->setBuffer($s);
- }
- }
- }
-
- /**
- * rewritten to close opened parsers
- *
- */
- function _enddoc() {
- parent::_enddoc();
- $this->_closeParsers();
- }
-
- /**
- * close all files opened by parsers
- */
- function _closeParsers() {
- if ($this->state > 2 && count($this->parsers) > 0) {
- foreach ($this->parsers as $k => $_){
- $this->parsers[$k]->closeFile();
- $this->parsers[$k] = null;
- unset($this->parsers[$k]);
- }
- return true;
- }
- return false;
- }
+current_filename = $filename;
+
+ if (!isset($this->parsers[$filename]))
+ $this->parsers[$filename] = $this->_getPdfParser($filename);
+ $this->current_parser =& $this->parsers[$filename];
+
+ return $this->parsers[$filename]->getPageCount();
+ }
+
+ /**
+ * Returns a PDF parser object
+ *
+ * @param string $filename
+ * @return fpdi_pdf_parser
+ */
+ function _getPdfParser($filename) {
+ return new fpdi_pdf_parser($filename, $this);
+ }
+
+ /**
+ * Get the current PDF version
+ *
+ * @return string
+ */
+ function getPDFVersion() {
+ return $this->PDFVersion;
+ }
+
+ /**
+ * Set the PDF version
+ *
+ * @return string
+ */
+ function setPDFVersion($version = '1.3') {
+ $this->PDFVersion = $version;
+ }
+
+ /**
+ * Import a page
+ *
+ * @param int $pageno pagenumber
+ * @return int Index of imported page - to use with fpdf_tpl::useTemplate()
+ */
+ function importPage($pageno, $boxName = '/CropBox') {
+ if ($this->_intpl) {
+ return $this->error('Please import the desired pages before creating a new template.');
+ }
+
+ $fn = $this->current_filename;
+
+ // check if page already imported
+ $pageKey = $fn . '-' . ((int)$pageno) . $boxName;
+ if (isset($this->_importedPages[$pageKey]))
+ return $this->_importedPages[$pageKey];
+
+ $parser =& $this->parsers[$fn];
+ $parser->setPageno($pageno);
+
+ if (!in_array($boxName, $parser->availableBoxes))
+ return $this->Error(sprintf('Unknown box: %s', $boxName));
+
+ $pageboxes = $parser->getPageBoxes($pageno, $this->k);
+
+ /**
+ * MediaBox
+ * CropBox: Default -> MediaBox
+ * BleedBox: Default -> CropBox
+ * TrimBox: Default -> CropBox
+ * ArtBox: Default -> CropBox
+ */
+ if (!isset($pageboxes[$boxName]) && ($boxName == '/BleedBox' || $boxName == '/TrimBox' || $boxName == '/ArtBox'))
+ $boxName = '/CropBox';
+ if (!isset($pageboxes[$boxName]) && $boxName == '/CropBox')
+ $boxName = '/MediaBox';
+
+ if (!isset($pageboxes[$boxName]))
+ return false;
+
+ $this->lastUsedPageBox = $boxName;
+
+ $box = $pageboxes[$boxName];
+
+ $this->tpl++;
+ $this->tpls[$this->tpl] = array();
+ $tpl =& $this->tpls[$this->tpl];
+ $tpl['parser'] =& $parser;
+ $tpl['resources'] = $parser->getPageResources();
+ $tpl['buffer'] = $parser->getContent();
+ $tpl['box'] = $box;
+
+ // To build an array that can be used by PDF_TPL::useTemplate()
+ $this->tpls[$this->tpl] = array_merge($this->tpls[$this->tpl], $box);
+
+ // An imported page will start at 0,0 everytime. Translation will be set in _putformxobjects()
+ $tpl['x'] = 0;
+ $tpl['y'] = 0;
+
+ // handle rotated pages
+ $rotation = $parser->getPageRotation($pageno);
+ $tpl['_rotationAngle'] = 0;
+ if (isset($rotation[1]) && ($angle = $rotation[1] % 360) != 0) {
+ $steps = $angle / 90;
+
+ $_w = $tpl['w'];
+ $_h = $tpl['h'];
+ $tpl['w'] = $steps % 2 == 0 ? $_w : $_h;
+ $tpl['h'] = $steps % 2 == 0 ? $_h : $_w;
+
+ if ($angle < 0)
+ $angle += 360;
+
+ $tpl['_rotationAngle'] = $angle * -1;
+ }
+
+ $this->_importedPages[$pageKey] = $this->tpl;
+
+ return $this->tpl;
+ }
+
+ /**
+ * Returns the last used page box
+ *
+ * @return string
+ */
+ function getLastUsedPageBox() {
+ return $this->lastUsedPageBox;
+ }
+
+
+ function useTemplate($tplidx, $_x = null, $_y = null, $_w = 0, $_h = 0, $adjustPageSize = false) {
+ if ($adjustPageSize == true && is_null($_x) && is_null($_y)) {
+ $size = $this->getTemplateSize($tplidx, $_w, $_h);
+ $orientation = $size['w'] > $size['h'] ? 'L' : 'P';
+ $size = array($size['w'], $size['h']);
+
+ if (is_subclass_of($this, 'TCPDF')) {
+ $this->setPageFormat($size, $orientation);
+ } else {
+ $size = $this->_getpagesize($size);
+
+ if($orientation!=$this->CurOrientation || $size[0]!=$this->CurPageSize[0] || $size[1]!=$this->CurPageSize[1])
+ {
+ // New size or orientation
+ if($orientation=='P')
+ {
+ $this->w = $size[0];
+ $this->h = $size[1];
+ }
+ else
+ {
+ $this->w = $size[1];
+ $this->h = $size[0];
+ }
+ $this->wPt = $this->w*$this->k;
+ $this->hPt = $this->h*$this->k;
+ $this->PageBreakTrigger = $this->h-$this->bMargin;
+ $this->CurOrientation = $orientation;
+ $this->CurPageSize = $size;
+ $this->PageSizes[$this->page] = array($this->wPt, $this->hPt);
+ }
+ }
+ }
+
+ $this->_out('q 0 J 1 w 0 j 0 G 0 g'); // reset standard values
+ $s = parent::useTemplate($tplidx, $_x, $_y, $_w, $_h);
+ $this->_out('Q');
+
+ return $s;
+ }
+
+ /**
+ * Private method, that rebuilds all needed objects of source files
+ */
+ function _putimportedobjects() {
+ if (is_array($this->parsers) && count($this->parsers) > 0) {
+ foreach($this->parsers AS $filename => $p) {
+ $this->current_parser =& $this->parsers[$filename];
+ if (isset($this->_obj_stack[$filename]) && is_array($this->_obj_stack[$filename])) {
+ while(($n = key($this->_obj_stack[$filename])) !== null) {
+ $nObj = $this->current_parser->pdf_resolve_object($this->current_parser->c, $this->_obj_stack[$filename][$n][1]);
+
+ $this->_newobj($this->_obj_stack[$filename][$n][0]);
+
+ if ($nObj[0] == PDF_TYPE_STREAM) {
+ $this->pdf_write_value($nObj);
+ } else {
+ $this->pdf_write_value($nObj[1]);
+ }
+
+ $this->_out('endobj');
+ $this->_obj_stack[$filename][$n] = null; // free memory
+ unset($this->_obj_stack[$filename][$n]);
+ reset($this->_obj_stack[$filename]);
+ }
+ }
+ }
+ }
+ }
+
+
+ /**
+ * Private Method that writes the form xobjects
+ */
+ function _putformxobjects() {
+ $filter=($this->compress) ? '/Filter /FlateDecode ' : '';
+ reset($this->tpls);
+ foreach($this->tpls AS $tplidx => $tpl) {
+ $p=($this->compress) ? gzcompress($tpl['buffer']) : $tpl['buffer'];
+ $this->_newobj();
+ $cN = $this->n; // TCPDF/Protection: rem current "n"
+
+ $this->tpls[$tplidx]['n'] = $this->n;
+ $this->_out('<<' . $filter . '/Type /XObject');
+ $this->_out('/Subtype /Form');
+ $this->_out('/FormType 1');
+
+ $this->_out(sprintf('/BBox [%.2F %.2F %.2F %.2F]',
+ (isset($tpl['box']['llx']) ? $tpl['box']['llx'] : $tpl['x']) * $this->k,
+ (isset($tpl['box']['lly']) ? $tpl['box']['lly'] : -$tpl['y']) * $this->k,
+ (isset($tpl['box']['urx']) ? $tpl['box']['urx'] : $tpl['w'] + $tpl['x']) * $this->k,
+ (isset($tpl['box']['ury']) ? $tpl['box']['ury'] : $tpl['h'] - $tpl['y']) * $this->k
+ ));
+
+ $c = 1;
+ $s = 0;
+ $tx = 0;
+ $ty = 0;
+
+ if (isset($tpl['box'])) {
+ $tx = -$tpl['box']['llx'];
+ $ty = -$tpl['box']['lly'];
+
+ if ($tpl['_rotationAngle'] <> 0) {
+ $angle = $tpl['_rotationAngle'] * M_PI/180;
+ $c=cos($angle);
+ $s=sin($angle);
+
+ switch($tpl['_rotationAngle']) {
+ case -90:
+ $tx = -$tpl['box']['lly'];
+ $ty = $tpl['box']['urx'];
+ break;
+ case -180:
+ $tx = $tpl['box']['urx'];
+ $ty = $tpl['box']['ury'];
+ break;
+ case -270:
+ $tx = $tpl['box']['ury'];
+ $ty = -$tpl['box']['llx'];
+ break;
+ }
+ }
+ } else if ($tpl['x'] != 0 || $tpl['y'] != 0) {
+ $tx = -$tpl['x'] * 2;
+ $ty = $tpl['y'] * 2;
+ }
+
+ $tx *= $this->k;
+ $ty *= $this->k;
+
+ if ($c != 1 || $s != 0 || $tx != 0 || $ty != 0) {
+ $this->_out(sprintf('/Matrix [%.5F %.5F %.5F %.5F %.5F %.5F]',
+ $c, $s, -$s, $c, $tx, $ty
+ ));
+ }
+
+ $this->_out('/Resources ');
+
+ if (isset($tpl['resources'])) {
+ $this->current_parser =& $tpl['parser'];
+ $this->pdf_write_value($tpl['resources']); // "n" will be changed
+ } else {
+ $this->_out('<_res['tpl'][$tplidx]['fonts']) && count($this->_res['tpl'][$tplidx]['fonts'])) {
+ $this->_out('/Font <<');
+ foreach($this->_res['tpl'][$tplidx]['fonts'] as $font)
+ $this->_out('/F' . $font['i'] . ' ' . $font['n'] . ' 0 R');
+ $this->_out('>>');
+ }
+ if(isset($this->_res['tpl'][$tplidx]['images']) && count($this->_res['tpl'][$tplidx]['images']) ||
+ isset($this->_res['tpl'][$tplidx]['tpls']) && count($this->_res['tpl'][$tplidx]['tpls']))
+ {
+ $this->_out('/XObject <<');
+ if (isset($this->_res['tpl'][$tplidx]['images']) && count($this->_res['tpl'][$tplidx]['images'])) {
+ foreach($this->_res['tpl'][$tplidx]['images'] as $image)
+ $this->_out('/I' . $image['i'] . ' ' . $image['n'] . ' 0 R');
+ }
+ if (isset($this->_res['tpl'][$tplidx]['tpls']) && count($this->_res['tpl'][$tplidx]['tpls'])) {
+ foreach($this->_res['tpl'][$tplidx]['tpls'] as $i => $tpl)
+ $this->_out($this->tplprefix . $i . ' ' . $tpl['n'] . ' 0 R');
+ }
+ $this->_out('>>');
+ }
+ $this->_out('>>');
+ }
+
+ $nN = $this->n; // TCPDF: rem new "n"
+ $this->n = $cN; // TCPDF: reset to current "n"
+ if (is_subclass_of($this, 'TCPDF')) {
+ $p = $this->_getrawstream($p);
+ $this->_out('/Length ' . strlen($p) . ' >>');
+ $this->_out("stream\n" . $p . "\nendstream");
+ } else {
+ $this->_out('/Length ' . strlen($p) . ' >>');
+ $this->_putstream($p);
+ }
+ $this->_out('endobj');
+ $this->n = $nN; // TCPDF: reset to new "n"
+ }
+
+ $this->_putimportedobjects();
+ }
+
+ /**
+ * Rewritten to handle existing own defined objects
+ */
+ function _newobj($obj_id = false, $onlynewobj = false) {
+ if (!$obj_id) {
+ $obj_id = ++$this->n;
+ }
+
+ //Begin a new object
+ if (!$onlynewobj) {
+ $this->offsets[$obj_id] = is_subclass_of($this, 'TCPDF') ? $this->bufferlen : strlen($this->buffer);
+ $this->_out($obj_id . ' 0 obj');
+ $this->_current_obj_id = $obj_id; // for later use with encryption
+ }
+
+ return $obj_id;
+ }
+
+ /**
+ * Writes a value
+ * Needed to rebuild the source document
+ *
+ * @param mixed $value A PDF-Value. Structure of values see cases in this method
+ */
+ function pdf_write_value(&$value)
+ {
+ if (is_subclass_of($this, 'TCPDF')) {
+ parent::pdf_write_value($value);
+ }
+
+ switch ($value[0]) {
+
+ case PDF_TYPE_TOKEN:
+ $this->_straightOut($value[1] . ' ');
+ break;
+ case PDF_TYPE_NUMERIC:
+ case PDF_TYPE_REAL:
+ if (is_float($value[1]) && $value[1] != 0) {
+ $this->_straightOut(rtrim(rtrim(sprintf('%F', $value[1]), '0'), '.') . ' ');
+ } else {
+ $this->_straightOut($value[1] . ' ');
+ }
+ break;
+
+ case PDF_TYPE_ARRAY:
+
+ // An array. Output the proper
+ // structure and move on.
+
+ $this->_straightOut('[');
+ for ($i = 0; $i < count($value[1]); $i++) {
+ $this->pdf_write_value($value[1][$i]);
+ }
+
+ $this->_out(']');
+ break;
+
+ case PDF_TYPE_DICTIONARY:
+
+ // A dictionary.
+ $this->_straightOut('<<');
+
+ reset ($value[1]);
+
+ while (list($k, $v) = each($value[1])) {
+ $this->_straightOut($k . ' ');
+ $this->pdf_write_value($v);
+ }
+
+ $this->_straightOut('>>');
+ break;
+
+ case PDF_TYPE_OBJREF:
+
+ // An indirect object reference
+ // Fill the object stack if needed
+ $cpfn =& $this->current_parser->filename;
+
+ if (!isset($this->_don_obj_stack[$cpfn][$value[1]])) {
+ $this->_newobj(false, true);
+ $this->_obj_stack[$cpfn][$value[1]] = array($this->n, $value);
+ $this->_don_obj_stack[$cpfn][$value[1]] = array($this->n, $value); // Value is maybee obsolete!!!
+ }
+ $objid = $this->_don_obj_stack[$cpfn][$value[1]][0];
+
+ $this->_out($objid . ' 0 R');
+ break;
+
+ case PDF_TYPE_STRING:
+
+ // A string.
+ $this->_straightOut('(' . $value[1] . ')');
+
+ break;
+
+ case PDF_TYPE_STREAM:
+
+ // A stream. First, output the
+ // stream dictionary, then the
+ // stream data itself.
+ $this->pdf_write_value($value[1]);
+ $this->_out('stream');
+ $this->_out($value[2][1]);
+ $this->_out('endstream');
+ break;
+
+ case PDF_TYPE_HEX:
+ $this->_straightOut('<' . $value[1] . '>');
+ break;
+
+ case PDF_TYPE_BOOLEAN:
+ $this->_straightOut($value[1] ? 'true ' : 'false ');
+ break;
+
+ case PDF_TYPE_NULL:
+ // The null object.
+
+ $this->_straightOut('null ');
+ break;
+ }
+ }
+
+
+ /**
+ * Modified so not each call will add a newline to the output.
+ */
+ function _straightOut($s) {
+ if (!is_subclass_of($this, 'TCPDF')) {
+ if($this->state==2)
+ $this->pages[$this->page] .= $s;
+ else
+ $this->buffer .= $s;
+ } else {
+ if ($this->state == 2) {
+ if (isset($this->footerlen[$this->page]) AND ($this->footerlen[$this->page] > 0)) {
+ // puts data before page footer
+ $page = substr($this->getPageBuffer($this->page), 0, -$this->footerlen[$this->page]);
+ $footer = substr($this->getPageBuffer($this->page), -$this->footerlen[$this->page]);
+ $this->setPageBuffer($this->page, $page . ' ' . $s . "\n" . $footer);
+ } else {
+ $this->setPageBuffer($this->page, $s, true);
+ }
+ } else {
+ $this->setBuffer($s);
+ }
+ }
+ }
+
+ /**
+ * rewritten to close opened parsers
+ *
+ */
+ function _enddoc() {
+ parent::_enddoc();
+ $this->_closeParsers();
+ }
+
+ /**
+ * close all files opened by parsers
+ */
+ function _closeParsers() {
+ if ($this->state > 2 && count($this->parsers) > 0) {
+ foreach ($this->parsers as $k => $_){
+ $this->parsers[$k]->closeFile();
+ $this->parsers[$k] = null;
+ unset($this->parsers[$k]);
+ }
+ return true;
+ }
+ return false;
+ }
}
\ No newline at end of file
diff --git a/htdocs/includes/fpdfi/fpdi2tcpdf_bridge.php b/htdocs/includes/fpdfi/fpdi2tcpdf_bridge.php
index 640700a8322..8a031a38c69 100755
--- a/htdocs/includes/fpdfi/fpdi2tcpdf_bridge.php
+++ b/htdocs/includes/fpdfi/fpdi2tcpdf_bridge.php
@@ -1,6 +1,6 @@
encrypted) {
$value[1] = $this->_unescape($value[1]);
- $value[1] = $this->_RC4($this->_objectkey($this->_current_obj_id), $value[1]);
+ $value[1] = $this->_encrypt_data($this->_current_obj_id, $value[1]);
$value[1] = $this->_escape($value[1]);
}
break;
case PDF_TYPE_STREAM:
if ($this->encrypted) {
- $value[2][1] = $this->_RC4($this->_objectkey($this->_current_obj_id), $value[2][1]);
+ $value[2][1] = $this->_encrypt_data($this->_current_obj_id, $value[2][1]);
+ $value[1][1]['/Length'] = array(
+ PDF_TYPE_NUMERIC,
+ strlen($value[2][1])
+ );
}
break;
case PDF_TYPE_HEX:
if ($this->encrypted) {
$value[1] = $this->hex2str($value[1]);
- $value[1] = $this->_RC4($this->_objectkey($this->_current_obj_id), $value[1]);
+ $value[1] = $this->_encrypt_data($this->_current_obj_id, $value[1]);
// remake hexstring of encrypted string
$value[1] = $this->str2hex($value[1]);
diff --git a/htdocs/includes/fpdfi/fpdi_pdf_parser.php b/htdocs/includes/fpdfi/fpdi_pdf_parser.php
index 1e87f891e87..fd2b4414c76 100755
--- a/htdocs/includes/fpdfi/fpdi_pdf_parser.php
+++ b/htdocs/includes/fpdfi/fpdi_pdf_parser.php
@@ -1,409 +1,408 @@
-fpdi =& $fpdi;
-
- parent::pdf_parser($filename);
-
- // resolve Pages-Dictonary
- $pages = $this->pdf_resolve_object($this->c, $this->root[1][1]['/Pages']);
-
- // Read pages
- $this->read_pages($this->c, $pages, $this->pages);
-
- // count pages;
- $this->page_count = count($this->pages);
- }
-
- /**
- * Overwrite parent::error()
- *
- * @param string $msg Error-Message
- */
- function error($msg) {
- $this->fpdi->error($msg);
- }
-
- /**
- * Get pagecount from sourcefile
- *
- * @return int
- */
- function getPageCount() {
- return $this->page_count;
- }
-
-
- /**
- * Set pageno
- *
- * @param int $pageno Pagenumber to use
- */
- function setPageno($pageno) {
- $pageno = ((int) $pageno) - 1;
-
- if ($pageno < 0 || $pageno >= $this->getPageCount()) {
- $this->fpdi->error('Pagenumber is wrong!');
- }
-
- $this->pageno = $pageno;
- }
-
- /**
- * Get page-resources from current page
- *
- * @return array
- */
- function getPageResources() {
- return $this->_getPageResources($this->pages[$this->pageno]);
- }
-
- /**
- * Get page-resources from /Page
- *
- * @param array $obj Array of pdf-data
- */
- function _getPageResources ($obj) { // $obj = /Page
- $obj = $this->pdf_resolve_object($this->c, $obj);
-
- // If the current object has a resources
- // dictionary associated with it, we use
- // it. Otherwise, we move back to its
- // parent object.
- if (isset ($obj[1][1]['/Resources'])) {
- $res = $this->pdf_resolve_object($this->c, $obj[1][1]['/Resources']);
- if ($res[0] == PDF_TYPE_OBJECT)
- return $res[1];
- return $res;
- } else {
- if (!isset ($obj[1][1]['/Parent'])) {
- return false;
- } else {
- $res = $this->_getPageResources($obj[1][1]['/Parent']);
- if ($res[0] == PDF_TYPE_OBJECT)
- return $res[1];
- return $res;
- }
- }
- }
-
-
- /**
- * Get content of current page
- *
- * If more /Contents is an array, the streams are concated
- *
- * @return string
- */
- function getContent() {
- $buffer = '';
-
- if (isset($this->pages[$this->pageno][1][1]['/Contents'])) {
- $contents = $this->_getPageContent($this->pages[$this->pageno][1][1]['/Contents']);
- foreach($contents AS $tmp_content) {
- $buffer .= $this->_rebuildContentStream($tmp_content) . ' ';
- }
- }
-
- return $buffer;
- }
-
-
- /**
- * Resolve all content-objects
- *
- * @param array $content_ref
- * @return array
- */
- function _getPageContent($content_ref) {
- $contents = array();
-
- if ($content_ref[0] == PDF_TYPE_OBJREF) {
- $content = $this->pdf_resolve_object($this->c, $content_ref);
- if ($content[1][0] == PDF_TYPE_ARRAY) {
- $contents = $this->_getPageContent($content[1]);
- } else {
- $contents[] = $content;
- }
- } else if ($content_ref[0] == PDF_TYPE_ARRAY) {
- foreach ($content_ref[1] AS $tmp_content_ref) {
- $contents = array_merge($contents,$this->_getPageContent($tmp_content_ref));
- }
- }
-
- return $contents;
- }
-
-
- /**
- * Rebuild content-streams
- *
- * @param array $obj
- * @return string
- */
- function _rebuildContentStream($obj) {
- $filters = array();
-
- if (isset($obj[1][1]['/Filter'])) {
- $_filter = $obj[1][1]['/Filter'];
-
- if ($_filter[0] == PDF_TYPE_OBJREF) {
- $tmpFilter = $this->pdf_resolve_object($this->c, $_filter);
- $_filter = $tmpFilter[1];
- }
-
- if ($_filter[0] == PDF_TYPE_TOKEN) {
- $filters[] = $_filter;
- } else if ($_filter[0] == PDF_TYPE_ARRAY) {
- $filters = $_filter[1];
- }
- }
-
- $stream = $obj[2][1];
-
- foreach ($filters AS $_filter) {
- switch ($_filter[1]) {
- case '/FlateDecode':
- case '/Fl':
- // $stream .= "\x0F\x0D"; // in an errorious stream this suffix could work
- // $stream .= "\x0A";
- // $stream .= "\x0D";
- if (function_exists('gzuncompress')) {
- $stream = (strlen($stream) > 0) ? @gzuncompress($stream) : '';
- } else {
- $this->error(sprintf('To handle %s filter, please compile php with zlib support.',$_filter[1]));
- }
-
- if ($stream === false) {
- $this->error('Error while decompressing stream.');
- }
- break;
- case '/LZWDecode':
- include_once('filters/FilterLZW_FPDI.php');
- $decoder = new FilterLZW_FPDI($this->fpdi);
- $stream = $decoder->decode($stream);
- break;
- case '/ASCII85Decode':
- include_once('filters/FilterASCII85_FPDI.php');
- $decoder = new FilterASCII85_FPDI($this->fpdi);
- $stream = $decoder->decode($stream);
- break;
- case null:
- $stream = $stream;
- break;
- default:
- $this->error(sprintf('Unsupported Filter: %s',$_filter[1]));
- }
- }
-
- return $stream;
- }
-
-
- /**
- * Get a Box from a page
- * Arrayformat is same as used by fpdf_tpl
- *
- * @param array $page a /Page
- * @param string $box_index Type of Box @see $availableBoxes
- * @param float Scale factor from user space units to points
- * @return array
- */
- function getPageBox($page, $box_index, $k) {
- $page = $this->pdf_resolve_object($this->c, $page);
- $box = null;
- if (isset($page[1][1][$box_index]))
- $box =& $page[1][1][$box_index];
-
- if (!is_null($box) && $box[0] == PDF_TYPE_OBJREF) {
- $tmp_box = $this->pdf_resolve_object($this->c, $box);
- $box = $tmp_box[1];
- }
-
- if (!is_null($box) && $box[0] == PDF_TYPE_ARRAY) {
- $b =& $box[1];
- return array('x' => $b[0][1]/$k,
- 'y' => $b[1][1]/$k,
- 'w' => abs($b[0][1]-$b[2][1])/$k,
- 'h' => abs($b[1][1]-$b[3][1])/$k,
- 'llx' => min($b[0][1], $b[2][1])/$k,
- 'lly' => min($b[1][1], $b[3][1])/$k,
- 'urx' => max($b[0][1], $b[2][1])/$k,
- 'ury' => max($b[1][1], $b[3][1])/$k,
- );
- } else if (!isset ($page[1][1]['/Parent'])) {
- return false;
- } else {
- return $this->getPageBox($this->pdf_resolve_object($this->c, $page[1][1]['/Parent']), $box_index, $k);
- }
- }
-
- /**
- * Get all page boxes by page no
- *
- * @param int The page number
- * @param float Scale factor from user space units to points
- * @return array
- */
- function getPageBoxes($pageno, $k) {
- return $this->_getPageBoxes($this->pages[$pageno-1], $k);
- }
-
- /**
- * Get all boxes from /Page
- *
- * @param array a /Page
- * @return array
- */
- function _getPageBoxes($page, $k) {
- $boxes = array();
-
- foreach($this->availableBoxes AS $box) {
- if ($_box = $this->getPageBox($page, $box, $k)) {
- $boxes[$box] = $_box;
- }
- }
-
- return $boxes;
- }
-
- /**
- * Get the page rotation by pageno
- *
- * @param integer $pageno
- * @return array
- */
- function getPageRotation($pageno) {
- return $this->_getPageRotation($this->pages[$pageno-1]);
- }
-
- function _getPageRotation($obj) { // $obj = /Page
- $obj = $this->pdf_resolve_object($this->c, $obj);
- if (isset ($obj[1][1]['/Rotate'])) {
- $res = $this->pdf_resolve_object($this->c, $obj[1][1]['/Rotate']);
- if ($res[0] == PDF_TYPE_OBJECT)
- return $res[1];
- return $res;
- } else {
- if (!isset ($obj[1][1]['/Parent'])) {
- return false;
- } else {
- $res = $this->_getPageRotation($obj[1][1]['/Parent']);
- if ($res[0] == PDF_TYPE_OBJECT)
- return $res[1];
- return $res;
- }
- }
- }
-
- /**
- * Read all /Page(es)
- *
- * @param object pdf_context
- * @param array /Pages
- * @param array the result-array
- */
- function read_pages(&$c, &$pages, &$result) {
- // Get the kids dictionary
- $_kids = $this->pdf_resolve_object ($c, $pages[1][1]['/Kids']);
-
- if (!is_array($_kids))
- $this->error('Cannot find /Kids in current /Page-Dictionary');
-
- if ($_kids[1][0] == PDF_TYPE_ARRAY) {
- $kids = $_kids[1][1];
- } else {
- $kids = $_kids[1];
- }
-
- foreach ($kids as $v) {
- $pg = $this->pdf_resolve_object ($c, $v);
- if ($pg[1][1]['/Type'][1] === '/Pages') {
- // If one of the kids is an embedded
- // /Pages array, resolve it as well.
- $this->read_pages($c, $pg, $result);
- } else {
- $result[] = $pg;
- }
- }
- }
-
-
-
- /**
- * Get PDF-Version
- *
- * And reset the PDF Version used in FPDI if needed
- */
- function getPDFVersion() {
- parent::getPDFVersion();
- $this->fpdi->setPDFVersion(max($this->fpdi->getPDFVersion(), $this->pdfVersion));
- }
-
+fpdi =& $fpdi;
+
+ parent::pdf_parser($filename);
+
+ // resolve Pages-Dictonary
+ $pages = $this->pdf_resolve_object($this->c, $this->root[1][1]['/Pages']);
+
+ // Read pages
+ $this->read_pages($this->c, $pages, $this->pages);
+
+ // count pages;
+ $this->page_count = count($this->pages);
+ }
+
+ /**
+ * Overwrite parent::error()
+ *
+ * @param string $msg Error-Message
+ */
+ function error($msg) {
+ $this->fpdi->error($msg);
+ }
+
+ /**
+ * Get pagecount from sourcefile
+ *
+ * @return int
+ */
+ function getPageCount() {
+ return $this->page_count;
+ }
+
+
+ /**
+ * Set pageno
+ *
+ * @param int $pageno Pagenumber to use
+ */
+ function setPageno($pageno) {
+ $pageno = ((int) $pageno) - 1;
+
+ if ($pageno < 0 || $pageno >= $this->getPageCount()) {
+ $this->fpdi->error('Pagenumber is wrong!');
+ }
+
+ $this->pageno = $pageno;
+ }
+
+ /**
+ * Get page-resources from current page
+ *
+ * @return array
+ */
+ function getPageResources() {
+ return $this->_getPageResources($this->pages[$this->pageno]);
+ }
+
+ /**
+ * Get page-resources from /Page
+ *
+ * @param array $obj Array of pdf-data
+ */
+ function _getPageResources ($obj) { // $obj = /Page
+ $obj = $this->pdf_resolve_object($this->c, $obj);
+
+ // If the current object has a resources
+ // dictionary associated with it, we use
+ // it. Otherwise, we move back to its
+ // parent object.
+ if (isset ($obj[1][1]['/Resources'])) {
+ $res = $this->pdf_resolve_object($this->c, $obj[1][1]['/Resources']);
+ if ($res[0] == PDF_TYPE_OBJECT)
+ return $res[1];
+ return $res;
+ } else {
+ if (!isset ($obj[1][1]['/Parent'])) {
+ return false;
+ } else {
+ $res = $this->_getPageResources($obj[1][1]['/Parent']);
+ if ($res[0] == PDF_TYPE_OBJECT)
+ return $res[1];
+ return $res;
+ }
+ }
+ }
+
+
+ /**
+ * Get content of current page
+ *
+ * If more /Contents is an array, the streams are concated
+ *
+ * @return string
+ */
+ function getContent() {
+ $buffer = '';
+
+ if (isset($this->pages[$this->pageno][1][1]['/Contents'])) {
+ $contents = $this->_getPageContent($this->pages[$this->pageno][1][1]['/Contents']);
+ foreach($contents AS $tmp_content) {
+ $buffer .= $this->_rebuildContentStream($tmp_content) . ' ';
+ }
+ }
+
+ return $buffer;
+ }
+
+
+ /**
+ * Resolve all content-objects
+ *
+ * @param array $content_ref
+ * @return array
+ */
+ function _getPageContent($content_ref) {
+ $contents = array();
+
+ if ($content_ref[0] == PDF_TYPE_OBJREF) {
+ $content = $this->pdf_resolve_object($this->c, $content_ref);
+ if ($content[1][0] == PDF_TYPE_ARRAY) {
+ $contents = $this->_getPageContent($content[1]);
+ } else {
+ $contents[] = $content;
+ }
+ } else if ($content_ref[0] == PDF_TYPE_ARRAY) {
+ foreach ($content_ref[1] AS $tmp_content_ref) {
+ $contents = array_merge($contents,$this->_getPageContent($tmp_content_ref));
+ }
+ }
+
+ return $contents;
+ }
+
+
+ /**
+ * Rebuild content-streams
+ *
+ * @param array $obj
+ * @return string
+ */
+ function _rebuildContentStream($obj) {
+ $filters = array();
+
+ if (isset($obj[1][1]['/Filter'])) {
+ $_filter = $obj[1][1]['/Filter'];
+
+ if ($_filter[0] == PDF_TYPE_OBJREF) {
+ $tmpFilter = $this->pdf_resolve_object($this->c, $_filter);
+ $_filter = $tmpFilter[1];
+ }
+
+ if ($_filter[0] == PDF_TYPE_TOKEN) {
+ $filters[] = $_filter;
+ } else if ($_filter[0] == PDF_TYPE_ARRAY) {
+ $filters = $_filter[1];
+ }
+ }
+
+ $stream = $obj[2][1];
+
+ foreach ($filters AS $_filter) {
+ switch ($_filter[1]) {
+ case '/FlateDecode':
+ case '/Fl':
+ // $stream .= "\x0F\x0D"; // in an errorious stream this suffix could work
+ // $stream .= "\x0A";
+ // $stream .= "\x0D";
+ if (function_exists('gzuncompress')) {
+ $stream = (strlen($stream) > 0) ? @gzuncompress($stream) : '';
+ } else {
+ $this->error(sprintf('To handle %s filter, please compile php with zlib support.',$_filter[1]));
+ }
+
+ if ($stream === false) {
+ $this->error('Error while decompressing stream.');
+ }
+ break;
+ case '/LZWDecode':
+ include_once('filters/FilterLZW_FPDI.php');
+ $decoder = new FilterLZW_FPDI($this->fpdi);
+ $stream = $decoder->decode($stream);
+ break;
+ case '/ASCII85Decode':
+ include_once('filters/FilterASCII85_FPDI.php');
+ $decoder = new FilterASCII85_FPDI($this->fpdi);
+ $stream = $decoder->decode($stream);
+ break;
+ case null:
+ $stream = $stream;
+ break;
+ default:
+ $this->error(sprintf('Unsupported Filter: %s',$_filter[1]));
+ }
+ }
+
+ return $stream;
+ }
+
+
+ /**
+ * Get a Box from a page
+ * Arrayformat is same as used by fpdf_tpl
+ *
+ * @param array $page a /Page
+ * @param string $box_index Type of Box @see $availableBoxes
+ * @param float Scale factor from user space units to points
+ * @return array
+ */
+ function getPageBox($page, $box_index, $k) {
+ $page = $this->pdf_resolve_object($this->c, $page);
+ $box = null;
+ if (isset($page[1][1][$box_index]))
+ $box =& $page[1][1][$box_index];
+
+ if (!is_null($box) && $box[0] == PDF_TYPE_OBJREF) {
+ $tmp_box = $this->pdf_resolve_object($this->c, $box);
+ $box = $tmp_box[1];
+ }
+
+ if (!is_null($box) && $box[0] == PDF_TYPE_ARRAY) {
+ $b =& $box[1];
+ return array('x' => $b[0][1] / $k,
+ 'y' => $b[1][1] / $k,
+ 'w' => abs($b[0][1] - $b[2][1]) / $k,
+ 'h' => abs($b[1][1] - $b[3][1]) / $k,
+ 'llx' => min($b[0][1], $b[2][1]) / $k,
+ 'lly' => min($b[1][1], $b[3][1]) / $k,
+ 'urx' => max($b[0][1], $b[2][1]) / $k,
+ 'ury' => max($b[1][1], $b[3][1]) / $k,
+ );
+ } else if (!isset ($page[1][1]['/Parent'])) {
+ return false;
+ } else {
+ return $this->getPageBox($this->pdf_resolve_object($this->c, $page[1][1]['/Parent']), $box_index, $k);
+ }
+ }
+
+ /**
+ * Get all page boxes by page no
+ *
+ * @param int The page number
+ * @param float Scale factor from user space units to points
+ * @return array
+ */
+ function getPageBoxes($pageno, $k) {
+ return $this->_getPageBoxes($this->pages[$pageno - 1], $k);
+ }
+
+ /**
+ * Get all boxes from /Page
+ *
+ * @param array a /Page
+ * @return array
+ */
+ function _getPageBoxes($page, $k) {
+ $boxes = array();
+
+ foreach($this->availableBoxes AS $box) {
+ if ($_box = $this->getPageBox($page, $box, $k)) {
+ $boxes[$box] = $_box;
+ }
+ }
+
+ return $boxes;
+ }
+
+ /**
+ * Get the page rotation by pageno
+ *
+ * @param integer $pageno
+ * @return array
+ */
+ function getPageRotation($pageno) {
+ return $this->_getPageRotation($this->pages[$pageno - 1]);
+ }
+
+ function _getPageRotation($obj) { // $obj = /Page
+ $obj = $this->pdf_resolve_object($this->c, $obj);
+ if (isset ($obj[1][1]['/Rotate'])) {
+ $res = $this->pdf_resolve_object($this->c, $obj[1][1]['/Rotate']);
+ if ($res[0] == PDF_TYPE_OBJECT)
+ return $res[1];
+ return $res;
+ } else {
+ if (!isset ($obj[1][1]['/Parent'])) {
+ return false;
+ } else {
+ $res = $this->_getPageRotation($obj[1][1]['/Parent']);
+ if ($res[0] == PDF_TYPE_OBJECT)
+ return $res[1];
+ return $res;
+ }
+ }
+ }
+
+ /**
+ * Read all /Page(es)
+ *
+ * @param object pdf_context
+ * @param array /Pages
+ * @param array the result-array
+ */
+ function read_pages(&$c, &$pages, &$result) {
+ // Get the kids dictionary
+ $_kids = $this->pdf_resolve_object ($c, $pages[1][1]['/Kids']);
+
+ if (!is_array($_kids))
+ $this->error('Cannot find /Kids in current /Page-Dictionary');
+
+ if ($_kids[1][0] == PDF_TYPE_ARRAY) {
+ $kids = $_kids[1][1];
+ } else {
+ $kids = $_kids[1];
+ }
+
+ foreach ($kids as $v) {
+ $pg = $this->pdf_resolve_object ($c, $v);
+ if ($pg[1][1]['/Type'][1] === '/Pages') {
+ // If one of the kids is an embedded
+ // /Pages array, resolve it as well.
+ $this->read_pages($c, $pg, $result);
+ } else {
+ $result[] = $pg;
+ }
+ }
+ }
+
+
+
+ /**
+ * Get PDF-Version
+ *
+ * And reset the PDF Version used in FPDI if needed
+ */
+ function getPDFVersion() {
+ parent::getPDFVersion();
+ $this->fpdi->setPDFVersion(max($this->fpdi->getPDFVersion(), $this->pdfVersion));
+ }
}
\ No newline at end of file
diff --git a/htdocs/includes/fpdfi/pdf_context.php b/htdocs/includes/fpdfi/pdf_context.php
index bd7f2be7f84..435df1e83da 100755
--- a/htdocs/includes/fpdfi/pdf_context.php
+++ b/htdocs/includes/fpdfi/pdf_context.php
@@ -1,104 +1,104 @@
-file =& $f;
- if (is_string($this->file))
- $this->_mode = 1;
- $this->reset();
- }
-
- // Optionally move the file
- // pointer to a new location
- // and reset the buffered data
-
- function reset($pos = null, $l = 100) {
- if ($this->_mode == 0) {
- if (!is_null ($pos)) {
- fseek ($this->file, $pos);
- }
-
- $this->buffer = $l > 0 ? fread($this->file, $l) : '';
- $this->length = strlen($this->buffer);
- if ($this->length < $l)
- $this->increase_length($l - $this->length);
- } else {
- $this->buffer = $this->file;
- $this->length = strlen($this->buffer);
- }
- $this->offset = 0;
- $this->stack = array();
- }
-
- // Make sure that there is at least one
- // character beyond the current offset in
- // the buffer to prevent the tokenizer
- // from attempting to access data that does
- // not exist
-
- function ensure_content() {
- if ($this->offset >= $this->length - 1) {
- return $this->increase_length();
- } else {
- return true;
- }
- }
-
- // Forcefully read more data into the buffer
-
- function increase_length($l = 100) {
- if ($this->_mode == 0 && feof($this->file)) {
- return false;
- } else if ($this->_mode == 0) {
- $totalLength = $this->length + $l;
- do {
- $toRead = $totalLength - $this->length;
- if ($toRead < 1)
- break;
-
- $this->buffer .= fread($this->file, $toRead);
- } while ((($this->length = strlen($this->buffer)) != $totalLength) && !feof($this->file));
-
- return true;
- } else {
- return false;
- }
- }
- }
+file =& $f;
+ if (is_string($this->file))
+ $this->_mode = 1;
+ $this->reset();
+ }
+
+ // Optionally move the file
+ // pointer to a new location
+ // and reset the buffered data
+
+ function reset($pos = null, $l = 100) {
+ if ($this->_mode == 0) {
+ if (!is_null ($pos)) {
+ fseek ($this->file, $pos);
+ }
+
+ $this->buffer = $l > 0 ? fread($this->file, $l) : '';
+ $this->length = strlen($this->buffer);
+ if ($this->length < $l)
+ $this->increase_length($l - $this->length);
+ } else {
+ $this->buffer = $this->file;
+ $this->length = strlen($this->buffer);
+ }
+ $this->offset = 0;
+ $this->stack = array();
+ }
+
+ // Make sure that there is at least one
+ // character beyond the current offset in
+ // the buffer to prevent the tokenizer
+ // from attempting to access data that does
+ // not exist
+
+ function ensure_content() {
+ if ($this->offset >= $this->length - 1) {
+ return $this->increase_length();
+ } else {
+ return true;
+ }
+ }
+
+ // Forcefully read more data into the buffer
+
+ function increase_length($l = 100) {
+ if ($this->_mode == 0 && feof($this->file)) {
+ return false;
+ } else if ($this->_mode == 0) {
+ $totalLength = $this->length + $l;
+ do {
+ $toRead = $totalLength - $this->length;
+ if ($toRead < 1)
+ break;
+
+ $this->buffer .= fread($this->file, $toRead);
+ } while ((($this->length = strlen($this->buffer)) != $totalLength) && !feof($this->file));
+
+ return true;
+ } else {
+ return false;
+ }
+ }
+ }
}
\ No newline at end of file
diff --git a/htdocs/includes/fpdfi/pdf_parser.php b/htdocs/includes/fpdfi/pdf_parser.php
index 3dbc557f493..4c6dd8e83e3 100755
--- a/htdocs/includes/fpdfi/pdf_parser.php
+++ b/htdocs/includes/fpdfi/pdf_parser.php
@@ -1,719 +1,719 @@
-filename = $filename;
-
- $this->f = @fopen($this->filename, 'rb');
-
- if (!$this->f)
- $this->error(sprintf('Cannot open %s !', $filename));
-
- $this->getPDFVersion();
-
- $this->c = new pdf_context($this->f);
-
- // Read xref-Data
- $this->xref = array();
- $this->pdf_read_xref($this->xref, $this->pdf_find_xref());
-
- // Check for Encryption
- $this->getEncryption();
-
- // Read root
- $this->pdf_read_root();
- }
-
- /**
- * Close the opened file
- */
- function closeFile() {
- if (isset($this->f) && is_resource($this->f)) {
- fclose($this->f);
- unset($this->f);
- }
- }
-
- /**
- * Print Error and die
- *
- * @param string $msg Error-Message
- */
- function error($msg) {
- die('PDF-Parser Error: '.$msg);
- }
-
- /**
- * Check Trailer for Encryption
- */
- function getEncryption() {
- if (isset($this->xref['trailer'][1]['/Encrypt'])) {
- $this->error('File is encrypted!');
- }
- }
-
- /**
- * Find/Return /Root
- *
- * @return array
- */
- function pdf_find_root() {
- if ($this->xref['trailer'][1]['/Root'][0] != PDF_TYPE_OBJREF) {
- $this->error('Wrong Type of Root-Element! Must be an indirect reference');
- }
-
- return $this->xref['trailer'][1]['/Root'];
- }
-
- /**
- * Read the /Root
- */
- function pdf_read_root() {
- // read root
- $this->root = $this->pdf_resolve_object($this->c, $this->pdf_find_root());
- }
-
- /**
- * Get PDF-Version
- *
- * And reset the PDF Version used in FPDI if needed
- */
- function getPDFVersion() {
- fseek($this->f, 0);
- preg_match('/\d\.\d/',fread($this->f,16),$m);
- if (isset($m[0]))
- $this->pdfVersion = $m[0];
- return $this->pdfVersion;
- }
-
- /**
- * Find the xref-Table
- */
- function pdf_find_xref() {
- $toRead = 1500;
-
- $stat = fseek ($this->f, -$toRead, SEEK_END);
- if ($stat === -1) {
- fseek ($this->f, 0);
- }
- $data = fread($this->f, $toRead);
-
- $pos = strlen($data) - strpos(strrev($data), strrev('startxref'));
- $data = substr($data, $pos);
-
- if (!preg_match('/\s*(\d+).*$/s', $data, $matches)) {
- $this->error('Unable to find pointer to xref table');
- }
-
- return (int) $matches[1];
- }
-
- /**
- * Read xref-table
- *
- * @param array $result Array of xref-table
- * @param integer $offset of xref-table
- */
- function pdf_read_xref(&$result, $offset) {
- $o_pos = $offset-min(20, $offset);
- fseek($this->f, $o_pos); // set some bytes backwards to fetch errorious docs
-
- $data = fread($this->f, 100);
-
- $xrefPos = strrpos($data, 'xref');
-
- if ($xrefPos === false) {
- fseek($this->f, $offset);
- $c = new pdf_context($this->f);
- $xrefStreamObjDec = $this->pdf_read_value($c);
-
- if (is_array($xrefStreamObjDec) && isset($xrefStreamObjDec[0]) && $xrefStreamObjDec[0] == PDF_TYPE_OBJDEC) {
- $this->error(sprintf('This document (%s) probably uses a compression technique which is not supported by the free parser shipped with FPDI.', $this->filename));
- } else {
- $this->error('Unable to find xref table.');
- }
- }
-
- if (!isset($result['xref_location'])) {
- $result['xref_location'] = $o_pos+$xrefPos;
- $result['max_object'] = 0;
- }
-
- $cylces = -1;
- $bytesPerCycle = 100;
-
- fseek($this->f, $o_pos = $o_pos+$xrefPos+4); // set the handle directly after the "xref"-keyword
- $data = fread($this->f, $bytesPerCycle);
-
- while (($trailerPos = strpos($data, 'trailer', max($bytesPerCycle*$cylces++, 0))) === false && !feof($this->f)) {
- $data .= fread($this->f, $bytesPerCycle);
- }
-
- if ($trailerPos === false) {
- $this->error('Trailer keyword not found after xref table');
- }
-
- $data = substr($data, 0, $trailerPos);
-
- // get Line-Ending
- preg_match_all("/(\r\n|\n|\r)/", substr($data, 0, 100), $m); // check the first 100 bytes for linebreaks
-
- $differentLineEndings = count(array_unique($m[0]));
- if ($differentLineEndings > 1) {
- $lines = preg_split("/(\r\n|\n|\r)/", $data, -1, PREG_SPLIT_NO_EMPTY);
- } else {
- $lines = explode($m[0][1], $data);
- }
-
- $data = $differentLineEndings = $m = null;
- unset($data, $differentLineEndings, $m);
-
- $linesCount = count($lines);
-
- $start = 1;
-
- for ($i = 0; $i < $linesCount; $i++) {
- $line = trim($lines[$i]);
- if ($line) {
- $pieces = explode(' ', $line);
- $c = count($pieces);
- switch($c) {
- case 2:
- $start = (int)$pieces[0];
- $end = $start+(int)$pieces[1];
- if ($end > $result['max_object'])
- $result['max_object'] = $end;
- break;
- case 3:
- if (!isset($result['xref'][$start]))
- $result['xref'][$start] = array();
-
- if (!array_key_exists($gen = (int) $pieces[1], $result['xref'][$start])) {
- $result['xref'][$start][$gen] = $pieces[2] == 'n' ? (int) $pieces[0] : null;
- }
- $start++;
- break;
- default:
- $this->error('Unexpected data in xref table');
- }
- }
- }
-
- $lines = $pieces = $line = $start = $end = $gen = null;
- unset($lines, $pieces, $line, $start, $end, $gen);
-
- fseek($this->f, $o_pos+$trailerPos+7);
-
- $c = new pdf_context($this->f);
- $trailer = $this->pdf_read_value($c);
-
- $c = null;
- unset($c);
-
- if (!isset($result['trailer'])) {
- $result['trailer'] = $trailer;
- }
-
- if (isset($trailer[1]['/Prev'])) {
- $this->pdf_read_xref($result, $trailer[1]['/Prev'][1]);
- }
-
- $trailer = null;
- unset($trailer);
-
- return true;
- }
-
- /**
- * Reads an Value
- *
- * @param object $c pdf_context
- * @param string $token a Token
- * @return mixed
- */
- function pdf_read_value(&$c, $token = null) {
- if (is_null($token)) {
- $token = $this->pdf_read_token($c);
- }
-
- if ($token === false) {
- return false;
- }
-
- switch ($token) {
- case '<':
- // This is a hex string.
- // Read the value, then the terminator
-
- $pos = $c->offset;
-
- while(1) {
-
- $match = strpos ($c->buffer, '>', $pos);
-
- // If you can't find it, try
- // reading more data from the stream
-
- if ($match === false) {
- if (!$c->increase_length()) {
- return false;
- } else {
- continue;
- }
- }
-
- $result = substr ($c->buffer, $c->offset, $match - $c->offset);
- $c->offset = $match + 1;
-
- return array (PDF_TYPE_HEX, $result);
- }
-
- break;
- case '<<':
- // This is a dictionary.
-
- $result = array();
-
- // Recurse into this function until we reach
- // the end of the dictionary.
- while (($key = $this->pdf_read_token($c)) !== '>>') {
- if ($key === false) {
- return false;
- }
-
- if (($value = $this->pdf_read_value($c)) === false) {
- return false;
- }
-
- // Catch missing value
- if ($value[0] == PDF_TYPE_TOKEN && $value[1] == '>>') {
- $result[$key] = array(PDF_TYPE_NULL);
- break;
- }
-
- $result[$key] = $value;
- }
-
- return array (PDF_TYPE_DICTIONARY, $result);
-
- case '[':
- // This is an array.
-
- $result = array();
-
- // Recurse into this function until we reach
- // the end of the array.
- while (($token = $this->pdf_read_token($c)) !== ']') {
- if ($token === false) {
- return false;
- }
-
- if (($value = $this->pdf_read_value($c, $token)) === false) {
- return false;
- }
-
- $result[] = $value;
- }
-
- return array (PDF_TYPE_ARRAY, $result);
-
- case '(' :
- // This is a string
- $pos = $c->offset;
-
- $openBrackets = 1;
- do {
- for (; $openBrackets != 0 && $pos < $c->length; $pos++) {
- switch (ord($c->buffer[$pos])) {
- case 0x28: // '('
- $openBrackets++;
- break;
- case 0x29: // ')'
- $openBrackets--;
- break;
- case 0x5C: // backslash
- $pos++;
- }
- }
- } while($openBrackets != 0 && $c->increase_length());
-
- $result = substr($c->buffer, $c->offset, $pos - $c->offset - 1);
- $c->offset = $pos;
-
- return array (PDF_TYPE_STRING, $result);
-
- case 'stream':
- $o_pos = ftell($c->file)-strlen($c->buffer);
- $o_offset = $c->offset;
-
- $c->reset($startpos = $o_pos + $o_offset);
-
- $e = 0; // ensure line breaks in front of the stream
- if ($c->buffer[0] == chr(10) || $c->buffer[0] == chr(13))
- $e++;
- if ($c->buffer[1] == chr(10) && $c->buffer[0] != chr(10))
- $e++;
-
- if ($this->actual_obj[1][1]['/Length'][0] == PDF_TYPE_OBJREF) {
- $tmp_c = new pdf_context($this->f);
- $tmp_length = $this->pdf_resolve_object($tmp_c, $this->actual_obj[1][1]['/Length']);
- $length = $tmp_length[1][1];
- } else {
- $length = $this->actual_obj[1][1]['/Length'][1];
- }
-
- if ($length > 0) {
- $c->reset($startpos+$e,$length);
- $v = $c->buffer;
- } else {
- $v = '';
- }
- $c->reset($startpos+$e+$length+9); // 9 = strlen("endstream")
-
- return array(PDF_TYPE_STREAM, $v);
-
- default :
- if (is_numeric ($token)) {
- // A numeric token. Make sure that
- // it is not part of something else.
- if (($tok2 = $this->pdf_read_token ($c)) !== false) {
- if (is_numeric ($tok2)) {
-
- // Two numeric tokens in a row.
- // In this case, we're probably in
- // front of either an object reference
- // or an object specification.
- // Determine the case and return the data
- if (($tok3 = $this->pdf_read_token ($c)) !== false) {
- switch ($tok3) {
- case 'obj' :
- return array (PDF_TYPE_OBJDEC, (int) $token, (int) $tok2);
- case 'R' :
- return array (PDF_TYPE_OBJREF, (int) $token, (int) $tok2);
- }
- // If we get to this point, that numeric value up
- // there was just a numeric value. Push the extra
- // tokens back into the stack and return the value.
- array_push ($c->stack, $tok3);
- }
- }
-
- array_push ($c->stack, $tok2);
- }
-
- if ($token === (string)((int)$token))
- return array (PDF_TYPE_NUMERIC, (int)$token);
- else
- return array (PDF_TYPE_REAL, (float)$token);
- } else if ($token == 'true' || $token == 'false') {
- return array (PDF_TYPE_BOOLEAN, $token == 'true');
- } else if ($token == 'null') {
- return array (PDF_TYPE_NULL);
- } else {
- // Just a token. Return it.
- return array (PDF_TYPE_TOKEN, $token);
- }
- }
- }
-
- /**
- * Resolve an object
- *
- * @param object $c pdf_context
- * @param array $obj_spec The object-data
- * @param boolean $encapsulate Must set to true, cause the parsing and fpdi use this method only without this para
- */
- function pdf_resolve_object(&$c, $obj_spec, $encapsulate = true) {
- // Exit if we get invalid data
- if (!is_array($obj_spec)) {
- $ret = false;
- return $ret;
- }
-
- if ($obj_spec[0] == PDF_TYPE_OBJREF) {
-
- // This is a reference, resolve it
- if (isset($this->xref['xref'][$obj_spec[1]][$obj_spec[2]])) {
-
- // Save current file position
- // This is needed if you want to resolve
- // references while you're reading another object
- // (e.g.: if you need to determine the length
- // of a stream)
-
- $old_pos = ftell($c->file);
-
- // Reposition the file pointer and
- // load the object header.
-
- $c->reset($this->xref['xref'][$obj_spec[1]][$obj_spec[2]]);
-
- $header = $this->pdf_read_value($c);
-
- if ($header[0] != PDF_TYPE_OBJDEC || $header[1] != $obj_spec[1] || $header[2] != $obj_spec[2]) {
- $toSearchFor = $obj_spec[1].' '.$obj_spec[2].' obj';
- if (preg_match('/'.$toSearchFor.'/', $c->buffer)) {
- $c->offset = strpos($c->buffer, $toSearchFor) + strlen($toSearchFor);
- // reset stack
- $c->stack = array();
- } else {
- $this->error("Unable to find object ({$obj_spec[1]}, {$obj_spec[2]}) at expected location");
- }
- }
-
- // If we're being asked to store all the information
- // about the object, we add the object ID and generation
- // number for later use
- $result = array();
- $this->actual_obj =& $result;
- if ($encapsulate) {
- $result = array (
- PDF_TYPE_OBJECT,
- 'obj' => $obj_spec[1],
- 'gen' => $obj_spec[2]
- );
- }
-
- // Now simply read the object data until
- // we encounter an end-of-object marker
- while(1) {
- $value = $this->pdf_read_value($c);
- if ($value === false || count($result) > 4) {
- // in this case the parser coudn't find an endobj so we break here
- break;
- }
-
- if ($value[0] == PDF_TYPE_TOKEN && $value[1] === 'endobj') {
- break;
- }
-
- $result[] = $value;
- }
-
- $c->reset($old_pos);
-
- if (isset($result[2][0]) && $result[2][0] == PDF_TYPE_STREAM) {
- $result[0] = PDF_TYPE_STREAM;
- }
-
- return $result;
- }
- } else {
- return $obj_spec;
- }
- }
-
-
-
- /**
- * Reads a token from the file
- *
- * @param object $c pdf_context
- * @return mixed
- */
- function pdf_read_token(&$c)
- {
- // If there is a token available
- // on the stack, pop it out and
- // return it.
-
- if (count($c->stack)) {
- return array_pop($c->stack);
- }
-
- // Strip away any whitespace
-
- do {
- if (!$c->ensure_content()) {
- return false;
- }
- $c->offset += strspn($c->buffer, " \n\r\t", $c->offset);
- } while ($c->offset >= $c->length - 1);
-
- // Get the first character in the stream
-
- $char = $c->buffer[$c->offset++];
-
- switch ($char) {
-
- case '[':
- case ']':
- case '(':
- case ')':
-
- // This is either an array or literal string
- // delimiter, Return it
-
- return $char;
-
- case '<':
- case '>':
-
- // This could either be a hex string or
- // dictionary delimiter. Determine the
- // appropriate case and return the token
-
- if ($c->buffer[$c->offset] == $char) {
- if (!$c->ensure_content()) {
- return false;
- }
- $c->offset++;
- return $char . $char;
- } else {
- return $char;
- }
-
- case '%':
-
- // This is a comment - jump over it!
-
- $pos = $c->offset;
- while(1) {
- $match = preg_match("/(\r\n|\r|\n)/", $c->buffer, $m, PREG_OFFSET_CAPTURE, $pos);
- if ($match === 0) {
- if (!$c->increase_length()) {
- return false;
- } else {
- continue;
- }
- }
-
- $c->offset = $m[0][1]+strlen($m[0][0]);
-
- return $this->pdf_read_token($c);
- }
-
- default:
-
- // This is "another" type of token (probably
- // a dictionary entry or a numeric value)
- // Find the end and return it.
-
- if (!$c->ensure_content()) {
- return false;
- }
-
- while(1) {
-
- // Determine the length of the token
-
- $pos = strcspn($c->buffer, " %[]<>()\r\n\t/", $c->offset);
-
- if ($c->offset + $pos <= $c->length - 1) {
- break;
- } else {
- // If the script reaches this point,
- // the token may span beyond the end
- // of the current buffer. Therefore,
- // we increase the size of the buffer
- // and try again--just to be safe.
-
- $c->increase_length();
- }
- }
-
- $result = substr($c->buffer, $c->offset - 1, $pos + 1);
-
- $c->offset += $pos;
- return $result;
- }
- }
- }
-}
+filename = $filename;
+
+ $this->f = @fopen($this->filename, 'rb');
+
+ if (!$this->f)
+ $this->error(sprintf('Cannot open %s !', $filename));
+
+ $this->getPDFVersion();
+
+ $this->c = new pdf_context($this->f);
+
+ // Read xref-Data
+ $this->xref = array();
+ $this->pdf_read_xref($this->xref, $this->pdf_find_xref());
+
+ // Check for Encryption
+ $this->getEncryption();
+
+ // Read root
+ $this->pdf_read_root();
+ }
+
+ /**
+ * Close the opened file
+ */
+ function closeFile() {
+ if (isset($this->f) && is_resource($this->f)) {
+ fclose($this->f);
+ unset($this->f);
+ }
+ }
+
+ /**
+ * Print Error and die
+ *
+ * @param string $msg Error-Message
+ */
+ function error($msg) {
+ die('PDF-Parser Error: ' . $msg);
+ }
+
+ /**
+ * Check Trailer for Encryption
+ */
+ function getEncryption() {
+ if (isset($this->xref['trailer'][1]['/Encrypt'])) {
+ $this->error('File is encrypted!');
+ }
+ }
+
+ /**
+ * Find/Return /Root
+ *
+ * @return array
+ */
+ function pdf_find_root() {
+ if ($this->xref['trailer'][1]['/Root'][0] != PDF_TYPE_OBJREF) {
+ $this->error('Wrong Type of Root-Element! Must be an indirect reference');
+ }
+
+ return $this->xref['trailer'][1]['/Root'];
+ }
+
+ /**
+ * Read the /Root
+ */
+ function pdf_read_root() {
+ // read root
+ $this->root = $this->pdf_resolve_object($this->c, $this->pdf_find_root());
+ }
+
+ /**
+ * Get PDF-Version
+ *
+ * And reset the PDF Version used in FPDI if needed
+ */
+ function getPDFVersion() {
+ fseek($this->f, 0);
+ preg_match('/\d\.\d/',fread($this->f, 16), $m);
+ if (isset($m[0]))
+ $this->pdfVersion = $m[0];
+ return $this->pdfVersion;
+ }
+
+ /**
+ * Find the xref-Table
+ */
+ function pdf_find_xref() {
+ $toRead = 1500;
+
+ $stat = fseek ($this->f, -$toRead, SEEK_END);
+ if ($stat === -1) {
+ fseek ($this->f, 0);
+ }
+ $data = fread($this->f, $toRead);
+
+ $pos = strlen($data) - strpos(strrev($data), strrev('startxref'));
+ $data = substr($data, $pos);
+
+ if (!preg_match('/\s*(\d+).*$/s', $data, $matches)) {
+ $this->error('Unable to find pointer to xref table');
+ }
+
+ return (int) $matches[1];
+ }
+
+ /**
+ * Read xref-table
+ *
+ * @param array $result Array of xref-table
+ * @param integer $offset of xref-table
+ */
+ function pdf_read_xref(&$result, $offset) {
+ $o_pos = $offset-min(20, $offset);
+ fseek($this->f, $o_pos); // set some bytes backwards to fetch errorious docs
+
+ $data = fread($this->f, 100);
+
+ $xrefPos = strrpos($data, 'xref');
+
+ if ($xrefPos === false) {
+ fseek($this->f, $offset);
+ $c = new pdf_context($this->f);
+ $xrefStreamObjDec = $this->pdf_read_value($c);
+
+ if (is_array($xrefStreamObjDec) && isset($xrefStreamObjDec[0]) && $xrefStreamObjDec[0] == PDF_TYPE_OBJDEC) {
+ $this->error(sprintf('This document (%s) probably uses a compression technique which is not supported by the free parser shipped with FPDI.', $this->filename));
+ } else {
+ $this->error('Unable to find xref table.');
+ }
+ }
+
+ if (!isset($result['xref_location'])) {
+ $result['xref_location'] = $o_pos + $xrefPos;
+ $result['max_object'] = 0;
+ }
+
+ $cylces = -1;
+ $bytesPerCycle = 100;
+
+ fseek($this->f, $o_pos = $o_pos + $xrefPos + 4); // set the handle directly after the "xref"-keyword
+ $data = fread($this->f, $bytesPerCycle);
+
+ while (($trailerPos = strpos($data, 'trailer', max($bytesPerCycle * $cylces++, 0))) === false && !feof($this->f)) {
+ $data .= fread($this->f, $bytesPerCycle);
+ }
+
+ if ($trailerPos === false) {
+ $this->error('Trailer keyword not found after xref table');
+ }
+
+ $data = substr($data, 0, $trailerPos);
+
+ // get Line-Ending
+ preg_match_all("/(\r\n|\n|\r)/", substr($data, 0, 100), $m); // check the first 100 bytes for linebreaks
+
+ $differentLineEndings = count(array_unique($m[0]));
+ if ($differentLineEndings > 1) {
+ $lines = preg_split("/(\r\n|\n|\r)/", $data, -1, PREG_SPLIT_NO_EMPTY);
+ } else {
+ $lines = explode($m[0][1], $data);
+ }
+
+ $data = $differentLineEndings = $m = null;
+ unset($data, $differentLineEndings, $m);
+
+ $linesCount = count($lines);
+
+ $start = 1;
+
+ for ($i = 0; $i < $linesCount; $i++) {
+ $line = trim($lines[$i]);
+ if ($line) {
+ $pieces = explode(' ', $line);
+ $c = count($pieces);
+ switch($c) {
+ case 2:
+ $start = (int)$pieces[0];
+ $end = $start + (int)$pieces[1];
+ if ($end > $result['max_object'])
+ $result['max_object'] = $end;
+ break;
+ case 3:
+ if (!isset($result['xref'][$start]))
+ $result['xref'][$start] = array();
+
+ if (!array_key_exists($gen = (int) $pieces[1], $result['xref'][$start])) {
+ $result['xref'][$start][$gen] = $pieces[2] == 'n' ? (int) $pieces[0] : null;
+ }
+ $start++;
+ break;
+ default:
+ $this->error('Unexpected data in xref table');
+ }
+ }
+ }
+
+ $lines = $pieces = $line = $start = $end = $gen = null;
+ unset($lines, $pieces, $line, $start, $end, $gen);
+
+ fseek($this->f, $o_pos + $trailerPos + 7);
+
+ $c = new pdf_context($this->f);
+ $trailer = $this->pdf_read_value($c);
+
+ $c = null;
+ unset($c);
+
+ if (!isset($result['trailer'])) {
+ $result['trailer'] = $trailer;
+ }
+
+ if (isset($trailer[1]['/Prev'])) {
+ $this->pdf_read_xref($result, $trailer[1]['/Prev'][1]);
+ }
+
+ $trailer = null;
+ unset($trailer);
+
+ return true;
+ }
+
+ /**
+ * Reads an Value
+ *
+ * @param object $c pdf_context
+ * @param string $token a Token
+ * @return mixed
+ */
+ function pdf_read_value(&$c, $token = null) {
+ if (is_null($token)) {
+ $token = $this->pdf_read_token($c);
+ }
+
+ if ($token === false) {
+ return false;
+ }
+
+ switch ($token) {
+ case '<':
+ // This is a hex string.
+ // Read the value, then the terminator
+
+ $pos = $c->offset;
+
+ while(1) {
+
+ $match = strpos ($c->buffer, '>', $pos);
+
+ // If you can't find it, try
+ // reading more data from the stream
+
+ if ($match === false) {
+ if (!$c->increase_length()) {
+ return false;
+ } else {
+ continue;
+ }
+ }
+
+ $result = substr ($c->buffer, $c->offset, $match - $c->offset);
+ $c->offset = $match + 1;
+
+ return array (PDF_TYPE_HEX, $result);
+ }
+
+ break;
+ case '<<':
+ // This is a dictionary.
+
+ $result = array();
+
+ // Recurse into this function until we reach
+ // the end of the dictionary.
+ while (($key = $this->pdf_read_token($c)) !== '>>') {
+ if ($key === false) {
+ return false;
+ }
+
+ if (($value = $this->pdf_read_value($c)) === false) {
+ return false;
+ }
+
+ // Catch missing value
+ if ($value[0] == PDF_TYPE_TOKEN && $value[1] == '>>') {
+ $result[$key] = array(PDF_TYPE_NULL);
+ break;
+ }
+
+ $result[$key] = $value;
+ }
+
+ return array (PDF_TYPE_DICTIONARY, $result);
+
+ case '[':
+ // This is an array.
+
+ $result = array();
+
+ // Recurse into this function until we reach
+ // the end of the array.
+ while (($token = $this->pdf_read_token($c)) !== ']') {
+ if ($token === false) {
+ return false;
+ }
+
+ if (($value = $this->pdf_read_value($c, $token)) === false) {
+ return false;
+ }
+
+ $result[] = $value;
+ }
+
+ return array (PDF_TYPE_ARRAY, $result);
+
+ case '(' :
+ // This is a string
+ $pos = $c->offset;
+
+ $openBrackets = 1;
+ do {
+ for (; $openBrackets != 0 && $pos < $c->length; $pos++) {
+ switch (ord($c->buffer[$pos])) {
+ case 0x28: // '('
+ $openBrackets++;
+ break;
+ case 0x29: // ')'
+ $openBrackets--;
+ break;
+ case 0x5C: // backslash
+ $pos++;
+ }
+ }
+ } while($openBrackets != 0 && $c->increase_length());
+
+ $result = substr($c->buffer, $c->offset, $pos - $c->offset - 1);
+ $c->offset = $pos;
+
+ return array (PDF_TYPE_STRING, $result);
+
+ case 'stream':
+ $o_pos = ftell($c->file)-strlen($c->buffer);
+ $o_offset = $c->offset;
+
+ $c->reset($startpos = $o_pos + $o_offset);
+
+ $e = 0; // ensure line breaks in front of the stream
+ if ($c->buffer[0] == chr(10) || $c->buffer[0] == chr(13))
+ $e++;
+ if ($c->buffer[1] == chr(10) && $c->buffer[0] != chr(10))
+ $e++;
+
+ if ($this->actual_obj[1][1]['/Length'][0] == PDF_TYPE_OBJREF) {
+ $tmp_c = new pdf_context($this->f);
+ $tmp_length = $this->pdf_resolve_object($tmp_c, $this->actual_obj[1][1]['/Length']);
+ $length = $tmp_length[1][1];
+ } else {
+ $length = $this->actual_obj[1][1]['/Length'][1];
+ }
+
+ if ($length > 0) {
+ $c->reset($startpos + $e,$length);
+ $v = $c->buffer;
+ } else {
+ $v = '';
+ }
+ $c->reset($startpos + $e + $length + 9); // 9 = strlen("endstream")
+
+ return array(PDF_TYPE_STREAM, $v);
+
+ default :
+ if (is_numeric ($token)) {
+ // A numeric token. Make sure that
+ // it is not part of something else.
+ if (($tok2 = $this->pdf_read_token ($c)) !== false) {
+ if (is_numeric ($tok2)) {
+
+ // Two numeric tokens in a row.
+ // In this case, we're probably in
+ // front of either an object reference
+ // or an object specification.
+ // Determine the case and return the data
+ if (($tok3 = $this->pdf_read_token ($c)) !== false) {
+ switch ($tok3) {
+ case 'obj':
+ return array (PDF_TYPE_OBJDEC, (int) $token, (int) $tok2);
+ case 'R':
+ return array (PDF_TYPE_OBJREF, (int) $token, (int) $tok2);
+ }
+ // If we get to this point, that numeric value up
+ // there was just a numeric value. Push the extra
+ // tokens back into the stack and return the value.
+ array_push ($c->stack, $tok3);
+ }
+ }
+
+ array_push ($c->stack, $tok2);
+ }
+
+ if ($token === (string)((int)$token))
+ return array (PDF_TYPE_NUMERIC, (int)$token);
+ else
+ return array (PDF_TYPE_REAL, (float)$token);
+ } else if ($token == 'true' || $token == 'false') {
+ return array (PDF_TYPE_BOOLEAN, $token == 'true');
+ } else if ($token == 'null') {
+ return array (PDF_TYPE_NULL);
+ } else {
+ // Just a token. Return it.
+ return array (PDF_TYPE_TOKEN, $token);
+ }
+ }
+ }
+
+ /**
+ * Resolve an object
+ *
+ * @param object $c pdf_context
+ * @param array $obj_spec The object-data
+ * @param boolean $encapsulate Must set to true, cause the parsing and fpdi use this method only without this para
+ */
+ function pdf_resolve_object(&$c, $obj_spec, $encapsulate = true) {
+ // Exit if we get invalid data
+ if (!is_array($obj_spec)) {
+ $ret = false;
+ return $ret;
+ }
+
+ if ($obj_spec[0] == PDF_TYPE_OBJREF) {
+
+ // This is a reference, resolve it
+ if (isset($this->xref['xref'][$obj_spec[1]][$obj_spec[2]])) {
+
+ // Save current file position
+ // This is needed if you want to resolve
+ // references while you're reading another object
+ // (e.g.: if you need to determine the length
+ // of a stream)
+
+ $old_pos = ftell($c->file);
+
+ // Reposition the file pointer and
+ // load the object header.
+
+ $c->reset($this->xref['xref'][$obj_spec[1]][$obj_spec[2]]);
+
+ $header = $this->pdf_read_value($c);
+
+ if ($header[0] != PDF_TYPE_OBJDEC || $header[1] != $obj_spec[1] || $header[2] != $obj_spec[2]) {
+ $toSearchFor = $obj_spec[1] . ' ' . $obj_spec[2] . ' obj';
+ if (preg_match('/' . $toSearchFor . '/', $c->buffer)) {
+ $c->offset = strpos($c->buffer, $toSearchFor) + strlen($toSearchFor);
+ // reset stack
+ $c->stack = array();
+ } else {
+ $this->error("Unable to find object ({$obj_spec[1]}, {$obj_spec[2]}) at expected location");
+ }
+ }
+
+ // If we're being asked to store all the information
+ // about the object, we add the object ID and generation
+ // number for later use
+ $result = array();
+ $this->actual_obj =& $result;
+ if ($encapsulate) {
+ $result = array (
+ PDF_TYPE_OBJECT,
+ 'obj' => $obj_spec[1],
+ 'gen' => $obj_spec[2]
+ );
+ }
+
+ // Now simply read the object data until
+ // we encounter an end-of-object marker
+ while(1) {
+ $value = $this->pdf_read_value($c);
+ if ($value === false || count($result) > 4) {
+ // in this case the parser coudn't find an endobj so we break here
+ break;
+ }
+
+ if ($value[0] == PDF_TYPE_TOKEN && $value[1] === 'endobj') {
+ break;
+ }
+
+ $result[] = $value;
+ }
+
+ $c->reset($old_pos);
+
+ if (isset($result[2][0]) && $result[2][0] == PDF_TYPE_STREAM) {
+ $result[0] = PDF_TYPE_STREAM;
+ }
+
+ return $result;
+ }
+ } else {
+ return $obj_spec;
+ }
+ }
+
+
+
+ /**
+ * Reads a token from the file
+ *
+ * @param object $c pdf_context
+ * @return mixed
+ */
+ function pdf_read_token(&$c)
+ {
+ // If there is a token available
+ // on the stack, pop it out and
+ // return it.
+
+ if (count($c->stack)) {
+ return array_pop($c->stack);
+ }
+
+ // Strip away any whitespace
+
+ do {
+ if (!$c->ensure_content()) {
+ return false;
+ }
+ $c->offset += strspn($c->buffer, " \n\r\t", $c->offset);
+ } while ($c->offset >= $c->length - 1);
+
+ // Get the first character in the stream
+
+ $char = $c->buffer[$c->offset++];
+
+ switch ($char) {
+
+ case '[':
+ case ']':
+ case '(':
+ case ')':
+
+ // This is either an array or literal string
+ // delimiter, Return it
+
+ return $char;
+
+ case '<':
+ case '>':
+
+ // This could either be a hex string or
+ // dictionary delimiter. Determine the
+ // appropriate case and return the token
+
+ if ($c->buffer[$c->offset] == $char) {
+ if (!$c->ensure_content()) {
+ return false;
+ }
+ $c->offset++;
+ return $char . $char;
+ } else {
+ return $char;
+ }
+
+ case '%':
+
+ // This is a comment - jump over it!
+
+ $pos = $c->offset;
+ while(1) {
+ $match = preg_match("/(\r\n|\r|\n)/", $c->buffer, $m, PREG_OFFSET_CAPTURE, $pos);
+ if ($match === 0) {
+ if (!$c->increase_length()) {
+ return false;
+ } else {
+ continue;
+ }
+ }
+
+ $c->offset = $m[0][1]+strlen($m[0][0]);
+
+ return $this->pdf_read_token($c);
+ }
+
+ default:
+
+ // This is "another" type of token (probably
+ // a dictionary entry or a numeric value)
+ // Find the end and return it.
+
+ if (!$c->ensure_content()) {
+ return false;
+ }
+
+ while(1) {
+
+ // Determine the length of the token
+
+ $pos = strcspn($c->buffer, " %[]<>()\r\n\t/", $c->offset);
+
+ if ($c->offset + $pos <= $c->length - 1) {
+ break;
+ } else {
+ // If the script reaches this point,
+ // the token may span beyond the end
+ // of the current buffer. Therefore,
+ // we increase the size of the buffer
+ // and try again--just to be safe.
+
+ $c->increase_length();
+ }
+ }
+
+ $result = substr($c->buffer, $c->offset - 1, $pos + 1);
+
+ $c->offset += $pos;
+ return $result;
+ }
+ }
+ }
+}
diff --git a/htdocs/includes/tcpdf/2dbarcodes.php b/htdocs/includes/tcpdf/2dbarcodes.php
index e04b3073ce1..6490dfa7eaf 100644
--- a/htdocs/includes/tcpdf/2dbarcodes.php
+++ b/htdocs/includes/tcpdf/2dbarcodes.php
@@ -1,9 +1,9 @@
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;
diff --git a/htdocs/includes/tcpdf/CHANGELOG.TXT b/htdocs/includes/tcpdf/CHANGELOG.TXT
index 23a14f9991d..d3c29f94068 100644
--- a/htdocs/includes/tcpdf/CHANGELOG.TXT
+++ b/htdocs/includes/tcpdf/CHANGELOG.TXT
@@ -1,3 +1,94 @@
+5.9.180 (2012-08-22)
+ - Bug item #3560493 "Problems with nested cells in HTML" was fixed.
+
+5.9.179 (2012-08-04)
+ - SVG 'use' tag was fixed for 'circle' and 'ellipse' shift problem.
+ - Alpha status is now correctly stored and restored by getGraphicVars() and SetGraphicVars() methods.
+
+5.9.178 (2012-08-02)
+ - SVG 'use' tag was fixed for 'circle' and 'ellipse'.
+
+5.9.177 (2012-08-02)
+ - An additional control on annotations was fixed.
+
+5.9.176 (2012-07-25)
+ - A bug related to stroke width was fixed.
+ - A problem related to font spacing in HTML was fixed.
+
+5.9.175 (2012-07-25)
+ - The problem of missing letter on hyphen break was fixed.
+
+5.9.174 (2012-07-25)
+ - The problem of wrong filename when downloading PDF from an Android device was fixed.
+ - The method setHeaderData() was extended to set text and line color for header (see example n. 1).
+ - The method setFooterData() was added to set text and line color for footer (see example n. 1).
+ - The methods setTextShadow() and getTextShadow() were added to set text shadows (see example n. 1).
+ - The GetCharWidth() method was fixed for negative character spacing.
+ - A 'none' border mode is now correctly recognized.
+ - Break on hyphen problem was fixed.
+
+5.9.173 (2012-07-23)
+ - Some additional control wher added on barcode methods.
+ - The option CURLOPT_FOLLOWLOCATION on Image method is now disabled if PHP safe_mode is on or open_basedir is set.
+ - Method Bookmark() was extended to include X parameter.
+ - Method setDestination() was extended to include X parameter.
+ - A problem with Thai language was fixed.
+
+5.9.172 (2012-07-02)
+ - A PNG color profile issue was fixed.
+
+5.9.171 (2012-07-01)
+ - Some SVG rendering problems were fixed.
+
+5.9.170 (2012-06-27)
+ - Bug #3538227 "Numerous errors inserting shared images" was fixed.
+
+5.9.169 (2012-06-25)
+ - Some SVG rendering problems were fixed.
+
+5.9.168 (2012-06-22)
+ - Thai language rendering was fixed.
+
+5.9.167 (2012-06-22)
+ - Thai language rendering was fixed and improved.
+ - Method isCharDefined() was improved.
+ - Protected method replaceChar() was added.
+ - Font "kerning" word was corrected to "tracking".
+
+5.9.166 (2012-06-21)
+ - Array to string conversion on file_id creation was fixed.
+ - Thai language rendering was fixed (thanks to Atsawin Chaowanakritsanakul).
+
+5.9.165 (2012-06-07)
+ - Some HTML form related bugs were fixed.
+
+5.9.164 (2012-06-06)
+ - A bug introduced on the latest release was fixed.
+
+5.9.163 (2012-06-05)
+ - Method getGDgamma() was changed.
+ - Rendering performances of PNG images with alpha channel were improved.
+
+5.9.162 (2012-05-11)
+ - A bug related to long text on TD cells was fixed.
+
+5.9.161 (2012-05-09)
+ - A bug on XREF table was fixed (Bug ID: 3525051).
+ - Deprecated Imagick:clone was replaced.
+ - Method objclone() was fixed for PHP4.
+
+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.
@@ -567,7 +658,7 @@
- The problem of blank page for nobr table higher than a single page was fixed.
5.9.000 (2010-10-06)
- - Support for text stretching and spacing (kerning) was added, see example n. 63 and methods setFontStretching(), getFontStretching(), setFontSpacing(), getFontSpacing().
+ - Support for text stretching and spacing (tracking) was added, see example n. 63 and methods setFontStretching(), getFontStretching(), setFontSpacing(), getFontSpacing().
- Support for CSS properties 'font-stretch' and 'letter-spacing' was added (see example n. 63).
- The cMargin state was replaced by cell_padding array that can be set/get using setCellPadding() and getCellPadding() methods.
- Methods getCellPaddings() and setCellPaddings() were added to fine tune cell paddings (see example n. 5).
diff --git a/htdocs/includes/tcpdf/README.TXT b/htdocs/includes/tcpdf/README.TXT
index 83520bb1272..ff86c9d23b0 100644
--- a/htdocs/includes/tcpdf/README.TXT
+++ b/htdocs/includes/tcpdf/README.TXT
@@ -8,8 +8,8 @@ http://sourceforge.net/donate/index.php?group_id=128076
------------------------------------------------------------
Name: TCPDF
-Version: 5.9.156
-Release date: 2012-04-10
+Version: 5.9.180
+Release date: 2012-08-22
Author: Nicola Asuni
Copyright (c) 2002-2012:
@@ -47,7 +47,7 @@ Main Features:
* no-write page regions;
* bookmarks, named destinations and table of content;
* text hyphenation;
- * text stretching and spacing (tracking/kerning);
+ * text stretching and spacing (tracking);
* automatic page break, line break and text alignments including justification;
* automatic page numbering and page groups;
* move and delete pages;
diff --git a/htdocs/includes/tcpdf/barcodes.php b/htdocs/includes/tcpdf/barcodes.php
index 4027aa7109a..c6c0172e4a3 100644
--- a/htdocs/includes/tcpdf/barcodes.php
+++ b/htdocs/includes/tcpdf/barcodes.php
@@ -1,9 +1,9 @@
* @package com.tecnick.tcpdf
- * @version 1.0.023
+ * @version 1.0.024
* @author Nicola Asuni
*/
class TCPDFBarcode {
@@ -201,9 +201,9 @@ class TCPDFBarcode {
$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;
diff --git a/htdocs/includes/tcpdf/config/lang/bul.php b/htdocs/includes/tcpdf/config/lang/bul.php
index 00a44ef03e4..d7bbaaf6a30 100644
--- a/htdocs/includes/tcpdf/config/lang/bul.php
+++ b/htdocs/includes/tcpdf/config/lang/bul.php
@@ -1,47 +1,47 @@
-dataStr) > 0) {
- if ($this->dataStr == '') {
- return 0;
- }
$mode = $this->identifyMode(0);
switch ($mode) {
case QR_MODE_NM: {
@@ -1476,6 +1474,7 @@ class QRcode {
}
$this->dataStr = substr($this->dataStr, $length);
}
+ return 0;
}
/**
@@ -2028,7 +2027,7 @@ class QRcode {
if ($ver > $this->version) {
$this->version = $ver;
}
- for (;;) {
+ while (true) {
$cbs = $this->createBitStream($items);
$items = $cbs[0];
$bits = $cbs[1];
@@ -2315,17 +2314,18 @@ class QRcode {
/**
* Return a version number that satisfies the input code length.
- * @param $size (int) input code length (byte)
+ * @param $size (int) input code length (bytes)
* @param $level (int) error correction level
* @return int version number
*/
protected function getMinimumVersion($size, $level) {
- for ($i=1; $i <= QRSPEC_VERSION_MAX; ++$i) {
- $words = $this->capacity[$i][QRCAP_WORDS] - $this->capacity[$i][QRCAP_EC][$level];
+ for ($i = 1; $i <= QRSPEC_VERSION_MAX; ++$i) {
+ $words = ($this->capacity[$i][QRCAP_WORDS] - $this->capacity[$i][QRCAP_EC][$level]);
if ($words >= $size) {
return $i;
}
}
+ // the size of input data is greater than QR capacity, try to lover the error correction mode
return -1;
}
diff --git a/htdocs/includes/tcpdf/tcpdf.php b/htdocs/includes/tcpdf/tcpdf.php
index 7c18096a52a..21da1606ed1 100644
--- a/htdocs/includes/tcpdf/tcpdf.php
+++ b/htdocs/includes/tcpdf/tcpdf.php
@@ -1,9 +1,9 @@
no-write page regions;
* bookmarks, named destinations and table of content;
* text hyphenation;
- * text stretching and spacing (tracking/kerning);
+ * text stretching and spacing (tracking);
* automatic page break, line break and text alignments including justification;
* automatic page numbering and page groups;
* move and delete pages;
@@ -137,7 +138,7 @@
* Tools to encode your unicode fonts are on fonts/utils directory.
* @package com.tecnick.tcpdf
* @author Nicola Asuni
- * @version 5.9.156
+ * @version 5.9.180
*/
// Main configuration file. Define the K_TCPDF_EXTERNAL_CONFIG constant to skip this file.
@@ -149,7 +150,7 @@ require_once(dirname(__FILE__).'/config/tcpdf_config.php');
* 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.
* @package com.tecnick.tcpdf
* @brief PHP class for generating PDF documents without requiring external extensions.
- * @version 5.9.156
+ * @version 5.9.180
* @author Nicola Asuni - info@tecnick.com
*/
class TCPDF {
@@ -160,7 +161,7 @@ class TCPDF {
* Current TCPDF version.
* @private
*/
- private $tcpdf_version = '5.9.156';
+ private $tcpdf_version = '5.9.180';
// Protected properties
@@ -180,7 +181,13 @@ class TCPDF {
* Array of object offsets.
* @protected
*/
- protected $offsets;
+ protected $offsets = array();
+
+ /**
+ * Array of object IDs for each page.
+ * @protected
+ */
+ protected $pageobjects = array();
/**
* Buffer holding in-memory PDF.
@@ -705,6 +712,41 @@ class TCPDF {
*/
protected $header_string = '';
+ /**
+ * Color for header text (RGB array).
+ * @since 5.9.174 (2012-07-25)
+ * @protected
+ */
+ protected $header_text_color = array(0,0,0);
+
+ /**
+ * Color for header line (RGB array).
+ * @since 5.9.174 (2012-07-25)
+ * @protected
+ */
+ protected $header_line_color = array(0,0,0);
+
+ /**
+ * Color for footer text (RGB array).
+ * @since 5.9.174 (2012-07-25)
+ * @protected
+ */
+ protected $footer_text_color = array(0,0,0);
+
+ /**
+ * Color for footer line (RGB array).
+ * @since 5.9.174 (2012-07-25)
+ * @protected
+ */
+ protected $footer_line_color = array(0,0,0);
+
+ /**
+ * Text shadow data array.
+ * @since 5.9.174 (2012-07-25)
+ * @protected
+ */
+ protected $txtshadow = array('enabled'=>false, 'depth_w'=>0, 'depth_h'=>0, 'color'=>false, 'opacity'=>1, 'blend_mode'=>'Normal');
+
/**
* Default number of columns for html table.
* @protected
@@ -1590,7 +1632,7 @@ class TCPDF {
protected $font_stretching = 100;
/**
- * Increases or decreases the space between characters in a text by the specified amount (tracking/kerning).
+ * Increases or decreases the space between characters in a text by the specified amount (tracking).
* @protected
* @since 5.9.000 (2010-09-29)
*/
@@ -1873,6 +1915,13 @@ class TCPDF {
*/
protected $tcpdflink = true;
+ /**
+ * Cache array for computed GD gamma values.
+ * @protected
+ * @since 5.9.1632 (2012-06-05)
+ */
+ protected $gdgammacache = array();
+
//------------------------------------------------------------
// METHODS
//------------------------------------------------------------
@@ -2006,6 +2055,7 @@ class TCPDF {
$this->strokecolor = array('R' => 0, 'G' => 0, 'B' => 0);
$this->bgcolor = array('R' => 255, 'G' => 255, 'B' => 255);
$this->extgstates = array();
+ $this->setTextShadow();
// user's rights
$this->sign = false;
$this->ur['enabled'] = false;
@@ -2037,7 +2087,8 @@ class TCPDF {
}
$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));
+ $serformat = (is_array($format) ? serialize($format) : $format);
+ $this->file_id = md5($this->getRandomSeed('TCPDF'.$orientation.$unit.$serformat.$encoding));
// set document creation and modification timestamp
$this->doc_creation_timestamp = time();
$this->doc_modification_timestamp = $this->doc_creation_timestamp;
@@ -3059,8 +3110,8 @@ class TCPDF {
// swap X and Y coordinates (change page orientation)
$this->swapPageBoxCoordinates($this->page);
}
- $this->w = $this->wPt / $this->k;
- $this->h = $this->hPt / $this->k;
+ $this->w = ($this->wPt / $this->k);
+ $this->h = ($this->hPt / $this->k);
if ($this->empty_string($autopagebreak)) {
if (isset($this->AutoPageBreak)) {
$autopagebreak = $this->AutoPageBreak;
@@ -4083,13 +4134,28 @@ class TCPDF {
* @param $lw (string) header image logo width in mm
* @param $ht (string) string to print as title on document header
* @param $hs (string) string to print on document header
+ * @param $tc (array) RGB array color for text.
+ * @param $lc (array) RGB array color for line.
* @public
*/
- public function setHeaderData($ln='', $lw=0, $ht='', $hs='') {
+ public function setHeaderData($ln='', $lw=0, $ht='', $hs='', $tc=array(0,0,0), $lc=array(0,0,0)) {
$this->header_logo = $ln;
$this->header_logo_width = $lw;
$this->header_title = $ht;
$this->header_string = $hs;
+ $this->header_text_color = $tc;
+ $this->header_line_color = $lc;
+ }
+
+ /**
+ * Set footer data.
+ * @param $tc (array) RGB array color for text.
+ * @param $lc (array) RGB array color for line.
+ * @public
+ */
+ public function setFooterData($tc=array(0,0,0), $lc=array(0,0,0)) {
+ $this->footer_text_color = $tc;
+ $this->footer_line_color = $lc;
}
/**
@@ -4105,6 +4171,8 @@ class TCPDF {
$ret['logo_width'] = $this->header_logo_width;
$ret['title'] = $this->header_title;
$ret['string'] = $this->header_string;
+ $ret['text_color'] = $this->header_text_color;
+ $ret['line_color'] = $this->header_line_color;
return $ret;
}
@@ -4238,7 +4306,7 @@ class TCPDF {
$header_x = $this->original_lMargin + ($headerdata['logo_width'] * 1.1);
}
$cw = $this->w - $this->original_lMargin - $this->original_rMargin - ($headerdata['logo_width'] * 1.1);
- $this->SetTextColor(0, 0, 0);
+ $this->SetTextColorArray($this->header_text_color);
// header title
$this->SetFont($headerfont[0], 'B', $headerfont[2] + 1);
$this->SetX($header_x);
@@ -4248,7 +4316,7 @@ class TCPDF {
$this->SetX($header_x);
$this->MultiCell($cw, $cell_height, $headerdata['string'], 0, '', 0, 1, '', '', true, 0, false, true, 0, 'T', false);
// print an ending header line
- $this->SetLineStyle(array('width' => 0.85 / $this->k, 'cap' => 'butt', 'join' => 'miter', 'dash' => 0, 'color' => array(0, 0, 0)));
+ $this->SetLineStyle(array('width' => 0.85 / $this->k, 'cap' => 'butt', 'join' => 'miter', 'dash' => 0, 'color' => $headerdata['line_color']));
$this->SetY((2.835 / $this->k) + max($imgy, $this->y));
if ($this->rtl) {
$this->SetX($this->original_rMargin);
@@ -4284,10 +4352,10 @@ class TCPDF {
*/
public function Footer() {
$cur_y = $this->y;
- $this->SetTextColor(0, 0, 0);
+ $this->SetTextColorArray($this->footer_text_color);
//set style for cell border
- $line_width = 0.85 / $this->k;
- $this->SetLineStyle(array('width' => $line_width, 'cap' => 'butt', 'join' => 'miter', 'dash' => 0, 'color' => array(0, 0, 0)));
+ $line_width = (0.85 / $this->k);
+ $this->SetLineStyle(array('width' => $line_width, 'cap' => 'butt', 'join' => 'miter', 'dash' => 0, 'color' => $this->footer_line_color));
//print document barcode
$barcode = $this->getBarcode();
if (!empty($barcode)) {
@@ -4919,9 +4987,9 @@ class TCPDF {
}
/**
- * Returns the length of the char in user unit for the current font considering current stretching and spacing (tracking/kerning).
+ * Returns the length of the char in user unit for the current font considering current stretching and spacing (tracking).
* @param $char (int) The char code whose length is to be returned
- * @param $notlast (boolean) set to false for the latest character on string, true otherwise (default)
+ * @param $notlast (boolean) If false ignore the font-spacing.
* @return float char width
* @author Nicola Asuni
* @public
@@ -4930,7 +4998,7 @@ class TCPDF {
public function GetCharWidth($char, $notlast=true) {
// get raw width
$chw = $this->getRawCharWidth($char);
- if (($this->font_spacing != 0) AND $notlast) {
+ if (($this->font_spacing < 0) OR (($this->font_spacing > 0) AND $notlast)) {
// increase/decrease font spacing
$chw += $this->font_spacing;
}
@@ -5400,7 +5468,7 @@ class TCPDF {
}
/**
- * Return the font ascent value
+ * Return the font ascent value.
* @param $font (string) font name
* @param $style (string) font style
* @param $size (float) The size (in points)
@@ -5421,7 +5489,7 @@ class TCPDF {
}
/**
- * Return the font descent value
+ * Return true in the character is present in the specified font.
* @param $char (mixed) Character to check (integer value or string)
* @param $font (string) Font name (family name).
* @param $style (string) Font style.
@@ -5436,6 +5504,9 @@ class TCPDF {
$char = $char[0];
}
if ($this->empty_string($font)) {
+ if ($this->empty_string($style)) {
+ return (isset($this->CurrentFont['cw'][intval($char)]));
+ }
$font = $this->FontFamily;
}
$fontdata = $this->AddFont($font, $style);
@@ -5828,6 +5899,35 @@ class TCPDF {
}
}
$this->checkPageBreak($h + $this->cell_margin['T'] + $this->cell_margin['B']);
+ // apply text shadow if enabled
+ if ($this->txtshadow['enabled']) {
+ // save data
+ $x = $this->x;
+ $y = $this->y;
+ $bc = $this->bgcolor;
+ $fc = $this->fgcolor;
+ $sc = $this->strokecolor;
+ $alpha = $this->alpha;
+ // print shadow
+ $this->x += $this->txtshadow['depth_w'];
+ $this->y += $this->txtshadow['depth_h'];
+ $this->SetFillColorArray($this->txtshadow['color']);
+ $this->SetTextColorArray($this->txtshadow['color']);
+ $this->SetDrawColorArray($this->txtshadow['color']);
+ if ($this->txtshadow['opacity'] != $alpha['CA']) {
+ $this->setAlpha($this->txtshadow['opacity'], $this->txtshadow['blend_mode']);
+ }
+ $this->_out($this->getCellCode($w, $h, $txt, $border, $ln, $align, $fill, $link, $stretch, true, $calign, $valign));
+ //restore data
+ $this->x = $x;
+ $this->y = $y;
+ $this->SetFillColorArray($bc);
+ $this->SetTextColorArray($fc);
+ $this->SetDrawColorArray($sc);
+ if ($this->txtshadow['opacity'] != $alpha['CA']) {
+ $this->setAlpha($alpha['CA'], $alpha['BM'], $alpha['ca'], $alpha['AIS']);
+ }
+ }
$this->_out($this->getCellCode($w, $h, $txt, $border, $ln, $align, $fill, $link, $stretch, true, $calign, $valign));
$this->cell_padding = $prev_cell_padding;
$this->cell_margin = $prev_cell_margin;
@@ -6023,34 +6123,97 @@ class TCPDF {
} else {
$unicode = $this->UTF8StringToArray($txt); // array of UTF-8 unicode values
$unicode = $this->utf8Bidi($unicode, '', $this->tmprtl);
+ // replace thai chars (if any)
if (defined('K_THAI_TOPCHARS') AND (K_THAI_TOPCHARS == true)) {
- // ---- Fix for bug #2977340 "Incorrect Thai characters position arrangement" ----
- // NOTE: this doesn't work with HTML justification
- // Symbols that could overlap on the font top (only works in LTR)
- $topchar = array(3611, 3613, 3615, 3650, 3651, 3652); // chars that extends on top
- $topsym = array(3633, 3636, 3637, 3638, 3639, 3655, 3656, 3657, 3658, 3659, 3660, 3661, 3662); // symbols with top position
- $numchars = count($unicode); // number of chars
- $unik = 0;
- $uniblock = array();
- $uniblock[$unik] = array();
- $uniblock[$unik][] = $unicode[0];
- // resolve overlapping conflicts by splitting the string in several parts
- for ($i = 1; $i < $numchars; ++$i) {
- // check if symbols overlaps at top
- if (in_array($unicode[$i], $topsym) AND (in_array($unicode[($i - 1)], $topsym) OR in_array($unicode[($i - 1)], $topchar))) {
- // move symbols to another array
- ++$unik;
- $uniblock[$unik] = array();
- $uniblock[$unik][] = $unicode[$i];
- ++$unik;
- $uniblock[$unik] = array();
- $unicode[$i] = 0x200b; // Unicode Character 'ZERO WIDTH SPACE' (DEC:8203, U+200B)
+ // number of chars
+ $numchars = count($unicode);
+ // po pla, for far, for fan
+ $longtail = array(0x0e1b, 0x0e1d, 0x0e1f);
+ // do chada, to patak
+ $lowtail = array(0x0e0e, 0x0e0f);
+ // mai hun arkad, sara i, sara ii, sara ue, sara uee
+ $upvowel = array(0x0e31, 0x0e34, 0x0e35, 0x0e36, 0x0e37);
+ // mai ek, mai tho, mai tri, mai chattawa, karan
+ $tonemark = array(0x0e48, 0x0e49, 0x0e4a, 0x0e4b, 0x0e4c);
+ // sara u, sara uu, pinthu
+ $lowvowel = array(0x0e38, 0x0e39, 0x0e3a);
+ $output = array();
+ for ($i = 0; $i < $numchars; $i++) {
+ if (($unicode[$i] >= 0x0e00) && ($unicode[$i] <= 0x0e5b)) {
+ $ch0 = $unicode[$i];
+ $ch1 = ($i > 0) ? $unicode[($i - 1)] : 0;
+ $ch2 = ($i > 1) ? $unicode[($i - 2)] : 0;
+ $chn = ($i < ($numchars - 1)) ? $unicode[($i + 1)] : 0;
+ if (in_array($ch0, $tonemark)) {
+ if ($chn == 0x0e33) {
+ // sara um
+ if (in_array($ch1, $longtail)) {
+ // tonemark at upper left
+ $output[] = $this->replaceChar($ch0, (0xf713 + $ch0 - 0x0e48));
+ } else {
+ // tonemark at upper right (normal position)
+ $output[] = $ch0;
+ }
+ } elseif (in_array($ch1, $longtail) OR (in_array($ch2, $longtail) AND in_array($ch1, $lowvowel))) {
+ // tonemark at lower left
+ $output[] = $this->replaceChar($ch0, (0xf705 + $ch0 - 0x0e48));
+ } elseif (in_array($ch1, $upvowel)) {
+ if (in_array($ch2, $longtail)) {
+ // tonemark at upper left
+ $output[] = $this->replaceChar($ch0, (0xf713 + $ch0 - 0x0e48));
+ } else {
+ // tonemark at upper right (normal position)
+ $output[] = $ch0;
+ }
+ } else {
+ // tonemark at lower right
+ $output[] = $this->replaceChar($ch0, (0xf70a + $ch0 - 0x0e48));
+ }
+ } elseif (($ch0 == 0x0e33) AND (in_array($ch1, $longtail) OR (in_array($ch2, $longtail) AND in_array($ch1, $tonemark)))) {
+ // add lower left nikhahit and sara aa
+ if ($this->isCharDefined(0xf711) AND $this->isCharDefined(0x0e32)) {
+ $output[] = 0xf711;
+ $this->CurrentFont['subsetchars'][0xf711] = true;
+ $output[] = 0x0e32;
+ $this->CurrentFont['subsetchars'][0x0e32] = true;
+ } else {
+ $output[] = $ch0;
+ }
+ } elseif (in_array($ch1, $longtail)) {
+ if ($ch0 == 0x0e31) {
+ // lower left mai hun arkad
+ $output[] = $this->replaceChar($ch0, 0xf710);
+ } elseif (in_array($ch0, $upvowel)) {
+ // lower left
+ $output[] = $this->replaceChar($ch0, (0xf701 + $ch0 - 0x0e34));
+ } elseif ($ch0 == 0x0e47) {
+ // lower left mai tai koo
+ $output[] = $this->replaceChar($ch0, 0xf712);
+ } else {
+ // normal character
+ $output[] = $ch0;
+ }
+ } elseif (in_array($ch1, $lowtail) AND in_array($ch0, $lowvowel)) {
+ // lower vowel
+ $output[] = $this->replaceChar($ch0, (0xf718 + $ch0 - 0x0e38));
+ } elseif (($ch0 == 0x0e0d) AND in_array($chn, $lowvowel)) {
+ // yo ying without lower part
+ $output[] = $this->replaceChar($ch0, 0xf70f);
+ } elseif (($ch0 == 0x0e10) AND in_array($chn, $lowvowel)) {
+ // tho santan without lower part
+ $output[] = $this->replaceChar($ch0, 0xf700);
+ } else {
+ $output[] = $ch0;
+ }
} else {
- $uniblock[$unik][] = $unicode[$i];
+ // non-thai character
+ $output[] = $unicode[$i];
}
}
- // ---- END OF Fix for bug #2977340
- }
+ $unicode = $output;
+ // update font subsetchars
+ $this->setFontSubBuffer($this->CurrentFont['fontkey'], 'subsetchars', $this->CurrentFont['subsetchars']);
+ } // end of K_THAI_TOPCHARS
$txt2 = $this->arrUTF8ToUTF16BE($unicode, false);
}
}
@@ -6094,7 +6257,7 @@ class TCPDF {
$s .= 'q '.$this->TextColor.' ';
}
// rendering mode
- $s .= sprintf('BT %d Tr %F w ET ', $this->textrendermode, $this->textstrokewidth);
+ $s .= sprintf('BT %d Tr %F w ET ', $this->textrendermode, ($this->textstrokewidth * $this->k));
// count number of spaces
$ns = substr_count($txt, chr(32));
// Justification
@@ -6250,6 +6413,25 @@ class TCPDF {
return $rs;
}
+ /**
+ * Replace a char if is defined on the current font.
+ * @param $oldchar (int) Integer code (unicode) of the character to replace.
+ * @param $newchar (int) Integer code (unicode) of the new character.
+ * @return int the replaced char or the old char in case the new char i not defined
+ * @protected
+ * @since 5.9.167 (2012-06-22)
+ */
+ protected function replaceChar($oldchar, $newchar) {
+ if ($this->isCharDefined($newchar)) {
+ // add the new char on the subset list
+ $this->CurrentFont['subsetchars'][$newchar] = true;
+ // return the new character
+ return $newchar;
+ }
+ // return the old char
+ return $oldchar;
+ }
+
/**
* Returns the code to draw the cell border
* @param $x (float) X coordinate.
@@ -7069,7 +7251,7 @@ class TCPDF {
$w = $this->w - $this->rMargin - $this->x;
}
// max column width
- $wmax = $w - $wadj;
+ $wmax = ($w - $wadj);
if (!$firstline) {
$wmax -= ($this->cell_padding['L'] + $this->cell_padding['R']);
}
@@ -7155,18 +7337,27 @@ class TCPDF {
$this->rMargin += $margin['R'];
}
$w = $this->getRemainingWidth();
- $wmax = $w - $this->cell_padding['L'] - $this->cell_padding['R'];
+ $wmax = ($w - $this->cell_padding['L'] - $this->cell_padding['R']);
} else {
// 160 is the non-breaking space.
// 173 is SHY (Soft Hypen).
// \p{Z} or \p{Separator}: any kind of Unicode whitespace or invisible separator.
// \p{Lo} or \p{Other_Letter}: a Unicode letter or ideograph that does not have lowercase and uppercase variants.
// \p{Lo} is needed because Chinese characters are packed next to each other without spaces in between.
- if (($c != 160) AND (($c == 173) OR preg_match($this->re_spaces, $this->unichr($c)))) {
+ if (($c != 160)
+ AND (($c == 173)
+ OR preg_match($this->re_spaces, $this->unichr($c))
+ OR (($c == 45)
+ AND ($i < ($nb - 1))
+ AND @preg_match('/[\p{L}]/'.$this->re_space['m'], $this->unichr($pc))
+ AND @preg_match('/[\p{L}]/'.$this->re_space['m'], $this->unichr($chars[($i + 1)]))
+ )
+ )
+ ) {
// update last blank space position
$sep = $i;
// check if is a SHY
- if ($c == 173) {
+ if (($c == 173) OR ($c == 45)) {
$shy = true;
if ($pc == 45) {
$tmp_shy_replacement_width = 0;
@@ -7191,8 +7382,8 @@ class TCPDF {
// we have reached the end of column
if ($sep == -1) {
// check if the line was already started
- if (($this->rtl AND ($this->x <= ($this->w - $this->rMargin - $chrwidth)))
- OR ((!$this->rtl) AND ($this->x >= ($this->lMargin + $chrwidth)))) {
+ if (($this->rtl AND ($this->x <= ($this->w - $this->rMargin - $this->cell_padding['R'] - $margin['R'] - $chrwidth)))
+ OR ((!$this->rtl) AND ($this->x >= ($this->lMargin + $this->cell_padding['L'] + $margin['L'] + $chrwidth)))) {
// print a void cell and go to next line
$this->Cell($w, $h, '', 0, 1);
$linebreak = true;
@@ -7255,9 +7446,9 @@ class TCPDF {
$linew = $this->GetArrStringWidth($tmparr);
unset($tmparr);
if ($this->rtl) {
- $this->endlinex = $startx - $linew;
+ $this->endlinex = ($startx - $linew);
} else {
- $this->endlinex = $startx + $linew;
+ $this->endlinex = ($startx + $linew);
}
$w = $linew;
$tmpcellpadding = $this->cell_padding;
@@ -7320,6 +7511,9 @@ class TCPDF {
$this->Cell($w, $h, $shy_char_left.$tmpstr.$shy_char_right, 0, 1, $align, $fill, $link, $stretch);
unset($tmpstr);
if ($firstline) {
+ if ($chars[$sep] == 45) {
+ $endspace += 1;
+ }
// return the remaining text
$this->cell_padding = $tmpcellpadding;
return ($this->UniArrSubString($uchars, ($sep + $endspace)));
@@ -7327,7 +7521,7 @@ class TCPDF {
$i = $sep;
$sep = -1;
$shy = false;
- $j = ($i+1);
+ $j = ($i + 1);
}
}
// account for margin changes
@@ -7661,7 +7855,7 @@ class TCPDF {
if ($file[0] === '@') {
// image from string
$imgdata = substr($file, 1);
- $file = K_PATH_CACHE.'img_'.md5($imgdata);
+ $file = $this->getObjFilename('img');
$fp = fopen($file, 'w');
fwrite($fp, $imgdata);
fclose($fp);
@@ -7697,7 +7891,9 @@ class TCPDF {
curl_setopt($cs, CURLOPT_BINARYTRANSFER, true);
curl_setopt($cs, CURLOPT_FAILONERROR, true);
curl_setopt($cs, CURLOPT_RETURNTRANSFER, true);
- curl_setopt($cs, CURLOPT_FOLLOWLOCATION, true);
+ if ((ini_get('open_basedir') == '') AND (ini_get('safe_mode') == 'Off')) {
+ curl_setopt($cs, CURLOPT_FOLLOWLOCATION, true);
+ }
curl_setopt($cs, CURLOPT_CONNECTTIMEOUT, 5);
curl_setopt($cs, CURLOPT_TIMEOUT, 30);
curl_setopt($cs, CURLOPT_SSL_VERIFYPEER, false);
@@ -7707,7 +7903,7 @@ class TCPDF {
curl_close($cs);
if ($imgdata !== FALSE) {
// copy image to cache
- $file = K_PATH_CACHE.'img_'.md5($imgdata);
+ $file = $this->getObjFilename('img');
$fp = fopen($file, 'w');
fwrite($fp, $imgdata);
fclose($fp);
@@ -7738,7 +7934,7 @@ class TCPDF {
}
}
// file hash
- $filehash = md5($file);
+ $filehash = md5($this->file_id.$file);
// get original image width and height in pixels
list($pixw, $pixh) = $imsize;
// calculate image width and height on document
@@ -8320,11 +8516,13 @@ class TCPDF {
$data .= $this->rfread($f, $n);
fread($f, 4);
} elseif ($type == 'iCCP') {
- // skip profile name and null separator
+ // skip profile name
$len = 0;
while ((ord(fread($f, 1)) > 0) AND ($len < 80)) {
++$len;
}
+ // skip null separator
+ fread($f, 1);
// get compression method
if (ord(fread($f, 1)) != 0) {
//$this->Error('Unknown filter method: '.$file);
@@ -8396,7 +8594,7 @@ class TCPDF {
*/
protected function ImagePngAlpha($file, $x, $y, $wpx, $hpx, $w, $h, $type, $link, $align, $resize, $dpi, $palign, $filehash='') {
if (empty($filehash)) {
- $filehash = md5($file);
+ $filehash = md5($this->file_id.$file);
}
// create temp image file (without alpha channel)
$tempfile_plain = K_PATH_CACHE.'mskp_'.$filehash;
@@ -8407,7 +8605,7 @@ class TCPDF {
$img = new Imagick();
$img->readImage($file);
// clone image object
- $imga = $img->clone();
+ $imga = $this->objclone($img);
// extract alpha channel
$img->separateImageChannel(8); // 8 = (imagick::CHANNEL_ALPHA | imagick::CHANNEL_OPACITY | imagick::CHANNEL_MATTE);
$img->negateImage(true);
@@ -8429,9 +8627,7 @@ class TCPDF {
for ($xpx = 0; $xpx < $wpx; ++$xpx) {
for ($ypx = 0; $ypx < $hpx; ++$ypx) {
$color = imagecolorat($img, $xpx, $ypx);
- $alpha = ($color >> 24); // shifts off the first 24 bits (where 8x3 are used for each color), and returns the remaining 7 allocated bits (commonly used for alpha)
- $alpha = (((127 - $alpha) / 127) * 255); // GD alpha is only 7 bit (0 -> 127)
- $alpha = $this->getGDgamma($alpha); // correct gamma
+ $alpha = $this->getGDgamma($color); // correct gamma
imagesetpixel($imgalpha, $xpx, $ypx, $alpha);
}
}
@@ -8455,13 +8651,27 @@ class TCPDF {
}
/**
- * Correct the gamma value to be used with GD library
- * @param $v (float) the gamma value to be corrected
+ * Get the GD-corrected PNG gamma value from alpha color
+ * @param $c (int) alpha color
* @protected
* @since 4.3.007 (2008-12-04)
*/
- protected function getGDgamma($v) {
- return (pow(($v / 255), 2.2) * 255);
+ protected function getGDgamma($c) {
+ if (!isset($this->gdgammacache["'".$c."'"])) {
+ // shifts off the first 24 bits (where 8x3 are used for each color),
+ // and returns the remaining 7 allocated bits (commonly used for alpha)
+ $alpha = ($c >> 24);
+ // GD alpha is only 7 bit (0 -> 127)
+ $alpha = (((127 - $alpha) / 127) * 255);
+ // correct gamma
+ $this->gdgammacache["'".$c."'"] = (pow(($alpha / 255), 2.2) * 255);
+ // store the latest values on cache to improve performances
+ if (count($this->gdgammacache) > 8) {
+ // remove one element from the cache array
+ array_shift($this->gdgammacache);
+ }
+ }
+ return $this->gdgammacache["'".$c."'"];
}
/**
@@ -8736,7 +8946,7 @@ class TCPDF {
header('Pragma: public');
header('Expires: Sat, 26 Jul 1997 05:00:00 GMT'); // Date in the past
header('Last-Modified: '.gmdate('D, d M Y H:i:s').' GMT');
- header('Content-Disposition: inline; filename="'.basename($name).'";');
+ header('Content-Disposition: inline; filename="'.basename($name).'"');
$this->sendOutputData($this->getBuffer(), $this->bufferlen);
} else {
echo $this->getBuffer();
@@ -8767,7 +8977,7 @@ class TCPDF {
header('Content-Type: application/pdf');
}
// use the Content-Disposition header to supply a recommended filename
- header('Content-Disposition: attachment; filename="'.basename($name).'";');
+ header('Content-Disposition: attachment; filename="'.basename($name).'"');
header('Content-Transfer-Encoding: binary');
$this->sendOutputData($this->getBuffer(), $this->bufferlen);
break;
@@ -8794,7 +9004,7 @@ class TCPDF {
header('Pragma: public');
header('Expires: Sat, 26 Jul 1997 05:00:00 GMT'); // Date in the past
header('Last-Modified: '.gmdate('D, d M Y H:i:s').' GMT');
- header('Content-Disposition: inline; filename="'.basename($name).'";');
+ header('Content-Disposition: inline; filename="'.basename($name).'"');
$this->sendOutputData(file_get_contents($name), filesize($name));
} elseif ($dest == 'FD') {
// send headers to browser
@@ -8819,7 +9029,7 @@ class TCPDF {
header('Content-Type: application/pdf');
}
// use the Content-Disposition header to supply a recommended filename
- header('Content-Disposition: attachment; filename="'.basename($name).'";');
+ header('Content-Disposition: attachment; filename="'.basename($name).'"');
header('Content-Transfer-Encoding: binary');
$this->sendOutputData(file_get_contents($name), filesize($name));
}
@@ -9430,7 +9640,7 @@ class TCPDF {
if (isset($pl['opt']['be']) AND (is_array($pl['opt']['be']))) {
$annots .= ' /BE <<';
$bstyles = array('S', 'C');
- if (isset($pl['opt']['be']['s']) AND in_array($pl['opt']['be']['s'], $markups)) {
+ if (isset($pl['opt']['be']['s']) AND in_array($pl['opt']['be']['s'], $bstyles)) {
$annots .= ' /S /'.$pl['opt']['bs']['s'];
} else {
$annots .= ' /S /S';
@@ -9509,9 +9719,11 @@ class TCPDF {
$annots .= ' /A <_datastring($this->unhtmlentities($pl['txt']), $annot_obj_id).'>>';
} else {
// internal link
- $l = $this->links[$pl['txt']];
- if (isset($this->page_obj_id[($l[0])])) {
- $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)));
+ if (isset($this->links[$pl['txt']])) {
+ $l = $this->links[$pl['txt']];
+ if (isset($this->page_obj_id[($l[0])])) {
+ $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');
@@ -12855,11 +13067,14 @@ class TCPDF {
$this->_out('xref');
$this->_out('0 '.($this->n + 1));
$this->_out('0000000000 65535 f ');
+ $freegen = ($this->n + 2);
for ($i=1; $i <= $this->n; ++$i) {
if (!isset($this->offsets[$i]) AND ($i > 1)) {
- $this->offsets[$i] = $this->offsets[($i - 1)];
+ $this->_out(sprintf('0000000000 %05d f ', $freegen));
+ ++$freegen;
+ } else {
+ $this->_out(sprintf('%010d 00000 n ', $this->offsets[$i]));
}
- $this->_out(sprintf('%010d 00000 n ', $this->offsets[$i]));
}
// TRAILER
$out = 'trailer'."\n";
@@ -12899,6 +13114,7 @@ class TCPDF {
*/
protected function _beginpage($orientation='', $format='') {
++$this->page;
+ $this->pageobjects[$this->page] = array();
$this->setPageBuffer($this->page, '');
// initialize array for graphics tranformation positions inside a page buffer
$this->transfmrk[$this->page] = array();
@@ -12967,6 +13183,7 @@ class TCPDF {
$objid = $this->n;
}
$this->offsets[$objid] = $this->bufferlen;
+ $this->pageobjects[$this->page][] = $objid;
return $objid.' 0 obj';
}
@@ -15012,7 +15229,7 @@ class TCPDF {
* @since 2.1.000 (2008-01-08)
*/
protected function _outPoint($x, $y) {
- $this->_out(sprintf('%F %F m', $x * $this->k, ($this->h - $y) * $this->k));
+ $this->_out(sprintf('%F %F m', ($x * $this->k), (($this->h - $y) * $this->k)));
}
/**
@@ -15024,7 +15241,7 @@ class TCPDF {
* @since 2.1.000 (2008-01-08)
*/
protected function _outLine($x, $y) {
- $this->_out(sprintf('%F %F l', $x * $this->k, ($this->h - $y) * $this->k));
+ $this->_out(sprintf('%F %F l', ($x * $this->k), (($this->h - $y) * $this->k)));
}
/**
@@ -16404,12 +16621,13 @@ class TCPDF {
* @param $name (string) Destination name.
* @param $y (float) Y position in user units of the destiantion on the selected page (default = -1 = current position; 0 = page start;).
* @param $page (int) Target page number (leave empty for current page).
+ * @param $x (float) X position in user units of the destiantion on the selected page (default = -1 = current position;).
* @return (string) Stripped named destination identifier or false in case of error.
* @public
* @author Christian Deligant, Nicola Asuni
* @since 5.9.097 (2011-06-23)
*/
- public function setDestination($name, $y=-1, $page='') {
+ public function setDestination($name, $y=-1, $page='', $x=-1) {
// remove unsupported characters
$name = $this->encodeNameObject($name);
if ($this->empty_string($name)) {
@@ -16417,6 +16635,17 @@ class TCPDF {
}
if ($y == -1) {
$y = $this->GetY();
+ } elseif ($y < 0) {
+ $y = 0;
+ } elseif ($y > $this->h) {
+ $y = $this->h;
+ }
+ if ($x == -1) {
+ $x = $this->GetX();
+ } elseif ($x < 0) {
+ $x = 0;
+ } elseif ($x > $this->w) {
+ $x = $this->w;
}
if (empty($page)) {
$page = $this->PageNo();
@@ -16424,7 +16653,7 @@ class TCPDF {
return;
}
}
- $this->dests[$name] = array('y' => $y, 'p' => $page);
+ $this->dests[$name] = array('x' => $x, 'y' => $y, 'p' => $page);
return $name;
}
@@ -16452,7 +16681,7 @@ class TCPDF {
$this->n_dests = $this->_newobj();
$out = ' <<';
foreach($this->dests as $name => $o) {
- $out .= ' /'.$name.' '.sprintf('[%u 0 R /XYZ 0 %F null]', $this->page_obj_id[($o['p'])], ($this->pagedim[$o['p']]['h'] - ($o['y'] * $this->k)));
+ $out .= ' /'.$name.' '.sprintf('[%u 0 R /XYZ %F %F null]', $this->page_obj_id[($o['p'])], ($o['x'] * $this->k), ($this->pagedim[$o['p']]['h'] - ($o['y'] * $this->k)));
}
$out .= ' >>';
$out .= "\n".'endobj';
@@ -16481,11 +16710,12 @@ class TCPDF {
* @param $page (int) Target page number (leave empty for current page).
* @param $style (string) Font style: B = Bold, I = Italic, BI = Bold + Italic.
* @param $color (array) RGB color array (values from 0 to 255).
+ * @param $x (float) X position in user units of the bookmark on the selected page (default = -1 = current position;).
* @public
* @author Olivier Plathey, Nicola Asuni
* @since 2.1.002 (2008-02-12)
*/
- public function Bookmark($txt, $level=0, $y=-1, $page='', $style='', $color=array(0,0,0)) {
+ public function Bookmark($txt, $level=0, $y=-1, $page='', $style='', $color=array(0,0,0), $x=-1) {
if ($level < 0) {
$level = 0;
}
@@ -16500,6 +16730,17 @@ class TCPDF {
}
if ($y == -1) {
$y = $this->GetY();
+ } elseif ($y < 0) {
+ $y = 0;
+ } elseif ($y > $this->h) {
+ $y = $this->h;
+ }
+ if ($x == -1) {
+ $x = $this->GetX();
+ } elseif ($x < 0) {
+ $x = 0;
+ } elseif ($x > $this->w) {
+ $x = $this->w;
}
if (empty($page)) {
$page = $this->PageNo();
@@ -16507,7 +16748,7 @@ class TCPDF {
return;
}
}
- $this->outlines[] = array('t' => $txt, 'l' => $level, 'y' => $y, 'p' => $page, 's' => strtoupper($style), 'c' => $color);
+ $this->outlines[] = array('t' => $txt, 'l' => $level, 'x' => $x, 'y' => $y, 'p' => $page, 's' => strtoupper($style), 'c' => $color);
}
/**
@@ -16590,7 +16831,7 @@ class TCPDF {
$out .= ' /Last '.($n + $o['last']).' 0 R';
}
if (isset($this->page_obj_id[($o['p'])])) {
- $out .= ' '.sprintf('/Dest [%u 0 R /XYZ 0 %F null]', $this->page_obj_id[($o['p'])], ($this->pagedim[$o['p']]['h'] - ($o['y'] * $this->k)));
+ $out .= ' '.sprintf('/Dest [%u 0 R /XYZ %F %F null]', $this->page_obj_id[($o['p'])], ($o['x'] * $this->k), ($this->pagedim[$o['p']]['h'] - ($o['y'] * $this->k)));
}
// set font style
$style = 0;
@@ -19169,7 +19410,7 @@ class TCPDF {
*/
public function PieSectorXY($xc, $yc, $rx, $ry, $a, $b, $style='FD', $cw=false, $o=0, $nc=2) {
if ($this->rtl) {
- $xc = $this->w - $xc;
+ $xc = ($this->w - $xc);
}
$op = $this->getPathPaintOperator($style);
if ($op == 'f') {
@@ -19177,8 +19418,8 @@ class TCPDF {
}
if ($cw) {
$d = $b;
- $b = 360 - $a + $o;
- $a = 360 - $d + $o;
+ $b = (360 - $a + $o);
+ $a = (360 - $d + $o);
} else {
$b += $o;
$a += $o;
@@ -19578,7 +19819,7 @@ class TCPDF {
// create new barcode object
$barcodeobj = new TCPDFBarcode($code, $type);
$arrcode = $barcodeobj->getBarcodeArray();
- if ($arrcode === false) {
+ if (($arrcode === false) OR empty($arrcode) OR ($arrcode['maxw'] == 0)) {
$this->Error('Error in 1D barcode string');
}
// set default values
@@ -19949,7 +20190,7 @@ class TCPDF {
// create new barcode object
$barcodeobj = new TCPDF2DBarcode($code, $type);
$arrcode = $barcodeobj->getBarcodeArray();
- if (($arrcode === false) OR empty($arrcode)) {
+ if (($arrcode === false) OR empty($arrcode) OR !isset($arrcode['num_rows']) OR ($arrcode['num_rows'] == 0) OR !isset($arrcode['num_cols']) OR ($arrcode['num_cols'] == 0)) {
$this->Error('Error in 2D barcode string');
}
// set default values
@@ -20004,6 +20245,9 @@ class TCPDF {
// module width and height
$mw = $style['module_width'];
$mh = $style['module_height'];
+ if (($mw == 0) OR ($mh == 0)) {
+ $this->Error('Error in 2D barcode string');
+ }
// get max dimensions
if ($this->rtl) {
$maxw = $x - $this->lMargin;
@@ -20886,7 +21130,7 @@ class TCPDF {
/**
* Returns the letter-spacing value from CSS value
* @param $spacing (string) letter-spacing value
- * @param $parent (float) font spacing (tracking/kerning) value of the parent element
+ * @param $parent (float) font spacing (tracking) value of the parent element
* @return float quantity to increases or decreases the space between characters in a text.
* @protected
* @since 5.9.000 (2010-10-02)
@@ -21499,7 +21743,7 @@ class TCPDF {
}
if (isset($dom[$key]['style']['border-style'])) {
$brd_styles = preg_split('/[\s]+/', trim($dom[$key]['style']['border-style']));
- if (isset($brd_styles[3])) {
+ if (isset($brd_styles[3]) AND ($brd_styles[3]!='none')) {
$dom[$key]['border']['L']['cap'] = 'square';
$dom[$key]['border']['L']['join'] = 'miter';
$dom[$key]['border']['L']['dash'] = $this->getCSSBorderDashStyle($brd_styles[3]);
@@ -21834,7 +22078,7 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value:
$curfontascent = $this->getFontAscent($curfontname, $curfontstyle, $curfontsize);
$curfontdescent = $this->getFontDescent($curfontname, $curfontstyle, $curfontsize);
$curfontstretcing = $this->font_stretching;
- $curfontkerning = $this->font_spacing;
+ $curfonttracking = $this->font_spacing;
$this->newline = true;
$newline = true;
$startlinepage = $this->page;
@@ -21973,7 +22217,7 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value:
$this_method_vars['curfontascent'] = $curfontascent;
$this_method_vars['curfontdescent'] = $curfontdescent;
$this_method_vars['curfontstretcing'] = $curfontstretcing;
- $this_method_vars['curfontkerning'] = $curfontkerning;
+ $this_method_vars['curfonttracking'] = $curfonttracking;
$this_method_vars['minstartliney'] = $minstartliney;
$this_method_vars['maxbottomliney'] = $maxbottomliney;
$this_method_vars['yshift'] = $yshift;
@@ -23051,9 +23295,9 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value:
} else {
$wadj = 0; // space to leave for block continuity
if ($this->rtl) {
- $cwa = $this->x - $this->lMargin;
+ $cwa = ($this->x - $this->lMargin);
} else {
- $cwa = $this->w - $this->rMargin - $this->x;
+ $cwa = ($this->w - $this->rMargin - $this->x);
}
if (($strlinelen < $cwa) AND (isset($dom[($key + 1)])) AND ($dom[($key + 1)]['tag']) AND (!$dom[($key + 1)]['block'])) {
// check the next text blocks for continuity
@@ -23143,6 +23387,14 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value:
}
} else {
$loop = 0;
+ // add the positive font spacing of the last character (if any)
+ if ($this->font_spacing > 0) {
+ if ($this->rtl) {
+ $this->x -= $this->font_spacing;
+ } else {
+ $this->x += $this->font_spacing;
+ }
+ }
}
}
++$key;
@@ -23740,7 +23992,7 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value:
$value = $tag['attribute']['value'];
}
if (isset($tag['attribute']['maxlength']) AND !$this->empty_string($tag['attribute']['maxlength'])) {
- $opt['maxlen'] = intval($tag['attribute']['value']);
+ $opt['maxlen'] = intval($tag['attribute']['maxlength']);
}
$h = $this->FontSize * $this->cell_height_ratio;
if (isset($tag['attribute']['size']) AND !$this->empty_string($tag['attribute']['size'])) {
@@ -23786,14 +24038,23 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value:
break;
}
case 'checkbox': {
+ if (!isset($value)) {
+ break;
+ }
$this->CheckBox($name, $w, $checked, $prop, $opt, $value, '', '', false);
break;
}
case 'radio': {
+ if (!isset($value)) {
+ break;
+ }
$this->RadioButton($name, $w, $prop, $opt, $value, $checked, '', '', false);
break;
}
case 'submit': {
+ if (!isset($value)) {
+ $value = 'submit';
+ }
$w = $this->GetStringWidth($value) * 1.5;
$h *= 1.6;
$prop = array('lineWidth'=>1, 'borderStyle'=>'beveled', 'fillColor'=>array(196, 196, 196), 'strokeColor'=>array(255, 255, 255));
@@ -23810,6 +24071,9 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value:
break;
}
case 'reset': {
+ if (!isset($value)) {
+ $value = 'reset';
+ }
$w = $this->GetStringWidth($value) * 1.5;
$h *= 1.6;
$prop = array('lineWidth'=>1, 'borderStyle'=>'beveled', 'fillColor'=>array(196, 196, 196), 'strokeColor'=>array(255, 255, 255));
@@ -23855,6 +24119,9 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value:
break;
}
case 'button': {
+ if (!isset($value)) {
+ $value = ' ';
+ }
$w = $this->GetStringWidth($value) * 1.5;
$h *= 1.6;
$prop = array('lineWidth'=>1, 'borderStyle'=>'beveled', 'fillColor'=>array(196, 196, 196), 'strokeColor'=>array(255, 255, 255));
@@ -24328,13 +24595,10 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value:
if (end($this->transfmrk[$this->page]) !== false) {
$pagemarkkey = key($this->transfmrk[$this->page]);
$pagemark = $this->transfmrk[$this->page][$pagemarkkey];
- $this->transfmrk[$this->page][$pagemarkkey] += $offsetlen;
} elseif ($this->InFooter) {
$pagemark = $this->footerpos[$this->page];
- $this->footerpos[$this->page] += $offsetlen;
} else {
$pagemark = $this->intmrk[$this->page];
- $this->intmrk[$this->page] += $offsetlen;
}
$pagebuff = $this->getPageBuffer($this->page);
$pstart = substr($pagebuff, 0, $pagemark);
@@ -24738,17 +25002,14 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value:
if (end($this->transfmrk[$this->page]) !== false) {
$pagemarkkey = key($this->transfmrk[$this->page]);
$pagemark = $this->transfmrk[$this->page][$pagemarkkey];
- $this->transfmrk[$this->page][$pagemarkkey] += $offsetlen;
} elseif ($this->InFooter) {
$pagemark = $this->footerpos[$this->page];
- $this->footerpos[$this->page] += $offsetlen;
} else {
$pagemark = $this->intmrk[$this->page];
- $this->intmrk[$this->page] += $offsetlen;
}
$pagebuff = $this->getPageBuffer($this->page);
- $pstart = substr($pagebuff, 0, $this->bordermrk[$this->page]);
- $pend = substr($pagebuff, $this->bordermrk[$this->page]);
+ $pstart = substr($pagebuff, 0, $pagemark);
+ $pend = substr($pagebuff, $pagemark);
$this->setPageBuffer($this->page, $pstart.$ccode.$pend);
$this->bordermrk[$this->page] += $offsetlen;
$this->cntmrk[$this->page] += $offsetlen;
@@ -25278,6 +25539,7 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value:
'cell_height_ratio' => $this->cell_height_ratio,
'font_stretching' => $this->font_stretching,
'font_spacing' => $this->font_spacing,
+ 'alpha' => $this->alpha,
// extended
'lasth' => $this->lasth,
'tMargin' => $this->tMargin,
@@ -25337,6 +25599,7 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value:
$this->cell_height_ratio = $gvars['cell_height_ratio'];
$this->font_stretching = $gvars['font_stretching'];
$this->font_spacing = $gvars['font_spacing'];
+ $this->alpha = $gvars['alpha'];
if ($extended) {
// restore extended values
$this->lasth = $gvars['lasth'];
@@ -25651,6 +25914,7 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value:
$tmpintmrk = $this->intmrk[$frompage];
$tmpbordermrk = $this->bordermrk[$frompage];
$tmpcntmrk = $this->cntmrk[$frompage];
+ $tmppageobjects = $this->pageobjects[$frompage];
if (isset($this->footerpos[$frompage])) {
$tmpfooterpos = $this->footerpos[$frompage];
}
@@ -25686,6 +25950,7 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value:
$this->intmrk[$i] = $this->intmrk[$j];
$this->bordermrk[$i] = $this->bordermrk[$j];
$this->cntmrk[$i] = $this->cntmrk[$j];
+ $this->pageobjects[$i] = $this->pageobjects[$j];
if (isset($this->footerpos[$j])) {
$this->footerpos[$i] = $this->footerpos[$j];
} elseif (isset($this->footerpos[$i])) {
@@ -25720,6 +25985,7 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value:
$this->intmrk[$topage] = $tmpintmrk;
$this->bordermrk[$topage] = $tmpbordermrk;
$this->cntmrk[$topage] = $tmpcntmrk;
+ $this->pageobjects[$topage] = $tmppageobjects;
if (isset($tmpfooterpos)) {
$this->footerpos[$topage] = $tmpfooterpos;
} elseif (isset($this->footerpos[$topage])) {
@@ -25807,6 +26073,12 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value:
unset($this->intmrk[$page]);
unset($this->bordermrk[$page]);
unset($this->cntmrk[$page]);
+ foreach ($this->pageobjects[$page] as $oid) {
+ if (isset($this->offsets[$oid])){
+ unset($this->offsets[$oid]);
+ }
+ }
+ unset($this->pageobjects[$page]);
if (isset($this->footerpos[$page])) {
unset($this->footerpos[$page]);
}
@@ -25841,6 +26113,7 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value:
$this->intmrk[$i] = $this->intmrk[$j];
$this->bordermrk[$i] = $this->bordermrk[$j];
$this->cntmrk[$i] = $this->cntmrk[$j];
+ $this->pageobjects[$i] = $this->pageobjects[$j];
if (isset($this->footerpos[$j])) {
$this->footerpos[$i] = $this->footerpos[$j];
} elseif (isset($this->footerpos[$i])) {
@@ -25881,6 +26154,12 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value:
unset($this->intmrk[$this->numpages]);
unset($this->bordermrk[$this->numpages]);
unset($this->cntmrk[$this->numpages]);
+ foreach ($this->pageobjects[$this->numpages] as $oid) {
+ if (isset($this->offsets[$oid])){
+ unset($this->offsets[$oid]);
+ }
+ }
+ unset($this->pageobjects[$this->numpages]);
if (isset($this->footerpos[$this->numpages])) {
unset($this->footerpos[$this->numpages]);
}
@@ -25982,6 +26261,7 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value:
$this->intmrk[$this->page] = $this->intmrk[$page];
$this->bordermrk[$this->page] = $this->bordermrk[$page];
$this->cntmrk[$this->page] = $this->cntmrk[$page];
+ $this->pageobjects[$this->page] = $this->pageobjects[$page];
$this->pageopen[$this->page] = false;
if (isset($this->footerpos[$page])) {
$this->footerpos[$this->page] = $this->footerpos[$page];
@@ -26007,7 +26287,7 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value:
$tmpoutlines = $this->outlines;
foreach ($tmpoutlines as $key => $outline) {
if ($outline['p'] == $page) {
- $this->outlines[] = array('t' => $outline['t'], 'l' => $outline['l'], 'y' => $outline['y'], 'p' => $this->page, 's' => $outline['s'], 'c' => $outline['c']);
+ $this->outlines[] = array('t' => $outline['t'], 'l' => $outline['l'], 'x' => $outline['x'], 'y' => $outline['y'], 'p' => $this->page, 's' => $outline['s'], 'c' => $outline['c']);
}
}
// copy links
@@ -26695,7 +26975,59 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value:
}
}
$this->textrendermode = $textrendermode;
- $this->textstrokewidth = $stroke * $this->k;
+ $this->textstrokewidth = $stroke;
+ }
+
+ /**
+ * Set parameters for drop shadow effect for text.
+ * @param $params (array) Array of parameters: enabled (boolean) set to true to enable shadow; depth_w (float) shadow width in user units; depth_h (float) shadow height in user units; color (array) shadow color or false to use the stroke color; opacity (float) Alpha value: real value from 0 (transparent) to 1 (opaque); blend_mode (string) blend mode, one of the following: Normal, Multiply, Screen, Overlay, Darken, Lighten, ColorDodge, ColorBurn, HardLight, SoftLight, Difference, Exclusion, Hue, Saturation, Color, Luminosity.
+ * @since 5.9.174 (2012-07-25)
+ * @public
+ */
+ public function setTextShadow($params=array('enabled'=>false, 'depth_w'=>0, 'depth_h'=>0, 'color'=>false, 'opacity'=>1, 'blend_mode'=>'Normal')) {
+ if (isset($params['enabled'])) {
+ $this->txtshadow['enabled'] = $params['enabled']?true:false;
+ } else {
+ $this->txtshadow['enabled'] = false;
+ }
+ if (isset($params['depth_w'])) {
+ $this->txtshadow['depth_w'] = floatval($params['depth_w']);
+ } else {
+ $this->txtshadow['depth_w'] = 0;
+ }
+ if (isset($params['depth_h'])) {
+ $this->txtshadow['depth_h'] = floatval($params['depth_h']);
+ } else {
+ $this->txtshadow['depth_h'] = 0;
+ }
+ if (isset($params['color']) AND ($params['color'] !== false) AND is_array($params['color'])) {
+ $this->txtshadow['color'] = $params['color'];
+ } else {
+ $this->txtshadow['color'] = $this->strokecolor;
+ }
+ if (isset($params['opacity'])) {
+ $this->txtshadow['opacity'] = min(1, max(0, floatval($params['opacity'])));
+ } else {
+ $this->txtshadow['opacity'] = 1;
+ }
+ if (isset($params['blend_mode']) AND in_array($params['blend_mode'], array('Normal', 'Multiply', 'Screen', 'Overlay', 'Darken', 'Lighten', 'ColorDodge', 'ColorBurn', 'HardLight', 'SoftLight', 'Difference', 'Exclusion', 'Hue', 'Saturation', 'Color', 'Luminosity'))) {
+ $this->txtshadow['blend_mode'] = $params['blend_mode'];
+ } else {
+ $this->txtshadow['blend_mode'] = 'Normal';
+ }
+ if ((($this->txtshadow['depth_w'] == 0) AND ($this->txtshadow['depth_h'] == 0)) OR ($this->txtshadow['opacity'] == 0)) {
+ $this->txtshadow['enabled'] = false;
+ }
+ }
+
+ /**
+ * Return the text shadow parameters array.
+ * @return Array of parameters.
+ * @since 5.9.174 (2012-07-25)
+ * @public
+ */
+ public function getTextShadow() {
+ return $this->txtshadow;
}
/**
@@ -27337,7 +27669,7 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value:
/**
* Get the amount to increase or decrease the space between characters in a text.
- * @return int font spacing (tracking/kerning) value
+ * @return int font spacing (tracking) value
* @author Nicola Asuni
* @public
* @since 5.9.000 (2010-09-29)
@@ -27741,7 +28073,7 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value:
// scale and translate
$e = $ox * $this->k * (1 - $svgscale_x);
$f = ($this->h - $oy) * $this->k * (1 - $svgscale_y);
- $this->_out(sprintf('%F %F %F %F %F %F cm', $svgscale_x, 0, 0, $svgscale_y, $e + $svgoffset_x, $f + $svgoffset_y));
+ $this->_out(sprintf('%F %F %F %F %F %F cm', $svgscale_x, 0, 0, $svgscale_y, ($e + $svgoffset_x), ($f + $svgoffset_y)));
// creates a new XML parser to be used by the other XML functions
$this->parser = xml_parser_create('UTF-8');
// the following function allows to use parser inside object
@@ -28089,10 +28421,10 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value:
$gradient['coords'][3] += $y;
}
// calculate percentages
- $gradient['coords'][0] = ($gradient['coords'][0] - $x) / $w;
- $gradient['coords'][1] = ($gradient['coords'][1] - $y) / $h;
- $gradient['coords'][2] = ($gradient['coords'][2] - $x) / $w;
- $gradient['coords'][3] = ($gradient['coords'][3] - $y) / $h;
+ $gradient['coords'][0] = (($gradient['coords'][0] - $x) / $w);
+ $gradient['coords'][1] = (($gradient['coords'][1] - $y) / $h);
+ $gradient['coords'][2] = (($gradient['coords'][2] - $x) / $w);
+ $gradient['coords'][3] = (($gradient['coords'][3] - $y) / $h);
if (isset($gradient['coords'][4])) {
$gradient['coords'][4] /= $w;
}
@@ -28121,9 +28453,9 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value:
if ($gradient['type'] == 3) {
// circular gradient
$cy = $this->h - $y - ($gradient['coords'][1] * ($w + $h));
- $this->_out(sprintf('%F 0 0 %F %F %F cm', $w*$this->k, $w*$this->k, $x*$this->k, $cy*$this->k));
+ $this->_out(sprintf('%F 0 0 %F %F %F cm', ($w * $this->k), ($w * $this->k), ($x * $this->k), ($cy * $this->k)));
} else {
- $this->_out(sprintf('%F 0 0 %F %F %F cm', $w*$this->k, $h*$this->k, $x*$this->k, ($this->h-($y+$h))*$this->k));
+ $this->_out(sprintf('%F 0 0 %F %F %F cm', ($w * $this->k), ($h * $this->k), ($x * $this->k), (($this->h - ($y + $h)) * $this->k)));
}
if (count($gradient['stops']) > 1) {
$this->Gradient($gradient['type'], $gradient['coords'], $gradient['stops'], array(), false);
@@ -28331,6 +28663,8 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value:
} else {
$this->_outLine($x, $y);
}
+ $x0 = $x;
+ $y0 = $y;
}
$xmin = min($xmin, $x);
$ymin = min($ymin, $y);
@@ -28352,6 +28686,8 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value:
$y = $cp + $yoffset;
if ((abs($x0 - $x) >= $minlen) OR (abs($y0 - $y) >= $minlen)) {
$this->_outLine($x, $y);
+ $x0 = $x;
+ $y0 = $y;
}
$xmin = min($xmin, $x);
$ymin = min($ymin, $y);
@@ -28370,6 +28706,8 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value:
$x = $cp + $xoffset;
if ((abs($x0 - $x) >= $minlen) OR (abs($y0 - $y) >= $minlen)) {
$this->_outLine($x, $y);
+ $x0 = $x;
+ $y0 = $y;
}
$xmin = min($xmin, $x);
$xmax = max($xmax, $x);
@@ -28384,6 +28722,8 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value:
$y = $cp + $yoffset;
if ((abs($x0 - $x) >= $minlen) OR (abs($y0 - $y) >= $minlen)) {
$this->_outLine($x, $y);
+ $x0 = $x;
+ $y0 = $y;
}
$ymin = min($ymin, $y);
$ymax = max($ymax, $y);
@@ -28661,6 +29001,10 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value:
// get styling properties
$prev_svgstyle = $this->svgstyles[(count($this->svgstyles) - 1)]; // previous style
$svgstyle = $this->svgstyles[0]; // set default style
+ if ($clipping AND !isset($attribs['fill']) AND (!isset($attribs['style']) OR (!preg_match('/[;\"\s]{1}fill[\s]*:[\s]*([^;\"]*)/si', $attribs['style'], $attrval)))) {
+ // default fill attribute for clipping
+ $attribs['fill'] = 'none';
+ }
if (isset($attribs['style']) AND !$this->empty_string($attribs['style'])) {
// fix style for regular expression
$attribs['style'] = ';'.$attribs['style'];
@@ -28693,7 +29037,8 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value:
if (!empty($ctm)) {
$tm = $ctm;
} else {
- $tm = $this->svgstyles[(count($this->svgstyles) - 1)]['transfmatrix'];
+ //$tm = $this->svgstyles[(count($this->svgstyles) - 1)]['transfmatrix'];
+ $tm = array(1,0,0,1,0,0);
}
if (isset($attribs['transform']) AND !empty($attribs['transform'])) {
$tm = $this->getTransformationMatrixProduct($tm, $this->getSVGTransformMatrix($attribs['transform']));
@@ -28732,6 +29077,7 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value:
// group together related graphics elements
array_push($this->svgstyles, $svgstyle);
$this->StartTransform();
+ $this->SVGTransform($tm);
$this->setSVGStyles($svgstyle, $prev_svgstyle);
break;
}
@@ -28752,15 +29098,19 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value:
$this->svggradients[$this->svggradientid]['gradientUnits'] = 'objectBoundingBox';
}
//$attribs['spreadMethod']
- $x1 = (isset($attribs['x1'])?$attribs['x1']:'0%');
- $y1 = (isset($attribs['y1'])?$attribs['y1']:'0%');
- $x2 = (isset($attribs['x2'])?$attribs['x2']:'100%');
- $y2 = (isset($attribs['y2'])?$attribs['y2']:'0%');
- if (substr($x1, -1) != '%') {
- $this->svggradients[$this->svggradientid]['mode'] = 'measure';
- } else {
+ if (((!isset($attribs['x1'])) AND (!isset($attribs['y1'])) AND (!isset($attribs['x2'])) AND (!isset($attribs['y2'])))
+ OR ((isset($attribs['x1']) AND (substr($attribs['x1'], -1) == '%'))
+ OR (isset($attribs['y1']) AND (substr($attribs['y1'], -1) == '%'))
+ OR (isset($attribs['x2']) AND (substr($attribs['x2'], -1) == '%'))
+ OR (isset($attribs['y2']) AND (substr($attribs['y2'], -1) == '%')))) {
$this->svggradients[$this->svggradientid]['mode'] = 'percentage';
+ } else {
+ $this->svggradients[$this->svggradientid]['mode'] = 'measure';
}
+ $x1 = (isset($attribs['x1'])?$attribs['x1']:'0');
+ $y1 = (isset($attribs['y1'])?$attribs['y1']:'0');
+ $x2 = (isset($attribs['x2'])?$attribs['x2']:'100');
+ $y2 = (isset($attribs['y2'])?$attribs['y2']:'0');
if (isset($attribs['gradientTransform'])) {
$this->svggradients[$this->svggradientid]['gradientTransform'] = $this->getSVGTransformMatrix($attribs['gradientTransform']);
}
@@ -28788,16 +29138,18 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value:
$this->svggradients[$this->svggradientid]['gradientUnits'] = 'objectBoundingBox';
}
//$attribs['spreadMethod']
- $cx = (isset($attribs['cx'])?$attribs['cx']:0.5);
- $cy = (isset($attribs['cy'])?$attribs['cy']:0.5);
- $fx = (isset($attribs['fx'])?$attribs['fx']:$cx);
- $fy = (isset($attribs['fy'])?$attribs['fy']:$cy);
- $r = (isset($attribs['r'])?$attribs['r']:0.5);
- if (isset($attribs['cx']) AND (substr($attribs['cx'], -1) != '%')) {
- $this->svggradients[$this->svggradientid]['mode'] = 'measure';
- } else {
+ if (((!isset($attribs['cx'])) AND (!isset($attribs['cy'])))
+ OR ((isset($attribs['cx']) AND (substr($attribs['cx'], -1) == '%'))
+ OR (isset($attribs['cy']) AND (substr($attribs['cy'], -1) == '%')) )) {
$this->svggradients[$this->svggradientid]['mode'] = 'percentage';
+ } else {
+ $this->svggradients[$this->svggradientid]['mode'] = 'measure';
}
+ $cx = (isset($attribs['cx']) ? $attribs['cx'] : 0.5);
+ $cy = (isset($attribs['cy']) ? $attribs['cy'] : 0.5);
+ $fx = (isset($attribs['fx']) ? $attribs['fx'] : $cx);
+ $fy = (isset($attribs['fy']) ? $attribs['fy'] : $cy);
+ $r = (isset($attribs['r']) ? $attribs['r'] : 0.5);
if (isset($attribs['gradientTransform'])) {
$this->svggradients[$this->svggradientid]['gradientTransform'] = $this->getSVGTransformMatrix($attribs['gradientTransform']);
}
@@ -28876,12 +29228,12 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value:
if ($invisible) {
break;
}
- $cx = (isset($attribs['cx'])?$this->getHTMLUnitToUnits($attribs['cx'], 0, $this->svgunit, false):0);
- $cy = (isset($attribs['cy'])?$this->getHTMLUnitToUnits($attribs['cy'], 0, $this->svgunit, false):0);
- $r = (isset($attribs['r'])?$this->getHTMLUnitToUnits($attribs['r'], 0, $this->svgunit, false):0);
- $x = $cx - $r;
- $y = $cy - $r;
- $w = 2 * $r;
+ $r = (isset($attribs['r']) ? $this->getHTMLUnitToUnits($attribs['r'], 0, $this->svgunit, false) : 0);
+ $cx = (isset($attribs['cx']) ? $this->getHTMLUnitToUnits($attribs['cx'], 0, $this->svgunit, false) : (isset($attribs['x']) ? $this->getHTMLUnitToUnits($attribs['x'], 0, $this->svgunit, false) : 0));
+ $cy = (isset($attribs['cy']) ? $this->getHTMLUnitToUnits($attribs['cy'], 0, $this->svgunit, false) : (isset($attribs['y']) ? $this->getHTMLUnitToUnits($attribs['y'], 0, $this->svgunit, false) : 0));
+ $x = ($cx - $r);
+ $y = ($cy - $r);
+ $w = (2 * $r);
$h = $w;
if ($clipping) {
$this->SVGTransform($tm);
@@ -28901,14 +29253,14 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value:
if ($invisible) {
break;
}
- $cx = (isset($attribs['cx'])?$this->getHTMLUnitToUnits($attribs['cx'], 0, $this->svgunit, false):0);
- $cy = (isset($attribs['cy'])?$this->getHTMLUnitToUnits($attribs['cy'], 0, $this->svgunit, false):0);
- $rx = (isset($attribs['rx'])?$this->getHTMLUnitToUnits($attribs['rx'], 0, $this->svgunit, false):0);
- $ry = (isset($attribs['ry'])?$this->getHTMLUnitToUnits($attribs['ry'], 0, $this->svgunit, false):0);
- $x = $cx - $rx;
- $y = $cy - $ry;
- $w = 2 * $rx;
- $h = 2 * $ry;
+ $rx = (isset($attribs['rx']) ? $this->getHTMLUnitToUnits($attribs['rx'], 0, $this->svgunit, false) : 0);
+ $ry = (isset($attribs['ry']) ? $this->getHTMLUnitToUnits($attribs['ry'], 0, $this->svgunit, false) : 0);
+ $cx = (isset($attribs['cx']) ? $this->getHTMLUnitToUnits($attribs['cx'], 0, $this->svgunit, false) : (isset($attribs['x']) ? $this->getHTMLUnitToUnits($attribs['x'], 0, $this->svgunit, false) : 0));
+ $cy = (isset($attribs['cy']) ? $this->getHTMLUnitToUnits($attribs['cy'], 0, $this->svgunit, false) : (isset($attribs['y']) ? $this->getHTMLUnitToUnits($attribs['y'], 0, $this->svgunit, false) : 0));
+ $x = ($cx - $rx);
+ $y = ($cy - $ry);
+ $w = (2 * $rx);
+ $h = (2 * $ry);
if ($clipping) {
$this->SVGTransform($tm);
$this->Ellipse($cx, $cy, $rx, $ry, 0, 0, 360, 'CNZ', array(), array(), 8);
@@ -28981,7 +29333,9 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value:
$this->StartTransform();
$this->SVGTransform($tm);
$obstyle = $this->setSVGStyles($svgstyle, $prev_svgstyle, $x, $y, $w, $h, 'PolyLine', array($p, 'CNZ'));
- $this->PolyLine($p, 'D', array(), array());
+ if (!empty($obstyle)) {
+ $this->PolyLine($p, $obstyle, array(), array());
+ }
$this->StopTransform();
} else { // polygon
if ($clipping) {
@@ -29050,14 +29404,26 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value:
// text
case 'text':
case 'tspan': {
+ // only basic support - advanced features must be implemented
$this->svgtextmode['invisible'] = $invisible;
if ($invisible) {
break;
}
array_push($this->svgstyles, $svgstyle);
- // only basic support - advanced features must be implemented
- $x = (isset($attribs['x'])?$this->getHTMLUnitToUnits($attribs['x'], 0, $this->svgunit, false):$this->x);
- $y = (isset($attribs['y'])?$this->getHTMLUnitToUnits($attribs['y'], 0, $this->svgunit, false):$this->y);
+ if (isset($attribs['x'])) {
+ $x = $this->getHTMLUnitToUnits($attribs['x'], 0, $this->svgunit, false);
+ } elseif ($name == 'tspan') {
+ $x = $this->x;
+ } else {
+ $x = 0;
+ }
+ if (isset($attribs['y'])) {
+ $y = $this->getHTMLUnitToUnits($attribs['y'], 0, $this->svgunit, false);
+ } elseif ($name == 'tspan') {
+ $y = $this->y;
+ } else {
+ $y = 0;
+ }
$svgstyle['text-color'] = $svgstyle['fill'];
$this->svgtext = '';
if (isset($svgstyle['text-anchor'])) {
@@ -29088,16 +29454,19 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value:
}
// use
case 'use': {
- if (isset($attribs['xlink:href'])) {
- $use = $this->svgdefs[substr($attribs['xlink:href'], 1)];
- if (isset($attribs['xlink:href'])) {
- unset($attribs['xlink:href']);
+ if (isset($attribs['xlink:href']) AND !empty($attribs['xlink:href'])) {
+ $svgdefid = substr($attribs['xlink:href'], 1);
+ if (isset($this->svgdefs[$svgdefid])) {
+ $use = $this->svgdefs[$svgdefid];
+ if (isset($attribs['xlink:href'])) {
+ unset($attribs['xlink:href']);
+ }
+ if (isset($attribs['id'])) {
+ unset($attribs['id']);
+ }
+ $attribs = array_merge($attribs, $use['attribs']);
+ $this->startSVGElementHandler($parser, $use['name'], $attribs);
}
- if (isset($attribs['id'])) {
- unset($attribs['id']);
- }
- $attribs = array_merge($use['attribs'], $attribs);
- $this->startSVGElementHandler($parser, $use['name'], $use['attribs']);
}
break;
}
@@ -29162,7 +29531,17 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value:
$textrendermode = $this->textrendermode;
$textstrokewidth = $this->textstrokewidth;
$this->setTextRenderingMode($this->svgtextmode['stroke'], true, false);
+ if ($name == 'text') {
+ // store current coordinates
+ $tmpx = $this->x;
+ $tmpy = $this->y;
+ }
$this->Cell($textlen, 0, $text, 0, 0, '', false, '', 0, false, 'L', 'T');
+ if ($name == 'text') {
+ // restore coordinates
+ $this->x = $tmpx;
+ $this->y = $tmpy;
+ }
// restore previous rendering mode
$this->textrendermode = $textrendermode;
$this->textstrokewidth = $textstrokewidth;
diff --git a/htdocs/includes/tcpdf/tcpdf_parser.php b/htdocs/includes/tcpdf/tcpdf_parser.php
index 122676034d3..f17359f2134 100644
--- a/htdocs/includes/tcpdf/tcpdf_parser.php
+++ b/htdocs/includes/tcpdf/tcpdf_parser.php
@@ -1,9 +1,9 @@
* @package com.tecnick.tcpdf
* @author Nicola Asuni
- * @version 1.0.000
+ * @version 1.0.001
*/
// include class for decoding filters
@@ -48,7 +48,7 @@ require_once(dirname(__FILE__).'/tcpdf_filters.php');
* This is a PHP class for parsing PDF documents.
* @package com.tecnick.tcpdf
* @brief This is a PHP class for parsing PDF documents..
- * @version 1.0.000
+ * @version 1.0.001
* @author Nicola Asuni - info@tecnick.com
*/
class TCPDF_PARSER {
@@ -127,20 +127,29 @@ class TCPDF_PARSER {
* @since 1.0.000 (2011-05-24)
*/
protected function getXrefData($offset=0, $xref=array()) {
- // find last startxref
- if (preg_match_all('/[\r\n]startxref[\s]*[\r\n]+([0-9]+)[\s]*[\r\n]+%%EOF/i', $this->pdfdata, $matches, PREG_SET_ORDER, $offset) == 0) {
- $this->Error('Unable to find startxref');
+ if ($offset == 0) {
+ // find last startxref
+ if (preg_match_all('/[\r\n]startxref[\s]*[\r\n]+([0-9]+)[\s]*[\r\n]+%%EOF/i', $this->pdfdata, $matches, PREG_SET_ORDER, $offset) == 0) {
+ $this->Error('Unable to find startxref');
+ }
+ $matches = array_pop($matches);
+ $startxref = $matches[1];
+ } else {
+ // get the first xref at the specified offset
+ if (preg_match('/[\r\n]startxref[\s]*[\r\n]+([0-9]+)[\s]*[\r\n]+%%EOF/i', $this->pdfdata, $matches, PREG_OFFSET_CAPTURE, $offset) == 0) {
+ $this->Error('Unable to find startxref');
+ }
+ $startxref = $matches[1][0];
}
- $matches = array_pop($matches);
- $startxref = $matches[1];
// check xref position
if (strpos($this->pdfdata, 'xref', $startxref) != $startxref) {
$this->Error('Unable to find xref');
}
// extract xref data (object indexes and offsets)
- $offset = $startxref + 5;
+ $xoffset = $startxref + 5;
// initialize object number
$obj_num = 0;
+ $offset = $xoffset;
while (preg_match('/^([0-9]+)[\s]([0-9]+)[\s]?([nf]?)/im', $this->pdfdata, $matches, PREG_OFFSET_CAPTURE, $offset) > 0) {
$offset = (strlen($matches[0][0]) + $matches[0][1]);
if ($matches[3][0] == 'n') {
@@ -162,7 +171,7 @@ class TCPDF_PARSER {
}
}
// get trailer data
- if (preg_match('/trailer[\s]*<<(.*)>>[\s]*[\r\n]+startxref[\s]*[\r\n]+/isU', $this->pdfdata, $matches, PREG_OFFSET_CAPTURE, $offset) > 0) {
+ if (preg_match('/trailer[\s]*<<(.*)>>[\s]*[\r\n]+startxref[\s]*[\r\n]+/isU', $this->pdfdata, $matches, PREG_OFFSET_CAPTURE, $xoffset) > 0) {
$trailer_data = $matches[1][0];
if (!isset($xref['trailer'])) {
// get only the last updated version
@@ -188,7 +197,7 @@ class TCPDF_PARSER {
}
if (preg_match('/Prev[\s]+([0-9]+)/i', $trailer_data, $matches) > 0) {
// get previous xref
- $xref = getXrefData(substr($this->pdfdata, 0, $startxref), intval($matches[1]), $xref);
+ $xref = $this->getXrefData(intval($matches[1]), $xref);
}
} else {
$this->Error('Unable to find trailer');
@@ -399,7 +408,7 @@ class TCPDF_PARSER {
$offset = $element[2];
// decode stream using stream's dictionary information
if ($decoding AND ($element[0] == 'stream') AND (isset($objdata[($i - 1)][0])) AND ($objdata[($i - 1)][0] == '<<')) {
- $element[3] = $this->decodeStream($objdata[($i - 1)][1], $element[1]);
+ $element[3] = $this->decodeStream($objdata[($i - 1)][1], substr($element[1], 1));
}
$objdata[$i] = $element;
++$i;