Example #1
0
 /**
  * Writes a PDF value to the resulting document.
  *
  * Prepares the value for encryption of imported data by FPDI
  *
  * @param array $value
  */
 protected function _prepareValue(&$value)
 {
     switch ($value[0]) {
         case pdf_parser::TYPE_STRING:
             if ($this->encrypted) {
                 $value[1] = $this->_unescape($value[1]);
                 $value[1] = $this->_encrypt_data($this->_currentObjId, $value[1]);
                 $value[1] = TCPDF_STATIC::_escape($value[1]);
             }
             break;
         case pdf_parser::TYPE_STREAM:
             if ($this->encrypted) {
                 $value[2][1] = $this->_encrypt_data($this->_currentObjId, $value[2][1]);
                 $value[1][1]['/Length'] = array(pdf_parser::TYPE_NUMERIC, strlen($value[2][1]));
             }
             break;
         case pdf_parser::TYPE_HEX:
             if ($this->encrypted) {
                 $value[1] = $this->hex2str($value[1]);
                 $value[1] = $this->_encrypt_data($this->_currentObjId, $value[1]);
                 // remake hexstring of encrypted string
                 $value[1] = $this->str2hex($value[1]);
             }
             break;
     }
 }
 /**
  * Encryption of imported data by FPDI
  *
  * @param array $value
  */
 function pdf_write_value(&$value)
 {
     switch ($value[0]) {
         case PDF_TYPE_STRING:
             if ($this->encrypted) {
                 $value[1] = $this->_unescape($value[1]);
                 $value[1] = $this->_encrypt_data($this->_current_obj_id, $value[1]);
                 $value[1] = TCPDF_STATIC::_escape($value[1]);
             }
             break;
         case PDF_TYPE_STREAM:
             if ($this->encrypted) {
                 $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->_encrypt_data($this->_current_obj_id, $value[1]);
                 // remake hexstring of encrypted string
                 $value[1] = $this->str2hex($value[1]);
             }
             break;
     }
 }
 /**
  * Add page if needed.
  *
  * @param float|int $h       cell height. Default value: 0
  * @param mixed     $y       starting y position, leave empty for current
  *                           position
  * @param boolean   $addpage if true add a page, otherwise only return
  *                           the true/false state
  *
  * @return boolean true in case of page break, false otherwise.
  */
 function checkPageBreak($h = 0, $y = '', $addpage = true)
 {
     if (TCPDF_STATIC::empty_string($y)) {
         $y = $this->y;
     }
     $current_page = $this->page;
     if ($y + $h > $this->PageBreakTrigger and !$this->InFooter and $this->AcceptPageBreak()) {
         if ($addpage) {
             //Automatic page break
             $x = $this->x;
             $this->AddPage($this->CurOrientation);
             $this->y = $this->dataY;
             $oldpage = $this->page - 1;
             $this_page_orm = $this->pagedim[$this->page]['orm'];
             $old_page_orm = $this->pagedim[$oldpage]['orm'];
             $this_page_olm = $this->pagedim[$this->page]['olm'];
             $old_page_olm = $this->pagedim[$oldpage]['olm'];
             if ($this->rtl) {
                 if ($this_page_orm != $old_page_orm) {
                     $this->x = $x - ($this_page_orm - $old_page_orm);
                 } else {
                     $this->x = $x;
                 }
             } else {
                 if ($this_page_olm != $old_page_olm) {
                     $this->x = $x + ($this_page_olm - $old_page_olm);
                 } else {
                     $this->x = $x;
                 }
             }
         }
         return true;
     }
     if ($current_page != $this->page) {
         // account for columns mode
         return true;
     }
     return false;
 }
Example #4
0
 /**
  * Extract info from a PNG file without using the GD library.
  * @param $file (string) image file to parse
  * @return array structure containing the image data
  * @public static
  */
 public static function _parsepng($file)
 {
     $f = @fopen($file, 'rb');
     if ($f === false) {
         // Can't open image file
         return false;
     }
     //Check signature
     if (fread($f, 8) != chr(137) . 'PNG' . chr(13) . chr(10) . chr(26) . chr(10)) {
         // Not a PNG file
         return false;
     }
     //Read header chunk
     fread($f, 4);
     if (fread($f, 4) != 'IHDR') {
         //Incorrect PNG file
         return false;
     }
     $w = TCPDF_STATIC::_freadint($f);
     $h = TCPDF_STATIC::_freadint($f);
     $bpc = ord(fread($f, 1));
     $ct = ord(fread($f, 1));
     if ($ct == 0) {
         $colspace = 'DeviceGray';
     } elseif ($ct == 2) {
         $colspace = 'DeviceRGB';
     } elseif ($ct == 3) {
         $colspace = 'Indexed';
     } else {
         // alpha channel
         fclose($f);
         return 'pngalpha';
     }
     if (ord(fread($f, 1)) != 0) {
         // Unknown compression method
         fclose($f);
         return false;
     }
     if (ord(fread($f, 1)) != 0) {
         // Unknown filter method
         fclose($f);
         return false;
     }
     if (ord(fread($f, 1)) != 0) {
         // Interlacing not supported
         fclose($f);
         return false;
     }
     fread($f, 4);
     $channels = $ct == 2 ? 3 : 1;
     $parms = '/DecodeParms << /Predictor 15 /Colors ' . $channels . ' /BitsPerComponent ' . $bpc . ' /Columns ' . $w . ' >>';
     //Scan chunks looking for palette, transparency and image data
     $pal = '';
     $trns = '';
     $data = '';
     $icc = false;
     do {
         $n = TCPDF_STATIC::_freadint($f);
         $type = fread($f, 4);
         if ($type == 'PLTE') {
             // read palette
             $pal = TCPDF_STATIC::rfread($f, $n);
             fread($f, 4);
         } elseif ($type == 'tRNS') {
             // read transparency info
             $t = TCPDF_STATIC::rfread($f, $n);
             if ($ct == 0) {
                 // DeviceGray
                 $trns = array(ord($t[1]));
             } elseif ($ct == 2) {
                 // DeviceRGB
                 $trns = array(ord($t[1]), ord($t[3]), ord($t[5]));
             } else {
                 // Indexed
                 if ($n > 0) {
                     $trns = array();
                     for ($i = 0; $i < $n; ++$i) {
                         $trns[] = ord($t[$i]);
                     }
                 }
             }
             fread($f, 4);
         } elseif ($type == 'IDAT') {
             // read image data block
             $data .= TCPDF_STATIC::rfread($f, $n);
             fread($f, 4);
         } elseif ($type == 'iCCP') {
             // skip profile name
             $len = 0;
             while (ord(fread($f, 1)) != 0 and $len < 80) {
                 ++$len;
             }
             // get compression method
             if (ord(fread($f, 1)) != 0) {
                 // Unknown filter method
                 fclose($f);
                 return false;
             }
             // read ICC Color Profile
             $icc = TCPDF_STATIC::rfread($f, $n - $len - 2);
             // decompress profile
             $icc = gzuncompress($icc);
             fread($f, 4);
         } elseif ($type == 'IEND') {
             break;
         } else {
             TCPDF_STATIC::rfread($f, $n + 4);
         }
     } while ($n);
     if ($colspace == 'Indexed' and empty($pal)) {
         // Missing palette
         fclose($f);
         return false;
     }
     fclose($f);
     return array('w' => $w, 'h' => $h, 'ch' => $channels, 'icc' => $icc, 'cs' => $colspace, 'bpc' => $bpc, 'f' => 'FlateDecode', 'parms' => $parms, 'pal' => $pal, 'trns' => $trns, 'data' => $data);
 }
	/**
	 * Sets the opening SVG element handler function for the XML parser. (*** TO BE COMPLETED ***)
	 * @param $parser (resource) The first parameter, parser, is a reference to the XML parser calling the handler.
	 * @param $name (string) The second parameter, name, contains the name of the element for which this handler is called. If case-folding is in effect for this parser, the element name will be in uppercase letters.
	 * @param $attribs (array) The third parameter, attribs, contains an associative array with the element's attributes (if any). The keys of this array are the attribute names, the values are the attribute values. Attribute names are case-folded on the same criteria as element names. Attribute values are not case-folded. The original order of the attributes can be retrieved by walking through attribs the normal way, using each(). The first key in the array was the first attribute, and so on.
	 * @param $ctm (array) tranformation matrix for clipping mode (starting transformation matrix).
	 * @author Nicola Asuni
	 * @since 5.0.000 (2010-05-02)
	 * @protected
	 */
	protected function startSVGElementHandler($parser, $name, $attribs, $ctm=array()) {
		$name = $this->removeTagNamespace($name);
		// check if we are in clip mode
		if ($this->svgclipmode) {
			$this->svgclippaths[$this->svgclipid][] = array('name' => $name, 'attribs' => $attribs, 'tm' => $this->svgcliptm[$this->svgclipid]);
			return;
		}
		if ($this->svgdefsmode AND !in_array($name, array('clipPath', 'linearGradient', 'radialGradient', 'stop'))) {
			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;
				}
			}
			return;
		}
		$clipping = false;
		if ($parser == 'clip-path') {
			// set clipping mode
			$clipping = true;
		}
		// get styling properties
		$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']) AND ($attribs['style'][0] != ';')) {
			// fix style for regular expression
			$attribs['style'] = ';'.$attribs['style'];
		}
		foreach ($prev_svgstyle as $key => $val) {
			if (in_array($key, TCPDF_IMAGES::$svginheritprop)) {
				// inherit previous value
				$svgstyle[$key] = $val;
			}
			if (isset($attribs[$key]) AND !TCPDF_STATIC::empty_string($attribs[$key])) {
				// specific attribute settings
				if ($attribs[$key] == 'inherit') {
					$svgstyle[$key] = $val;
				} else {
					$svgstyle[$key] = $attribs[$key];
				}
			} elseif (isset($attribs['style']) AND !TCPDF_STATIC::empty_string($attribs['style'])) {
				// CSS style syntax
				$attrval = array();
				if (preg_match('/[;\"\s]{1}'.$key.'[\s]*:[\s]*([^;\"]*)/si', $attribs['style'], $attrval) AND isset($attrval[1])) {
					if ($attrval[1] == 'inherit') {
						$svgstyle[$key] = $val;
					} else {
						$svgstyle[$key] = $attrval[1];
					}
				}
			}
		}
		// transformation matrix
		if (!empty($ctm)) {
			$tm = $ctm;
		} else {
			$tm = array(1,0,0,1,0,0);
		}
		if (isset($attribs['transform']) AND !empty($attribs['transform'])) {
			$tm = TCPDF_STATIC::getTransformationMatrixProduct($tm, TCPDF_STATIC::getSVGTransformMatrix($attribs['transform']));
		}
		$svgstyle['transfmatrix'] = $tm;
		$invisible = false;
		if (($svgstyle['visibility'] == 'hidden') OR ($svgstyle['visibility'] == 'collapse') OR ($svgstyle['display'] == 'none')) {
			// the current graphics element is invisible (nothing is painted)
			$invisible = true;
		}
		// process tag
		switch($name) {
			case 'defs': {
				$this->svgdefsmode = true;
				break;
			}
			// clipPath
			case 'clipPath': {
				if ($invisible) {
					break;
				}
				$this->svgclipmode = true;
				if (!isset($attribs['id'])) {
					$attribs['id'] = 'CP_'.(count($this->svgcliptm) + 1);
				}
				$this->svgclipid = $attribs['id'];
				$this->svgclippaths[$this->svgclipid] = array();
				$this->svgcliptm[$this->svgclipid] = $tm;
				break;
			}
			case 'svg': {
				// start of SVG object
				if(++$this->svg_tag_depth <= 1) {
					break;
				}
				// inner SVG
				array_push($this->svgstyles, $svgstyle);
				$this->StartTransform();
				$svgX = (isset($attribs['x'])?$attribs['x']:0);
				$svgY = (isset($attribs['y'])?$attribs['y']:0);
				$svgW = (isset($attribs['width'])?$attribs['width']:0);
				$svgH = (isset($attribs['height'])?$attribs['height']:0);
				// set x, y position using transform matrix
				$tm = TCPDF_STATIC::getTransformationMatrixProduct($tm, array( 1, 0, 0, 1, $svgX, $svgY));
				$this->SVGTransform($tm);
				// set clipping for width and height
				$x = 0;
				$y = 0;
				$w = (isset($attribs['width'])?$this->getHTMLUnitToUnits($attribs['width'], 0, $this->svgunit, false):$this->w);
				$h = (isset($attribs['height'])?$this->getHTMLUnitToUnits($attribs['height'], 0, $this->svgunit, false):$this->h);
				// draw clipping rect
				$this->Rect($x, $y, $w, $h, 'CNZ', array(), array());
				// parse viewbox, calculate extra transformation matrix
				if (isset($attribs['viewBox'])) {
					$tmp = array();
					preg_match_all("/[0-9]+/", $attribs['viewBox'], $tmp);
					$tmp = $tmp[0];
					if (sizeof($tmp) == 4) {
						$vx = $tmp[0];
						$vy = $tmp[1];
						$vw = $tmp[2];
						$vh = $tmp[3];
						// get aspect ratio
						$tmp = array();
						$aspectX = 'xMid';
						$aspectY = 'YMid';
						$fit = 'meet';
						if (isset($attribs['preserveAspectRatio'])) {
							if($attribs['preserveAspectRatio'] == 'none') {
								$fit = 'none';
							} else {
								preg_match_all('/[a-zA-Z]+/', $attribs['preserveAspectRatio'], $tmp);
								$tmp = $tmp[0];
								if ((sizeof($tmp) == 2) AND (strlen($tmp[0]) == 8) AND (in_array($tmp[1], array('meet', 'slice', 'none')))) {
									$aspectX = substr($tmp[0], 0, 4);
									$aspectY = substr($tmp[0], 4, 4);
									$fit = $tmp[1];
								}
							}
						}
						$wr = ($svgW / $vw);
						$hr = ($svgH / $vh);
						$ax = $ay = 0;
						if ((($fit == 'meet') AND ($hr < $wr)) OR (($fit == 'slice') AND ($hr > $wr))) {
							if ($aspectX == 'xMax') {
								$ax = (($vw * ($wr / $hr)) - $vw);
							}
							if ($aspectX == 'xMid') {
								$ax = ((($vw * ($wr / $hr)) - $vw) / 2);
							}
							$wr = $hr;
						} elseif ((($fit == 'meet') AND ($hr > $wr)) OR (($fit == 'slice') AND ($hr < $wr))) {
							if ($aspectY == 'YMax') {
								$ay = (($vh * ($hr / $wr)) - $vh);
							}
							if ($aspectY == 'YMid') {
								$ay = ((($vh * ($hr / $wr)) - $vh) / 2);
							}
							$hr = $wr;
						}
						$newtm = array($wr, 0, 0, $hr, (($wr * ($ax - $vx)) - $svgX), (($hr * ($ay - $vy)) - $svgY));
						$tm = TCPDF_STATIC::getTransformationMatrixProduct($tm, $newtm);
						$this->SVGTransform($tm);
					}
				}
				$this->setSVGStyles($svgstyle, $prev_svgstyle);
				break;
			}
			case 'g': {
				// 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 = 1;//(isset($attribs['width'])?$attribs['width']:1);
				$h = 1;//(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;
			}
			case 'linearGradient': {
				if ($this->pdfa_mode) {
					break;
				}
				if (!isset($attribs['id'])) {
					$attribs['id'] = 'GR_'.(count($this->svggradients) + 1);
				}
				$this->svggradientid = $attribs['id'];
				$this->svggradients[$this->svggradientid] = array();
				$this->svggradients[$this->svggradientid]['type'] = 2;
				$this->svggradients[$this->svggradientid]['stops'] = array();
				if (isset($attribs['gradientUnits'])) {
					$this->svggradients[$this->svggradientid]['gradientUnits'] = $attribs['gradientUnits'];
				} else {
					$this->svggradients[$this->svggradientid]['gradientUnits'] = 'objectBoundingBox';
				}
				//$attribs['spreadMethod']
				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'] = TCPDF_STATIC::getSVGTransformMatrix($attribs['gradientTransform']);
				}
				$this->svggradients[$this->svggradientid]['coords'] = array($x1, $y1, $x2, $y2);
				if (isset($attribs['xlink:href']) AND !empty($attribs['xlink:href'])) {
					// gradient is defined on another place
					$this->svggradients[$this->svggradientid]['xref'] = substr($attribs['xlink:href'], 1);
				}
				break;
			}
			case 'radialGradient': {
				if ($this->pdfa_mode) {
					break;
				}
				if (!isset($attribs['id'])) {
					$attribs['id'] = 'GR_'.(count($this->svggradients) + 1);
				}
				$this->svggradientid = $attribs['id'];
				$this->svggradients[$this->svggradientid] = array();
				$this->svggradients[$this->svggradientid]['type'] = 3;
				$this->svggradients[$this->svggradientid]['stops'] = array();
				if (isset($attribs['gradientUnits'])) {
					$this->svggradients[$this->svggradientid]['gradientUnits'] = $attribs['gradientUnits'];
				} else {
					$this->svggradients[$this->svggradientid]['gradientUnits'] = 'objectBoundingBox';
				}
				//$attribs['spreadMethod']
				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';
				} elseif (isset($attribs['r']) AND is_numeric($attribs['r']) AND ($attribs['r']) <= 1) {
					$this->svggradients[$this->svggradientid]['mode'] = 'ratio';
				} 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'] = TCPDF_STATIC::getSVGTransformMatrix($attribs['gradientTransform']);
				}
				$this->svggradients[$this->svggradientid]['coords'] = array($cx, $cy, $fx, $fy, $r);
				if (isset($attribs['xlink:href']) AND !empty($attribs['xlink:href'])) {
					// gradient is defined on another place
					$this->svggradients[$this->svggradientid]['xref'] = substr($attribs['xlink:href'], 1);
				}
				break;
			}
			case 'stop': {
				// gradient stops
				if (substr($attribs['offset'], -1) == '%') {
					$offset = floatval(substr($attribs['offset'], -1)) / 100;
				} else {
					$offset = floatval($attribs['offset']);
					if ($offset > 1) {
						$offset /= 100;
					}
				}
				$stop_color = isset($svgstyle['stop-color'])?TCPDF_COLORS::convertHTMLColorToDec($svgstyle['stop-color'], $this->spot_colors):'black';
				$opacity = isset($svgstyle['stop-opacity'])?$svgstyle['stop-opacity']:1;
				$this->svggradients[$this->svggradientid]['stops'][] = array('offset' => $offset, 'color' => $stop_color, 'opacity' => $opacity);
				break;
			}
			// paths
			case 'path': {
				if ($invisible) {
					break;
				}
				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, $x, $y, $w, $h, 'SVGPath', array($d, 'CNZ'));
							if (!empty($obstyle)) {
								$this->SVGPath($d, $obstyle);
							}
							$this->StopTransform();
						}
					}
				}
				break;
			}
			// shapes
			case 'rect': {
				if ($invisible) {
					break;
				}
				$x = (isset($attribs['x'])?$this->getHTMLUnitToUnits($attribs['x'], 0, $this->svgunit, false):0);
				$y = (isset($attribs['y'])?$this->getHTMLUnitToUnits($attribs['y'], 0, $this->svgunit, false):0);
				$w = (isset($attribs['width'])?$this->getHTMLUnitToUnits($attribs['width'], 0, $this->svgunit, false):0);
				$h = (isset($attribs['height'])?$this->getHTMLUnitToUnits($attribs['height'], 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):$rx);
				if ($clipping) {
					$this->SVGTransform($tm);
					$this->RoundedRectXY($x, $y, $w, $h, $rx, $ry, '1111', 'CNZ', array(), array());
				} else {
					$this->StartTransform();
					$this->SVGTransform($tm);
					$obstyle = $this->setSVGStyles($svgstyle, $prev_svgstyle, $x, $y, $w, $h, 'RoundedRectXY', array($x, $y, $w, $h, $rx, $ry, '1111', 'CNZ'));
					if (!empty($obstyle)) {
						$this->RoundedRectXY($x, $y, $w, $h, $rx, $ry, '1111', $obstyle, array(), array());
					}
					$this->StopTransform();
				}
				break;
			}
			case 'circle': {
				if ($invisible) {
					break;
				}
				$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);
					$this->Circle($cx, $cy, $r, 0, 360, 'CNZ', array(), array(), 8);
				} else {
					$this->StartTransform();
					$this->SVGTransform($tm);
					$obstyle = $this->setSVGStyles($svgstyle, $prev_svgstyle, $x, $y, $w, $h, 'Circle', array($cx, $cy, $r, 0, 360, 'CNZ'));
					if (!empty($obstyle)) {
						$this->Circle($cx, $cy, $r, 0, 360, $obstyle, array(), array(), 8);
					}
					$this->StopTransform();
				}
				break;
			}
			case 'ellipse': {
				if ($invisible) {
					break;
				}
				$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);
				} else {
					$this->StartTransform();
					$this->SVGTransform($tm);
					$obstyle = $this->setSVGStyles($svgstyle, $prev_svgstyle, $x, $y, $w, $h, 'Ellipse', array($cx, $cy, $rx, $ry, 0, 0, 360, 'CNZ'));
					if (!empty($obstyle)) {
						$this->Ellipse($cx, $cy, $rx, $ry, 0, 0, 360, $obstyle, array(), array(), 8);
					}
					$this->StopTransform();
				}
				break;
			}
			case 'line': {
				if ($invisible) {
					break;
				}
				$x1 = (isset($attribs['x1'])?$this->getHTMLUnitToUnits($attribs['x1'], 0, $this->svgunit, false):0);
				$y1 = (isset($attribs['y1'])?$this->getHTMLUnitToUnits($attribs['y1'], 0, $this->svgunit, false):0);
				$x2 = (isset($attribs['x2'])?$this->getHTMLUnitToUnits($attribs['x2'], 0, $this->svgunit, false):0);
				$y2 = (isset($attribs['y2'])?$this->getHTMLUnitToUnits($attribs['y2'], 0, $this->svgunit, false):0);
				$x = $x1;
				$y = $y1;
				$w = abs($x2 - $x1);
				$h = abs($y2 - $y1);
				if (!$clipping) {
					$this->StartTransform();
					$this->SVGTransform($tm);
					$obstyle = $this->setSVGStyles($svgstyle, $prev_svgstyle, $x, $y, $w, $h, 'Line', array($x1, $y1, $x2, $y2));
					$this->Line($x1, $y1, $x2, $y2);
					$this->StopTransform();
				}
				break;
			}
			case 'polyline':
			case 'polygon': {
				if ($invisible) {
					break;
				}
				$points = (isset($attribs['points'])?$attribs['points']:'0 0');
				$points = trim($points);
				// note that point may use a complex syntax not covered here
				$points = preg_split('/[\,\s]+/si', $points);
				if (count($points) < 4) {
					break;
				}
				$p = array();
				$xmin = 2147483647;
				$xmax = 0;
				$ymin = 2147483647;
				$ymax = 0;
				foreach ($points as $key => $val) {
					$p[$key] = $this->getHTMLUnitToUnits($val, 0, $this->svgunit, false);
					if (($key % 2) == 0) {
						// X coordinate
						$xmin = min($xmin, $p[$key]);
						$xmax = max($xmax, $p[$key]);
					} else {
						// Y coordinate
						$ymin = min($ymin, $p[$key]);
						$ymax = max($ymax, $p[$key]);
					}
				}
				$x = $xmin;
				$y = $ymin;
				$w = ($xmax - $xmin);
				$h = ($ymax - $ymin);
				if ($name == 'polyline') {
					$this->StartTransform();
					$this->SVGTransform($tm);
					$obstyle = $this->setSVGStyles($svgstyle, $prev_svgstyle, $x, $y, $w, $h, 'PolyLine', array($p, 'CNZ'));
					if (!empty($obstyle)) {
						$this->PolyLine($p, $obstyle, array(), array());
					}
					$this->StopTransform();
				} else { // polygon
					if ($clipping) {
						$this->SVGTransform($tm);
						$this->Polygon($p, 'CNZ', array(), array(), true);
					} else {
						$this->StartTransform();
						$this->SVGTransform($tm);
						$obstyle = $this->setSVGStyles($svgstyle, $prev_svgstyle, $x, $y, $w, $h, 'Polygon', array($p, 'CNZ'));
						if (!empty($obstyle)) {
							$this->Polygon($p, $obstyle, array(), array(), true);
						}
						$this->StopTransform();
					}
				}
				break;
			}
			// image
			case 'image': {
				if ($invisible) {
					break;
				}
				if (!isset($attribs['xlink:href']) OR empty($attribs['xlink:href'])) {
					break;
				}
				$x = (isset($attribs['x'])?$this->getHTMLUnitToUnits($attribs['x'], 0, $this->svgunit, false):0);
				$y = (isset($attribs['y'])?$this->getHTMLUnitToUnits($attribs['y'], 0, $this->svgunit, false):0);
				$w = (isset($attribs['width'])?$this->getHTMLUnitToUnits($attribs['width'], 0, $this->svgunit, false):0);
				$h = (isset($attribs['height'])?$this->getHTMLUnitToUnits($attribs['height'], 0, $this->svgunit, false):0);
				$img = $attribs['xlink:href'];
				if (!$clipping) {
					$this->StartTransform();
					$this->SVGTransform($tm);
					$obstyle = $this->setSVGStyles($svgstyle, $prev_svgstyle, $x, $y, $w, $h);
					if (preg_match('/^data:image\/[^;]+;base64,/', $img, $m) > 0) {
						// embedded image encoded as base64
						$img = '@'.base64_decode(substr($img, strlen($m[0])));
					} else {
						// fix image path
						if (!TCPDF_STATIC::empty_string($this->svgdir) AND (($img[0] == '.') OR (basename($img) == $img))) {
							// replace relative path with full server path
							$img = $this->svgdir.'/'.$img;
						}
						if (($img[0] == '/') AND !empty($_SERVER['DOCUMENT_ROOT']) AND ($_SERVER['DOCUMENT_ROOT'] != '/')) {
							$findroot = strpos($img, $_SERVER['DOCUMENT_ROOT']);
							if (($findroot === false) OR ($findroot > 1)) {
								if (substr($_SERVER['DOCUMENT_ROOT'], -1) == '/') {
									$img = substr($_SERVER['DOCUMENT_ROOT'], 0, -1).$img;
								} else {
									$img = $_SERVER['DOCUMENT_ROOT'].$img;
								}
							}
						}
						$img = urldecode($img);
						$testscrtype = @parse_url($img);
						if (!isset($testscrtype['query']) OR empty($testscrtype['query'])) {
							// convert URL to server path
							$img = str_replace(K_PATH_URL, K_PATH_MAIN, $img);
						}
					}
					// get image type
					$imgtype = TCPDF_IMAGES::getImageFileType($img);
					if (($imgtype == 'eps') OR ($imgtype == 'ai')) {
						$this->ImageEps($img, $x, $y, $w, $h);
					} elseif ($imgtype == 'svg') {
						// store SVG vars
						$svggradients = $this->svggradients;
						$svggradientid = $this->svggradientid;
						$svgdefsmode = $this->svgdefsmode;
						$svgdefs = $this->svgdefs;
						$svgclipmode = $this->svgclipmode;
						$svgclippaths = $this->svgclippaths;
						$svgcliptm = $this->svgcliptm;
						$svgclipid = $this->svgclipid;
						$svgtext = $this->svgtext;
						$svgtextmode = $this->svgtextmode;
						$this->ImageSVG($img, $x, $y, $w, $h);
						// restore SVG vars
						$this->svggradients = $svggradients;
						$this->svggradientid = $svggradientid;
						$this->svgdefsmode = $svgdefsmode;
						$this->svgdefs = $svgdefs;
						$this->svgclipmode = $svgclipmode;
						$this->svgclippaths = $svgclippaths;
						$this->svgcliptm = $svgcliptm;
						$this->svgclipid = $svgclipid;
						$this->svgtext = $svgtext;
						$this->svgtextmode = $svgtextmode;
					} else {
						$this->Image($img, $x, $y, $w, $h);
					}
					$this->StopTransform();
				}
				break;
			}
			// text
			case 'text':
			case 'tspan': {
				if (isset($this->svgtextmode['text-anchor']) AND !empty($this->svgtext)) {
					// @TODO: unsupported feature
				}
				// only basic support - advanced features must be implemented
				$this->svgtextmode['invisible'] = $invisible;
				if ($invisible) {
					break;
				}
				array_push($this->svgstyles, $svgstyle);
				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['dx'])) {
					$x += $this->getHTMLUnitToUnits($attribs['dx'], 0, $this->svgunit, false);
				}
				if (isset($attribs['y'])) {
					$y = $this->getHTMLUnitToUnits($attribs['y'], 0, $this->svgunit, false);
				} elseif ($name == 'tspan') {
					$y = $this->y;
				} else {
					$y = 0;
				}
				if (isset($attribs['dy'])) {
					$y += $this->getHTMLUnitToUnits($attribs['dy'], 0, $this->svgunit, false);
				}
				$svgstyle['text-color'] = $svgstyle['fill'];
				$this->svgtext = '';
				if (isset($svgstyle['text-anchor'])) {
					$this->svgtextmode['text-anchor'] = $svgstyle['text-anchor'];
				} else {
					$this->svgtextmode['text-anchor'] = 'start';
				}
				if (isset($svgstyle['direction'])) {
					if ($svgstyle['direction'] == 'rtl') {
						$this->svgtextmode['rtl'] = true;
					} else {
						$this->svgtextmode['rtl'] = false;
					}
				} else {
					$this->svgtextmode['rtl'] = false;
				}
				if (isset($svgstyle['stroke']) AND ($svgstyle['stroke'] != 'none') AND isset($svgstyle['stroke-width']) AND ($svgstyle['stroke-width'] > 0)) {
					$this->svgtextmode['stroke'] = $this->getHTMLUnitToUnits($svgstyle['stroke-width'], 0, $this->svgunit, false);
				} else {
					$this->svgtextmode['stroke'] = false;
				}
				$this->StartTransform();
				$this->SVGTransform($tm);
				$obstyle = $this->setSVGStyles($svgstyle, $prev_svgstyle, $x, $y, 1, 1);
				$this->x = $x;
				$this->y = $y;
				break;
			}
			// use
			case 'use': {
				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']);
						}
						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($parser, $use['name'], $attribs);
						return;
					}
				}
				break;
			}
			default: {
				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']);
				}
			}
		}
	}
 /**
  * Returns an array of hyphenation patterns.
  * @param $file (string) TEX file containing hypenation patterns. TEX pattrns can be downloaded from http://www.ctan.org/tex-archive/language/hyph-utf8/tex/generic/hyph-utf8/patterns/
  * @return array of hyphenation patterns
  * @author Nicola Asuni
  * @since 4.9.012 (2010-04-12)
  * @public static
  */
 public static function getHyphenPatternsFromTEX($file)
 {
     // TEX patterns are available at:
     // http://www.ctan.org/tex-archive/language/hyph-utf8/tex/generic/hyph-utf8/patterns/
     $data = file_get_contents($file);
     $patterns = array();
     // remove comments
     $data = preg_replace('/\\%[^\\n]*/', '', $data);
     // extract the patterns part
     preg_match('/\\\\patterns\\{([^\\}]*)\\}/i', $data, $matches);
     $data = trim(substr($matches[0], 10, -1));
     // extract each pattern
     $patterns_array = preg_split('/[\\s]+/', $data);
     // create new language array of patterns
     $patterns = array();
     foreach ($patterns_array as $val) {
         if (!TCPDF_STATIC::empty_string($val)) {
             $val = trim($val);
             $val = str_replace('\'', '\\\'', $val);
             $key = preg_replace('/[0-9]+/', '', $val);
             $patterns[$key] = $val;
         }
     }
     return $patterns;
 }
 /**
  * show Libraries information in system information
  *
  * @since version 0.84
  **/
 static function showLibrariesInformation()
 {
     // No gettext
     echo "<tr class='tab_bg_2'><th>Libraries</th></tr>\n";
     echo "<tr class='tab_bg_1'><td><pre>\n&nbsp;\n";
     include_once GLPI_HTMLAWED;
     echo "htmLawed version " . hl_version() . " in (" . realpath(dirname(GLPI_HTMLAWED)) . ")\n";
     include GLPI_PHPCAS;
     echo "phpCas version " . phpCAS::getVersion() . " in (" . (dirname(GLPI_PHPCAS) ? realpath(dirname(GLPI_PHPCAS)) : "system") . ")\n";
     require_once GLPI_PHPMAILER_DIR . "/class.phpmailer.php";
     $pm = new PHPMailer();
     echo "PHPMailer version " . $pm->Version . " in (" . realpath(GLPI_PHPMAILER_DIR) . ")\n";
     // EZ component
     echo "ZetaComponent ezcGraph installed in (" . dirname(dirname(GLPI_EZC_BASE)) . "):  " . (class_exists('ezcGraph') ? 'OK' : 'KO') . "\n";
     // Zend
     $zv = new Zend\Version\Version();
     echo "Zend Framework version " . $zv::VERSION . " in (" . realpath(GLPI_ZEND_PATH) . ")\n";
     // SimplePie :
     $sp = new SimplePie();
     echo "SimplePie version " . SIMPLEPIE_VERSION . " in (" . realpath(GLPI_SIMPLEPIE_PATH) . ")\n";
     // TCPDF
     include_once GLPI_TCPDF_DIR . '/include/tcpdf_static.php';
     echo "TCPDF version " . TCPDF_STATIC::getTCPDFVersion() . " in (" . realpath(GLPI_TCPDF_DIR) . ")\n";
     // password_compat
     require_once GLPI_PASSWORD_COMPAT;
     $check = PasswordCompat\binary\check() ? "Ok" : "KO";
     echo "ircmaxell/password-compat in (" . realpath(dirname(GLPI_PASSWORD_COMPAT)) . "). Compatitility: {$check}\n";
     echo "\n</pre></td></tr>";
 }
Example #8
0
 $doc->setHeaderFont(array($fontfamily, 'b', 10));
 $doc->setHeaderData('pix/moodlelogo-med.png', 40, $SITE->fullname, $CFG->wwwroot);
 $doc->setPrintFooter(true);
 $doc->setFooterMargin(10);
 $doc->setFooterFont(array($fontfamily, '', 8));
 $doc->AddPage();
 $doc->SetTextColor(255, 255, 255);
 $doc->SetFillColor(255, 203, 68);
 $doc->SetFont($fontfamily, 'B', 24);
 $doc->Cell(0, 0, 'Moodle PDF library test', 0, 1, 'C', 1);
 $doc->SetFont($fontfamily, '', 12);
 $doc->Ln(6);
 $doc->SetTextColor(0, 0, 0);
 $c = '<h3>General information</h3>';
 $c .= 'Moodle release: ' . $CFG->release . '<br />';
 $c .= 'PDF producer: TCPDF ' . TCPDF_STATIC::getTCPDFVersion() . ' (http://www.tcpdf.org) <br />';
 $c .= 'Font of this test page: ' . $fontfamily . '<br />';
 $c .= '<h3>Current settings</h3>';
 $c .= '<table border="1"  cellspacing="0" cellpadding="1">';
 foreach (array('K_PATH_MAIN', 'K_PATH_URL', 'K_PATH_FONTS', 'K_PATH_CACHE', 'K_PATH_IMAGES', 'K_BLANK_IMAGE', 'K_CELL_HEIGHT_RATIO', 'K_SMALL_RATIO', 'PDF_CUSTOM_FONT_PATH', 'PDF_DEFAULT_FONT') as $setting) {
     if (defined($setting)) {
         $c .= '<tr style="font-size: x-small;"><td>' . $setting . '</td><td>' . constant($setting) . '</td></tr>';
     }
 }
 $c .= '<tr  style="font-size: x-small;"><td>Effective font path</td><td>' . $doc->_getfontpath() . '</td></tr>';
 $c .= '</table><br />';
 $c .= '<h3>Available font files</h3>';
 $fontfiles = $doc->returnFontsList();
 sort($fontfiles);
 $c .= implode(', ', $fontfiles);
 $c .= '<br />';
	/**
	 * Reverse the RLT substrings using the Bidirectional Algorithm (http://unicode.org/reports/tr9/).
	 * @param $ta (array) array of characters composing the string.
	 * @param $str (string) string to process
	 * @param $forcertl (bool) if 'R' forces RTL, if 'L' forces LTR
	 * @param $isunicode (boolean) True if the document is in Unicode mode, false otherwise.
	 * @param $currentfont (array) Reference to current font array.
	 * @return array of unicode chars
	 * @author Nicola Asuni
	 * @since 2.4.000 (2008-03-06)
	 * @public static
	 */
	public static function utf8Bidi($ta, $str='', $forcertl=false, $isunicode=true, &$currentfont) {
		// paragraph embedding level
		$pel = 0;
		// max level
		$maxlevel = 0;
		if (TCPDF_STATIC::empty_string($str)) {
			// create string from array
			$str = self::UTF8ArrSubString($ta, '', '', $isunicode);
		}
		// check if string contains arabic text
		if (preg_match(TCPDF_FONT_DATA::$uni_RE_PATTERN_ARABIC, $str)) {
			$arabic = true;
		} else {
			$arabic = false;
		}
		// check if string contains RTL text
		if (!($forcertl OR $arabic OR preg_match(TCPDF_FONT_DATA::$uni_RE_PATTERN_RTL, $str))) {
			return $ta;
		}

		// get number of chars
		$numchars = count($ta);

		if ($forcertl == 'R') {
			$pel = 1;
		} elseif ($forcertl == 'L') {
			$pel = 0;
		} else {
			// P2. In each paragraph, find the first character of type L, AL, or R.
			// P3. If a character is found in P2 and it is of type AL or R, then set the paragraph embedding level to one; otherwise, set it to zero.
			for ($i=0; $i < $numchars; ++$i) {
				$type = TCPDF_FONT_DATA::$uni_type[$ta[$i]];
				if ($type == 'L') {
					$pel = 0;
					break;
				} elseif (($type == 'AL') OR ($type == 'R')) {
					$pel = 1;
					break;
				}
			}
		}

		// Current Embedding Level
		$cel = $pel;
		// directional override status
		$dos = 'N';
		$remember = array();
		// start-of-level-run
		$sor = $pel % 2 ? 'R' : 'L';
		$eor = $sor;

		// Array of characters data
		$chardata = Array();

		// X1. Begin by setting the current embedding level to the paragraph embedding level. Set the directional override status to neutral. Process each character iteratively, applying rules X2 through X9. Only embedding levels from 0 to 61 are valid in this phase.
		// In the resolution of levels in rules I1 and I2, the maximum embedding level of 62 can be reached.
		for ($i=0; $i < $numchars; ++$i) {
			if ($ta[$i] == TCPDF_FONT_DATA::$uni_RLE) {
				// X2. With each RLE, compute the least greater odd embedding level.
				//	a. If this new level would be valid, then this embedding code is valid. Remember (push) the current embedding level and override status. Reset the current level to this new level, and reset the override status to neutral.
				//	b. If the new level would not be valid, then this code is invalid. Do not change the current level or override status.
				$next_level = $cel + ($cel % 2) + 1;
				if ($next_level < 62) {
					$remember[] = array('num' => TCPDF_FONT_DATA::$uni_RLE, 'cel' => $cel, 'dos' => $dos);
					$cel = $next_level;
					$dos = 'N';
					$sor = $eor;
					$eor = $cel % 2 ? 'R' : 'L';
				}
			} elseif ($ta[$i] == TCPDF_FONT_DATA::$uni_LRE) {
				// X3. With each LRE, compute the least greater even embedding level.
				//	a. If this new level would be valid, then this embedding code is valid. Remember (push) the current embedding level and override status. Reset the current level to this new level, and reset the override status to neutral.
				//	b. If the new level would not be valid, then this code is invalid. Do not change the current level or override status.
				$next_level = $cel + 2 - ($cel % 2);
				if ( $next_level < 62 ) {
					$remember[] = array('num' => TCPDF_FONT_DATA::$uni_LRE, 'cel' => $cel, 'dos' => $dos);
					$cel = $next_level;
					$dos = 'N';
					$sor = $eor;
					$eor = $cel % 2 ? 'R' : 'L';
				}
			} elseif ($ta[$i] == TCPDF_FONT_DATA::$uni_RLO) {
				// X4. With each RLO, compute the least greater odd embedding level.
				//	a. If this new level would be valid, then this embedding code is valid. Remember (push) the current embedding level and override status. Reset the current level to this new level, and reset the override status to right-to-left.
				//	b. If the new level would not be valid, then this code is invalid. Do not change the current level or override status.
				$next_level = $cel + ($cel % 2) + 1;
				if ($next_level < 62) {
					$remember[] = array('num' => TCPDF_FONT_DATA::$uni_RLO, 'cel' => $cel, 'dos' => $dos);
					$cel = $next_level;
					$dos = 'R';
					$sor = $eor;
					$eor = $cel % 2 ? 'R' : 'L';
				}
			} elseif ($ta[$i] == TCPDF_FONT_DATA::$uni_LRO) {
				// X5. With each LRO, compute the least greater even embedding level.
				//	a. If this new level would be valid, then this embedding code is valid. Remember (push) the current embedding level and override status. Reset the current level to this new level, and reset the override status to left-to-right.
				//	b. If the new level would not be valid, then this code is invalid. Do not change the current level or override status.
				$next_level = $cel + 2 - ($cel % 2);
				if ( $next_level < 62 ) {
					$remember[] = array('num' => TCPDF_FONT_DATA::$uni_LRO, 'cel' => $cel, 'dos' => $dos);
					$cel = $next_level;
					$dos = 'L';
					$sor = $eor;
					$eor = $cel % 2 ? 'R' : 'L';
				}
			} elseif ($ta[$i] == TCPDF_FONT_DATA::$uni_PDF) {
				// X7. With each PDF, determine the matching embedding or override code. If there was a valid matching code, restore (pop) the last remembered (pushed) embedding level and directional override.
				if (count($remember)) {
					$last = count($remember ) - 1;
					if (($remember[$last]['num'] == TCPDF_FONT_DATA::$uni_RLE) OR
						($remember[$last]['num'] == TCPDF_FONT_DATA::$uni_LRE) OR
						($remember[$last]['num'] == TCPDF_FONT_DATA::$uni_RLO) OR
						($remember[$last]['num'] == TCPDF_FONT_DATA::$uni_LRO)) {
						$match = array_pop($remember);
						$cel = $match['cel'];
						$dos = $match['dos'];
						$sor = $eor;
						$eor = ($cel > $match['cel'] ? $cel : $match['cel']) % 2 ? 'R' : 'L';
					}
				}
			} elseif (($ta[$i] != TCPDF_FONT_DATA::$uni_RLE) AND
							 ($ta[$i] != TCPDF_FONT_DATA::$uni_LRE) AND
							 ($ta[$i] != TCPDF_FONT_DATA::$uni_RLO) AND
							 ($ta[$i] != TCPDF_FONT_DATA::$uni_LRO) AND
							 ($ta[$i] != TCPDF_FONT_DATA::$uni_PDF)) {
				// X6. For all types besides RLE, LRE, RLO, LRO, and PDF:
				//	a. Set the level of the current character to the current embedding level.
				//	b. Whenever the directional override status is not neutral, reset the current character type to the directional override status.
				if ($dos != 'N') {
					$chardir = $dos;
				} else {
					if (isset(TCPDF_FONT_DATA::$uni_type[$ta[$i]])) {
						$chardir = TCPDF_FONT_DATA::$uni_type[$ta[$i]];
					} else {
						$chardir = 'L';
					}
				}
				// stores string characters and other information
				$chardata[] = array('char' => $ta[$i], 'level' => $cel, 'type' => $chardir, 'sor' => $sor, 'eor' => $eor);
			}
		} // end for each char

		// X8. All explicit directional embeddings and overrides are completely terminated at the end of each paragraph. Paragraph separators are not included in the embedding.
		// X9. Remove all RLE, LRE, RLO, LRO, PDF, and BN codes.
		// X10. The remaining rules are applied to each run of characters at the same level. For each run, determine the start-of-level-run (sor) and end-of-level-run (eor) type, either L or R. This depends on the higher of the two levels on either side of the boundary (at the start or end of the paragraph, the level of the 'other' run is the base embedding level). If the higher level is odd, the type is R; otherwise, it is L.

		// 3.3.3 Resolving Weak Types
		// Weak types are now resolved one level run at a time. At level run boundaries where the type of the character on the other side of the boundary is required, the type assigned to sor or eor is used.
		// Nonspacing marks are now resolved based on the previous characters.
		$numchars = count($chardata);

		// W1. Examine each nonspacing mark (NSM) in the level run, and change the type of the NSM to the type of the previous character. If the NSM is at the start of the level run, it will get the type of sor.
		$prevlevel = -1; // track level changes
		$levcount = 0; // counts consecutive chars at the same level
		for ($i=0; $i < $numchars; ++$i) {
			if ($chardata[$i]['type'] == 'NSM') {
				if ($levcount) {
					$chardata[$i]['type'] = $chardata[$i]['sor'];
				} elseif ($i > 0) {
					$chardata[$i]['type'] = $chardata[($i-1)]['type'];
				}
			}
			if ($chardata[$i]['level'] != $prevlevel) {
				$levcount = 0;
			} else {
				++$levcount;
			}
			$prevlevel = $chardata[$i]['level'];
		}

		// W2. Search backward from each instance of a European number until the first strong type (R, L, AL, or sor) is found. If an AL is found, change the type of the European number to Arabic number.
		$prevlevel = -1;
		$levcount = 0;
		for ($i=0; $i < $numchars; ++$i) {
			if ($chardata[$i]['char'] == 'EN') {
				for ($j=$levcount; $j >= 0; $j--) {
					if ($chardata[$j]['type'] == 'AL') {
						$chardata[$i]['type'] = 'AN';
					} elseif (($chardata[$j]['type'] == 'L') OR ($chardata[$j]['type'] == 'R')) {
						break;
					}
				}
			}
			if ($chardata[$i]['level'] != $prevlevel) {
				$levcount = 0;
			} else {
				++$levcount;
			}
			$prevlevel = $chardata[$i]['level'];
		}

		// W3. Change all ALs to R.
		for ($i=0; $i < $numchars; ++$i) {
			if ($chardata[$i]['type'] == 'AL') {
				$chardata[$i]['type'] = 'R';
			}
		}

		// W4. A single European separator between two European numbers changes to a European number. A single common separator between two numbers of the same type changes to that type.
		$prevlevel = -1;
		$levcount = 0;
		for ($i=0; $i < $numchars; ++$i) {
			if (($levcount > 0) AND (($i+1) < $numchars) AND ($chardata[($i+1)]['level'] == $prevlevel)) {
				if (($chardata[$i]['type'] == 'ES') AND ($chardata[($i-1)]['type'] == 'EN') AND ($chardata[($i+1)]['type'] == 'EN')) {
					$chardata[$i]['type'] = 'EN';
				} elseif (($chardata[$i]['type'] == 'CS') AND ($chardata[($i-1)]['type'] == 'EN') AND ($chardata[($i+1)]['type'] == 'EN')) {
					$chardata[$i]['type'] = 'EN';
				} elseif (($chardata[$i]['type'] == 'CS') AND ($chardata[($i-1)]['type'] == 'AN') AND ($chardata[($i+1)]['type'] == 'AN')) {
					$chardata[$i]['type'] = 'AN';
				}
			}
			if ($chardata[$i]['level'] != $prevlevel) {
				$levcount = 0;
			} else {
				++$levcount;
			}
			$prevlevel = $chardata[$i]['level'];
		}

		// W5. A sequence of European terminators adjacent to European numbers changes to all European numbers.
		$prevlevel = -1;
		$levcount = 0;
		for ($i=0; $i < $numchars; ++$i) {
			if ($chardata[$i]['type'] == 'ET') {
				if (($levcount > 0) AND ($chardata[($i-1)]['type'] == 'EN')) {
					$chardata[$i]['type'] = 'EN';
				} else {
					$j = $i+1;
					while (($j < $numchars) AND ($chardata[$j]['level'] == $prevlevel)) {
						if ($chardata[$j]['type'] == 'EN') {
							$chardata[$i]['type'] = 'EN';
							break;
						} elseif ($chardata[$j]['type'] != 'ET') {
							break;
						}
						++$j;
					}
				}
			}
			if ($chardata[$i]['level'] != $prevlevel) {
				$levcount = 0;
			} else {
				++$levcount;
			}
			$prevlevel = $chardata[$i]['level'];
		}

		// W6. Otherwise, separators and terminators change to Other Neutral.
		$prevlevel = -1;
		$levcount = 0;
		for ($i=0; $i < $numchars; ++$i) {
			if (($chardata[$i]['type'] == 'ET') OR ($chardata[$i]['type'] == 'ES') OR ($chardata[$i]['type'] == 'CS')) {
				$chardata[$i]['type'] = 'ON';
			}
			if ($chardata[$i]['level'] != $prevlevel) {
				$levcount = 0;
			} else {
				++$levcount;
			}
			$prevlevel = $chardata[$i]['level'];
		}

		//W7. Search backward from each instance of a European number until the first strong type (R, L, or sor) is found. If an L is found, then change the type of the European number to L.
		$prevlevel = -1;
		$levcount = 0;
		for ($i=0; $i < $numchars; ++$i) {
			if ($chardata[$i]['char'] == 'EN') {
				for ($j=$levcount; $j >= 0; $j--) {
					if ($chardata[$j]['type'] == 'L') {
						$chardata[$i]['type'] = 'L';
					} elseif ($chardata[$j]['type'] == 'R') {
						break;
					}
				}
			}
			if ($chardata[$i]['level'] != $prevlevel) {
				$levcount = 0;
			} else {
				++$levcount;
			}
			$prevlevel = $chardata[$i]['level'];
		}

		// N1. A sequence of neutrals takes the direction of the surrounding strong text if the text on both sides has the same direction. European and Arabic numbers act as if they were R in terms of their influence on neutrals. Start-of-level-run (sor) and end-of-level-run (eor) are used at level run boundaries.
		$prevlevel = -1;
		$levcount = 0;
		for ($i=0; $i < $numchars; ++$i) {
			if (($levcount > 0) AND (($i+1) < $numchars) AND ($chardata[($i+1)]['level'] == $prevlevel)) {
				if (($chardata[$i]['type'] == 'N') AND ($chardata[($i-1)]['type'] == 'L') AND ($chardata[($i+1)]['type'] == 'L')) {
					$chardata[$i]['type'] = 'L';
				} elseif (($chardata[$i]['type'] == 'N') AND
				 (($chardata[($i-1)]['type'] == 'R') OR ($chardata[($i-1)]['type'] == 'EN') OR ($chardata[($i-1)]['type'] == 'AN')) AND
				 (($chardata[($i+1)]['type'] == 'R') OR ($chardata[($i+1)]['type'] == 'EN') OR ($chardata[($i+1)]['type'] == 'AN'))) {
					$chardata[$i]['type'] = 'R';
				} elseif ($chardata[$i]['type'] == 'N') {
					// N2. Any remaining neutrals take the embedding direction
					$chardata[$i]['type'] = $chardata[$i]['sor'];
				}
			} elseif (($levcount == 0) AND (($i+1) < $numchars) AND ($chardata[($i+1)]['level'] == $prevlevel)) {
				// first char
				if (($chardata[$i]['type'] == 'N') AND ($chardata[$i]['sor'] == 'L') AND ($chardata[($i+1)]['type'] == 'L')) {
					$chardata[$i]['type'] = 'L';
				} elseif (($chardata[$i]['type'] == 'N') AND
				 (($chardata[$i]['sor'] == 'R') OR ($chardata[$i]['sor'] == 'EN') OR ($chardata[$i]['sor'] == 'AN')) AND
				 (($chardata[($i+1)]['type'] == 'R') OR ($chardata[($i+1)]['type'] == 'EN') OR ($chardata[($i+1)]['type'] == 'AN'))) {
					$chardata[$i]['type'] = 'R';
				} elseif ($chardata[$i]['type'] == 'N') {
					// N2. Any remaining neutrals take the embedding direction
					$chardata[$i]['type'] = $chardata[$i]['sor'];
				}
			} elseif (($levcount > 0) AND ((($i+1) == $numchars) OR (($i+1) < $numchars) AND ($chardata[($i+1)]['level'] != $prevlevel))) {
				//last char
				if (($chardata[$i]['type'] == 'N') AND ($chardata[($i-1)]['type'] == 'L') AND ($chardata[$i]['eor'] == 'L')) {
					$chardata[$i]['type'] = 'L';
				} elseif (($chardata[$i]['type'] == 'N') AND
				 (($chardata[($i-1)]['type'] == 'R') OR ($chardata[($i-1)]['type'] == 'EN') OR ($chardata[($i-1)]['type'] == 'AN')) AND
				 (($chardata[$i]['eor'] == 'R') OR ($chardata[$i]['eor'] == 'EN') OR ($chardata[$i]['eor'] == 'AN'))) {
					$chardata[$i]['type'] = 'R';
				} elseif ($chardata[$i]['type'] == 'N') {
					// N2. Any remaining neutrals take the embedding direction
					$chardata[$i]['type'] = $chardata[$i]['sor'];
				}
			} elseif ($chardata[$i]['type'] == 'N') {
				// N2. Any remaining neutrals take the embedding direction
				$chardata[$i]['type'] = $chardata[$i]['sor'];
			}
			if ($chardata[$i]['level'] != $prevlevel) {
				$levcount = 0;
			} else {
				++$levcount;
			}
			$prevlevel = $chardata[$i]['level'];
		}

		// I1. For all characters with an even (left-to-right) embedding direction, those of type R go up one level and those of type AN or EN go up two levels.
		// I2. For all characters with an odd (right-to-left) embedding direction, those of type L, EN or AN go up one level.
		for ($i=0; $i < $numchars; ++$i) {
			$odd = $chardata[$i]['level'] % 2;
			if ($odd) {
				if (($chardata[$i]['type'] == 'L') OR ($chardata[$i]['type'] == 'AN') OR ($chardata[$i]['type'] == 'EN')) {
					$chardata[$i]['level'] += 1;
				}
			} else {
				if ($chardata[$i]['type'] == 'R') {
					$chardata[$i]['level'] += 1;
				} elseif (($chardata[$i]['type'] == 'AN') OR ($chardata[$i]['type'] == 'EN')) {
					$chardata[$i]['level'] += 2;
				}
			}
			$maxlevel = max($chardata[$i]['level'],$maxlevel);
		}

		// L1. On each line, reset the embedding level of the following characters to the paragraph embedding level:
		//	1. Segment separators,
		//	2. Paragraph separators,
		//	3. Any sequence of whitespace characters preceding a segment separator or paragraph separator, and
		//	4. Any sequence of white space characters at the end of the line.
		for ($i=0; $i < $numchars; ++$i) {
			if (($chardata[$i]['type'] == 'B') OR ($chardata[$i]['type'] == 'S')) {
				$chardata[$i]['level'] = $pel;
			} elseif ($chardata[$i]['type'] == 'WS') {
				$j = $i+1;
				while ($j < $numchars) {
					if ((($chardata[$j]['type'] == 'B') OR ($chardata[$j]['type'] == 'S')) OR
						(($j == ($numchars-1)) AND ($chardata[$j]['type'] == 'WS'))) {
						$chardata[$i]['level'] = $pel;
						break;
					} elseif ($chardata[$j]['type'] != 'WS') {
						break;
					}
					++$j;
				}
			}
		}

		// Arabic Shaping
		// Cursively connected scripts, such as Arabic or Syriac, require the selection of positional character shapes that depend on adjacent characters. Shaping is logically applied after the Bidirectional Algorithm is used and is limited to characters within the same directional run.
		if ($arabic) {
			$endedletter = array(1569,1570,1571,1572,1573,1575,1577,1583,1584,1585,1586,1608,1688);
			$alfletter = array(1570,1571,1573,1575);
			$chardata2 = $chardata;
			$laaletter = false;
			$charAL = array();
			$x = 0;
			for ($i=0; $i < $numchars; ++$i) {
				if ((TCPDF_FONT_DATA::$uni_type[$chardata[$i]['char']] == 'AL') OR ($chardata[$i]['char'] == 32) OR ($chardata[$i]['char'] == 8204)) {
					$charAL[$x] = $chardata[$i];
					$charAL[$x]['i'] = $i;
					$chardata[$i]['x'] = $x;
					++$x;
				}
			}
			$numAL = $x;
			for ($i=0; $i < $numchars; ++$i) {
				$thischar = $chardata[$i];
				if ($i > 0) {
					$prevchar = $chardata[($i-1)];
				} else {
					$prevchar = false;
				}
				if (($i+1) < $numchars) {
					$nextchar = $chardata[($i+1)];
				} else {
					$nextchar = false;
				}
				if (TCPDF_FONT_DATA::$uni_type[$thischar['char']] == 'AL') {
					$x = $thischar['x'];
					if ($x > 0) {
						$prevchar = $charAL[($x-1)];
					} else {
						$prevchar = false;
					}
					if (($x+1) < $numAL) {
						$nextchar = $charAL[($x+1)];
					} else {
						$nextchar = false;
					}
					// if laa letter
					if (($prevchar !== false) AND ($prevchar['char'] == 1604) AND (in_array($thischar['char'], $alfletter))) {
						$arabicarr = TCPDF_FONT_DATA::$uni_laa_array;
						$laaletter = true;
						if ($x > 1) {
							$prevchar = $charAL[($x-2)];
						} else {
							$prevchar = false;
						}
					} else {
						$arabicarr = TCPDF_FONT_DATA::$uni_arabicsubst;
						$laaletter = false;
					}
					if (($prevchar !== false) AND ($nextchar !== false) AND
						((TCPDF_FONT_DATA::$uni_type[$prevchar['char']] == 'AL') OR (TCPDF_FONT_DATA::$uni_type[$prevchar['char']] == 'NSM')) AND
						((TCPDF_FONT_DATA::$uni_type[$nextchar['char']] == 'AL') OR (TCPDF_FONT_DATA::$uni_type[$nextchar['char']] == 'NSM')) AND
						($prevchar['type'] == $thischar['type']) AND
						($nextchar['type'] == $thischar['type']) AND
						($nextchar['char'] != 1567)) {
						if (in_array($prevchar['char'], $endedletter)) {
							if (isset($arabicarr[$thischar['char']][2])) {
								// initial
								$chardata2[$i]['char'] = $arabicarr[$thischar['char']][2];
							}
						} else {
							if (isset($arabicarr[$thischar['char']][3])) {
								// medial
								$chardata2[$i]['char'] = $arabicarr[$thischar['char']][3];
							}
						}
					} elseif (($nextchar !== false) AND
						((TCPDF_FONT_DATA::$uni_type[$nextchar['char']] == 'AL') OR (TCPDF_FONT_DATA::$uni_type[$nextchar['char']] == 'NSM')) AND
						($nextchar['type'] == $thischar['type']) AND
						($nextchar['char'] != 1567)) {
						if (isset($arabicarr[$chardata[$i]['char']][2])) {
							// initial
							$chardata2[$i]['char'] = $arabicarr[$thischar['char']][2];
						}
					} elseif ((($prevchar !== false) AND
						((TCPDF_FONT_DATA::$uni_type[$prevchar['char']] == 'AL') OR (TCPDF_FONT_DATA::$uni_type[$prevchar['char']] == 'NSM')) AND
						($prevchar['type'] == $thischar['type'])) OR
						(($nextchar !== false) AND ($nextchar['char'] == 1567))) {
						// final
						if (($i > 1) AND ($thischar['char'] == 1607) AND
							($chardata[$i-1]['char'] == 1604) AND
							($chardata[$i-2]['char'] == 1604)) {
							//Allah Word
							// mark characters to delete with false
							$chardata2[$i-2]['char'] = false;
							$chardata2[$i-1]['char'] = false;
							$chardata2[$i]['char'] = 65010;
						} else {
							if (($prevchar !== false) AND in_array($prevchar['char'], $endedletter)) {
								if (isset($arabicarr[$thischar['char']][0])) {
									// isolated
									$chardata2[$i]['char'] = $arabicarr[$thischar['char']][0];
								}
							} else {
								if (isset($arabicarr[$thischar['char']][1])) {
									// final
									$chardata2[$i]['char'] = $arabicarr[$thischar['char']][1];
								}
							}
						}
					} elseif (isset($arabicarr[$thischar['char']][0])) {
						// isolated
						$chardata2[$i]['char'] = $arabicarr[$thischar['char']][0];
					}
					// if laa letter
					if ($laaletter) {
						// mark characters to delete with false
						$chardata2[($charAL[($x-1)]['i'])]['char'] = false;
					}
				} // end if AL (Arabic Letter)
			} // end for each char
			/*
			 * Combining characters that can occur with Arabic Shadda (0651 HEX, 1617 DEC) are replaced.
			 * Putting the combining mark and shadda in the same glyph allows us to avoid the two marks overlapping each other in an illegible manner.
			 */
			for ($i = 0; $i < ($numchars-1); ++$i) {
				if (($chardata2[$i]['char'] == 1617) AND (isset(TCPDF_FONT_DATA::$uni_diacritics[($chardata2[$i+1]['char'])]))) {
					// check if the subtitution font is defined on current font
					if (isset($currentfont['cw'][(TCPDF_FONT_DATA::$uni_diacritics[($chardata2[$i+1]['char'])])])) {
						$chardata2[$i]['char'] = false;
						$chardata2[$i+1]['char'] = TCPDF_FONT_DATA::$uni_diacritics[($chardata2[$i+1]['char'])];
					}
				}
			}
			// remove marked characters
			foreach ($chardata2 as $key => $value) {
				if ($value['char'] === false) {
					unset($chardata2[$key]);
				}
			}
			$chardata = array_values($chardata2);
			$numchars = count($chardata);
			unset($chardata2);
			unset($arabicarr);
			unset($laaletter);
			unset($charAL);
		}

		// L2. From the highest level found in the text to the lowest odd level on each line, including intermediate levels not actually present in the text, reverse any contiguous sequence of characters that are at that level or higher.
		for ($j=$maxlevel; $j > 0; $j--) {
			$ordarray = Array();
			$revarr = Array();
			$onlevel = false;
			for ($i=0; $i < $numchars; ++$i) {
				if ($chardata[$i]['level'] >= $j) {
					$onlevel = true;
					if (isset(TCPDF_FONT_DATA::$uni_mirror[$chardata[$i]['char']])) {
						// L4. A character is depicted by a mirrored glyph if and only if (a) the resolved directionality of that character is R, and (b) the Bidi_Mirrored property value of that character is true.
						$chardata[$i]['char'] = TCPDF_FONT_DATA::$uni_mirror[$chardata[$i]['char']];
					}
					$revarr[] = $chardata[$i];
				} else {
					if ($onlevel) {
						$revarr = array_reverse($revarr);
						$ordarray = array_merge($ordarray, $revarr);
						$revarr = Array();
						$onlevel = false;
					}
					$ordarray[] = $chardata[$i];
				}
			}
			if ($onlevel) {
				$revarr = array_reverse($revarr);
				$ordarray = array_merge($ordarray, $revarr);
			}
			$chardata = $ordarray;
		}
		$ordarray = array();
		foreach ($chardata as $cd) {
			$ordarray[] = $cd['char'];
			// store char values for subsetting
			$currentfont['subsetchars'][$cd['char']] = true;
		}
		return $ordarray;
	}
Example #10
0
 /**
  * Returns the PDF string code to print a cell (rectangular area) with optional borders, background color and character string. The upper-left corner of the cell corresponds to the current position. The text can be aligned or centered. After the call, the current position moves to the right or to the next line. It is possible to put a link on the text.<br />
  * If automatic page breaking is enabled and the cell goes beyond the limit, a page break is done before outputting.
  * @param $w (float) Cell width. If 0, the cell extends up to the right margin.
  * @param $h (float) Cell height. Default value: 0.
  * @param $txt (string) String to print. Default value: empty string.
  * @param $border (mixed) Indicates if borders must be drawn around the cell. The value can be a number:<ul><li>0: no border (default)</li><li>1: frame</li></ul> or a string containing some or all of the following characters (in any order):<ul><li>L: left</li><li>T: top</li><li>R: right</li><li>B: bottom</li></ul> 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)))
  * @param $ln (int) Indicates where the current position should go after the call. Possible values are:<ul><li>0: to the right (or left for RTL languages)</li><li>1: to the beginning of the next line</li><li>2: below</li></ul>Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: 0.
  * @param $align (string) Allows to center or align the text. Possible values are:<ul><li>L or empty string: left align (default value)</li><li>C: center</li><li>R: right align</li><li>J: justify</li></ul>
  * @param $fill (boolean) Indicates if the cell background must be painted (true) or transparent (false).
  * @param $link (mixed) URL or identifier returned by AddLink().
  * @param $stretch (int) font stretch mode: <ul><li>0 = disabled</li><li>1 = horizontal scaling only if text is larger than cell width</li><li>2 = forced horizontal scaling to fit cell width</li><li>3 = character spacing only if text is larger than cell width</li><li>4 = forced character spacing to fit cell width</li></ul> General font stretching and scaling values will be preserved when possible.
  * @param $ignore_min_height (boolean) if true ignore automatic minimum height value.
  * @param $calign (string) cell vertical alignment relative to the specified Y value. Possible values are:<ul><li>T : cell top</li><li>C : center</li><li>B : cell bottom</li><li>A : font top</li><li>L : font baseline</li><li>D : font bottom</li></ul>
  * @param $valign (string) text vertical alignment inside the cell. Possible values are:<ul><li>T : top</li><li>M : middle</li><li>B : bottom</li></ul>
  * @return string containing cell code
  * @protected
  * @since 1.0
  * @see Cell()
  */
 protected function getCellCode($w, $h = 0, $txt = '', $border = 0, $ln = 0, $align = '', $fill = false, $link = '', $stretch = 0, $ignore_min_height = false, $calign = 'T', $valign = 'M')
 {
     // replace 'NO-BREAK SPACE' (U+00A0) character with a simple space
     $txt = str_replace(TCPDF_FONTS::unichr(160, $this->isunicode), ' ', $txt);
     $prev_cell_margin = $this->cell_margin;
     $prev_cell_padding = $this->cell_padding;
     $txt = TCPDF_STATIC::removeSHY($txt, $this->isunicode);
     $rs = '';
     //string to be returned
     $this->adjustCellPadding($border);
     if (!$ignore_min_height) {
         $min_cell_height = $this->getCellHeight($this->FontSize);
         if ($h < $min_cell_height) {
             $h = $min_cell_height;
         }
     }
     $k = $this->k;
     // check page for no-write regions and adapt page margins if necessary
     list($this->x, $this->y) = $this->checkPageRegions($h, $this->x, $this->y);
     if ($this->rtl) {
         $x = $this->x - $this->cell_margin['R'];
     } else {
         $x = $this->x + $this->cell_margin['L'];
     }
     $y = $this->y + $this->cell_margin['T'];
     $prev_font_stretching = $this->font_stretching;
     $prev_font_spacing = $this->font_spacing;
     // cell vertical alignment
     switch ($calign) {
         case 'A':
             // font top
             switch ($valign) {
                 case 'T':
                     // top
                     $y -= $this->cell_padding['T'];
                     break;
                 case 'B':
                     // bottom
                     $y -= $h - $this->cell_padding['B'] - $this->FontAscent - $this->FontDescent;
                     break;
                 default:
                 case 'C':
                 case 'M':
                     // center
                     $y -= ($h - $this->FontAscent - $this->FontDescent) / 2;
                     break;
             }
             break;
         case 'L':
             // font baseline
             switch ($valign) {
                 case 'T':
                     // top
                     $y -= $this->cell_padding['T'] + $this->FontAscent;
                     break;
                 case 'B':
                     // bottom
                     $y -= $h - $this->cell_padding['B'] - $this->FontDescent;
                     break;
                 default:
                 case 'C':
                 case 'M':
                     // center
                     $y -= ($h + $this->FontAscent - $this->FontDescent) / 2;
                     break;
             }
             break;
         case 'D':
             // font bottom
             switch ($valign) {
                 case 'T':
                     // top
                     $y -= $this->cell_padding['T'] + $this->FontAscent + $this->FontDescent;
                     break;
                 case 'B':
                     // bottom
                     $y -= $h - $this->cell_padding['B'];
                     break;
                 default:
                 case 'C':
                 case 'M':
                     // center
                     $y -= ($h + $this->FontAscent + $this->FontDescent) / 2;
                     break;
             }
             break;
         case 'B':
             // cell bottom
             $y -= $h;
             break;
         case 'C':
         case 'M':
             // cell center
             $y -= $h / 2;
             break;
         default:
         case 'T':
             // cell top
             break;
     }
     // text vertical alignment
     switch ($valign) {
         case 'T':
             // top
             $yt = $y + $this->cell_padding['T'];
             break;
         case 'B':
             // bottom
             $yt = $y + $h - $this->cell_padding['B'] - $this->FontAscent - $this->FontDescent;
             break;
         default:
         case 'C':
         case 'M':
             // center
             $yt = $y + ($h - $this->FontAscent - $this->FontDescent) / 2;
             break;
     }
     $basefonty = $yt + $this->FontAscent;
     if (TCPDF_STATIC::empty_string($w) or $w <= 0) {
         if ($this->rtl) {
             $w = $x - $this->lMargin;
         } else {
             $w = $this->w - $this->rMargin - $x;
         }
     }
     $s = '';
     // fill and borders
     if (is_string($border) and strlen($border) == 4) {
         // full border
         $border = 1;
     }
     if ($fill or $border == 1) {
         if ($fill) {
             $op = $border == 1 ? 'B' : 'f';
         } else {
             $op = 'S';
         }
         if ($this->rtl) {
             $xk = ($x - $w) * $k;
         } else {
             $xk = $x * $k;
         }
         $s .= sprintf('%F %F %F %F re %s ', $xk, ($this->h - $y) * $k, $w * $k, -$h * $k, $op);
     }
     // draw borders
     $s .= $this->getCellBorder($x, $y, $w, $h, $border);
     if ($txt != '') {
         $txt2 = $txt;
         if ($this->isunicode) {
             $txt2 = $this->UTF8ToLatin2($txt2, $this->isunicode);
         }
         $txt2 = TCPDF_STATIC::_escape($txt2);
         // get current text width (considering general font stretching and spacing)
         $txwidth = $this->GetStringWidth($txt);
         $width = $txwidth;
         // check for stretch mode
         if ($stretch > 0) {
             // calculate ratio between cell width and text width
             if ($width <= 0) {
                 $ratio = 1;
             } else {
                 $ratio = ($w - $this->cell_padding['L'] - $this->cell_padding['R']) / $width;
             }
             // check if stretching is required
             if ($ratio < 1 or $ratio > 1 and $stretch % 2 == 0) {
                 // the text will be stretched to fit cell width
                 if ($stretch > 2) {
                     // set new character spacing
                     $this->font_spacing += ($w - $this->cell_padding['L'] - $this->cell_padding['R'] - $width) / (max($this->GetNumChars($txt) - 1, 1) * ($this->font_stretching / 100));
                 } else {
                     // set new horizontal stretching
                     $this->font_stretching *= $ratio;
                 }
                 // recalculate text width (the text fills the entire cell)
                 $width = $w - $this->cell_padding['L'] - $this->cell_padding['R'];
                 // reset alignment
                 $align = '';
             }
         }
         if ($this->font_stretching != 100) {
             // apply font stretching
             $rs .= sprintf('BT %F Tz ET ', $this->font_stretching);
         }
         if ($this->font_spacing != 0) {
             // increase/decrease font spacing
             $rs .= sprintf('BT %F Tc ET ', $this->font_spacing * $this->k);
         }
         if ($this->ColorFlag and $this->textrendermode < 4) {
             $s .= 'q ' . $this->TextColor . ' ';
         }
         // rendering mode
         $s .= sprintf('BT %d Tr %F w ET ', $this->textrendermode, $this->textstrokewidth * $this->k);
         // count number of spaces
         $ns = substr_count($txt, chr(32));
         // Justification
         $spacewidth = 0;
         if ($align == 'J' and $ns > 0) {
             if ($this->isUnicodeFont()) {
                 // get string width without spaces
                 $width = $this->GetStringWidth(str_replace(' ', '', $txt));
                 // calculate average space width
                 $spacewidth = -1000 * ($w - $width - $this->cell_padding['L'] - $this->cell_padding['R']) / ($ns ? $ns : 1) / ($this->FontSize ? $this->FontSize : 1);
                 if ($this->font_stretching != 100) {
                     // word spacing is affected by stretching
                     $spacewidth /= $this->font_stretching / 100;
                 }
                 // set word position to be used with TJ operator
                 $txt2 = str_replace(chr(0) . chr(32), ') ' . sprintf('%F', $spacewidth) . ' (', $txt2);
                 $unicode_justification = true;
             } else {
                 // get string width
                 $width = $txwidth;
                 // new space width
                 $spacewidth = ($w - $width - $this->cell_padding['L'] - $this->cell_padding['R']) / ($ns ? $ns : 1) * $this->k;
                 if ($this->font_stretching != 100) {
                     // word spacing (Tw) is affected by stretching
                     $spacewidth /= $this->font_stretching / 100;
                 }
                 // set word spacing
                 $rs .= sprintf('BT %F Tw ET ', $spacewidth);
             }
             $width = $w - $this->cell_padding['L'] - $this->cell_padding['R'];
         }
         // replace carriage return characters
         $txt2 = str_replace("\r", ' ', $txt2);
         switch ($align) {
             case 'C':
                 $dx = ($w - $width) / 2;
                 break;
             case 'R':
                 if ($this->rtl) {
                     $dx = $this->cell_padding['R'];
                 } else {
                     $dx = $w - $width - $this->cell_padding['R'];
                 }
                 break;
             case 'L':
                 if ($this->rtl) {
                     $dx = $w - $width - $this->cell_padding['L'];
                 } else {
                     $dx = $this->cell_padding['L'];
                 }
                 break;
             case 'J':
             default:
                 if ($this->rtl) {
                     $dx = $this->cell_padding['R'];
                 } else {
                     $dx = $this->cell_padding['L'];
                 }
                 break;
         }
         if ($this->rtl) {
             $xdx = $x - $dx - $width;
         } else {
             $xdx = $x + $dx;
         }
         $xdk = $xdx * $k;
         // print text
         $s .= sprintf('BT %F %F Td [(%s)] TJ ET', $xdk, ($this->h - $basefonty) * $k, $txt2);
         if (isset($uniblock)) {
             // print overlapping characters as separate string
             $xshift = 0;
             // horizontal shift
             $ty = ($this->h - $basefonty + 0.2 * $this->FontSize) * $k;
             $spw = ($w - $txwidth - $this->cell_padding['L'] - $this->cell_padding['R']) / ($ns ? $ns : 1);
             foreach ($uniblock as $uk => $uniarr) {
                 if ($uk % 2 == 0) {
                     // x space to skip
                     if ($spacewidth != 0) {
                         // justification shift
                         $xshift += count(array_keys($uniarr, 32)) * $spw;
                     }
                     $xshift += $this->GetArrStringWidth($uniarr);
                     // + shift justification
                 } else {
                     // character to print
                     $topchr = TCPDF_FONTS::arrUTF8ToUTF16BE($uniarr, false);
                     $topchr = TCPDF_STATIC::_escape($topchr);
                     $s .= sprintf(' BT %F %F Td [(%s)] TJ ET', $xdk + $xshift * $k, $ty, $topchr);
                 }
             }
         }
         if ($this->underline) {
             $s .= ' ' . $this->_dounderlinew($xdx, $basefonty, $width);
         }
         if ($this->linethrough) {
             $s .= ' ' . $this->_dolinethroughw($xdx, $basefonty, $width);
         }
         if ($this->overline) {
             $s .= ' ' . $this->_dooverlinew($xdx, $basefonty, $width);
         }
         if ($this->ColorFlag and $this->textrendermode < 4) {
             $s .= ' Q';
         }
         if ($link) {
             $this->Link($xdx, $yt, $width, $this->FontAscent + $this->FontDescent, $link, $ns);
         }
     }
     // output cell
     if ($s) {
         // output cell
         $rs .= $s;
         if ($this->font_spacing != 0) {
             // reset font spacing mode
             $rs .= ' BT 0 Tc ET';
         }
         if ($this->font_stretching != 100) {
             // reset font stretching mode
             $rs .= ' BT 100 Tz ET';
         }
     }
     // reset word spacing
     if (!$this->isUnicodeFont() and $align == 'J') {
         $rs .= ' BT 0 Tw ET';
     }
     // reset stretching and spacing
     $this->font_stretching = $prev_font_stretching;
     $this->font_spacing = $prev_font_spacing;
     $this->lasth = $h;
     if ($ln > 0) {
         //Go to the beginning of the next line
         $this->y = $y + $h + $this->cell_margin['B'];
         if ($ln == 1) {
             if ($this->rtl) {
                 $this->x = $this->w - $this->rMargin;
             } else {
                 $this->x = $this->lMargin;
             }
         }
     } else {
         // go left or right by case
         if ($this->rtl) {
             $this->x = $x - $w - $this->cell_margin['L'];
         } else {
             $this->x = $x + $w + $this->cell_margin['R'];
         }
     }
     $gstyles = '' . $this->linestyleWidth . ' ' . $this->linestyleCap . ' ' . $this->linestyleJoin . ' ' . $this->linestyleDash . ' ' . $this->DrawColor . ' ' . $this->FillColor . "\n";
     $rs = $gstyles . $rs;
     $this->cell_padding = $prev_cell_padding;
     $this->cell_margin = $prev_cell_margin;
     return $rs;
 }
Example #11
0
 protected function renderRow($x, $y, $row, $options, &$view = NULL, $key = NULL, $printLabels = TRUE)
 {
     $pageDim = $this->getPageDimensions();
     // Render the content if it is not already:
     if (is_object($view) && $key != NULL && isset($view->field[$key]) && is_object($view->field[$key]) && !is_string($row)) {
         $content = $view->field[$key]->theme($row);
     } elseif (is_string($row)) {
         $content = $row;
     } else {
         // We got bad data. So return.
         return;
     }
     if (empty($key) || !empty($view->field[$key]->options['exclude']) || empty($content) && $view->field[$key]->options['hide_empty']) {
         return '';
     }
     // Apply the hyphenation patterns to the content:
     if (!isset($options['text']['hyphenate']) && is_object($view) && is_object($view->display_handler)) {
         $options['text']['hyphenate'] = $view->display_handler->get_option('default_text_hyphenate');
     }
     if (isset($options['text']['hyphenate']) && $options['text']['hyphenate'] != 'none') {
         $patternFile = $options['text']['hyphenate'];
         if ($options['text']['hyphenate'] == 'auto' && is_object($row)) {
             // Workaround:
             // Since "$nodeLanguage = $row->node_language;" does not work anymore,
             // we using this:
             if (isset($row->_field_data['nid']['entity']->language)) {
                 $nodeLanguage = $row->_field_data['nid']['entity']->language;
                 foreach (self::getAvailableHyphenatePatterns() as $file => $pattern) {
                     if (stristr($pattern, $nodeLanguage) !== FALSE) {
                         $patternFile = $file;
                         break;
                     }
                 }
             }
         }
         $patternFile = views_pdf_get_library('tcpdf') . '/hyphenate_patterns/' . $patternFile;
         if (file_exists($patternFile)) {
             if (method_exists('TCPDF_STATIC', 'getHyphenPatternsFromTEX')) {
                 $hyphen_patterns = TCPDF_STATIC::getHyphenPatternsFromTEX($patternFile);
             } else {
                 $hyphen_patterns = $this->getHyphenPatternsFromTEX($patternFile);
             }
             // Bugfix if you like to print some html code to the PDF, we
             // need to prevent the replacement of this tags.
             $content = str_replace('&gt;', '&amp;gt;', $content);
             $content = str_replace('&lt;', '&amp;lt;', $content);
             $content = $this->hyphenateText($content, $hyphen_patterns);
         }
     }
     // Set css variable
     if (is_object($view) && is_object($view->display_handler)) {
         $css_file = $view->display_handler->get_option('css_file');
     }
     // Render Labels
     $prefix = '';
     if ($printLabels && !empty($view->field[$key]->options['label'])) {
         $prefix = $view->field[$key]->options['label'];
         if ($view->field[$key]->options['element_label_colon']) {
             $prefix .= ':';
         }
         $prefix .= ' ';
     }
     $font_size = empty($options['text']['font_size']) ? $this->defaultFontSize : $options['text']['font_size'];
     $font_family = $options['text']['font_family'] == 'default' || empty($options['text']['font_family']) ? $this->defaultFontFamily : $options['text']['font_family'];
     $font_style = is_array($options['text']['font_style']) ? $options['text']['font_style'] : $this->defaultFontStyle;
     $textColor = !empty($options['text']['color']) ? $this->parseColor($options['text']['color']) : $this->parseColor($this->defaultFontColor);
     $w = $options['position']['width'];
     $h = $options['position']['height'];
     $border = 0;
     $align = isset($options['text']['align']) ? $options['text']['align'] : $this->defaultTextAlign;
     $fill = 0;
     $ln = 1;
     $reseth = TRUE;
     $stretch = 0;
     $ishtml = isset($options['render']['is_html']) ? $options['render']['is_html'] : 1;
     $stripHTML = !$ishtml;
     $autopadding = TRUE;
     $maxh = 0;
     $valign = 'T';
     $fitcell = FALSE;
     // Run eval before.
     if (!empty($options['render']['bypass_eval_before']) && !empty($options['render']['eval_before'])) {
         eval($options['render']['eval_before']);
     } elseif (!empty($options['render']['eval_before'])) {
         $content = php_eval($options['render']['eval_before']);
     }
     // Add css if there is a css file set and stripHTML is not active.
     if (!empty($css_file) && is_string($css_file) && !$stripHTML && $ishtml && !empty($content)) {
         $content = '<link type="text/css" rel="stylesheet" media="all" href="' . $css_file . '" />' . PHP_EOL . $content;
     }
     // Set Text Color.
     $this->SetTextColorArray($textColor);
     // Set font.
     $this->SetFont($font_family, implode('', $font_style), $font_size);
     // Save the last page before starting writing, this
     // is needed to dected if we write over a page. Then we need
     // to reset the y coordinate for the 'last_writing' position option.
     $this->lastWritingPage = $this->getPage();
     if ($stripHTML) {
         $content = strip_tags($content);
     }
     // Write the content of a field to the pdf file:
     if (!empty($content)) {
         $this->MultiCell($w, $h, $prefix . $content, $border, $align, $fill, $ln, $x, $y, $reseth, $stretch, $ishtml, $autopadding, $maxh, $valign, $fitcell);
     } else {
         $this->MultiCell($w, $h, $prefix, $border, $align, $fill, $ln, $x, $y, $reseth, $stretch, $ishtml, $autopadding, $maxh, $valign, $fitcell);
     }
     // Reset font to default.
     $this->SetFont($this->defaultFontFamily, implode('', $this->defaultFontStyle), $this->defaultFontSize);
     // Run eval after.
     if (!empty($options['render']['bypass_eval_after']) && !empty($options['render']['eval_after'])) {
         eval($options['render']['eval_after']);
     } elseif (!empty($options['render']['eval_after'])) {
         $content = php_eval($options['render']['eval_after']);
     }
     // Write Coordinates of element.
     $this->elements[$key] = array('x' => $x, 'y' => $y, 'width' => empty($w) ? $pageDim['wk'] - $this->rMargin - $x : $w, 'height' => $this->y - $y, 'page' => $this->lastWritingPage);
     $this->lastWritingElement = $key;
 }
Example #12
0
For security reasons, the parameters for the 'params' attribute of TCPDF
tag must be prepared as an array and encoded with the
serializeTCPDFtagParameters() method (see the example below).

 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
$html = '<h1>Test TCPDF Methods in HTML</h1>
<h2 style="color:red;">IMPORTANT:</h2>
<span style="color:red;">If you are using user-generated content, the tcpdf tag can be unsafe.<br />
You can disable this tag by setting to false the <b>K_TCPDF_CALLS_IN_HTML</b> constant on TCPDF configuration file.</span>
<h2>write1DBarcode method in HTML</h2>';
$params = TCPDF_STATIC::serializeTCPDFtagParameters(array('CODE 39', 'C39', '', '', 80, 30, 0.4, array('position' => 'S', 'border' => true, 'padding' => 4, 'fgcolor' => array(0, 0, 0), 'bgcolor' => array(255, 255, 255), 'text' => true, 'font' => 'helvetica', 'fontsize' => 8, 'stretchtext' => 4), 'N'));
$html .= '<tcpdf method="write1DBarcode" params="' . $params . '" />';
$params = TCPDF_STATIC::serializeTCPDFtagParameters(array('CODE 128', 'C128', '', '', 80, 30, 0.4, array('position' => 'S', 'border' => true, 'padding' => 4, 'fgcolor' => array(0, 0, 0), 'bgcolor' => array(255, 255, 255), 'text' => true, 'font' => 'helvetica', 'fontsize' => 8, 'stretchtext' => 4), 'N'));
$html .= '<tcpdf method="write1DBarcode" params="' . $params . '" />';
$html .= '<tcpdf method="AddPage" /><h2>Graphic Functions</h2>';
$params = TCPDF_STATIC::serializeTCPDFtagParameters(array(0));
$html .= '<tcpdf method="SetDrawColor" params="' . $params . '" />';
$params = TCPDF_STATIC::serializeTCPDFtagParameters(array(50, 50, 40, 10, 'DF', array(), array(0, 128, 255)));
$html .= '<tcpdf method="Rect" params="' . $params . '" />';
// output the HTML content
$pdf->writeHTML($html, true, 0, true, 0);
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// reset pointer to the last page
$pdf->lastPage();
// ---------------------------------------------------------
//Close and output PDF document
$pdf->Output('example_049.pdf', 'I');
//============================================================+
// END OF FILE
//============================================================+
Example #13
0
 /**
  * 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)
 {
     switch ($value[0]) {
         case PDF_TYPE_STRING:
             if ($this->encrypted) {
                 $value[1] = $this->_unescape($value[1]);
                 $value[1] = $this->_encrypt_data($this->_current_obj_id, $value[1]);
                 $value[1] = TCPDF_STATIC::_escape($value[1]);
             }
             break;
         case PDF_TYPE_STREAM:
             if ($this->encrypted) {
                 $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->_encrypt_data($this->_current_obj_id, $value[1]);
                 // remake hexstring of encrypted string
                 $value[1] = $this->str2hex($value[1]);
             }
             break;
     }
     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->uniqueid;
             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;
     }
 }
Example #14
0
 /**
  * Overriden to allow unicode in filenames
  * @see http://sourceforge.net/p/tcpdf/feature-requests/184/
  *
  * Send the document to a given destination: string, local file or browser.
  * In the last case, the plug-in may be used (if present) or a download ("Save as" dialog box) may be forced.<br />
  * The method first calls Close() if necessary to terminate the document.
  * @param $name (string) The name of the file when saved. Note that special characters are removed and blanks characters are replaced with the underscore character.
  * @param $dest (string) Destination where to send the document. It can take one of the following values:<ul><li>I: send the file inline to the browser (default). The plug-in is used if available. The name given by name is used when one selects the "Save as" option on the link generating the PDF.</li><li>D: send to the browser and force a file download with the name given by name.</li><li>F: save to a local server file with the name given by name.</li><li>S: return the document as a string (name is ignored).</li><li>FI: equivalent to F + I option</li><li>FD: equivalent to F + D option</li><li>E: return the document as base64 mime multi-part email attachment (RFC 2045)</li></ul>
  * @public
  * @since 1.0
  * @see Close()
  */
 public function Output($name = 'doc.pdf', $dest = 'I')
 {
     //Output PDF to some destination
     //Finish document if necessary
     if ($this->state < 3) {
         $this->Close();
     }
     //Normalize parameters
     if (is_bool($dest)) {
         $dest = $dest ? 'D' : 'F';
     }
     $dest = strtoupper($dest);
     if ($dest[0] != 'F') {
         $name = preg_replace('/[\\s]+/', '_', $name);
         $name = preg_replace('/[^\\p{L}\\p{N}_\\.-]/u', '', $name);
     }
     if ($this->sign) {
         // *** apply digital signature to the document ***
         // get the document content
         $pdfdoc = $this->getBuffer();
         // remove last newline
         $pdfdoc = substr($pdfdoc, 0, -1);
         // Remove the original buffer
         if (isset($this->diskcache) and $this->diskcache) {
             // remove buffer file from cache
             unlink($this->buffer);
         }
         unset($this->buffer);
         // remove filler space
         $byterange_string_len = strlen(TCPDF_STATIC::$byterange_string);
         // define the ByteRange
         $byte_range = array();
         $byte_range[0] = 0;
         $byte_range[1] = strpos($pdfdoc, TCPDF_STATIC::$byterange_string) + $byterange_string_len + 10;
         $byte_range[2] = $byte_range[1] + $this->signature_max_length + 2;
         $byte_range[3] = strlen($pdfdoc) - $byte_range[2];
         $pdfdoc = substr($pdfdoc, 0, $byte_range[1]) . substr($pdfdoc, $byte_range[2]);
         // replace the ByteRange
         $byterange = sprintf('/ByteRange[0 %u %u %u]', $byte_range[1], $byte_range[2], $byte_range[3]);
         $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('doc');
         $f = fopen($tempdoc, 'wb');
         if (!$f) {
             $this->Error('Unable to create temporary file: ' . $tempdoc);
         }
         $pdfdoc_length = strlen($pdfdoc);
         fwrite($f, $pdfdoc, $pdfdoc_length);
         fclose($f);
         // get digital signature via openssl library
         $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 {
             openssl_pkcs7_sign($tempdoc, $tempsign, $this->signature_data['signcert'], array($this->signature_data['privkey'], $this->signature_data['password']), array(), PKCS7_BINARY | PKCS7_DETACHED, $this->signature_data['extracerts']);
         }
         unlink($tempdoc);
         // read signature
         $signature = file_get_contents($tempsign);
         unlink($tempsign);
         // extract signature
         $signature = substr($signature, $pdfdoc_length);
         $signature = substr($signature, strpos($signature, "%%EOF\n\n------") + 13);
         $tmparr = explode("\n\n", $signature);
         $signature = $tmparr[1];
         unset($tmparr);
         // decode signature
         $signature = base64_decode(trim($signature));
         // convert signature to hex
         $signature = current(unpack('H*', $signature));
         $signature = str_pad($signature, $this->signature_max_length, '0');
         // disable disk caching
         $this->diskcache = false;
         // Add signature to the document
         $this->buffer = substr($pdfdoc, 0, $byte_range[1]) . '<' . $signature . '>' . substr($pdfdoc, $byte_range[1]);
         $this->bufferlen = strlen($this->buffer);
     }
     switch ($dest) {
         case 'I':
             // Send PDF to the standard output
             if (ob_get_contents()) {
                 $this->Error('Some data has already been output, can\'t send PDF file');
             }
             if (php_sapi_name() != 'cli') {
                 // send output to a browser
                 header('Content-Type: application/pdf');
                 if (headers_sent()) {
                     $this->Error('Some data has already been output to browser, can\'t send PDF file');
                 }
                 header('Cache-Control: private, must-revalidate, post-check=0, pre-check=0, max-age=1');
                 //header('Cache-Control: public, must-revalidate, max-age=0'); // HTTP/1.1
                 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) . '"');
                 TCPDF_STATIC::sendOutputData($this->getBuffer(), $this->bufferlen);
             } else {
                 echo $this->getBuffer();
             }
             break;
         case 'D':
             // download PDF as file
             if (ob_get_contents()) {
                 $this->Error('Some data has already been output, can\'t send PDF file');
             }
             header('Content-Description: File Transfer');
             if (headers_sent()) {
                 $this->Error('Some data has already been output to browser, can\'t send PDF file');
             }
             header('Cache-Control: private, must-revalidate, post-check=0, pre-check=0, max-age=1');
             //header('Cache-Control: public, must-revalidate, max-age=0'); // HTTP/1.1
             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');
             // force download dialog
             if (strpos(php_sapi_name(), 'cgi') === false) {
                 header('Content-Type: application/force-download');
                 header('Content-Type: application/octet-stream', false);
                 header('Content-Type: application/download', false);
                 header('Content-Type: application/pdf', false);
             } else {
                 header('Content-Type: application/pdf');
             }
             // use the Content-Disposition header to supply a recommended filename
             header('Content-Disposition: attachment; filename="' . basename($name) . '"');
             header('Content-Transfer-Encoding: binary');
             TCPDF_STATIC::sendOutputData($this->getBuffer(), $this->bufferlen);
             break;
         case 'F':
         case 'FI':
         case 'FD':
             // save PDF to a local file
             if ($this->diskcache) {
                 copy($this->buffer, $name);
             } else {
                 $f = fopen($name, 'wb');
                 if (!$f) {
                     $this->Error('Unable to create output file: ' . $name);
                 }
                 fwrite($f, $this->getBuffer(), $this->bufferlen);
                 fclose($f);
             }
             if ($dest == 'FI') {
                 // send headers to browser
                 header('Content-Type: application/pdf');
                 header('Cache-Control: private, must-revalidate, post-check=0, pre-check=0, max-age=1');
                 //header('Cache-Control: public, must-revalidate, max-age=0'); // HTTP/1.1
                 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) . '"');
                 TCPDF_STATIC::sendOutputData(file_get_contents($name), filesize($name));
             } elseif ($dest == 'FD') {
                 // send headers to browser
                 if (ob_get_contents()) {
                     $this->Error('Some data has already been output, can\'t send PDF file');
                 }
                 header('Content-Description: File Transfer');
                 if (headers_sent()) {
                     $this->Error('Some data has already been output to browser, can\'t send PDF file');
                 }
                 header('Cache-Control: private, must-revalidate, post-check=0, pre-check=0, max-age=1');
                 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');
                 // force download dialog
                 if (strpos(php_sapi_name(), 'cgi') === false) {
                     header('Content-Type: application/force-download');
                     header('Content-Type: application/octet-stream', false);
                     header('Content-Type: application/download', false);
                     header('Content-Type: application/pdf', false);
                 } else {
                     header('Content-Type: application/pdf');
                 }
                 // use the Content-Disposition header to supply a recommended filename
                 header('Content-Disposition: attachment; filename="' . basename($name) . '"');
                 header('Content-Transfer-Encoding: binary');
                 TCPDF_STATIC::sendOutputData(file_get_contents($name), filesize($name));
             }
             break;
         case 'E':
             // return PDF as base64 mime multi-part email attachment (RFC 2045)
             $retval = 'Content-Type: application/pdf;' . "\r\n";
             $retval .= ' name="' . $name . '"' . "\r\n";
             $retval .= 'Content-Transfer-Encoding: base64' . "\r\n";
             $retval .= 'Content-Disposition: attachment;' . "\r\n";
             $retval .= ' filename="' . $name . '"' . "\r\n\r\n";
             $retval .= chunk_split(base64_encode($this->getBuffer()), 76, "\r\n");
             return $retval;
         case 'S':
             // returns PDF as a string
             return $this->getBuffer();
         default:
             $this->Error('Incorrect output destination: ' . $dest);
     }
     return '';
 }
Example #15
0
 /**
  * show Libraries information in system information
  *
  * @since version 0.84
  **/
 static function showLibrariesInformation()
 {
     // No gettext
     echo "<tr class='tab_bg_2'><th>Libraries</th></tr>\n";
     echo "<tr class='tab_bg_1'><td><pre>\n&nbsp;\n";
     include_once GLPI_HTMLAWED;
     echo "htmLawed version " . hl_version() . " in (" . self::getLibraryDir("hl_version") . ")\n";
     echo "phpCas version " . phpCAS::getVersion() . " in (" . (self::getLibraryDir("phpCAS") ? self::getLibraryDir("phpCAS") : "system") . ")\n";
     $pm = new PHPMailer();
     echo "PHPMailer version " . $pm->Version . " in (" . self::getLibraryDir("PHPMailer") . ")\n";
     // EZ component
     echo "ZetaComponent ezcGraph installed in (" . self::getLibraryDir("ezcGraph") . "): " . (class_exists('ezcGraph') ? 'OK' : 'KO') . "\n";
     // Zend
     echo "Zend Framework in (" . self::getLibraryDir("Zend\\Loader\\StandardAutoloader") . ")\n";
     // SimplePie :
     $sp = new SimplePie();
     echo "SimplePie version " . SIMPLEPIE_VERSION . " in (" . self::getLibraryDir($sp) . ")\n";
     // TCPDF
     echo "TCPDF version " . TCPDF_STATIC::getTCPDFVersion() . " in (" . self::getLibraryDir("TCPDF") . ")\n";
     // password_compat
     $check = PasswordCompat\binary\check() ? "Ok" : "KO";
     echo "ircmaxell/password-compat in (" . self::getLibraryDir("PasswordCompat\\binary\\check") . "). Compatitility: {$check}\n";
     // autolink
     echo "iacaml/autolink in (" . self::getLibraryDir("autolink") . ")\n";
     // sabre/vobject
     echo "sabre/vobject in (" . self::getLibraryDir("Sabre\\VObject\\Component") . ")\n";
     // vcard
     echo "guzzlehttp/guzzle in (" . self::getLibraryDir("JeroenDesloovere\\VCard\\VCard") . ")\n";
     echo "\n</pre></td></tr>";
 }
Example #16
0
 /**
  * show Libraries information in system information
  *
  * @since version 0.84
  **/
 static function showLibrariesInformation()
 {
     // No gettext
     echo "<tr class='tab_bg_2'><th>Libraries</th></tr>\n";
     echo "<tr class='tab_bg_1'><td><pre>\n&nbsp;\n";
     include_once GLPI_HTMLAWED;
     $pm = new PHPMailer();
     $sp = new SimplePie();
     $deps = [['name' => 'htmLawed', 'version' => hl_version(), 'check' => 'hl_version'], ['name' => 'phpCas', 'version' => phpCAS::getVersion(), 'check' => 'phpCAS'], ['name' => 'PHPMailer', 'version' => $pm->Version, 'check' => 'PHPMailer'], ['name' => 'Zend Framework', 'check' => 'Zend\\Loader\\StandardAutoloader'], ['name' => 'zetacomponents/graph', 'check' => 'ezcGraph'], ['name' => 'SimplePie', 'version' => SIMPLEPIE_VERSION, 'check' => $sp], ['name' => 'TCPDF', 'version' => TCPDF_STATIC::getTCPDFVersion(), 'check' => 'TCPDF'], ['name' => 'ircmaxell/password-compat', 'check' => 'password_hash'], ['name' => 'ramsey/array_column', 'check' => 'array_column'], ['name' => 'michelf/php-markdown', 'check' => 'Michelf\\Markdown'], ['name' => 'true/punycode', 'check' => 'TrueBV\\Punycode'], ['name' => 'iacaml/autolink', 'check' => 'autolink'], ['name' => 'sabre/vobject', 'check' => 'Sabre\\VObject\\Component']];
     foreach ($deps as $dep) {
         $path = self::getLibraryDir($dep['check']);
         if ($path) {
             echo "{$dep['name']} ";
             if (isset($dep['version'])) {
                 echo "version {$dep['version']} ";
             }
             echo "in ({$path})\n";
         }
     }
     echo "\n</pre></td></tr>";
 }
Example #17
0
 /**
  * Sets the opening SVG element handler function for the XML parser. (*** TO BE COMPLETED ***)
  * @param $parser (resource) The first parameter, parser, is a reference to the XML parser calling the handler.
  * @param $name (string) The second parameter, name, contains the name of the element for which this handler is called. If case-folding is in effect for this parser, the element name will be in uppercase letters.
  * @param $attribs (array) The third parameter, attribs, contains an associative array with the element's attributes (if any). The keys of this array are the attribute names, the values are the attribute values. Attribute names are case-folded on the same criteria as element names. Attribute values are not case-folded. The original order of the attributes can be retrieved by walking through attribs the normal way, using each(). The first key in the array was the first attribute, and so on.
  * @param $ctm (array) tranformation matrix for clipping mode (starting transformation matrix).
  * @author Nicola Asuni
  * @since 5.0.000 (2010-05-02)
  * @protected
  */
 protected function startSVGElementHandler($parser, $name, $attribs, $ctm = array())
 {
     // check if we are in clip mode
     if ($this->svgclipmode) {
         $this->svgclippaths[$this->svgclipid][] = array('name' => $name, 'attribs' => $attribs, 'tm' => $this->svgcliptm[$this->svgclipid]);
         return;
     }
     if ($this->svgdefsmode and !in_array($name, array('clipPath', 'linearGradient', 'radialGradient', 'stop'))) {
         if (!isset($attribs['id'])) {
             $attribs['id'] = 'DF_' . (count($this->svgdefs) + 1);
         }
         $this->svgdefs[$attribs['id']] = array('name' => $name, 'attribs' => $attribs);
         return;
     }
     $clipping = false;
     if ($parser == 'clip-path') {
         // set clipping mode
         $clipping = true;
     }
     // 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 !TCPDF_STATIC::empty_string($attribs['style'])) {
         // fix style for regular expression
         $attribs['style'] = ';' . $attribs['style'];
     }
     foreach ($prev_svgstyle as $key => $val) {
         if (in_array($key, TCPDF_IMAGES::$svginheritprop)) {
             // inherit previous value
             $svgstyle[$key] = $val;
         }
         if (isset($attribs[$key]) and !TCPDF_STATIC::empty_string($attribs[$key])) {
             // specific attribute settings
             if ($attribs[$key] == 'inherit') {
                 $svgstyle[$key] = $val;
             } else {
                 $svgstyle[$key] = $attribs[$key];
             }
         } elseif (isset($attribs['style']) and !TCPDF_STATIC::empty_string($attribs['style'])) {
             // CSS style syntax
             $attrval = array();
             if (preg_match('/[;\\"\\s]{1}' . $key . '[\\s]*:[\\s]*([^;\\"]*)/si', $attribs['style'], $attrval) and isset($attrval[1])) {
                 if ($attrval[1] == 'inherit') {
                     $svgstyle[$key] = $val;
                 } else {
                     $svgstyle[$key] = $attrval[1];
                 }
             }
         }
     }
     // transformation matrix
     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'])) {
         $tm = TCPDF_STATIC::getTransformationMatrixProduct($tm, TCPDF_STATIC::getSVGTransformMatrix($attribs['transform']));
     }
     $svgstyle['transfmatrix'] = $tm;
     $invisible = false;
     if ($svgstyle['visibility'] == 'hidden' or $svgstyle['visibility'] == 'collapse' or $svgstyle['display'] == 'none') {
         // the current graphics element is invisible (nothing is painted)
         $invisible = true;
     }
     // process tag
     switch ($name) {
         case 'defs':
             $this->svgdefsmode = true;
             break;
             // clipPath
         // clipPath
         case 'clipPath':
             if ($invisible) {
                 break;
             }
             $this->svgclipmode = true;
             if (!isset($attribs['id'])) {
                 $attribs['id'] = 'CP_' . (count($this->svgcliptm) + 1);
             }
             $this->svgclipid = $attribs['id'];
             $this->svgclippaths[$this->svgclipid] = array();
             $this->svgcliptm[$this->svgclipid] = $tm;
             break;
         case 'svg':
             // start of SVG object
             break;
         case 'g':
             // group together related graphics elements
             array_push($this->svgstyles, $svgstyle);
             $this->StartTransform();
             $this->SVGTransform($tm);
             $this->setSVGStyles($svgstyle, $prev_svgstyle);
             break;
         case 'linearGradient':
             if ($this->pdfa_mode) {
                 break;
             }
             if (!isset($attribs['id'])) {
                 $attribs['id'] = 'GR_' . (count($this->svggradients) + 1);
             }
             $this->svggradientid = $attribs['id'];
             $this->svggradients[$this->svggradientid] = array();
             $this->svggradients[$this->svggradientid]['type'] = 2;
             $this->svggradients[$this->svggradientid]['stops'] = array();
             if (isset($attribs['gradientUnits'])) {
                 $this->svggradients[$this->svggradientid]['gradientUnits'] = $attribs['gradientUnits'];
             } else {
                 $this->svggradients[$this->svggradientid]['gradientUnits'] = 'objectBoundingBox';
             }
             //$attribs['spreadMethod']
             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'] = TCPDF_STATIC::getSVGTransformMatrix($attribs['gradientTransform']);
             }
             $this->svggradients[$this->svggradientid]['coords'] = array($x1, $y1, $x2, $y2);
             if (isset($attribs['xlink:href']) and !empty($attribs['xlink:href'])) {
                 // gradient is defined on another place
                 $this->svggradients[$this->svggradientid]['xref'] = substr($attribs['xlink:href'], 1);
             }
             break;
         case 'radialGradient':
             if ($this->pdfa_mode) {
                 break;
             }
             if (!isset($attribs['id'])) {
                 $attribs['id'] = 'GR_' . (count($this->svggradients) + 1);
             }
             $this->svggradientid = $attribs['id'];
             $this->svggradients[$this->svggradientid] = array();
             $this->svggradients[$this->svggradientid]['type'] = 3;
             $this->svggradients[$this->svggradientid]['stops'] = array();
             if (isset($attribs['gradientUnits'])) {
                 $this->svggradients[$this->svggradientid]['gradientUnits'] = $attribs['gradientUnits'];
             } else {
                 $this->svggradients[$this->svggradientid]['gradientUnits'] = 'objectBoundingBox';
             }
             //$attribs['spreadMethod']
             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'] = TCPDF_STATIC::getSVGTransformMatrix($attribs['gradientTransform']);
             }
             $this->svggradients[$this->svggradientid]['coords'] = array($cx, $cy, $fx, $fy, $r);
             if (isset($attribs['xlink:href']) and !empty($attribs['xlink:href'])) {
                 // gradient is defined on another place
                 $this->svggradients[$this->svggradientid]['xref'] = substr($attribs['xlink:href'], 1);
             }
             break;
         case 'stop':
             // gradient stops
             if (substr($attribs['offset'], -1) == '%') {
                 $offset = floatval(substr($attribs['offset'], -1)) / 100;
             } else {
                 $offset = floatval($attribs['offset']);
                 if ($offset > 1) {
                     $offset /= 100;
                 }
             }
             $stop_color = isset($svgstyle['stop-color']) ? TCPDF_COLORS::convertHTMLColorToDec($svgstyle['stop-color'], $this->spot_colors) : 'black';
             $opacity = isset($svgstyle['stop-opacity']) ? $svgstyle['stop-opacity'] : 1;
             $this->svggradients[$this->svggradientid]['stops'][] = array('offset' => $offset, 'color' => $stop_color, 'opacity' => $opacity);
             break;
             // paths
         // paths
         case 'path':
             if ($invisible) {
                 break;
             }
             if (isset($attribs['d'])) {
                 $d = trim($attribs['d']);
                 if (!empty($d)) {
                     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'));
                         if (!empty($obstyle)) {
                             $this->SVGPath($d, $obstyle);
                         }
                         $this->StopTransform();
                     }
                 }
             }
             break;
             // shapes
         // shapes
         case 'rect':
             if ($invisible) {
                 break;
             }
             $x = isset($attribs['x']) ? $this->getHTMLUnitToUnits($attribs['x'], 0, $this->svgunit, false) : 0;
             $y = isset($attribs['y']) ? $this->getHTMLUnitToUnits($attribs['y'], 0, $this->svgunit, false) : 0;
             $w = isset($attribs['width']) ? $this->getHTMLUnitToUnits($attribs['width'], 0, $this->svgunit, false) : 0;
             $h = isset($attribs['height']) ? $this->getHTMLUnitToUnits($attribs['height'], 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) : $rx;
             if ($clipping) {
                 $this->SVGTransform($tm);
                 $this->RoundedRectXY($x, $y, $w, $h, $rx, $ry, '1111', 'CNZ', array(), array());
             } else {
                 $this->StartTransform();
                 $this->SVGTransform($tm);
                 $obstyle = $this->setSVGStyles($svgstyle, $prev_svgstyle, $x, $y, $w, $h, 'RoundedRectXY', array($x, $y, $w, $h, $rx, $ry, '1111', 'CNZ'));
                 if (!empty($obstyle)) {
                     $this->RoundedRectXY($x, $y, $w, $h, $rx, $ry, '1111', $obstyle, array(), array());
                 }
                 $this->StopTransform();
             }
             break;
         case 'circle':
             if ($invisible) {
                 break;
             }
             $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);
                 $this->Circle($cx, $cy, $r, 0, 360, 'CNZ', array(), array(), 8);
             } else {
                 $this->StartTransform();
                 $this->SVGTransform($tm);
                 $obstyle = $this->setSVGStyles($svgstyle, $prev_svgstyle, $x, $y, $w, $h, 'Circle', array($cx, $cy, $r, 0, 360, 'CNZ'));
                 if (!empty($obstyle)) {
                     $this->Circle($cx, $cy, $r, 0, 360, $obstyle, array(), array(), 8);
                 }
                 $this->StopTransform();
             }
             break;
         case 'ellipse':
             if ($invisible) {
                 break;
             }
             $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);
             } else {
                 $this->StartTransform();
                 $this->SVGTransform($tm);
                 $obstyle = $this->setSVGStyles($svgstyle, $prev_svgstyle, $x, $y, $w, $h, 'Ellipse', array($cx, $cy, $rx, $ry, 0, 0, 360, 'CNZ'));
                 if (!empty($obstyle)) {
                     $this->Ellipse($cx, $cy, $rx, $ry, 0, 0, 360, $obstyle, array(), array(), 8);
                 }
                 $this->StopTransform();
             }
             break;
         case 'line':
             if ($invisible) {
                 break;
             }
             $x1 = isset($attribs['x1']) ? $this->getHTMLUnitToUnits($attribs['x1'], 0, $this->svgunit, false) : 0;
             $y1 = isset($attribs['y1']) ? $this->getHTMLUnitToUnits($attribs['y1'], 0, $this->svgunit, false) : 0;
             $x2 = isset($attribs['x2']) ? $this->getHTMLUnitToUnits($attribs['x2'], 0, $this->svgunit, false) : 0;
             $y2 = isset($attribs['y2']) ? $this->getHTMLUnitToUnits($attribs['y2'], 0, $this->svgunit, false) : 0;
             $x = $x1;
             $y = $y1;
             $w = abs($x2 - $x1);
             $h = abs($y2 - $y1);
             if (!$clipping) {
                 $this->StartTransform();
                 $this->SVGTransform($tm);
                 $obstyle = $this->setSVGStyles($svgstyle, $prev_svgstyle, $x, $y, $w, $h, 'Line', array($x1, $y1, $x2, $y2));
                 $this->Line($x1, $y1, $x2, $y2);
                 $this->StopTransform();
             }
             break;
         case 'polyline':
         case 'polygon':
             if ($invisible) {
                 break;
             }
             $points = isset($attribs['points']) ? $attribs['points'] : '0 0';
             $points = trim($points);
             // note that point may use a complex syntax not covered here
             $points = preg_split('/[\\,\\s]+/si', $points);
             if (count($points) < 4) {
                 break;
             }
             $p = array();
             $xmin = 2147483647;
             $xmax = 0;
             $ymin = 2147483647;
             $ymax = 0;
             foreach ($points as $key => $val) {
                 $p[$key] = $this->getHTMLUnitToUnits($val, 0, $this->svgunit, false);
                 if ($key % 2 == 0) {
                     // X coordinate
                     $xmin = min($xmin, $p[$key]);
                     $xmax = max($xmax, $p[$key]);
                 } else {
                     // Y coordinate
                     $ymin = min($ymin, $p[$key]);
                     $ymax = max($ymax, $p[$key]);
                 }
             }
             $x = $xmin;
             $y = $ymin;
             $w = $xmax - $xmin;
             $h = $ymax - $ymin;
             if ($name == 'polyline') {
                 $this->StartTransform();
                 $this->SVGTransform($tm);
                 $obstyle = $this->setSVGStyles($svgstyle, $prev_svgstyle, $x, $y, $w, $h, 'PolyLine', array($p, 'CNZ'));
                 if (!empty($obstyle)) {
                     $this->PolyLine($p, $obstyle, array(), array());
                 }
                 $this->StopTransform();
             } else {
                 // polygon
                 if ($clipping) {
                     $this->SVGTransform($tm);
                     $this->Polygon($p, 'CNZ', array(), array(), true);
                 } else {
                     $this->StartTransform();
                     $this->SVGTransform($tm);
                     $obstyle = $this->setSVGStyles($svgstyle, $prev_svgstyle, $x, $y, $w, $h, 'Polygon', array($p, 'CNZ'));
                     if (!empty($obstyle)) {
                         $this->Polygon($p, $obstyle, array(), array(), true);
                     }
                     $this->StopTransform();
                 }
             }
             break;
             // image
         // image
         case 'image':
             if ($invisible) {
                 break;
             }
             if (!isset($attribs['xlink:href']) or empty($attribs['xlink:href'])) {
                 break;
             }
             $x = isset($attribs['x']) ? $this->getHTMLUnitToUnits($attribs['x'], 0, $this->svgunit, false) : 0;
             $y = isset($attribs['y']) ? $this->getHTMLUnitToUnits($attribs['y'], 0, $this->svgunit, false) : 0;
             $w = isset($attribs['width']) ? $this->getHTMLUnitToUnits($attribs['width'], 0, $this->svgunit, false) : 0;
             $h = isset($attribs['height']) ? $this->getHTMLUnitToUnits($attribs['height'], 0, $this->svgunit, false) : 0;
             $img = $attribs['xlink:href'];
             if (!$clipping) {
                 $this->StartTransform();
                 $this->SVGTransform($tm);
                 $obstyle = $this->setSVGStyles($svgstyle, $prev_svgstyle, $x, $y, $w, $h);
                 if (preg_match('/^data:image\\/[^;]+;base64,/', $img, $m) > 0) {
                     // embedded image encoded as base64
                     $img = '@' . base64_decode(substr($img, strlen($m[0])));
                 } else {
                     // fix image path
                     if (!TCPDF_STATIC::empty_string($this->svgdir) and ($img[0] == '.' or basename($img) == $img)) {
                         // replace relative path with full server path
                         $img = $this->svgdir . '/' . $img;
                     }
                     if ($img[0] == '/' and !empty($_SERVER['DOCUMENT_ROOT']) and $_SERVER['DOCUMENT_ROOT'] != '/') {
                         $findroot = strpos($img, $_SERVER['DOCUMENT_ROOT']);
                         if ($findroot === false or $findroot > 1) {
                             if (substr($_SERVER['DOCUMENT_ROOT'], -1) == '/') {
                                 $img = substr($_SERVER['DOCUMENT_ROOT'], 0, -1) . $img;
                             } else {
                                 $img = $_SERVER['DOCUMENT_ROOT'] . $img;
                             }
                         }
                     }
                     $img = urldecode($img);
                     $testscrtype = @parse_url($img);
                     if (!isset($testscrtype['query']) or empty($testscrtype['query'])) {
                         // convert URL to server path
                         $img = str_replace(K_PATH_URL, K_PATH_MAIN, $img);
                     }
                 }
                 // get image type
                 $imgtype = TCPDF_IMAGES::getImageFileType($img);
                 if ($imgtype == 'eps' or $imgtype == 'ai') {
                     $this->ImageEps($img, $x, $y, $w, $h);
                 } elseif ($imgtype == 'svg') {
                     $this->ImageSVG($img, $x, $y, $w, $h);
                 } else {
                     $this->Image($img, $x, $y, $w, $h);
                 }
                 $this->StopTransform();
             }
             break;
             // text
         // 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);
             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['dx'])) {
                 $x += $this->getHTMLUnitToUnits($attribs['dx'], 0, $this->svgunit, false);
             }
             if (isset($attribs['y'])) {
                 $y = $this->getHTMLUnitToUnits($attribs['y'], 0, $this->svgunit, false);
             } elseif ($name == 'tspan') {
                 $y = $this->y;
             } else {
                 $y = 0;
             }
             if (isset($attribs['dy'])) {
                 $y += $this->getHTMLUnitToUnits($attribs['dy'], 0, $this->svgunit, false);
             }
             $svgstyle['text-color'] = $svgstyle['fill'];
             $this->svgtext = '';
             if (isset($svgstyle['text-anchor'])) {
                 $this->svgtextmode['text-anchor'] = $svgstyle['text-anchor'];
             } else {
                 $this->svgtextmode['text-anchor'] = 'start';
             }
             if (isset($svgstyle['direction'])) {
                 if ($svgstyle['direction'] == 'rtl') {
                     $this->svgtextmode['rtl'] = true;
                 } else {
                     $this->svgtextmode['rtl'] = false;
                 }
             } else {
                 $this->svgtextmode['rtl'] = false;
             }
             if (isset($svgstyle['stroke']) and $svgstyle['stroke'] != 'none' and isset($svgstyle['stroke-width']) and $svgstyle['stroke-width'] > 0) {
                 $this->svgtextmode['stroke'] = $this->getHTMLUnitToUnits($svgstyle['stroke-width'], 0, $this->svgunit, false);
             } else {
                 $this->svgtextmode['stroke'] = false;
             }
             $this->StartTransform();
             $this->SVGTransform($tm);
             $obstyle = $this->setSVGStyles($svgstyle, $prev_svgstyle, $x, $y, 1, 1);
             $this->x = $x;
             $this->y = $y;
             break;
             // use
         // use
         case 'use':
             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);
                 }
             }
             break;
         default:
             break;
     }
     // end of switch
 }
Example #18
0
 /**
  * Output a Table Of Content Index (TOC) using HTML templates.
  * This method must be called after all Bookmarks were set.
  * Before calling this method you have to open the page using the addTOCPage() method.
  * After calling this method you have to call endTOCPage() to close the TOC page.
  * @param $page (int) page number where this TOC should be inserted (leave empty for current page).
  * @param $toc_name (string) name to use for TOC bookmark.
  * @param $templates (array) array of html templates. Use: "#TOC_DESCRIPTION#" for bookmark title, "#TOC_PAGE_NUMBER#" for page number.
  * @param $correct_align (boolean) if true correct the number alignment (numbers must be in monospaced font like courier and right aligned on LTR, or left aligned on RTL)
  * @param $style (string) Font style for title: B = Bold, I = Italic, BI = Bold + Italic.
  * @param $color (array) RGB color array for title (values from 0 to 255).
  * @param $afterContent (string) Content to add after the TOC
  * @public
  * @author Nicola Asuni
  * @since 5.0.001 (2010-05-06)
  * @see addTOCPage(), endTOCPage(), addTOC()
  */
 public function addHTMLTOC($page = '', $toc_name = 'TOC', $templates = array(), $correct_align = true, $style = '', $color = array(0, 0, 0), $afterContent = '')
 {
     $filler = ' ';
     $prev_htmlLinkColorArray = $this->htmlLinkColorArray;
     $prev_htmlLinkFontStyle = $this->htmlLinkFontStyle;
     // set new style for link
     $this->htmlLinkColorArray = array();
     $this->htmlLinkFontStyle = '';
     $page_first = $this->getPage();
     $page_fill_start = false;
     $page_fill_end = false;
     // get the font type used for numbers in each template
     $current_font = $this->FontFamily;
     foreach ($templates as $level => $html) {
         $dom = $this->getHtmlDomArray($html);
         foreach ($dom as $key => $value) {
             if ($value['value'] == '#TOC_PAGE_NUMBER#') {
                 $this->SetFont($dom[$key - 1]['fontname']);
                 $templates['F' . $level] = $this->isUnicodeFont();
             }
         }
     }
     $this->SetFont($current_font);
     $maxpage = 0;
     //used for pages on attached documents
     foreach ($this->outlines as $key => $outline) {
         // get HTML template
         $row = $templates[$outline['l']];
         if (\TCPDF_STATIC::empty_string($page)) {
             $pagenum = $outline['p'];
         } else {
             // placemark to be replaced with the correct number
             $pagenum = '{#' . $outline['p'] . '}';
             if ($templates['F' . $outline['l']]) {
                 $pagenum = '{' . $pagenum . '}';
             }
             $maxpage = max($maxpage, $outline['p']);
         }
         // replace templates with current values
         $row = str_replace('#TOC_DESCRIPTION#', $outline['t'], $row);
         $row = str_replace('#TOC_DESCRIPTION#', $outline['t'], $row);
         $row = str_replace('#TOC_CHAPTERNUMBER#', $outline['cn'], $row);
         $row = str_replace('#TOC_CSSCLASS#', $outline['cssClass'], $row);
         $row = str_replace('#TOC_PAGE_NUMBER#', $pagenum, $row);
         // add link to page
         $row = '<a href="#' . $outline['p'] . ',' . $outline['y'] . '">' . $row . '</a>';
         // write bookmark entry
         $this->writeHTML($row, false, false, true, false, '');
     }
     // restore link styles
     $this->htmlLinkColorArray = $prev_htmlLinkColorArray;
     $this->htmlLinkFontStyle = $prev_htmlLinkFontStyle;
     // move TOC page and replace numbers
     $page_last = $this->getPage();
     $numpages = $page_last - $page_first + 1;
     // account for booklet mode
     if ($this->booklet) {
         // check if a blank page is required before TOC
         $page_fill_start = ($page_first % 2 == 0 xor $page % 2 == 0);
         $page_fill_end = !($numpages % 2 == 0 xor $page_fill_start);
         if ($page_fill_start) {
             // add a page at the end (to be moved before TOC)
             $this->addPage();
             ++$page_last;
             ++$numpages;
         }
         if ($page_fill_end) {
             // add a page at the end
             $this->addPage();
             ++$page_last;
             ++$numpages;
         }
     }
     $maxpage = max($maxpage, $page_last);
     if (!\TCPDF_STATIC::empty_string($page)) {
         for ($p = $page_first; $p <= $page_last; ++$p) {
             // get page data
             $temppage = $this->getPageBuffer($p);
             for ($n = 1; $n <= $maxpage; ++$n) {
                 // update page numbers
                 $a = '{#' . $n . '}';
                 // get page number aliases
                 $pnalias = $this->getInternalPageNumberAliases($a);
                 // calculate replacement number
                 if ($n >= $page) {
                     $np = $n + $numpages;
                 } else {
                     $np = $n;
                 }
                 $na = \TCPDF_STATIC::formatTOCPageNumber($this->starting_page_number + $np - 1);
                 $nu = \TCPDF_FONTS::UTF8ToUTF16BE($na, false, $this->isunicode, $this->CurrentFont);
                 // replace aliases with numbers
                 foreach ($pnalias['u'] as $u) {
                     if ($correct_align) {
                         $sfill = str_repeat($filler, strlen($u) - strlen($nu . ' '));
                         if ($this->rtl) {
                             $nr = $nu . \TCPDF_FONTS::UTF8ToUTF16BE(' ' . $sfill, false, $this->isunicode, $this->CurrentFont);
                         } else {
                             $nr = \TCPDF_FONTS::UTF8ToUTF16BE($sfill . ' ', false, $this->isunicode, $this->CurrentFont) . $nu;
                         }
                     } else {
                         $nr = $nu;
                     }
                     $temppage = str_replace($u, $nr, $temppage);
                 }
                 foreach ($pnalias['a'] as $a) {
                     if ($correct_align) {
                         $sfill = str_repeat($filler, strlen($a) - strlen($na . ' '));
                         if ($this->rtl) {
                             $nr = $na . ' ' . $sfill;
                         } else {
                             $nr = $sfill . ' ' . $na;
                         }
                     } else {
                         $nr = $na;
                     }
                     $temppage = str_replace($a, $nr, $temppage);
                 }
             }
             // save changes
             $this->setPageBuffer($p, $temppage);
         }
         // append afterContent if set
         if (!empty($afterContent)) {
             $this->writeHTML($afterContent, TRUE, FALSE, TRUE);
         }
         // move pages
         $this->Bookmark($toc_name, 0, 0, $page_first, $style, $color);
         if ($page_fill_start) {
             $this->movePage($page_last, $page_first);
         }
         for ($i = 0; $i < $numpages; ++$i) {
             $this->movePage($page_last, $page);
         }
     }
 }