From fc9cedb32122685014a9c00d6f69401aa8bd2df7 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Petr=20=C5=A0koda?=
Date: Mon, 10 Mar 2014 14:05:33 +0800
Subject: [PATCH] MDL-44521 import TCPDF 6.0.062
---
lib/pdflib.php | 2 +-
lib/tcpdf/CHANGELOG.TXT | 109 +++
lib/tcpdf/README.TXT | 9 +-
lib/tcpdf/composer.json | 3 +-
lib/tcpdf/config/tcpdf_config.php | 13 +-
lib/tcpdf/include/barcodes/datamatrix.php | 6 +-
lib/tcpdf/include/tcpdf_colors.php | 30 +-
lib/tcpdf/include/tcpdf_fonts.php | 50 +-
lib/tcpdf/include/tcpdf_images.php | 14 +-
lib/tcpdf/include/tcpdf_static.php | 8 +-
lib/tcpdf/readme_moodle.txt | 8 +-
lib/tcpdf/tcpdf.php | 932 ++++++++++++++--------
lib/tcpdf/tcpdf_autoconfig.php | 10 +-
lib/tcpdf/tcpdf_parser.php | 124 +--
lib/thirdpartylibs.xml | 2 +-
15 files changed, 871 insertions(+), 449 deletions(-)
diff --git a/lib/pdflib.php b/lib/pdflib.php
index 309698e3a76..1405ff1182e 100644
--- a/lib/pdflib.php
+++ b/lib/pdflib.php
@@ -73,7 +73,7 @@ define('K_PATH_CACHE', $CFG->cachedir . '/tcpdf/');
define('K_PATH_IMAGES', $CFG->dirroot . '/');
/** blank image */
-define('K_BLANK_IMAGE', K_PATH_IMAGES . '/pix/spacer.gif');
+define('K_BLANK_IMAGE', K_PATH_IMAGES . 'pix/spacer.gif');
/** height of cell repect font height */
define('K_CELL_HEIGHT_RATIO', 1.25);
diff --git a/lib/tcpdf/CHANGELOG.TXT b/lib/tcpdf/CHANGELOG.TXT
index 529f4732fdf..8eac585c5ec 100644
--- a/lib/tcpdf/CHANGELOG.TXT
+++ b/lib/tcpdf/CHANGELOG.TXT
@@ -1,3 +1,112 @@
+6.0.062 (2014-03-02)
+ - The method startLayer() now accepts the NULL value for the $print parameter to not set the print layer option.
+
+6.0.061 (2014-02-18)
+ - Bug #893 "Parsing error on streamed xref for secured pdf" was fixed.
+
+6.0.060 (2014-02-16)
+ - Bug #891 "Error on parsing hexa fields" was fixed.
+ - Bug #892 "Parsing pdf with trailing space at start" was fixed.
+
+6.0.059 (2014-02-03)
+ - SVG 'use' support was imporved.
+
+6.0.058 (2014-01-31)
+ - Bug #886 "Bugs with SVG using and
* @package com.tecnick.tcpdf
* @author Nicola Asuni
- * @version 6.0.031
+ * @version 6.0.061
*/
// TCPDF configuration
@@ -163,7 +128,7 @@ require_once(dirname(__FILE__).'/include/tcpdf_static.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 6.0.031
+ * @version 6.0.061
* @author Nicola Asuni - info@tecnick.com
*/
class TCPDF {
@@ -2438,13 +2403,27 @@ class TCPDF {
$this->lasth = $h;
}
+ /**
+ * Return the cell height
+ * @param $fontsize (int) Font size in internal units
+ * @param $padding (boolean) If true add cell padding
+ * @public
+ */
+ public function getCellHeight($fontsize, $padding=TRUE) {
+ $height = ($fontsize * $this->cell_height_ratio);
+ if ($padding) {
+ $height += ($this->cell_padding['T'] + $this->cell_padding['B']);
+ }
+ return round($height, 3);
+ }
+
/**
* Reset the last cell height.
* @public
* @since 5.9.000 (2010-10-03)
*/
public function resetLastH() {
- $this->lasth = ($this->FontSize * $this->cell_height_ratio) + $this->cell_padding['T'] + $this->cell_padding['B'];
+ $this->lasth = $this->getCellHeight($this->FontSize);
}
/**
@@ -3420,7 +3399,7 @@ class TCPDF {
} else {
$imgy = $this->y;
}
- $cell_height = round(($this->cell_height_ratio * $headerfont[2]) / $this->k, 2);
+ $cell_height = $this->getCellHeight($headerfont[2] / $this->k);
// set starting margin for text data cell
if ($this->getRTL()) {
$header_x = $this->original_rMargin + ($headerdata['logo_width'] * 1.1);
@@ -3656,8 +3635,16 @@ class TCPDF {
$this->x += $this->cell_padding['L'];
}
}
+ $gvars = $this->getGraphicVars();
+ if (!empty($this->theadMargins['gvars'])) {
+ // set the correct graphic style
+ $this->setGraphicVars($this->theadMargins['gvars']);
+ $this->rMargin = $gvars['rMargin'];
+ $this->lMargin = $gvars['lMargin'];
+ }
// print table header
$this->writeHTML($this->thead, false, false, false, false, '');
+ $this->setGraphicVars($gvars);
// set new top margin to skip the table headers
if (!isset($this->theadMargins['top'])) {
$this->theadMargins['top'] = $this->tMargin;
@@ -3687,6 +3674,16 @@ class TCPDF {
return $this->page;
}
+ /**
+ * Returns the array of spot colors.
+ * @return (array) Spot colors array.
+ * @public
+ * @since 6.0.038 (2013-09-30)
+ */
+ public function getAllSpotColors() {
+ return $this->spot_colors;
+ }
+
/**
* Defines a new spot color.
* It can be expressed in RGB components or gray scale.
@@ -3719,7 +3716,7 @@ class TCPDF {
public function setSpotColor($type, $name, $tint=100) {
$spotcolor = TCPDF_COLORS::getSpotColor($name, $this->spot_colors);
if ($spotcolor === false) {
- $this->Error('Undefined spot color: '.$name.', you must add it on the spotcolors.php file.');
+ $this->Error('Undefined spot color: '.$name.', you must add it using the AddSpotColor() method.');
}
$tint = (max(0, min(100, $tint)) / 100);
$pdfcolor = sprintf('/CS%d ', $this->spot_colors[$name]['i']);
@@ -5003,7 +5000,7 @@ class TCPDF {
$prev_cell_padding = $this->cell_padding;
$this->adjustCellPadding($border);
if (!$ignore_min_height) {
- $min_cell_height = ($this->FontSize * $this->cell_height_ratio) + $this->cell_padding['T'] + $this->cell_padding['B'];
+ $min_cell_height = $this->getCellHeight($this->FontSize);
if ($h < $min_cell_height) {
$h = $min_cell_height;
}
@@ -5076,7 +5073,7 @@ class TCPDF {
$rs = ''; //string to be returned
$this->adjustCellPadding($border);
if (!$ignore_min_height) {
- $min_cell_height = ($this->FontSize * $this->cell_height_ratio) + $this->cell_padding['T'] + $this->cell_padding['B'];
+ $min_cell_height = $this->getCellHeight($this->FontSize);
if ($h < $min_cell_height) {
$h = $min_cell_height;
}
@@ -6105,11 +6102,14 @@ class TCPDF {
* @param $cellpadding (float) Internal cell padding, if empty uses default cell padding.
* @param $border (mixed) Indicates if borders must be drawn around the cell. The value can be a number:- 0: no border (default)
- 1: frame
or a string containing some or all of the following characters (in any order):- L: left
- T: top
- R: right
- B: bottom
or an array of line styles for each border group - for example: array('LTRB' => array('width' => 2, 'cap' => 'butt', 'join' => 'miter', 'dash' => 0, 'color' => array(0, 0, 0)))
* @return float Return the minimal height needed for multicell method for printing the $txt param.
- * @author Alexander Escalona Fernández, Nicola Asuni
+ * @author Alexander Escalona Fern\E1ndez, Nicola Asuni
* @public
* @since 4.5.011
*/
public function getNumLines($txt, $w=0, $reseth=false, $autopadding=true, $cellpadding='', $border=0) {
+ if ($txt === NULL) {
+ return 0;
+ }
if ($txt === '') {
// empty string
return 1;
@@ -6140,13 +6140,23 @@ class TCPDF {
$length = count($chars);
$lastSeparator = -1;
for ($i = 0; $i < $length; ++$i) {
+ $c = $chars[$i];
$charWidth = $charsWidth[$i];
- if (preg_match($this->re_spaces, TCPDF_FONTS::unichr($chars[$i], $this->isunicode))) {
+ if (($c != 160)
+ AND (($c == 173)
+ OR preg_match($this->re_spaces, TCPDF_FONTS::unichr($c, $this->isunicode))
+ OR (($c == 45)
+ AND ($i > 0) AND ($i < ($length - 1))
+ AND @preg_match('/[\p{L}]/'.$this->re_space['m'], TCPDF_FONTS::unichr($chars[($i - 1)], $this->isunicode))
+ AND @preg_match('/[\p{L}]/'.$this->re_space['m'], TCPDF_FONTS::unichr($chars[($i + 1)], $this->isunicode))
+ )
+ )
+ ) {
$lastSeparator = $i;
}
- if ((($sum + $charWidth) > $wmax) OR ($chars[$i] == 10)) {
+ if ((($sum + $charWidth) > $wmax) OR ($c == 10)) {
++$lines;
- if ($chars[$i] == 10) {
+ if ($c == 10) {
$lastSeparator = -1;
$sum = 0;
} elseif ($lastSeparator != -1) {
@@ -6212,7 +6222,7 @@ class TCPDF {
* @param $cellpadding (float) Internal cell padding, if empty uses default cell padding.
* @param $border (mixed) Indicates if borders must be drawn around the cell. The value can be a number:- 0: no border (default)
- 1: frame
or a string containing some or all of the following characters (in any order):- L: left
- T: top
- R: right
- B: bottom
or an array of line styles for each border group - for example: array('LTRB' => array('width' => 2, 'cap' => 'butt', 'join' => 'miter', 'dash' => 0, 'color' => array(0, 0, 0)))
* @return float Return the minimal height needed for multicell method for printing the $txt param.
- * @author Nicola Asuni, Alexander Escalona Fernández
+ * @author Nicola Asuni, Alexander Escalona Fern\E1ndez
* @public
*/
public function getStringHeight($w, $txt, $reseth=false, $autopadding=true, $cellpadding='', $border=0) {
@@ -6224,11 +6234,7 @@ class TCPDF {
}
$this->adjustCellPadding($border);
$lines = $this->getNumLines($txt, $w, $reseth, $autopadding, $cellpadding, $border);
- $height = $lines * ($this->FontSize * $this->cell_height_ratio);
- if ($autopadding) {
- // add top and bottom padding
- $height += ($this->cell_padding['T'] + $this->cell_padding['B']);
- }
+ $height = $this->getCellHeight(($lines * $this->FontSize), $autopadding);
$this->cell_padding = $prev_cell_padding;
$this->lasth = $prev_lasth;
return $height;
@@ -6314,7 +6320,7 @@ class TCPDF {
return '';
}
// minimum row height
- $row_height = max($h, $this->FontSize * $this->cell_height_ratio);
+ $row_height = max($h, $this->getCellHeight($this->FontSize));
$start_page = $this->page;
$i = 0; // character position
$j = 0; // current starting position
@@ -6826,8 +6832,9 @@ class TCPDF {
$imgdata = TCPDF_STATIC::fileGetContents($file);
}
}
- if (isset($imgdata) AND ($imgdata !== FALSE)) {
+ if (isset($imgdata) AND ($imgdata !== FALSE) AND (strpos($file, '__tcpdf_img') === FALSE)) {
// copy image to cache
+ $original_file = $file;
$file = TCPDF_STATIC::getObjFilename('img');
$fp = fopen($file, 'w');
fwrite($fp, $imgdata);
@@ -6836,6 +6843,7 @@ class TCPDF {
$imsize = @getimagesize($file);
if ($imsize === FALSE) {
unlink($file);
+ $file = $original_file;
} else {
$this->cached_files[] = $file;
}
@@ -6847,7 +6855,7 @@ class TCPDF {
$ph = $this->getHTMLUnitToUnits($h, 0, $this->pdfunit, true) * $this->imgscale * $this->k;
$imsize = array($pw, $ph);
} else {
- $this->Error('[Image] Unable to get image: '.$file);
+ $this->Error('[Image] Unable to get the size of the image: '.$file);
}
}
// file hash
@@ -6941,17 +6949,19 @@ class TCPDF {
$newimage = false;
// get existing image data
$info = $this->getImageBuffer($file);
- if (substr($file, 0, -34) != K_PATH_CACHE.'msk') {
+ if (strpos($file, '__tcpdf_imgmask_') === FALSE) {
// check if the newer image is larger
$oldsize = ($info['w'] * $info['h']);
if ((($oldsize < $newsize) AND ($resize)) OR (($oldsize < $pixsize) AND (!$resize))) {
$newimage = true;
}
}
- } elseif (substr($file, 0, -34) != K_PATH_CACHE.'msk') {
- // check for cached images with alpha channel
- $tempfile_plain = K_PATH_CACHE.'mskp_'.$filehash;
- $tempfile_alpha = K_PATH_CACHE.'mska_'.$filehash;
+ } elseif (($ismask === false) AND ($imgmask === false) AND (strpos($file, '__tcpdf_imgmask_') === FALSE)) {
+ // create temp image file (without alpha channel)
+ $tempfile_plain = K_PATH_CACHE.'__tcpdf_imgmask_plain_'.$filehash;
+ // create temp alpha file
+ $tempfile_alpha = K_PATH_CACHE.'__tcpdf_imgmask_alpha_'.$filehash;
+ // check for cached images
if (in_array($tempfile_plain, $this->imagekeys)) {
// get existing image data
$info = $this->getImageBuffer($tempfile_plain);
@@ -6986,33 +6996,41 @@ class TCPDF {
if ((method_exists('TCPDF_IMAGES', $mtd)) AND (!($resize AND (function_exists($gdfunction) OR extension_loaded('imagick'))))) {
// TCPDF image functions
$info = TCPDF_IMAGES::$mtd($file);
- if (($info === 'pngalpha') OR (isset($info['trns']) AND !empty($info['trns']))) {
+ if (($ismask === false) AND ($imgmask === false) AND (strpos($file, '__tcpdf_imgmask_') === FALSE)
+ AND (($info === 'pngalpha') OR (isset($info['trns']) AND !empty($info['trns'])))) {
return $this->ImagePngAlpha($file, $x, $y, $pixw, $pixh, $w, $h, 'PNG', $link, $align, $resize, $dpi, $palign, $filehash);
}
}
- if (!$info) {
- if (function_exists($gdfunction)) {
+ if (($info === false) AND function_exists($gdfunction)) {
+ try {
// GD library
$img = $gdfunction($file);
- if ($resize) {
- $imgr = imagecreatetruecolor($neww, $newh);
- if (($type == 'gif') OR ($type == 'png')) {
- $imgr = TCPDF_IMAGES::setGDImageTransparency($imgr, $img);
- }
- imagecopyresampled($imgr, $img, 0, 0, 0, 0, $neww, $newh, $pixw, $pixh);
- if (($type == 'gif') OR ($type == 'png')) {
- $info = TCPDF_IMAGES::_toPNG($imgr);
+ if ($img !== false) {
+ if ($resize) {
+ $imgr = imagecreatetruecolor($neww, $newh);
+ if (($type == 'gif') OR ($type == 'png')) {
+ $imgr = TCPDF_IMAGES::setGDImageTransparency($imgr, $img);
+ }
+ imagecopyresampled($imgr, $img, 0, 0, 0, 0, $neww, $newh, $pixw, $pixh);
+ if (($type == 'gif') OR ($type == 'png')) {
+ $info = TCPDF_IMAGES::_toPNG($imgr);
+ } else {
+ $info = TCPDF_IMAGES::_toJPEG($imgr, $this->jpeg_quality);
+ }
} else {
- $info = TCPDF_IMAGES::_toJPEG($imgr, $this->jpeg_quality);
- }
- } else {
- if (($type == 'gif') OR ($type == 'png')) {
- $info = TCPDF_IMAGES::_toPNG($img);
- } else {
- $info = TCPDF_IMAGES::_toJPEG($img, $this->jpeg_quality);
+ if (($type == 'gif') OR ($type == 'png')) {
+ $info = TCPDF_IMAGES::_toPNG($img);
+ } else {
+ $info = TCPDF_IMAGES::_toJPEG($img, $this->jpeg_quality);
+ }
}
}
- } elseif (extension_loaded('imagick')) {
+ } catch(Exception $e) {
+ $info = false;
+ }
+ }
+ if (($info === false) AND extension_loaded('imagick')) {
+ try {
// ImageMagick library
$img = new Imagick();
if ($type == 'SVG') {
@@ -7058,17 +7076,17 @@ class TCPDF {
}
$img->setCompressionQuality($this->jpeg_quality);
$img->setImageFormat('jpeg');
- $tempname = TCPDF_STATIC::getObjFilename('jpg');
+ $tempname = TCPDF_STATIC::getObjFilename('img');
$img->writeImage($tempname);
$info = TCPDF_IMAGES::_parsejpeg($tempname);
unlink($tempname);
$img->destroy();
- } else {
- return;
+ } catch(Exception $e) {
+ $info = false;
}
}
if ($info === false) {
- //If false, we cannot process image
+ // unable to process image
return;
}
TCPDF_STATIC::set_mqr($mqr);
@@ -7192,61 +7210,85 @@ class TCPDF {
* @see Image()
*/
protected function ImagePngAlpha($file, $x, $y, $wpx, $hpx, $w, $h, $type, $link, $align, $resize, $dpi, $palign, $filehash='') {
+ // create temp images
if (empty($filehash)) {
$filehash = md5($this->file_id.$file);
}
// create temp image file (without alpha channel)
- $tempfile_plain = K_PATH_CACHE.'mskp_'.$filehash;
+ $tempfile_plain = K_PATH_CACHE.'__tcpdf_imgmask_plain_'.$filehash;
// create temp alpha file
- $tempfile_alpha = K_PATH_CACHE.'mska_'.$filehash;
- if (extension_loaded('imagick')) { // ImageMagick extension
- // ImageMagick library
- $img = new Imagick();
- $img->readImage($file);
- // clone image object
- $imga = TCPDF_STATIC::objclone($img);
- // extract alpha channel
- if (method_exists($img, 'setImageAlphaChannel') AND defined('Imagick::ALPHACHANNEL_EXTRACT')) {
- $img->setImageAlphaChannel(Imagick::ALPHACHANNEL_EXTRACT);
- } else {
- $img->separateImageChannel(8); // 8 = (imagick::CHANNEL_ALPHA | imagick::CHANNEL_OPACITY | imagick::CHANNEL_MATTE);
- $img->negateImage(true);
- }
- $img->setImageFormat('png');
- $img->writeImage($tempfile_alpha);
- // remove alpha channel
- if (method_exists($imga, 'setImageMatte')) {
- $imga->setImageMatte(false);
- } else {
- $imga->separateImageChannel(39); // 39 = (imagick::CHANNEL_ALL & ~(imagick::CHANNEL_ALPHA | imagick::CHANNEL_OPACITY | imagick::CHANNEL_MATTE));
- }
- $imga->setImageFormat('png');
- $imga->writeImage($tempfile_plain);
- } elseif (function_exists('imagecreatefrompng')) { // GD extension
- // generate images
- $img = imagecreatefrompng($file);
- $imgalpha = imagecreate($wpx, $hpx);
- // generate gray scale palette (0 -> 255)
- for ($c = 0; $c < 256; ++$c) {
- ImageColorAllocate($imgalpha, $c, $c, $c);
- }
- // extract alpha channel
- for ($xpx = 0; $xpx < $wpx; ++$xpx) {
- for ($ypx = 0; $ypx < $hpx; ++$ypx) {
- $color = imagecolorat($img, $xpx, $ypx);
- $alpha = $this->getGDgamma($color); // correct gamma
- imagesetpixel($imgalpha, $xpx, $ypx, $alpha);
+ $tempfile_alpha = K_PATH_CACHE.'__tcpdf_imgmask_alpha_'.$filehash;
+ $parsed = false;
+ $parse_error = '';
+ // ImageMagick extension
+ if (($parsed === false) AND extension_loaded('imagick')) {
+ try {
+ // ImageMagick library
+ $img = new Imagick();
+ $img->readImage($file);
+ // clone image object
+ $imga = TCPDF_STATIC::objclone($img);
+ // extract alpha channel
+ if (method_exists($img, 'setImageAlphaChannel') AND defined('Imagick::ALPHACHANNEL_EXTRACT')) {
+ $img->setImageAlphaChannel(Imagick::ALPHACHANNEL_EXTRACT);
+ } else {
+ $img->separateImageChannel(8); // 8 = (imagick::CHANNEL_ALPHA | imagick::CHANNEL_OPACITY | imagick::CHANNEL_MATTE);
+ $img->negateImage(true);
}
+ $img->setImageFormat('png');
+ $img->writeImage($tempfile_alpha);
+ // remove alpha channel
+ if (method_exists($imga, 'setImageMatte')) {
+ $imga->setImageMatte(false);
+ } else {
+ $imga->separateImageChannel(39); // 39 = (imagick::CHANNEL_ALL & ~(imagick::CHANNEL_ALPHA | imagick::CHANNEL_OPACITY | imagick::CHANNEL_MATTE));
+ }
+ $imga->setImageFormat('png');
+ $imga->writeImage($tempfile_plain);
+ $parsed = true;
+ } catch (Exception $e) {
+ // Imagemagick fails, try with GD
+ $parse_error = 'Imagick library error: '.$e->getMessage();
+ }
+ }
+ // GD extension
+ if (($parsed === false) AND function_exists('imagecreatefrompng')) {
+ try {
+ // generate images
+ $img = imagecreatefrompng($file);
+ $imgalpha = imagecreate($wpx, $hpx);
+ // generate gray scale palette (0 -> 255)
+ for ($c = 0; $c < 256; ++$c) {
+ ImageColorAllocate($imgalpha, $c, $c, $c);
+ }
+ // extract alpha channel
+ for ($xpx = 0; $xpx < $wpx; ++$xpx) {
+ for ($ypx = 0; $ypx < $hpx; ++$ypx) {
+ $color = imagecolorat($img, $xpx, $ypx);
+ // get and correct gamma color
+ $alpha = $this->getGDgamma($img, $color);
+ imagesetpixel($imgalpha, $xpx, $ypx, $alpha);
+ }
+ }
+ imagepng($imgalpha, $tempfile_alpha);
+ imagedestroy($imgalpha);
+ // extract image without alpha channel
+ $imgplain = imagecreatetruecolor($wpx, $hpx);
+ imagecopy($imgplain, $img, 0, 0, 0, 0, $wpx, $hpx);
+ imagepng($imgplain, $tempfile_plain);
+ imagedestroy($imgplain);
+ $parsed = true;
+ } catch (Exception $e) {
+ // GD fails
+ $parse_error = 'GD library error: '.$e->getMessage();
+ }
+ }
+ if ($parsed === false) {
+ if (empty($parse_error)) {
+ $this->Error('TCPDF requires the Imagick or GD extension to handle PNG images with alpha channel.');
+ } else {
+ $this->Error($parse_error);
}
- imagepng($imgalpha, $tempfile_alpha);
- imagedestroy($imgalpha);
- // extract image without alpha channel
- $imgplain = imagecreatetruecolor($wpx, $hpx);
- imagecopy($imgplain, $img, 0, 0, 0, 0, $wpx, $hpx);
- imagepng($imgplain, $tempfile_plain);
- imagedestroy($imgplain);
- } else {
- $this->Error('TCPDF requires the Imagick or GD extension to handle PNG images with alpha channel.');
}
// embed mask image
$imgmask = $this->Image($tempfile_alpha, $x, $y, $w, $h, 'PNG', '', '', $resize, $dpi, '', true, false);
@@ -7259,26 +7301,25 @@ class TCPDF {
/**
* Get the GD-corrected PNG gamma value from alpha color
+ * @param $img (int) GD image Resource ID.
* @param $c (int) alpha color
* @protected
* @since 4.3.007 (2008-12-04)
*/
- 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);
+ protected function getGDgamma($img, $c) {
+ if (!isset($this->gdgammacache['#'.$c])) {
+ $colors = imagecolorsforindex($img, $c);
// GD alpha is only 7 bit (0 -> 127)
- $alpha = (((127 - $alpha) / 127) * 255);
+ $this->gdgammacache['#'.$c] = (((127 - $colors['alpha']) / 127) * 255);
// correct gamma
- $this->gdgammacache["'".$c."'"] = (pow(($alpha / 255), 2.2) * 255);
+ $this->gdgammacache['#'.$c] = (pow(($this->gdgammacache['#'.$c] / 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."'"];
+ return $this->gdgammacache['#'.$c];
}
/**
@@ -7522,7 +7563,7 @@ class TCPDF {
$byterange .= str_repeat(' ', ($byterange_string_len - strlen($byterange)));
$pdfdoc = str_replace(TCPDF_STATIC::$byterange_string, $byterange, $pdfdoc);
// write the document to a temporary folder
- $tempdoc = TCPDF_STATIC::getObjFilename('tmppdf');
+ $tempdoc = TCPDF_STATIC::getObjFilename('doc');
$f = fopen($tempdoc, 'wb');
if (!$f) {
$this->Error('Unable to create temporary file: '.$tempdoc);
@@ -7531,7 +7572,7 @@ class TCPDF {
fwrite($f, $pdfdoc, $pdfdoc_length);
fclose($f);
// get digital signature via openssl library
- $tempsign = TCPDF_STATIC::getObjFilename('tmpsig');
+ $tempsign = TCPDF_STATIC::getObjFilename('sig');
if (empty($this->signature_data['extracerts'])) {
openssl_pkcs7_sign($tempdoc, $tempsign, $this->signature_data['signcert'], array($this->signature_data['privkey'], $this->signature_data['password']), array(), PKCS7_BINARY | PKCS7_DETACHED);
} else {
@@ -7697,7 +7738,7 @@ class TCPDF {
// remove buffer file from cache
unlink($this->buffer);
}
- if ($destroyall AND isset($this->cached_files) AND !empty($this->cached_files)) {
+ if ($destroyall AND !empty($this->cached_files)) {
// remove cached files
foreach ($this->cached_files as $cachefile) {
if (is_file($cachefile)) {
@@ -7846,6 +7887,7 @@ class TCPDF {
$groupnum = 0;
$ptgu = 1;
$ptga = 1;
+ $ptg_num_chars = 1;
for ($n = 1; $n <= $num_pages; ++$n) {
// get current page
$temppage = $this->getPageBuffer($n);
@@ -9393,7 +9435,7 @@ class TCPDF {
}
if (!TCPDF_STATIC::empty_string($this->keywords)) {
// Keywords associated with the document.
- $out .= ' /Keywords '.$this->_textstring($this->keywords.' TCPDF', $oid);
+ $out .= ' /Keywords '.$this->_textstring($this->keywords, $oid);
}
if (!TCPDF_STATIC::empty_string($this->creator)) {
// If the document was converted to PDF from another format, the name of the conforming product that created the original document from which it was converted.
@@ -9462,7 +9504,7 @@ class TCPDF {
$xmp .= "\t\t\t".''."\n";
$xmp .= "\t\t\t".''."\n";
$xmp .= "\t\t\t\t".''."\n";
- $xmp .= "\t\t\t\t\t".''.TCPDF_STATIC::_escapeXML($this->keywords).' TCPDF'."\n";
+ $xmp .= "\t\t\t\t\t".''.TCPDF_STATIC::_escapeXML($this->keywords).''."\n";
$xmp .= "\t\t\t\t".''."\n";
$xmp .= "\t\t\t".''."\n";
$xmp .= "\t\t".''."\n";
@@ -9485,7 +9527,7 @@ class TCPDF {
$xmp .= "\t\t\t".''.$doccreationdate.''."\n";
$xmp .= "\t\t".''."\n";
$xmp .= "\t\t".''."\n";
- $xmp .= "\t\t\t".''.TCPDF_STATIC::_escapeXML($this->keywords).' TCPDF'."\n";
+ $xmp .= "\t\t\t".''.TCPDF_STATIC::_escapeXML($this->keywords).''."\n";
$xmp .= "\t\t\t".''.TCPDF_STATIC::_escapeXML(TCPDF_STATIC::getTCPDFProducer()).''."\n";
$xmp .= "\t\t".''."\n";
$xmp .= "\t\t".''."\n";
@@ -10763,7 +10805,7 @@ class TCPDF {
// envelope data
$envelope = $seed.$pkpermissions;
// write the envelope data to a temporary file
- $tempkeyfile = TCPDF_STATIC::getObjFilename('tmpkey');
+ $tempkeyfile = TCPDF_STATIC::getObjFilename('key');
$f = fopen($tempkeyfile, 'wb');
if (!$f) {
$this->Error('Unable to create temporary key file: '.$tempkeyfile);
@@ -10771,7 +10813,7 @@ class TCPDF {
$envelope_length = strlen($envelope);
fwrite($f, $envelope, $envelope_length);
fclose($f);
- $tempencfile = TCPDF_STATIC::getObjFilename('tmpenc');
+ $tempencfile = TCPDF_STATIC::getObjFilename('enc');
if (!openssl_pkcs7_encrypt($tempkeyfile, $tempencfile, $pubkey['c'], array(), PKCS7_BINARY | PKCS7_DETACHED)) {
$this->Error('Unable to encrypt the file: '.$tempkeyfile);
}
@@ -11395,7 +11437,7 @@ class TCPDF {
}
/**
- * Append a cubic Bézier curve to the current path. The curve shall extend from the current point to the point (x3, y3), using (x1, y1) and (x2, y2) as the Bézier control points.
+ * Append a cubic Bezier curve to the current path. The curve shall extend from the current point to the point (x3, y3), using (x1, y1) and (x2, y2) as the Bezier control points.
* The new current point shall be (x3, y3).
* @param $x1 (float) Abscissa of control point 1.
* @param $y1 (float) Ordinate of control point 1.
@@ -11413,7 +11455,7 @@ class TCPDF {
}
/**
- * Append a cubic Bézier curve to the current path. The curve shall extend from the current point to the point (x3, y3), using the current point and (x2, y2) as the Bézier control points.
+ * Append a cubic Bezier curve to the current path. The curve shall extend from the current point to the point (x3, y3), using the current point and (x2, y2) as the Bezier control points.
* The new current point shall be (x3, y3).
* @param $x2 (float) Abscissa of control point 2.
* @param $y2 (float) Ordinate of control point 2.
@@ -11429,7 +11471,7 @@ class TCPDF {
}
/**
- * Append a cubic Bézier curve to the current path. The curve shall extend from the current point to the point (x3, y3), using (x1, y1) and (x3, y3) as the Bézier control points.
+ * Append a cubic Bezier curve to the current path. The curve shall extend from the current point to the point (x3, y3), using (x1, y1) and (x3, y3) as the Bezier control points.
* The new current point shall be (x3, y3).
* @param $x1 (float) Abscissa of control point 1.
* @param $y1 (float) Ordinate of control point 1.
@@ -11668,6 +11710,9 @@ class TCPDF {
* @since 4.9.019 (2010-04-26)
*/
protected function _outellipticalarc($xc, $yc, $rx, $ry, $xang=0, $angs=0, $angf=360, $pie=false, $nc=2, $startpoint=true, $ccw=true, $svg=false) {
+ if (($rx <= 0) OR ($ry < 0)) {
+ return;
+ }
$k = $this->k;
if ($nc < 2) {
$nc = 2;
@@ -12221,7 +12266,7 @@ class TCPDF {
/**
* Insert Named Destinations.
* @protected
- * @author Johannes Güntert, Nicola Asuni
+ * @author Johannes G\FCntert, Nicola Asuni
* @since 5.9.098 (2011-06-23)
*/
protected function _putdests() {
@@ -12449,7 +12494,7 @@ class TCPDF {
* Adds a javascript
* @param $script (string) Javascript code
* @public
- * @author Johannes Güntert, Nicola Asuni
+ * @author Johannes G\FCntert, Nicola Asuni
* @since 2.1.002 (2008-02-12)
*/
public function IncludeJS($script) {
@@ -12478,7 +12523,7 @@ class TCPDF {
/**
* Create a javascript PDF string.
* @protected
- * @author Johannes Güntert, Nicola Asuni
+ * @author Johannes G\FCntert, Nicola Asuni
* @since 2.1.002 (2008-02-12)
*/
protected function _putjavascript() {
@@ -13613,7 +13658,9 @@ class TCPDF {
$out = '<< /Type /OCG';
$out .= ' /Name '.$this->_textstring($layer['name'], $this->pdflayers[$key]['objid']);
$out .= ' /Usage <<';
- $out .= ' /Print <>';
+ if (isset($layer['print']) AND ($layer['print'] !== NULL)) {
+ $out .= ' /Print <>';
+ }
$out .= ' /View <>';
$out .= ' >> >>';
$out .= "\n".'endobj';
@@ -13624,7 +13671,7 @@ class TCPDF {
/**
* Start a new pdf layer.
* @param $name (string) Layer name (only a-z letters and numbers). Leave empty for automatic name.
- * @param $print (boolean) Set to true to print this layer.
+ * @param $print (boolean|null) Set to TRUE to print this layer, FALSE to not print and NULL to not set this option
* @param $view (boolean) Set to true to view this layer.
* @public
* @since 5.9.102 (2011-07-13)
@@ -13927,12 +13974,25 @@ class TCPDF {
* @param $h (float) height of the rectangle.
* @param $transition (boolean) if true prints tcolor transitions to white.
* @param $vertical (boolean) if true prints bar vertically.
- * @param $colors (string) colors to print, one letter per color separated by comma (for example 'A,W,R,G,B,C,M,Y,K'): A=black, W=white, R=red, G=green, B=blue, C=cyan, M=magenta, Y=yellow, K=black.
+ * @param $colors (string) colors to print separated by comma. Valid values are: A,W,R,G,B,C,M,Y,K,RGB,CMYK,ALL,ALLSPOT,. Where: A = grayscale black, W = grayscale white, R = RGB red, G RGB green, B RGB blue, C = CMYK cyan, M = CMYK magenta, Y = CMYK yellow, K = CMYK key/black, RGB = RGB registration color, CMYK = CMYK registration color, ALL = Spot registration color, ALLSPOT = print all defined spot colors, = name of the spot color to print.
* @author Nicola Asuni
* @since 4.9.000 (2010-03-26)
* @public
*/
public function colorRegistrationBar($x, $y, $w, $h, $transition=true, $vertical=false, $colors='A,R,G,B,C,M,Y,K') {
+ if (strpos($colors, 'ALLSPOT') !== false) {
+ // expand spot colors
+ $spot_colors = '';
+ foreach ($this->spot_colors as $spot_color_name => $v) {
+ $spot_colors .= ','.$spot_color_name;
+ }
+ if (!empty($spot_colors)) {
+ $spot_colors = substr($spot_colors, 1);
+ $colors = str_replace('ALLSPOT', $spot_colors, $colors);
+ } else {
+ $colors = str_replace('ALLSPOT', 'NONE', $colors);
+ }
+ }
$bars = explode(',', $colors);
$numbars = count($bars); // number of bars to print
if ($numbars <= 0) {
@@ -13957,67 +14017,93 @@ class TCPDF {
foreach ($bars as $col) {
switch ($col) {
// set transition colors
- case 'A': { // BLACK
+ case 'A': { // BLACK (GRAYSCALE)
$col_a = array(255);
$col_b = array(0);
break;
}
- case 'W': { // WHITE
+ case 'W': { // WHITE (GRAYSCALE)
$col_a = array(0);
$col_b = array(255);
break;
}
- case 'R': { // R
+ case 'R': { // RED (RGB)
$col_a = array(255,255,255);
$col_b = array(255,0,0);
break;
}
- case 'G': { // G
+ case 'G': { // GREEN (RGB)
$col_a = array(255,255,255);
$col_b = array(0,255,0);
break;
}
- case 'B': { // B
+ case 'B': { // BLUE (RGB)
$col_a = array(255,255,255);
$col_b = array(0,0,255);
break;
}
- case 'C': { // C
+ case 'C': { // CYAN (CMYK)
$col_a = array(0,0,0,0);
$col_b = array(100,0,0,0);
break;
}
- case 'M': { // M
+ case 'M': { // MAGENTA (CMYK)
$col_a = array(0,0,0,0);
$col_b = array(0,100,0,0);
break;
}
- case 'Y': { // Y
+ case 'Y': { // YELLOW (CMYK)
$col_a = array(0,0,0,0);
$col_b = array(0,0,100,0);
break;
}
- case 'K': { // K
+ case 'K': { // KEY - BLACK (CMYK)
$col_a = array(0,0,0,0);
$col_b = array(0,0,0,100);
break;
}
- default: { // GRAY
- $col_a = array(255);
- $col_b = array(0);
+ case 'RGB': { // BLACK REGISTRATION (RGB)
+ $col_a = array(255,255,255);
+ $col_b = array(0,0,0);
+ break;
+ }
+ case 'CMYK': { // BLACK REGISTRATION (CMYK)
+ $col_a = array(0,0,0,0);
+ $col_b = array(100,100,100,100);
+ break;
+ }
+ case 'ALL': { // SPOT COLOR REGISTRATION
+ $col_a = array(0,0,0,0,'None');
+ $col_b = array(100,100,100,100,'All');
+ break;
+ }
+ case 'NONE': { // SKIP THIS COLOR
+ $col_a = array(0,0,0,0,'None');
+ $col_b = array(0,0,0,0,'None');
+ break;
+ }
+ default: { // SPECIFIC SPOT COLOR NAME
+ $col_a = array(0,0,0,0,'None');
+ $col_b = TCPDF_COLORS::getSpotColor($col, $this->spot_colors);
+ if ($col_b === false) {
+ // in case of error defaults to the registration color
+ $col_b = array(100,100,100,100,'All');
+ }
break;
}
}
- if ($transition) {
- // color gradient
- $this->LinearGradient($xb, $yb, $wb, $hb, $col_a, $col_b, $coords);
- } else {
- // color rectangle
- $this->SetFillColorArray($col_b);
- $this->Rect($xb, $yb, $wb, $hb, 'F', array());
+ if ($col != 'NONE') {
+ if ($transition) {
+ // color gradient
+ $this->LinearGradient($xb, $yb, $wb, $hb, $col_a, $col_b, $coords);
+ } else {
+ $this->SetFillColorArray($col_b);
+ // colored rectangle
+ $this->Rect($xb, $yb, $wb, $hb, 'F', array());
+ }
+ $xb += $xd;
+ $yb += $yd;
}
- $xb += $xd;
- $yb += $yd;
}
}
@@ -14028,12 +14114,12 @@ class TCPDF {
* @param $w (float) width of the crop mark.
* @param $h (float) height of the crop mark.
* @param $type (string) type of crop mark, one symbol per type separated by comma: T = TOP, F = BOTTOM, L = LEFT, R = RIGHT, TL = A = TOP-LEFT, TR = B = TOP-RIGHT, BL = C = BOTTOM-LEFT, BR = D = BOTTOM-RIGHT.
- * @param $color (array) crop mark color (default black).
+ * @param $color (array) crop mark color (default spot registration color).
* @author Nicola Asuni
* @since 4.9.000 (2010-03-26)
* @public
*/
- public function cropMark($x, $y, $w, $h, $type='T,R,B,L', $color=array(0,0,0)) {
+ public function cropMark($x, $y, $w, $h, $type='T,R,B,L', $color=array(100,100,100,100,'All')) {
$this->SetLineStyle(array('width' => (0.5 / $this->k), 'cap' => 'butt', 'join' => 'miter', 'dash' => 0, 'color' => $color));
$type = strtoupper($type);
$type = preg_replace('/[^A-Z\-\,]*/', '', $type);
@@ -14098,30 +14184,70 @@ class TCPDF {
* @param $y (float) ordinate of the registration mark center.
* @param $r (float) radius of the crop mark.
* @param $double (boolean) if true print two concentric crop marks.
- * @param $cola (array) crop mark color (default black).
- * @param $colb (array) second crop mark color.
+ * @param $cola (array) crop mark color (default spot registration color 'All').
+ * @param $colb (array) second crop mark color (default spot registration color 'None').
* @author Nicola Asuni
* @since 4.9.000 (2010-03-26)
* @public
*/
- public function registrationMark($x, $y, $r, $double=false, $cola=array(0,0,0), $colb=array(255,255,255)) {
- $line_style = array('width' => (0.5 / $this->k), 'cap' => 'butt', 'join' => 'miter', 'dash' => 0, 'color' => $cola);
+ public function registrationMark($x, $y, $r, $double=false, $cola=array(100,100,100,100,'All'), $colb=array(0,0,0,0,'None')) {
+ $line_style = array('width' => max((0.5 / $this->k),($r / 30)), 'cap' => 'butt', 'join' => 'miter', 'dash' => 0, 'color' => $cola);
$this->SetFillColorArray($cola);
$this->PieSector($x, $y, $r, 90, 180, 'F');
$this->PieSector($x, $y, $r, 270, 360, 'F');
$this->Circle($x, $y, $r, 0, 360, 'C', $line_style, array(), 8);
if ($double) {
- $r2 = $r * 0.5;
+ $ri = $r * 0.5;
$this->SetFillColorArray($colb);
- $this->PieSector($x, $y, $r2, 90, 180, 'F');
- $this->PieSector($x, $y, $r2, 270, 360, 'F');
+ $this->PieSector($x, $y, $ri, 90, 180, 'F');
+ $this->PieSector($x, $y, $ri, 270, 360, 'F');
$this->SetFillColorArray($cola);
- $this->PieSector($x, $y, $r2, 0, 90, 'F');
- $this->PieSector($x, $y, $r2, 180, 270, 'F');
- $this->Circle($x, $y, $r2, 0, 360, 'C', $line_style, array(), 8);
+ $this->PieSector($x, $y, $ri, 0, 90, 'F');
+ $this->PieSector($x, $y, $ri, 180, 270, 'F');
+ $this->Circle($x, $y, $ri, 0, 360, 'C', $line_style, array(), 8);
}
}
+ /**
+ * Paints a CMYK registration mark
+ * @param $x (float) abscissa of the registration mark center.
+ * @param $y (float) ordinate of the registration mark center.
+ * @param $r (float) radius of the crop mark.
+ * @author Nicola Asuni
+ * @since 6.0.038 (2013-09-30)
+ * @public
+ */
+ public function registrationMarkCMYK($x, $y, $r) {
+ // line width
+ $lw = max((0.5 / $this->k),($r / 8));
+ // internal radius
+ $ri = ($r * 0.6);
+ // external radius
+ $re = ($r * 1.3);
+ // Cyan
+ $this->SetFillColorArray(array(100,0,0,0));
+ $this->PieSector($x, $y, $ri, 270, 360, 'F');
+ // Magenta
+ $this->SetFillColorArray(array(0,100,0,0));
+ $this->PieSector($x, $y, $ri, 0, 90, 'F');
+ // Yellow
+ $this->SetFillColorArray(array(0,0,100,0));
+ $this->PieSector($x, $y, $ri, 90, 180, 'F');
+ // Key - black
+ $this->SetFillColorArray(array(0,0,0,100));
+ $this->PieSector($x, $y, $ri, 180, 270, 'F');
+ // registration color
+ $line_style = array('width' => $lw, 'cap' => 'butt', 'join' => 'miter', 'dash' => 0, 'color' => array(100,100,100,100,'All'));
+ $this->SetFillColorArray(array(100,100,100,100,'All'));
+ // external circle
+ $this->Circle($x, $y, $r, 0, 360, 'C', $line_style, array(), 8);
+ // cross lines
+ $this->Line($x, ($y - $re), $x, ($y - $ri));
+ $this->Line($x, ($y + $ri), $x, ($y + $re));
+ $this->Line(($x - $re), $y, ($x - $ri), $y);
+ $this->Line(($x + $ri), $y, ($x + $re), $y);
+ }
+
/**
* Paints a linear colour gradient.
* @param $x (float) abscissa of the top left corner of the rectangle.
@@ -14131,7 +14257,7 @@ class TCPDF {
* @param $col1 (array) first color (Grayscale, RGB or CMYK components).
* @param $col2 (array) second color (Grayscale, RGB or CMYK components).
* @param $coords (array) array of the form (x1, y1, x2, y2) which defines the gradient vector (see linear_gradient_coords.jpg). The default value is from left to right (x1=0, y1=0, x2=1, y2=0).
- * @author Andreas Würmser, Nicola Asuni
+ * @author Andreas W\FCrmser, Nicola Asuni
* @since 3.1.000 (2008-06-09)
* @public
*/
@@ -14149,7 +14275,7 @@ class TCPDF {
* @param $col1 (array) first color (Grayscale, RGB or CMYK components).
* @param $col2 (array) second color (Grayscale, RGB or CMYK components).
* @param $coords (array) array of the form (fx, fy, cx, cy, r) where (fx, fy) is the starting point of the gradient with color1, (cx, cy) is the center of the circle with color2, and r is the radius of the circle (see radial_gradient_coords.jpg). (fx, fy) should be inside the circle, otherwise some areas will not be defined.
- * @author Andreas Würmser, Nicola Asuni
+ * @author Andreas W\FCrmser, Nicola Asuni
* @since 3.1.000 (2008-06-09)
* @public
*/
@@ -14172,7 +14298,7 @@ class TCPDF {
* @param $coords_min (array) minimum value used by the coordinates. If a coordinate's value is smaller than this it will be cut to coords_min. default: 0
* @param $coords_max (array) maximum value used by the coordinates. If a coordinate's value is greater than this it will be cut to coords_max. default: 1
* @param $antialias (boolean) A flag indicating whether to filter the shading function to prevent aliasing artifacts.
- * @author Andreas Würmser, Nicola Asuni
+ * @author Andreas W\FCrmser, Nicola Asuni
* @since 3.1.000 (2008-06-09)
* @public
*/
@@ -14264,7 +14390,7 @@ class TCPDF {
* @param $y (float) ordinate of the top left corner of the rectangle.
* @param $w (float) width of the rectangle.
* @param $h (float) height of the rectangle.
- * @author Andreas Würmser, Nicola Asuni
+ * @author Andreas W\FCrmser, Nicola Asuni
* @since 3.1.000 (2008-06-09)
* @protected
*/
@@ -14310,6 +14436,7 @@ class TCPDF {
$numcolspace = count($stops[0]['color']);
$bcolor = array_values($background);
switch($numcolspace) {
+ case 5: // SPOT
case 4: { // CMYK
$this->gradients[$n]['colspace'] = 'DeviceCMYK';
if (!empty($background)) {
@@ -14324,7 +14451,7 @@ class TCPDF {
}
break;
}
- case 1: { // Gray scale
+ case 1: { // GRAY SCALE
$this->gradients[$n]['colspace'] = 'DeviceGray';
if (!empty($background)) {
$this->gradients[$n]['background'] = sprintf('%F', $bcolor[0]/255);
@@ -14366,6 +14493,7 @@ class TCPDF {
// set colors
$color = array_values($stop['color']);
switch($numcolspace) {
+ case 5: // SPOT
case 4: { // CMYK
$this->gradients[$n]['colors'][$key]['color'] = sprintf('%F %F %F %F', $color[0]/100, $color[1]/100, $color[2]/100, $color[3]/100);
break;
@@ -14374,7 +14502,7 @@ class TCPDF {
$this->gradients[$n]['colors'][$key]['color'] = sprintf('%F %F %F', $color[0]/255, $color[1]/255, $color[2]/255);
break;
}
- case 1: { // Gray scale
+ case 1: { // GRAY SCALE
$this->gradients[$n]['colors'][$key]['color'] = sprintf('%F', $color[0]/255);
break;
}
@@ -15174,7 +15302,7 @@ class TCPDF {
}
}
}
- $text_height = ($this->cell_height_ratio * $fontsize / $this->k);
+ $text_height = $this->getCellHeight($fontsize / $this->k);
// height
if (($h === '') OR ($h <= 0)) {
// set default height
@@ -15185,7 +15313,7 @@ class TCPDF {
// try to reduce font or padding to fit barcode on available height
if ($text_height > $h) {
$fontsize = (($h * $this->k) / (4 * $this->cell_height_ratio));
- $text_height = ($this->cell_height_ratio * $fontsize / $this->k);
+ $text_height = $this->getCellHeight($fontsize / $this->k);
$this->SetFont($style['font'], '', $fontsize);
}
if ($vpadding > 0) {
@@ -16206,6 +16334,8 @@ class TCPDF {
$html = preg_replace('/'.$this->re_space['p'].'+/'.$this->re_space['m'], chr(32), $html); // replace multiple spaces with a single space
// trim string
$html = $this->stringTrim($html);
+ // fix br tag after li
+ $html = preg_replace('/
]*)>/', '
', $html);
// fix first image tag alignment
$html = preg_replace('/^![]()
rtl?'rtl':'ltr';
$thead = false; // true when we are inside the THEAD tag
@@ -16293,6 +16424,7 @@ class TCPDF {
$dom[$key]['fgcolor'] = $dom[($dom[($dom[$key]['parent'])]['parent'])]['fgcolor'];
$dom[$key]['strokecolor'] = $dom[($dom[($dom[$key]['parent'])]['parent'])]['strokecolor'];
$dom[$key]['align'] = $dom[($dom[($dom[$key]['parent'])]['parent'])]['align'];
+ $dom[$key]['text-transform'] = $dom[($dom[($dom[$key]['parent'])]['parent'])]['text-transform'];
$dom[$key]['dir'] = $dom[($dom[($dom[$key]['parent'])]['parent'])]['dir'];
if (isset($dom[($dom[($dom[$key]['parent'])]['parent'])]['listtype'])) {
$dom[$key]['listtype'] = $dom[($dom[($dom[$key]['parent'])]['parent'])]['listtype'];
@@ -16364,6 +16496,7 @@ class TCPDF {
$dom[$key]['align'] = $dom[$parentkey]['align'];
$dom[$key]['listtype'] = $dom[$parentkey]['listtype'];
$dom[$key]['text-indent'] = $dom[$parentkey]['text-indent'];
+ $dom[$key]['text-transform'] = $dom[$parentkey]['text-transform'];
$dom[$key]['border'] = array();
$dom[$key]['dir'] = $dom[$parentkey]['dir'];
}
@@ -16414,6 +16547,10 @@ class TCPDF {
$dom[$key]['text-indent'] = $dom[$parentkey]['text-indent'];
}
}
+ // text-transform
+ if (isset($dom[$key]['style']['text-transform'])) {
+ $dom[$key]['text-transform'] = $dom[$key]['style']['text-transform'];
+ }
// font size
if (isset($dom[$key]['style']['font-size'])) {
$fsize = trim($dom[$key]['style']['font-size']);
@@ -16427,7 +16564,7 @@ class TCPDF {
if (isset($dom[$key]['style']['letter-spacing'])) {
$dom[$key]['letter-spacing'] = $this->getCSSFontSpacing($dom[$key]['style']['letter-spacing'], $dom[$parentkey]['letter-spacing']);
}
- // line-height
+ // line-height (internally is the cell height ratio)
if (isset($dom[$key]['style']['line-height'])) {
$lineheight = trim($dom[$key]['style']['line-height']);
switch ($lineheight) {
@@ -16436,11 +16573,18 @@ class TCPDF {
$dom[$key]['line-height'] = $dom[0]['line-height'];
break;
}
+ case 'inherit': {
+ $dom[$key]['line-height'] = $dom[$parentkey]['line-height'];
+ }
default: {
if (is_numeric($lineheight)) {
- $lineheight = $lineheight * 100;
+ // convert to percentage of font height
+ $lineheight = ($lineheight * 100).'%';
}
$dom[$key]['line-height'] = $this->getHTMLUnitToUnits($lineheight, 1, '%', true);
+ if (substr($lineheight, -1) !== '%') {
+ $dom[$key]['line-height'] = (($dom[$key]['line-height'] - $this->cell_padding['T'] - $this->cell_padding['B']) / $dom[$key]['fontsize']);
+ }
}
}
}
@@ -16706,7 +16850,7 @@ class TCPDF {
if (($dom[$key]['value'] == 'pre') OR ($dom[$key]['value'] == 'tt')) {
$dom[$key]['fontname'] = $this->default_monospaced_font;
}
- if (($dom[$key]['value']{0} == 'h') AND (intval($dom[$key]['value']{1}) > 0) AND (intval($dom[$key]['value']{1}) < 7)) {
+ if (!empty($dom[$key]['value']) AND ($dom[$key]['value']{0} == 'h') AND (intval($dom[$key]['value']{1}) > 0) AND (intval($dom[$key]['value']{1}) < 7)) {
// headings h1, h2, h3, h4, h5, h6
if (!isset($dom[$key]['attribute']['size']) AND !isset($dom[$key]['style']['font-size'])) {
$headsize = (4 - intval($dom[$key]['value']{1})) * 2;
@@ -16799,10 +16943,33 @@ class TCPDF {
// text
$dom[$key]['tag'] = false;
$dom[$key]['block'] = false;
- //$element = str_replace(' ', TCPDF_FONTS::unichr(160, $this->isunicode), $element);
- $dom[$key]['value'] = stripslashes($this->unhtmlentities($element));
$dom[$key]['parent'] = end($level);
$dom[$key]['dir'] = $dom[$dom[$key]['parent']]['dir'];
+ if (!empty($dom[$dom[$key]['parent']]['text-transform'])) {
+ // text-transform for unicode requires mb_convert_case (Multibyte String Functions)
+ if (function_exists('mb_convert_case')) {
+ $ttm = array('capitalize' => MB_CASE_TITLE, 'uppercase' => MB_CASE_UPPER, 'lowercase' => MB_CASE_LOWER);
+ if (isset($ttm[$dom[$dom[$key]['parent']]['text-transform']])) {
+ $element = mb_convert_case($element, $ttm[$dom[$dom[$key]['parent']]['text-transform']], $this->encoding);
+ }
+ } elseif (!$this->isunicode) {
+ switch ($dom[$dom[$key]['parent']]['text-transform']) {
+ case 'capitalize': {
+ $element = ucwords(strtolower($element));
+ break;
+ }
+ case 'uppercase': {
+ $element = strtoupper($element);
+ break;
+ }
+ case 'lowercase': {
+ $element = strtolower($element);
+ break;
+ }
+ }
+ }
+ }
+ $dom[$key]['value'] = stripslashes($this->unhtmlentities($element));
}
++$elkey;
++$key;
@@ -16968,28 +17135,22 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value:
$dom = $this->getHtmlDomArray($html);
$maxel = count($dom);
$key = 0;
- $hidden_node_key = -1;
while ($key < $maxel) {
- if ($dom[$key]['tag']) {
- if ($dom[$key]['opening']) {
- if (($hidden_node_key <= 0) AND $dom[$key]['hide']) {
- // store the node key
- $hidden_node_key = $key;
+ if ($dom[$key]['tag'] AND $dom[$key]['opening'] AND $dom[$key]['hide']) {
+ // store the node key
+ $hidden_node_key = $key;
+ if ($dom[$key]['self']) {
+ // skip just this self-closing tag
+ ++$key;
+ } else {
+ // skip this and all children tags
+ while (($key < $maxel) AND (!$dom[$key]['tag'] OR $dom[$key]['opening'] OR ($dom[$key]['parent'] != $hidden_node_key))) {
+ // skip hidden objects
+ ++$key;
}
- } elseif (($hidden_node_key > 0) AND ($dom[$key]['parent'] == $hidden_node_key)) {
- // we have reached the closing tag of the hidden node
- $hidden_node_key = 0;
+ ++$key;
}
}
- if ($hidden_node_key >= 0) {
- // skip this node
- ++$key;
- if ($hidden_node_key == 0) {
- // reset hidden mode
- $hidden_node_key = -1;
- }
- continue;
- }
if ($dom[$key]['tag'] AND isset($dom[$key]['attribute']['pagebreak'])) {
// check for pagebreak
if (($dom[$key]['attribute']['pagebreak'] == 'true') OR ($dom[$key]['attribute']['pagebreak'] == 'left') OR ($dom[$key]['attribute']['pagebreak'] == 'right')) {
@@ -17183,18 +17344,18 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value:
$startliney = $this->y;
$this->newline = false;
}
- $this->y += ((($curfontsize * $this->cell_height_ratio / $this->k) + $curfontascent - $curfontdescent) / 2) - $imgh;
+ $this->y += (($this->getCellHeight($curfontsize / $this->k) + $curfontascent - $curfontdescent) / 2) - $imgh;
$minstartliney = min($this->y, $minstartliney);
- $maxbottomliney = ($startliney + ($this->FontSize * $this->cell_height_ratio));
+ $maxbottomliney = ($startliney + $this->getCellHeight($this->FontSize));
}
} elseif (isset($dom[$key]['fontname']) OR isset($dom[$key]['fontstyle']) OR isset($dom[$key]['fontsize']) OR isset($dom[$key]['line-height'])) {
// account for different font size
$pfontname = $curfontname;
$pfontstyle = $curfontstyle;
$pfontsize = $curfontsize;
- $fontname = isset($dom[$key]['fontname']) ? $dom[$key]['fontname'] : $curfontname;
- $fontstyle = isset($dom[$key]['fontstyle']) ? $dom[$key]['fontstyle'] : $curfontstyle;
- $fontsize = isset($dom[$key]['fontsize']) ? $dom[$key]['fontsize'] : $curfontsize;
+ $fontname = (isset($dom[$key]['fontname']) ? $dom[$key]['fontname'] : $curfontname);
+ $fontstyle = (isset($dom[$key]['fontstyle']) ? $dom[$key]['fontstyle'] : $curfontstyle);
+ $fontsize = (isset($dom[$key]['fontsize']) ? $dom[$key]['fontsize'] : $curfontsize);
$fontascent = $this->getFontAscent($fontname, $fontstyle, $fontsize);
$fontdescent = $this->getFontDescent($fontname, $fontstyle, $fontsize);
if (($fontname != $curfontname) OR ($fontstyle != $curfontstyle) OR ($fontsize != $curfontsize)
@@ -17256,10 +17417,10 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value:
$current_line_align_data = array($key, $minstartliney, $maxbottomliney);
if (isset($line_align_data) AND (($line_align_data[0] == ($key - 1)) OR (($line_align_data[0] == ($key - 2)) AND (isset($dom[($key - 1)])) AND (preg_match('/^([\s]+)$/', $dom[($key - 1)]['value']) > 0)))) {
$minstartliney = min($this->y, $line_align_data[1]);
- $maxbottomliney = max(($this->y + (($fontsize * $this->cell_height_ratio) / $this->k)), $line_align_data[2]);
+ $maxbottomliney = max(($this->y + $this->getCellHeight($fontsize / $this->k)), $line_align_data[2]);
} else {
$minstartliney = min($this->y, $minstartliney);
- $maxbottomliney = max(($this->y + (($fontsize * $this->cell_height_ratio) / $this->k)), $maxbottomliney);
+ $maxbottomliney = max(($this->y + $this->getCellHeight($fontsize / $this->k)), $maxbottomliney);
}
$line_align_data = $current_line_align_data;
}
@@ -17476,7 +17637,6 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value:
if ($this->isRTLTextDir()) {
$textpos = $this->wPt;
}
- global $spacew;
while (preg_match('/([0-9\.\+\-]*)[\s](Td|cm|m|l|c|re)[\s]/x', $pmid, $strpiece, PREG_OFFSET_CAPTURE, $offset) == 1) {
// check if we are inside a string section '[( ... )]'
$stroffset = strpos($pmid, '[(', $offset);
@@ -17522,6 +17682,9 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value:
case 'l': {
// get current X position
preg_match('/([0-9\.\+\-]*)[\s]('.$strpiece[1][0].')[\s]('.$strpiece[2][0].')([\s]*)/x', $pmid, $xmatches);
+ if (!isset($xmatches[1])) {
+ break;
+ }
$currentxpos = $xmatches[1];
$textpos = $currentxpos;
if (($strcount <= $maxkk) AND ($strpiece[2][0] == 'Td')) {
@@ -17532,10 +17695,11 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value:
++$strcount;
}
// justify block
- $pmid = preg_replace_callback('/([0-9\.\+\-]*)[\s]('.$strpiece[1][0].')[\s]('.$strpiece[2][0].')([\s]*)/x',
- create_function('$matches', 'global $spacew;
- $newx = sprintf("%F",(floatval($matches[1]) + $spacew));
- return "".$newx." ".$matches[2]." x*#!#*x".$matches[3].$matches[4];'), $pmid, 1);
+ if (preg_match('/([0-9\.\+\-]*)[\s]('.$strpiece[1][0].')[\s]('.$strpiece[2][0].')([\s]*)/x', $pmid, $pmatch) == 1) {
+ $newpmid = sprintf('%F',(floatval($pmatch[1]) + $spacew)).' '.$pmatch[2].' x*#!#*x'.$pmatch[3].$pmatch[4];
+ $pmid = str_replace($pmatch[0], $newpmid, $pmid);
+ unset($pmatch, $newpmid);
+ }
break;
}
case 're': {
@@ -17545,8 +17709,10 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value:
continue;
}
preg_match('/([0-9\.\+\-]*)[\s]([0-9\.\+\-]*)[\s]([0-9\.\+\-]*)[\s]('.$strpiece[1][0].')[\s](re)([\s]*)/x', $pmid, $xmatches);
+ if (!isset($xmatches[1])) {
+ break;
+ }
$currentxpos = $xmatches[1];
- global $x_diff, $w_diff;
$x_diff = 0;
$w_diff = 0;
if ($this->isRTLTextDir()) { // RTL
@@ -17574,24 +17740,31 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value:
}
}
}
- $pmid = preg_replace_callback('/('.$xmatches[1].')[\s]('.$xmatches[2].')[\s]('.$xmatches[3].')[\s]('.$strpiece[1][0].')[\s](re)([\s]*)/x',
- create_function('$matches', 'global $x_diff, $w_diff;
- $newx = sprintf("%F",(floatval($matches[1]) + $x_diff));
- $neww = sprintf("%F",(floatval($matches[3]) + $w_diff));
- return "".$newx." ".$matches[2]." ".$neww." ".$matches[4]." x*#!#*x".$matches[5].$matches[6];'), $pmid, 1);
+ if (preg_match('/('.$xmatches[1].')[\s]('.$xmatches[2].')[\s]('.$xmatches[3].')[\s]('.$strpiece[1][0].')[\s](re)([\s]*)/x', $pmid, $pmatch) == 1) {
+ $newx = sprintf('%F',(floatval($pmatch[1]) + $x_diff));
+ $neww = sprintf('%F',(floatval($pmatch[3]) + $w_diff));
+ $newpmid = $newx.' '.$pmatch[2].' '.$neww.' '.$pmatch[4].' x*#!#*x'.$pmatch[5].$pmatch[6];
+ $pmid = str_replace($pmatch[0], $newpmid, $pmid);
+ unset($pmatch, $newpmid, $newx, $neww);
+ }
break;
}
case 'c': {
// get current X position
preg_match('/([0-9\.\+\-]*)[\s]([0-9\.\+\-]*)[\s]([0-9\.\+\-]*)[\s]([0-9\.\+\-]*)[\s]([0-9\.\+\-]*)[\s]('.$strpiece[1][0].')[\s](c)([\s]*)/x', $pmid, $xmatches);
+ if (!isset($xmatches[1])) {
+ break;
+ }
$currentxpos = $xmatches[1];
// justify block
- $pmid = preg_replace_callback('/('.$xmatches[1].')[\s]('.$xmatches[2].')[\s]('.$xmatches[3].')[\s]('.$xmatches[4].')[\s]('.$xmatches[5].')[\s]('.$strpiece[1][0].')[\s](c)([\s]*)/x',
- create_function('$matches', 'global $spacew;
- $newx1 = sprintf("%F",(floatval($matches[1]) + $spacew));
- $newx2 = sprintf("%F",(floatval($matches[3]) + $spacew));
- $newx3 = sprintf("%F",(floatval($matches[5]) + $spacew));
- return "".$newx1." ".$matches[2]." ".$newx2." ".$matches[4]." ".$newx3." ".$matches[6]." x*#!#*x".$matches[7].$matches[8];'), $pmid, 1);
+ if (preg_match('/('.$xmatches[1].')[\s]('.$xmatches[2].')[\s]('.$xmatches[3].')[\s]('.$xmatches[4].')[\s]('.$xmatches[5].')[\s]('.$strpiece[1][0].')[\s](c)([\s]*)/x', $pmid, $pmatch) == 1) {
+ $newx1 = sprintf('%F',(floatval($pmatch[1]) + $spacew));
+ $newx2 = sprintf('%F',(floatval($pmatch[3]) + $spacew));
+ $newx3 = sprintf('%F',(floatval($pmatch[5]) + $spacew));
+ $newpmid = $newx1.' '.$pmatch[2].' '.$newx2.' '.$pmatch[4].' '.$newx3.' '.$pmatch[6].' x*#!#*x'.$pmatch[7].$pmatch[8];
+ $pmid = str_replace($pmatch[0], $newpmid, $pmid);
+ unset($pmatch, $newpmid, $newx1, $newx2, $newx3);
+ }
break;
}
}
@@ -17634,15 +17807,24 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value:
// word spacing is affected by stretching
$spacew /= ($this->font_stretching / 100);
}
- $pmidtemp = $pmid;
// escape special characters
- $pmidtemp = preg_replace('/[\\\][\(]/x', '\\#!#OP#!#', $pmidtemp);
- $pmidtemp = preg_replace('/[\\\][\)]/x', '\\#!#CP#!#', $pmidtemp);
- $pmid = preg_replace_callback("/\[\(([^\)]*)\)\]/x",
- create_function('$matches', 'global $spacew;
- $matches[1] = str_replace("#!#OP#!#", "(", $matches[1]);
- $matches[1] = str_replace("#!#CP#!#", ")", $matches[1]);
- return "[(".str_replace(chr(0).chr(32), ") ".sprintf("%F", $spacew)." (", $matches[1]).")]";'), $pmidtemp);
+ $pos = 0;
+ $pmid = preg_replace('/[\\\][\(]/x', '\\#!#OP#!#', $pmid);
+ $pmid = preg_replace('/[\\\][\)]/x', '\\#!#CP#!#', $pmid);
+ if (preg_match_all('/\[\(([^\)]*)\)\]/x', $pmid, $pamatch) > 0) {
+ foreach($pamatch[0] as $pk => $pmatch) {
+ $replace = $pamatch[1][$pk];
+ $replace = str_replace('#!#OP#!#', '(', $replace);
+ $replace = str_replace('#!#CP#!#', ')', $replace);
+ $newpmid = '[('.str_replace(chr(0).chr(32), ') '.sprintf('%F', $spacew).' (', $replace).')]';
+ $pos = strpos($pmid, $pmatch, $pos);
+ if ($pos !== FALSE) {
+ $pmid = substr_replace($pmid, $newpmid, $pos, strlen($pmatch));
+ }
+ ++$pos;
+ }
+ unset($pamatch);
+ }
if ($this->inxobj) {
// we are inside an XObject template
$this->xobjects[$this->xobjid]['outdata'] = $pstart."\n".$pmid."\n".$pend;
@@ -17708,7 +17890,7 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value:
$startliney -= (($this->FontSizePt / 0.7) / $this->k);
} else {
$minstartliney = $startliney;
- $maxbottomliney = ($this->y + (($fontsize * $this->cell_height_ratio) / $this->k));
+ $maxbottomliney = ($this->y + $this->getCellHeight($fontsize / $this->k));
}
$startlinepage = $this->page;
if (isset($endlinepos) AND (!$pbrk)) {
@@ -18043,16 +18225,18 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value:
$this->SetFont($pfontname, $pfontstyle, $pfontsize);
$this->resetLastH();
$minstartliney = $this->y;
- $maxbottomliney = ($startliney + ($this->FontSize * $this->cell_height_ratio));
- $this->putHtmlListBullet($this->listnum, $this->lispacer, $pfontsize);
+ $maxbottomliney = ($startliney + $this->getCellHeight($this->FontSize));
+ if (is_numeric($pfontsize) AND ($pfontsize > 0)) {
+ $this->putHtmlListBullet($this->listnum, $this->lispacer, $pfontsize);
+ }
$this->SetFont($curfontname, $curfontstyle, $curfontsize);
$this->resetLastH();
if (is_numeric($pfontsize) AND ($pfontsize > 0) AND is_numeric($curfontsize) AND ($curfontsize > 0) AND ($pfontsize != $curfontsize)) {
$pfontascent = $this->getFontAscent($pfontname, $pfontstyle, $pfontsize);
$pfontdescent = $this->getFontDescent($pfontname, $pfontstyle, $pfontsize);
- $this->y += ((($pfontsize - $curfontsize) * $this->cell_height_ratio / $this->k) + $pfontascent - $curfontascent - $pfontdescent + $curfontdescent) / 2;
+ $this->y += ($this->getCellHeight(($pfontsize - $curfontsize) / $this->k) + $pfontascent - $curfontascent - $pfontdescent + $curfontdescent) / 2;
$minstartliney = min($this->y, $minstartliney);
- $maxbottomliney = max(($this->y + (($pfontsize * $this->cell_height_ratio) / $this->k)), $maxbottomliney);
+ $maxbottomliney = max(($this->y + $this->getCellHeight($pfontsize / $this->k)), $maxbottomliney);
}
}
// text
@@ -18425,9 +18609,9 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value:
if (isset($this->tagvspaces[$tag['value']][0]['h']) AND ($this->tagvspaces[$tag['value']][0]['h'] >= 0)) {
$cur_h = $this->tagvspaces[$tag['value']][0]['h'];
} elseif (isset($tag['fontsize'])) {
- $cur_h = ($tag['fontsize'] / $this->k) * $this->cell_height_ratio;
+ $cur_h = $this->getCellHeight($tag['fontsize'] / $this->k);
} else {
- $cur_h = $this->FontSize * $this->cell_height_ratio;
+ $cur_h = $this->getCellHeight($this->FontSize);
}
if (isset($this->tagvspaces[$tag['value']][0]['n'])) {
$n = $this->tagvspaces[$tag['value']][0]['n'];
@@ -18443,9 +18627,9 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value:
}
if (($this->htmlvspace <= 0) AND ($n > 0)) {
if (isset($parent['fontsize'])) {
- $hbz = (($parent['fontsize'] / $this->k) * $this->cell_height_ratio);
+ $hbz = $this->getCellHeight($tag['fontsize'] / $this->k);
} else {
- $hbz = $this->FontSize * $this->cell_height_ratio;
+ $hbz = $this->getCellHeight($this->FontSize);
}
}
if (isset($dom[($key - 1)]) AND ($dom[($key - 1)]['value'] == 'table')) {
@@ -18472,6 +18656,7 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value:
$this->theadMargins['rmargin'] = $this->rMargin;
$this->theadMargins['page'] = $this->page;
$this->theadMargins['cell'] = $cell;
+ $this->theadMargins['gvars'] = $this->getGraphicVars();
}
}
}
@@ -18533,7 +18718,7 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value:
break;
}
case 'img': {
- if (isset($tag['attribute']['src'])) {
+ if (!empty($tag['attribute']['src'])) {
if ($tag['attribute']['src']{0} === '@') {
// data stream
$tag['attribute']['src'] = '@'.base64_decode(substr($tag['attribute']['src'], 1));
@@ -18797,7 +18982,7 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value:
if (isset($tag['attribute']['maxlength']) AND !TCPDF_STATIC::empty_string($tag['attribute']['maxlength'])) {
$opt['maxlen'] = intval($tag['attribute']['maxlength']);
}
- $h = $this->FontSize * $this->cell_height_ratio;
+ $h = $this->getCellHeight($this->FontSize);
if (isset($tag['attribute']['size']) AND !TCPDF_STATIC::empty_string($tag['attribute']['size'])) {
$w = intval($tag['attribute']['size']) * $this->GetStringWidth(chr(32)) * 2;
} else {
@@ -18959,7 +19144,7 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value:
$w = 40;
}
if (isset($tag['attribute']['rows']) AND !TCPDF_STATIC::empty_string($tag['attribute']['rows'])) {
- $h = intval($tag['attribute']['rows']) * $this->FontSize * $this->cell_height_ratio;
+ $h = intval($tag['attribute']['rows']) * $this->getCellHeight($this->FontSize);
} else {
$h = 10;
}
@@ -18968,7 +19153,7 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value:
break;
}
case 'select': {
- $h = $this->FontSize * $this->cell_height_ratio;
+ $h = $this->getCellHeight($this->FontSize);
if (isset($tag['attribute']['size']) AND !TCPDF_STATIC::empty_string($tag['attribute']['size'])) {
$h *= ($tag['attribute']['size'] + 1);
}
@@ -19076,9 +19261,9 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value:
if (isset($this->tagvspaces[$tag['value']][1]['h']) AND ($this->tagvspaces[$tag['value']][1]['h'] >= 0)) {
$pre_h = $this->tagvspaces[$tag['value']][1]['h'];
} elseif (isset($parent['fontsize'])) {
- $pre_h = (($parent['fontsize'] / $this->k) * $this->cell_height_ratio);
+ $pre_h = $this->getCellHeight($parent['fontsize'] / $this->k);
} else {
- $pre_h = $this->FontSize * $this->cell_height_ratio;
+ $pre_h = $this->getCellHeight($this->FontSize);
}
if (isset($this->tagvspaces[$tag['value']][1]['n'])) {
$n = $this->tagvspaces[$tag['value']][1]['n'];
@@ -19093,7 +19278,7 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value:
$hb = ($n * $pre_h);
}
if ($maxbottomliney > $this->PageBreakTrigger) {
- $hbz = ($this->FontSize * $this->cell_height_ratio);
+ $hbz = $this->getCellHeight($this->FontSize);
} elseif ($this->y < $maxbottomliney) {
$hbz = ($maxbottomliney - $this->y);
}
@@ -19844,32 +20029,11 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value:
return;
}
$symbol = strtolower($symbol);
- switch ($symbol) {
- case '!' :
- case '#' :
- case 'disc' :
- case 'circle' :
- case 'square' :
- case '1':
- case 'decimal':
- case 'decimal-leading-zero':
- case 'i':
- case 'lower-roman':
- case 'I':
- case 'upper-roman':
- case 'a':
- case 'lower-alpha':
- case 'lower-latin':
- case 'A':
- case 'upper-alpha':
- case 'upper-latin':
- case 'lower-greek': {
- $this->lisymbol = $symbol;
- break;
- }
- default : {
- $this->lisymbol = '';
- }
+ $valid_symbols = array('!', '#', 'disc', 'circle', 'square', '1', 'decimal', 'decimal-leading-zero', 'i', 'lower-roman', 'I', 'upper-roman', 'a', 'lower-alpha', 'lower-latin', 'A', 'upper-alpha', 'upper-latin', 'lower-greek');
+ if (in_array($symbol, $valid_symbols)) {
+ $this->lisymbol = $symbol;
+ } else {
+ $this->lisymbol = '';
}
}
@@ -20221,7 +20385,7 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value:
if (!TCPDF_STATIC::empty_string($textitem)) {
// Check whether we need a new page or new column
$prev_y = $this->y;
- $h = ($this->FontSize * $this->cell_height_ratio) + $this->cell_padding['T'] + $this->cell_padding['B'];
+ $h = $this->getCellHeight($this->FontSize);
if ($this->checkPageBreak($h) OR ($this->y < $prev_y)) {
$tmpx = $this->x;
}
@@ -20424,7 +20588,7 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value:
$this->bufferlen += strlen($data);
if ($this->diskcache) {
if (!isset($this->buffer) OR TCPDF_STATIC::empty_string($this->buffer)) {
- $this->buffer = TCPDF_STATIC::getObjFilename('buffer');
+ $this->buffer = TCPDF_STATIC::getObjFilename('buf');
}
$this->writeDiskCache($this->buffer, $data, true);
} else {
@@ -20442,7 +20606,7 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value:
$this->bufferlen = strlen($data);
if ($this->diskcache) {
if (!isset($this->buffer) OR TCPDF_STATIC::empty_string($this->buffer)) {
- $this->buffer = TCPDF_STATIC::getObjFilename('buffer');
+ $this->buffer = TCPDF_STATIC::getObjFilename('buf');
}
$this->writeDiskCache($this->buffer, $data, false);
} else {
@@ -20475,7 +20639,7 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value:
protected function setPageBuffer($page, $data, $append=false) {
if ($this->diskcache) {
if (!isset($this->pages[$page])) {
- $this->pages[$page] = TCPDF_STATIC::getObjFilename('page'.$page);
+ $this->pages[$page] = TCPDF_STATIC::getObjFilename('page');
}
$this->writeDiskCache($this->pages[$page], $data, $append);
} else {
@@ -20524,7 +20688,7 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value:
}
if ($this->diskcache) {
if (!isset($this->images[$image])) {
- $this->images[$image] = TCPDF_STATIC::getObjFilename('image'.$image);
+ $this->images[$image] = TCPDF_STATIC::getObjFilename('img');
}
$this->writeDiskCache($this->images[$image], serialize($data));
} else {
@@ -20775,22 +20939,24 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value:
}
}
// adjust javascript
- $tmpjavascript = $this->javascript;
- global $jfrompage, $jtopage;
$jfrompage = $frompage;
$jtopage = $topage;
- $this->javascript = preg_replace_callback('/this\.addField\(\'([^\']*)\',\'([^\']*)\',([0-9]+)/',
- create_function('$matches', 'global $jfrompage, $jtopage;
- $pagenum = intval($matches[3]) + 1;
- if (($pagenum >= $jtopage) AND ($pagenum < $jfrompage)) {
- $newpage = ($pagenum + 1);
- } elseif ($pagenum == $jfrompage) {
- $newpage = $jtopage;
- } else {
- $newpage = $pagenum;
+ if (preg_match_all('/this\.addField\(\'([^\']*)\',\'([^\']*)\',([0-9]+)/', $this->javascript, $pamatch) > 0) {
+ foreach($pamatch[0] as $pk => $pmatch) {
+ $pagenum = intval($pamatch[3][$pk]) + 1;
+ if (($pagenum >= $jtopage) AND ($pagenum < $jfrompage)) {
+ $newpage = ($pagenum + 1);
+ } elseif ($pagenum == $jfrompage) {
+ $newpage = $jtopage;
+ } else {
+ $newpage = $pagenum;
+ }
+ --$newpage;
+ $newjs = "this.addField(\'".$pamatch[1][$pk]."\',\'".$pamatch[2][$pk]."\',".$newpage;
+ $this->javascript = str_replace($pmatch, $newjs, $this->javascript);
}
- --$newpage;
- return "this.addField(\'".$matches[1]."\',\'".$matches[2]."\',".$newpage."";'), $tmpjavascript);
+ unset($pamatch);
+ }
// return to last page
$this->lastPage(true);
return true;
@@ -20956,21 +21122,23 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value:
}
}
// adjust javascript
- $tmpjavascript = $this->javascript;
- global $jpage;
$jpage = $page;
- $this->javascript = preg_replace_callback('/this\.addField\(\'([^\']*)\',\'([^\']*)\',([0-9]+)/',
- create_function('$matches', 'global $jpage;
- $pagenum = intval($matches[3]) + 1;
- if ($pagenum >= $jpage) {
- $newpage = ($pagenum - 1);
- } elseif ($pagenum == $jpage) {
- $newpage = 1;
- } else {
- $newpage = $pagenum;
+ if (preg_match_all('/this\.addField\(\'([^\']*)\',\'([^\']*)\',([0-9]+)/', $this->javascript, $pamatch) > 0) {
+ foreach($pamatch[0] as $pk => $pmatch) {
+ $pagenum = intval($pamatch[3][$pk]) + 1;
+ if ($pagenum >= $jpage) {
+ $newpage = ($pagenum - 1);
+ } elseif ($pagenum == $jpage) {
+ $newpage = 1;
+ } else {
+ $newpage = $pagenum;
+ }
+ --$newpage;
+ $newjs = "this.addField(\'".$pamatch[1][$pk]."\',\'".$pamatch[2][$pk]."\',".$newpage;
+ $this->javascript = str_replace($pmatch, $newjs, $this->javascript);
}
- --$newpage;
- return "this.addField(\'".$matches[1]."\',\'".$matches[2]."\',".$newpage."";'), $tmpjavascript);
+ unset($pamatch);
+ }
// return to last page
if ($this->numpages > 0) {
$this->lastPage(true);
@@ -21112,7 +21280,7 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value:
}
$this->SetTextColorArray($outline['c']);
// check for page break
- $this->checkPageBreak((2 * $this->FontSize * $this->cell_height_ratio));
+ $this->checkPageBreak(2 * $this->getCellHeight($this->FontSize));
// set margins and X position
if (($this->page == $current_page) AND ($this->current_column == $current_column)) {
$this->lMargin = $lmargin;
@@ -22355,7 +22523,7 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value:
return array($x, $y);
}
if (empty($h)) {
- $h = ($this->FontSize * $this->cell_height_ratio) + $this->cell_padding['T'] + $this->cell_padding['B'];
+ $h = $this->getCellHeight($this->FontSize);
}
// check for page break
if ($this->checkPageBreak($h, $y)) {
@@ -22449,6 +22617,17 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value:
if ($this->state != 2) {
return;
}
+ // reseet SVG vars
+ $this->svggradients = array();
+ $this->svggradientid = 0;
+ $this->svgdefsmode = false;
+ $this->svgdefs = array();
+ $this->svgclipmode = false;
+ $this->svgclippaths = array();
+ $this->svgcliptm = array();
+ $this->svgclipid = 0;
+ $this->svgtext = '';
+ $this->svgtextmode = array();
if ($this->rasterize_vector_images AND ($w > 0) AND ($h > 0)) {
// convert SVG to raster image using GD or ImageMagick libraries
return $this->Image($file, $x, $y, $w, $h, 'SVG', $link, $align, true, 300, $palign, false, false, $border, false, false, false);
@@ -23268,7 +23447,7 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value:
}
break;
}
- case 'Q': { // quadratic Bézier curveto
+ case 'Q': { // quadratic Bezier curveto
foreach ($params as $ck => $cp) {
$params[$ck] = $cp;
if ((($ck + 1) % 4) == 0) {
@@ -23294,7 +23473,7 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value:
}
break;
}
- case 'T': { // shorthand/smooth quadratic Bézier curveto
+ case 'T': { // shorthand/smooth quadratic Bezier curveto
foreach ($params as $ck => $cp) {
$params[$ck] = $cp;
if (($ck % 2) != 0) {
@@ -23447,10 +23626,19 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value:
return;
}
if ($this->svgdefsmode AND !in_array($name, array('clipPath', 'linearGradient', 'radialGradient', 'stop'))) {
- if (!isset($attribs['id'])) {
- $attribs['id'] = 'DF_'.(count($this->svgdefs) + 1);
+ if (isset($attribs['id'])) {
+ $attribs['child_elements'] = array();
+ $this->svgdefs[$attribs['id']] = array('name' => $name, 'attribs' => $attribs);
+ return;
+ }
+ if (end($this->svgdefs) !== FALSE) {
+ $last_svgdefs_id = key($this->svgdefs);
+ if (isset($this->svgdefs[$last_svgdefs_id]['attribs']['child_elements'])) {
+ $attribs['id'] = 'DF_'.(count($this->svgdefs[$last_svgdefs_id]['attribs']['child_elements']) + 1);
+ $this->svgdefs[$last_svgdefs_id]['attribs']['child_elements'][$attribs['id']] = array('name' => $name, 'attribs' => $attribs);
+ return;
+ }
}
- $this->svgdefs[$attribs['id']] = array('name' => $name, 'attribs' => $attribs);
return;
}
$clipping = false;
@@ -23459,13 +23647,13 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value:
$clipping = true;
}
// get styling properties
- $prev_svgstyle = $this->svgstyles[(count($this->svgstyles) - 1)]; // previous style
+ $prev_svgstyle = $this->svgstyles[max(0,(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 !TCPDF_STATIC::empty_string($attribs['style'])) {
+ if (isset($attribs['style']) AND !TCPDF_STATIC::empty_string($attribs['style']) AND ($attribs['style'][0] != ';')) {
// fix style for regular expression
$attribs['style'] = ';'.$attribs['style'];
}
@@ -23497,7 +23685,6 @@ 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 = array(1,0,0,1,0,0);
}
if (isset($attribs['transform']) AND !empty($attribs['transform'])) {
@@ -23537,6 +23724,11 @@ 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();
+ $x = (isset($attribs['x'])?$attribs['x']:0);
+ $y = (isset($attribs['y'])?$attribs['y']:0);
+ $w = (isset($attribs['width'])?$attribs['width']:1);
+ $h = (isset($attribs['height'])?$attribs['height']:1);
+ $tm = TCPDF_STATIC::getTransformationMatrixProduct($tm, array($w, 0, 0, $h, $x, $y));
$this->SVGTransform($tm);
$this->setSVGStyles($svgstyle, $prev_svgstyle);
break;
@@ -23643,13 +23835,18 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value:
if (isset($attribs['d'])) {
$d = trim($attribs['d']);
if (!empty($d)) {
+ $x = (isset($attribs['x'])?$attribs['x']:0);
+ $y = (isset($attribs['y'])?$attribs['y']:0);
+ $w = (isset($attribs['width'])?$attribs['width']:1);
+ $h = (isset($attribs['height'])?$attribs['height']:1);
+ $tm = TCPDF_STATIC::getTransformationMatrixProduct($tm, array($w, 0, 0, $h, $x, $y));
if ($clipping) {
$this->SVGTransform($tm);
$this->SVGPath($d, 'CNZ');
} else {
$this->StartTransform();
$this->SVGTransform($tm);
- $obstyle = $this->setSVGStyles($svgstyle, $prev_svgstyle, 0, 0, 1, 1, 'SVGPath', array($d, 'CNZ'));
+ $obstyle = $this->setSVGStyles($svgstyle, $prev_svgstyle, $x, $y, $w, $h, 'SVGPath', array($d, 'CNZ'));
if (!empty($obstyle)) {
$this->SVGPath($d, $obstyle);
}
@@ -23938,8 +24135,22 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value:
if (isset($attribs['id'])) {
unset($attribs['id']);
}
- $attribs = array_merge($attribs, $use['attribs']);
- $this->startSVGElementHandler($parser, $use['name'], $attribs);
+ if (isset($use['attribs']['x']) AND isset($attribs['x'])) {
+ $attribs['x'] += $use['attribs']['x'];
+ }
+ if (isset($use['attribs']['y']) AND isset($attribs['y'])) {
+ $attribs['y'] += $use['attribs']['y'];
+ }
+ if (empty($attribs['style'])) {
+ $attribs['style'] = '';
+ }
+ if (!empty($use['attribs']['style'])) {
+ // merge styles
+ $attribs['style'] = str_replace(';;',';',';'.$use['attribs']['style'].$attribs['style']);
+ }
+ $attribs = array_merge($use['attribs'], $attribs);
+ $this->startSVGElementHandler('use-tag', $use['name'], $attribs);
+ return;
}
}
break;
@@ -23948,6 +24159,21 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value:
break;
}
} // end of switch
+ // process child elements
+ if (!empty($attribs['child_elements'])) {
+ $child_elements = $attribs['child_elements'];
+ unset($attribs['child_elements']);
+ foreach($child_elements as $child_element) {
+ if (empty($child_element['attribs']['closing_tag'])) {
+ $this->startSVGElementHandler('child-tag', $child_element['name'], $child_element['attribs']);
+ } else {
+ if (isset($child_element['attribs']['content'])) {
+ $this->svgtext = $child_element['attribs']['content'];
+ }
+ $this->endSVGElementHandler('child-tag', $child_element['name']);
+ }
+ }
+ }
}
/**
@@ -23959,6 +24185,24 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value:
* @protected
*/
protected function endSVGElementHandler($parser, $name) {
+ if ($this->svgdefsmode AND !in_array($name, array('defs', 'clipPath', 'linearGradient', 'radialGradient', 'stop'))) {;
+ if (end($this->svgdefs) !== FALSE) {
+ $last_svgdefs_id = key($this->svgdefs);
+ if (isset($this->svgdefs[$last_svgdefs_id]['attribs']['child_elements'])) {
+ foreach($this->svgdefs[$last_svgdefs_id]['attribs']['child_elements'] as $child_element) {
+ if (isset($child_element['attribs']['id']) AND ($child_element['name'] == $name)) {
+ $this->svgdefs[$last_svgdefs_id]['attribs']['child_elements'][$child_element['attribs']['id'].'_CLOSE'] = array('name' => $name, 'attribs' => array('closing_tag' => TRUE, 'content' => $this->svgtext));
+ return;
+ }
+ }
+ if ($this->svgdefs[$last_svgdefs_id]['name'] == $name) {
+ $this->svgdefs[$last_svgdefs_id]['attribs']['child_elements'][$last_svgdefs_id.'_CLOSE'] = array('name' => $name, 'attribs' => array('closing_tag' => TRUE, 'content' => $this->svgtext));
+ return;
+ }
+ }
+ }
+ return;
+ }
switch($name) {
case 'defs': {
$this->svgdefsmode = false;
@@ -24021,7 +24265,9 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value:
$this->textstrokewidth = $textstrokewidth;
$this->svgtext = '';
$this->StopTransform();
- array_pop($this->svgstyles);
+ if (!$this->svgdefsmode) {
+ array_pop($this->svgstyles);
+ }
break;
}
default: {
diff --git a/lib/tcpdf/tcpdf_autoconfig.php b/lib/tcpdf/tcpdf_autoconfig.php
index 2fc1da6da58..b2f013e72d3 100644
--- a/lib/tcpdf/tcpdf_autoconfig.php
+++ b/lib/tcpdf/tcpdf_autoconfig.php
@@ -3,11 +3,11 @@
// File name : tcpdf_autoconfig.php
// Version : 1.0.000
// Begin : 2013-05-16
-// Last Update : 2013-05-16
+// Last Update : 2014-01-25
// Authors : Nicola Asuni - Tecnick.com LTD - www.tecnick.com - info@tecnick.com
// License : GNU-LGPL v3 (http://www.gnu.org/copyleft/lesser.html)
// -------------------------------------------------------------------
-// Copyright (C) 2011-2013 Nicola Asuni - Tecnick.com LTD
+// Copyright (C) 2011-2014 Nicola Asuni - Tecnick.com LTD
//
// This file is part of TCPDF software library.
//
@@ -117,7 +117,11 @@ if (!defined('PDF_HEADER_LOGO_WIDTH')) {
}
if (!defined('K_PATH_CACHE')) {
- define ('K_PATH_CACHE', sys_get_temp_dir().'/');
+ $K_PATH_CACHE = ini_get('upload_tmp_dir') ? ini_get('upload_tmp_dir') : sys_get_temp_dir();
+ if (substr($K_PATH_CACHE, -1) != '/') {
+ $K_PATH_CACHE .= '/';
+ }
+ define ('K_PATH_CACHE', $K_PATH_CACHE);
}
if (!defined('K_BLANK_IMAGE')) {
diff --git a/lib/tcpdf/tcpdf_parser.php b/lib/tcpdf/tcpdf_parser.php
index d3d8d45c481..0b2a7e144f3 100644
--- a/lib/tcpdf/tcpdf_parser.php
+++ b/lib/tcpdf/tcpdf_parser.php
@@ -1,13 +1,13 @@
* @package com.tecnick.tcpdf
* @author Nicola Asuni
- * @version 1.0.008
+ * @version 1.0.014
*/
// include class for decoding filters
@@ -48,7 +48,7 @@ require_once(dirname(__FILE__).'/include/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.005
+ * @version 1.0.010
* @author Nicola Asuni - info@tecnick.com
*/
class TCPDF_PARSER {
@@ -103,7 +103,40 @@ class TCPDF_PARSER {
if (empty($data)) {
$this->Error('Empty PDF data.');
}
+ // find the pdf header starting position
+ if (($trimpos = strpos($data, '%PDF-')) === FALSE) {
+ $this->Error('Invalid PDF data: missing %PDF header.');
+ }
+ // get PDF content string
+ $this->pdfdata = substr($data, $trimpos);
+ // get length
+ $pdflen = strlen($this->pdfdata);
// set configuration parameters
+ $this->setConfig($cfg);
+ // get xref and trailer data
+ $this->xref = $this->getXrefData();
+ // parse all document objects
+ $this->objects = array();
+ foreach ($this->xref['xref'] as $obj => $offset) {
+ if (!isset($this->objects[$obj]) AND ($offset > 0)) {
+ // decode objects with positive offset
+ $this->objects[$obj] = $this->getIndirectObject($obj, $offset, true);
+ }
+ }
+ // release some memory
+ unset($this->pdfdata);
+ $this->pdfdata = '';
+ }
+
+ /**
+ * Set the configuration parameters.
+ * @param $cfg (array) Array of configuration parameters:
+ * 'die_for_errors' : if true termitate the program execution in case of error, otherwise thows an exception;
+ * 'ignore_filter_decoding_errors' : if true ignore filter decoding errors;
+ * 'ignore_missing_filter_decoders' : if true ignore missing filter decoding errors.
+ * @public
+ */
+ protected function setConfig($cfg) {
if (isset($cfg['die_for_errors'])) {
$this->cfg['die_for_errors'] = !!$cfg['die_for_errors'];
}
@@ -113,25 +146,6 @@ class TCPDF_PARSER {
if (isset($cfg['ignore_missing_filter_decoders'])) {
$this->cfg['ignore_missing_filter_decoders'] = !!$cfg['ignore_missing_filter_decoders'];
}
- // get PDF content string
- $this->pdfdata = $data;
- // get length
- $pdflen = strlen($this->pdfdata);
- // initialize class for decoding filters
- $this->FilterDecoders = new TCPDF_FILTERS();
- // get xref and trailer data
- $this->xref = $this->getXrefData();
- // parse all document objects
- $this->objects = array();
- foreach ($this->xref['xref'] as $obj => $offset) {
- if (!isset($this->objects[$obj]) AND ($offset > 0)) {
- // decode only objects with positive offset
- $this->objects[$obj] = $this->getIndirectObject($obj, $offset, true);
- }
- }
- // release some memory
- unset($this->pdfdata);
- $this->pdfdata = '';
}
/**
@@ -188,20 +202,25 @@ class TCPDF_PARSER {
/**
* Decode the Cross-Reference section
- * @param $startxref (int) Offset at which the xref section starts.
+ * @param $startxref (int) Offset at which the xref section starts (position of the 'xref' keyword).
* @param $xref (array) Previous xref array (if any).
* @return Array containing xref and trailer data.
* @protected
* @since 1.0.000 (2011-06-20)
*/
protected function decodeXref($startxref, $xref=array()) {
- // extract xref data (object indexes and offsets)
- $xoffset = $startxref + 5;
+ $startxref += 4; // 4 is the lenght of the word 'xref'
+ // skip initial white space chars: \x00 null (NUL), \x09 horizontal tab (HT), \x0A line feed (LF), \x0C form feed (FF), \x0D carriage return (CR), \x20 space (SP)
+ $offset = $startxref + strspn($this->pdfdata, "\x00\x09\x0a\x0c\x0d\x20", $startxref);
// 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]);
+ // search for cross-reference entries or subsection
+ while (preg_match('/([0-9]+)[\x20]([0-9]+)[\x20]?([nf]?)(\r\n|[\x20]?[\r\n])/', $this->pdfdata, $matches, PREG_OFFSET_CAPTURE, $offset) > 0) {
+ if ($matches[0][1] != $offset) {
+ // we are on another section
+ break;
+ }
+ $offset += strlen($matches[0][0]);
if ($matches[3][0] == 'n') {
// create unique object index: [object number]_[generation number]
$index = $obj_num.'_'.intval($matches[2][0]);
@@ -211,17 +230,15 @@ class TCPDF_PARSER {
$xref['xref'][$index] = intval($matches[1][0]);
}
++$obj_num;
- $offset += 2;
} elseif ($matches[3][0] == 'f') {
++$obj_num;
- $offset += 2;
} else {
// object number (index)
$obj_num = intval($matches[1][0]);
}
}
// get trailer data
- if (preg_match('/trailer[\s]*<<(.*)>>[\s]*[\r\n]+startxref[\s]*[\r\n]+/isU', $this->pdfdata, $matches, PREG_OFFSET_CAPTURE, $xoffset) > 0) {
+ if (preg_match('/trailer[\s]*<<(.*)>>/isU', $this->pdfdata, $matches, PREG_OFFSET_CAPTURE, $offset) > 0) {
$trailer_data = $matches[1][0];
if (!isset($xref['trailer']) OR empty($xref['trailer'])) {
// get only the last updated version
@@ -274,7 +291,11 @@ class TCPDF_PARSER {
} else {
$filltrailer = false;
}
+ if (!isset($xref['xref'])) {
+ $xref['xref'] = array();
+ }
$valid_crs = false;
+ $columns = 0;
$sarr = $xrefcrs[0][1];
foreach ($sarr as $k => $v) {
if (($v[0] == '/') AND ($v[1] == 'Type') AND (isset($sarr[($k +1)]) AND ($sarr[($k +1)][0] == '/') AND ($sarr[($k +1)][1] == 'XRef'))) {
@@ -305,10 +326,12 @@ class TCPDF_PARSER {
} elseif ($filltrailer) {
if (($v[0] == '/') AND ($v[1] == 'Size') AND (isset($sarr[($k +1)]) AND ($sarr[($k +1)][0] == 'numeric'))) {
$xref['trailer']['size'] = $sarr[($k +1)][1];
- } elseif (($v[0] == '/') AND ($v[1] == 'Root') AND (isset($sarr[($k +1)]) AND ($sarr[($k +1)][0] == 'ojbref'))) {
+ } elseif (($v[0] == '/') AND ($v[1] == 'Root') AND (isset($sarr[($k +1)]) AND ($sarr[($k +1)][0] == 'objref'))) {
$xref['trailer']['root'] = $sarr[($k +1)][1];
- } elseif (($v[0] == '/') AND ($v[1] == 'Info') AND (isset($sarr[($k +1)]) AND ($sarr[($k +1)][0] == 'ojbref'))) {
+ } elseif (($v[0] == '/') AND ($v[1] == 'Info') AND (isset($sarr[($k +1)]) AND ($sarr[($k +1)][0] == 'objref'))) {
$xref['trailer']['info'] = $sarr[($k +1)][1];
+ } elseif (($v[0] == '/') AND ($v[1] == 'Encrypt') AND (isset($sarr[($k +1)]) AND ($sarr[($k +1)][0] == 'objref'))) {
+ $xref['trailer']['encrypt'] = $sarr[($k +1)][1];
} elseif (($v[0] == '/') AND ($v[1] == 'ID') AND (isset($sarr[($k +1)]))) {
$xref['trailer']['id'] = array();
$xref['trailer']['id'][0] = $sarr[($k +1)][1][0][1];
@@ -406,12 +429,14 @@ class TCPDF_PARSER {
// default type field
$sdata[$k][0] = 1;
}
- $i = 0; // count bytes on the row
+ $i = 0; // count bytes in the row
// for every column
for ($c = 0; $c < 3; ++$c) {
// for every byte on the column
for ($b = 0; $b < $wb[$c]; ++$b) {
- $sdata[$k][$c] += ($row[$i] << (($wb[$c] - 1 - $b) * 8));
+ if (isset($row[$i])) {
+ $sdata[$k][$c] += ($row[$i] << (($wb[$c] - 1 - $b) * 8));
+ }
++$i;
}
}
@@ -426,7 +451,6 @@ class TCPDF_PARSER {
foreach ($sdata as $k => $row) {
switch ($row[0]) {
case 0: { // (f) linked list of free objects
- ++$obj_num;
break;
}
case 1: { // (n) objects that are in use but are not compressed
@@ -437,7 +461,6 @@ class TCPDF_PARSER {
// store object offset position
$xref['xref'][$index] = $row[1];
}
- ++$obj_num;
break;
}
case 2: { // compressed objects
@@ -451,6 +474,7 @@ class TCPDF_PARSER {
break;
}
}
+ ++$obj_num;
}
} // end decoding data
if (isset($prevxref)) {
@@ -481,7 +505,7 @@ class TCPDF_PARSER {
$next = strcspn($this->pdfdata, "\r\n", $offset);
if ($next > 0) {
$offset += $next;
- return $this->getRawObject($this->pdfdata, $offset);
+ return $this->getRawObject($offset);
}
break;
}
@@ -575,7 +599,9 @@ class TCPDF_PARSER {
// remove white space characters
$objval = strtr($matches[1], "\x09\x0a\x0c\x0d\x20", '');
$offset += strlen($matches[0]);
- }
+ } elseif (($endpos = strpos($this->pdfdata, '>', $offset)) !== FALSE) {
+ $offset = $endpos + 1;
+ }
}
break;
}
@@ -605,9 +631,9 @@ class TCPDF_PARSER {
$offset += 6;
if (preg_match('/^([\r]?[\n])/isU', substr($this->pdfdata, $offset), $matches) == 1) {
$offset += strlen($matches[0]);
- if (preg_match('/([\r]?[\n])?(endstream)[\x09\x0a\x0c\x0d\x20]/isU', substr($this->pdfdata, $offset), $matches, PREG_OFFSET_CAPTURE) == 1) {
+ if (preg_match('/(endstream)[\x09\x0a\x0c\x0d\x20]/isU', substr($this->pdfdata, $offset), $matches, PREG_OFFSET_CAPTURE) == 1) {
$objval = substr($this->pdfdata, $offset, $matches[0][1]);
- $offset += $matches[2][1];
+ $offset += $matches[1][1];
}
}
} elseif (substr($this->pdfdata, $offset, 9) == 'endstream') {
@@ -616,12 +642,12 @@ class TCPDF_PARSER {
$offset += 9;
} elseif (preg_match('/^([0-9]+)[\s]+([0-9]+)[\s]+R/iU', substr($this->pdfdata, $offset, 33), $matches) == 1) {
// indirect object reference
- $objtype = 'ojbref';
+ $objtype = 'objref';
$offset += strlen($matches[0]);
$objval = intval($matches[1]).'_'.intval($matches[2]);
} elseif (preg_match('/^([0-9]+)[\s]+([0-9]+)[\s]+obj/iU', substr($this->pdfdata, $offset, 33), $matches) == 1) {
// object start
- $objtype = 'ojb';
+ $objtype = 'obj';
$objval = intval($matches[1]).'_'.intval($matches[2]);
$offset += strlen ($matches[0]);
} elseif (($numlen = strspn($this->pdfdata, '+-.0123456789', $offset)) > 0) {
@@ -652,6 +678,8 @@ class TCPDF_PARSER {
return;
}
$objref = $obj[0].' '.$obj[1].' obj';
+ // ignore leading zeros
+ $offset += strspn($this->pdfdata, '0', $offset);
if (strpos($this->pdfdata, $objref, $offset) != $offset) {
// an indirect reference to an undefined object shall be considered a reference to the null object
return array('null', 'null', $offset);
@@ -744,13 +772,13 @@ class TCPDF_PARSER {
// decode the stream
$remaining_filters = array();
foreach ($filters as $filter) {
- if (in_array($filter, $this->FilterDecoders->getAvailableFilters())) {
+ if (in_array($filter, TCPDF_FILTERS::getAvailableFilters())) {
try {
- $stream = $this->FilterDecoders->decodeFilter($filter, $stream);
+ $stream = TCPDF_FILTERS::decodeFilter($filter, $stream);
} catch (Exception $e) {
$emsg = $e->getMessage();
if ((($emsg[0] == '~') AND !$this->cfg['ignore_missing_filter_decoders'])
- OR (($emsg[0] != '~') AND !$this->cfg['ignore_filter_decoding_errors'])) {
+ OR (($emsg[0] != '~') AND !$this->cfg['ignore_filter_decoding_errors'])) {
$this->Error($e->getMessage());
}
}
diff --git a/lib/thirdpartylibs.xml b/lib/thirdpartylibs.xml
index 7656bdc7c6c..03174c7fb08 100644
--- a/lib/thirdpartylibs.xml
+++ b/lib/thirdpartylibs.xml
@@ -165,7 +165,7 @@
tcpdf
TCPDF
LGPL
- 6.0.031
+ 6.0.062
3