| ');
//replace some blank characters
$html = preg_replace('@(\r\n|\r)@', "\n", $html);
$repTable = array("\t" => ' ', "\0" => ' ', "\x0B" => ' ', "\\" => "\\\\");
$html = strtr($html, $repTable);
while (preg_match("' ]*)>(.*?)\n(.*?) 'si", $html)) {
// preserve newlines on tag
$html = preg_replace("']*)>(.*?)\n(.*?) 'si", "\\2 \\3 ", $html);
}
$html = str_replace("\n", ' ', $html);
/*
$html = preg_replace("']*)>'si", " ", $html);
$html = preg_replace("''si", " |
", $html);
$html = preg_replace("' ]*)>'si", " ", $html);
$html = preg_replace("''si", " |
", $html);
*/
// remove extra spaces from code
$html = preg_replace('/[\s]+<\/(table|tr|td|th|ul|ol|li)>/', '\\1>', $html);
$html = preg_replace('/[\s]+<(tr|td|th|ul|ol|li|br)/', '<\\1', $html);
$html = preg_replace('/<\/(table|tr|td|th|blockquote|dd|div|dt|h1|h2|h3|h4|h5|h6|hr|li|ol|p|ul)>[\s]+', '\\1><', $html);
$html = preg_replace('/<\/(td|th)>/', ' \\1>', $html);
$html = preg_replace('/<\/table>([\s]*) /', ' |
', $html);
$html = preg_replace('/]*)>/xi', '', $html);
// trim string
$html = preg_replace('/^[\s]+/', '', $html);
$html = preg_replace('/[\s]+$/', '', $html);
// pattern for generic tag
$tagpattern = '/(<[^>]+>)/';
// explodes the string
$a = preg_split($tagpattern, $html, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY);
// count elements
$maxel = count($a);
$elkey = 0;
$key = 0;
// create an array of elements
$dom = array();
$dom[$key] = array();
// set first void element
$dom[$key]['tag'] = false;
$dom[$key]['value'] = '';
$dom[$key]['parent'] = 0;
$dom[$key]['fontname'] = $this->FontFamily;
$dom[$key]['fontstyle'] = $this->FontStyle;
$dom[$key]['fontsize'] = $this->FontSizePt;
$dom[$key]['bgcolor'] = false;
$dom[$key]['fgcolor'] = $this->fgcolor;
$dom[$key]['align'] = '';
$dom[$key]['listtype'] = '';
$thead = false; // true when we are inside the THEAD tag
++$key;
$level = array();
array_push($level, 0); // root
while ($elkey < $maxel) {
$dom[$key] = array();
$element = $a[$elkey];
$dom[$key]['elkey'] = $elkey;
if (preg_match($tagpattern, $element)) {
// html tag
$element = substr($element, 1, -1);
// get tag name
preg_match('/[\/]?([a-zA-Z0-9]*)/', $element, $tag);
$tagname = strtolower($tag[1]);
// check if we are inside a table header
if ($tagname == 'thead') {
if ($element{0} == '/') {
$thead = false;
} else {
$thead = true;
}
++$elkey;
continue;
}
$dom[$key]['tag'] = true;
$dom[$key]['value'] = $tagname;
if ($element{0} == '/') {
// closing html tag
$dom[$key]['opening'] = false;
$dom[$key]['parent'] = end($level);
array_pop($level);
$dom[$key]['fontname'] = $dom[($dom[($dom[$key]['parent'])]['parent'])]['fontname'];
$dom[$key]['fontstyle'] = $dom[($dom[($dom[$key]['parent'])]['parent'])]['fontstyle'];
$dom[$key]['fontsize'] = $dom[($dom[($dom[$key]['parent'])]['parent'])]['fontsize'];
$dom[$key]['bgcolor'] = $dom[($dom[($dom[$key]['parent'])]['parent'])]['bgcolor'];
$dom[$key]['fgcolor'] = $dom[($dom[($dom[$key]['parent'])]['parent'])]['fgcolor'];
$dom[$key]['align'] = $dom[($dom[($dom[$key]['parent'])]['parent'])]['align'];
if (isset($dom[($dom[($dom[$key]['parent'])]['parent'])]['listtype'])) {
$dom[$key]['listtype'] = $dom[($dom[($dom[$key]['parent'])]['parent'])]['listtype'];
}
// set the number of columns in table tag
if (($dom[$key]['value'] == 'tr') AND (!isset($dom[($dom[($dom[$key]['parent'])]['parent'])]['cols']))) {
$dom[($dom[($dom[$key]['parent'])]['parent'])]['cols'] = $dom[($dom[$key]['parent'])]['cols'];
}
if (($dom[$key]['value'] == 'td') OR ($dom[$key]['value'] == 'th')) {
$dom[($dom[$key]['parent'])]['content'] = '';
for ($i = ($dom[$key]['parent'] + 1); $i < $key; ++$i) {
$dom[($dom[$key]['parent'])]['content'] .= $a[$dom[$i]['elkey']];
}
$key = $i;
}
// store header rows on a new table
if (($dom[$key]['value'] == 'tr') AND ($dom[($dom[$key]['parent'])]['thead'] == true)) {
if ($this->empty_string($dom[($dom[($dom[$key]['parent'])]['parent'])]['thead'])) {
$dom[($dom[($dom[$key]['parent'])]['parent'])]['thead'] = $a[$dom[($dom[($dom[$key]['parent'])]['parent'])]['elkey']];
}
for ($i = $dom[$key]['parent']; $i <= $key; ++$i) {
$dom[($dom[($dom[$key]['parent'])]['parent'])]['thead'] .= $a[$dom[$i]['elkey']];
}
}
if (($dom[$key]['value'] == 'table') AND (!$this->empty_string($dom[($dom[$key]['parent'])]['thead']))) {
$dom[($dom[$key]['parent'])]['thead'] .= '';
}
} else {
// opening html tag
$dom[$key]['opening'] = true;
$dom[$key]['parent'] = end($level);
if (substr($element, -1, 1) != '/') {
// not self-closing tag
array_push($level, $key);
$dom[$key]['self'] = false;
} else {
$dom[$key]['self'] = true;
}
// copy some values from parent
$parentkey = 0;
if ($key > 0) {
$parentkey = $dom[$key]['parent'];
$dom[$key]['fontname'] = $dom[$parentkey]['fontname'];
$dom[$key]['fontstyle'] = $dom[$parentkey]['fontstyle'];
$dom[$key]['fontsize'] = $dom[$parentkey]['fontsize'];
$dom[$key]['bgcolor'] = $dom[$parentkey]['bgcolor'];
$dom[$key]['fgcolor'] = $dom[$parentkey]['fgcolor'];
$dom[$key]['align'] = $dom[$parentkey]['align'];
$dom[$key]['listtype'] = $dom[$parentkey]['listtype'];
}
// get attributes
preg_match_all('/([^=\s]*)=["]?([^"]*)["]?/', $element, $attr_array, PREG_PATTERN_ORDER);
$dom[$key]['attribute'] = array(); // reset attribute array
while (list($id, $name) = each($attr_array[1])) {
$dom[$key]['attribute'][strtolower($name)] = $attr_array[2][$id];
}
// split style attributes
if (isset($dom[$key]['attribute']['style'])) {
// get style attributes
preg_match_all('/([^;:\s]*):([^;]*)/', $dom[$key]['attribute']['style'], $style_array, PREG_PATTERN_ORDER);
$dom[$key]['style'] = array(); // reset style attribute array
while (list($id, $name) = each($style_array[1])) {
$dom[$key]['style'][strtolower($name)] = trim($style_array[2][$id]);
}
// --- get some style attributes ---
if (isset($dom[$key]['style']['font-family'])) {
// font family
if (isset($dom[$key]['style']['font-family'])) {
$fontslist = split(',', strtolower($dom[$key]['style']['font-family']));
foreach ($fontslist as $font) {
$font = trim(strtolower($font));
if (in_array($font, $this->fontlist) OR in_array($font, $this->fontkeys)) {
$dom[$key]['fontname'] = $font;
break;
}
}
}
}
// list-style-type
if (isset($dom[$key]['style']['list-style-type'])) {
$dom[$key]['listtype'] = trim(strtolower($dom[$key]['style']['list-style-type']));
if ($dom[$key]['listtype'] == 'inherit') {
$dom[$key]['listtype'] = $dom[$parentkey]['listtype'];
}
}
// font size
if (isset($dom[$key]['style']['font-size'])) {
$fsize = trim($dom[$key]['style']['font-size']);
switch ($fsize) {
// absolute-size
case 'xx-small': {
$dom[$key]['fontsize'] = $dom[0]['fontsize'] - 4;
break;
}
case 'x-small': {
$dom[$key]['fontsize'] = $dom[0]['fontsize'] - 3;
break;
}
case 'small': {
$dom[$key]['fontsize'] = $dom[0]['fontsize'] - 2;
break;
}
case 'medium': {
$dom[$key]['fontsize'] = $dom[0]['fontsize'];
break;
}
case 'large': {
$dom[$key]['fontsize'] = $dom[0]['fontsize'] + 2;
break;
}
case 'x-large': {
$dom[$key]['fontsize'] = $dom[0]['fontsize'] + 4;
break;
}
case 'xx-large': {
$dom[$key]['fontsize'] = $dom[0]['fontsize'] + 6;
break;
}
// relative-size
case 'smaller': {
$dom[$key]['fontsize'] = $dom[$parentkey]['fontsize'] - 3;
break;
}
case 'larger': {
$dom[$key]['fontsize'] = $dom[$parentkey]['fontsize'] + 3;
break;
}
default: {
$dom[$key]['fontsize'] = $this->getHTMLUnitToUnits($fsize, $dom[$parentkey]['fontsize'], 'pt', true);
}
}
}
// font style
if (isset($dom[$key]['style']['font-weight']) AND (strtolower($dom[$key]['style']['font-weight']{0}) == 'b')) {
$dom[$key]['fontstyle'] .= 'B';
}
if (isset($dom[$key]['style']['font-style']) AND (strtolower($dom[$key]['style']['font-style']{0}) == 'i')) {
$dom[$key]['fontstyle'] .= '"I';
}
// font color
if (isset($dom[$key]['style']['color']) AND (!$this->empty_string($dom[$key]['style']['color']))) {
$dom[$key]['fgcolor'] = $this->convertHTMLColorToDec($dom[$key]['style']['color']);
}
// background color
if (isset($dom[$key]['style']['background-color']) AND (!$this->empty_string($dom[$key]['style']['background-color']))) {
$dom[$key]['bgcolor'] = $this->convertHTMLColorToDec($dom[$key]['style']['background-color']);
}
// text-decoration
if (isset($dom[$key]['style']['text-decoration'])) {
$decors = explode(' ', strtolower($dom[$key]['style']['text-decoration']));
foreach ($decors as $dec) {
$dec = trim($dec);
if (!$this->empty_string($dec)) {
if ($dec{0} == 'u') {
$dom[$key]['fontstyle'] .= 'U';
} elseif ($dec{0} == 'l') {
$dom[$key]['fontstyle'] .= 'D';
}
}
}
}
// check for width attribute
if (isset($dom[$key]['style']['width'])) {
$dom[$key]['width'] = $dom[$key]['style']['width'];
}
// check for height attribute
if (isset($dom[$key]['style']['height'])) {
$dom[$key]['height'] = $dom[$key]['style']['height'];
}
// check for text alignment
if (isset($dom[$key]['style']['text-align'])) {
$dom[$key]['align'] = strtoupper($dom[$key]['style']['text-align']{0});
}
// check for border attribute
if (isset($dom[$key]['style']['border'])) {
$dom[$key]['attribute']['border'] = $dom[$key]['style']['border'];
}
}
// check for font tag
if ($dom[$key]['value'] == 'font') {
// font family
if (isset($dom[$key]['attribute']['face'])) {
$fontslist = split(',', strtolower($dom[$key]['attribute']['face']));
foreach ($fontslist as $font) {
$font = trim(strtolower($font));
if (in_array($font, $this->fontlist) OR in_array($font, $this->fontkeys)) {
$dom[$key]['fontname'] = $font;
break;
}
}
}
// font size
if (isset($dom[$key]['attribute']['size'])) {
if ($key > 0) {
if ($dom[$key]['attribute']['size']{0} == '+') {
$dom[$key]['fontsize'] = $dom[($dom[$key]['parent'])]['fontsize'] + intval(substr($dom[$key]['attribute']['size'], 1));
} elseif ($dom[$key]['attribute']['size']{0} == '-') {
$dom[$key]['fontsize'] = $dom[($dom[$key]['parent'])]['fontsize'] - intval(substr($dom[$key]['attribute']['size'], 1));
} else {
$dom[$key]['fontsize'] = intval($dom[$key]['attribute']['size']);
}
} else {
$dom[$key]['fontsize'] = intval($dom[$key]['attribute']['size']);
}
}
}
// force natural alignment for lists
if ((($dom[$key]['value'] == 'ul') OR ($dom[$key]['value'] == 'ol') OR ($dom[$key]['value'] == 'dl'))
AND (!isset($dom[$key]['align']) OR $this->empty_string($dom[$key]['align']) OR ($dom[$key]['align'] != 'J'))) {
if ($this->rtl) {
$dom[$key]['align'] = 'R';
} else {
$dom[$key]['align'] = 'L';
}
}
if (($dom[$key]['value'] == 'small') OR ($dom[$key]['value'] == 'sup') OR ($dom[$key]['value'] == 'sub')) {
$dom[$key]['fontsize'] = $dom[$key]['fontsize'] * K_SMALL_RATIO;
}
if (($dom[$key]['value'] == 'strong') OR ($dom[$key]['value'] == 'b')) {
$dom[$key]['fontstyle'] .= 'B';
}
if (($dom[$key]['value'] == 'em') OR ($dom[$key]['value'] == 'i')) {
$dom[$key]['fontstyle'] .= 'I';
}
if ($dom[$key]['value'] == 'u') {
$dom[$key]['fontstyle'] .= 'U';
}
if ($dom[$key]['value'] == 'del') {
$dom[$key]['fontstyle'] .= 'D';
}
if (($dom[$key]['value'] == 'pre') OR ($dom[$key]['value'] == 'tt')) {
$dom[$key]['fontname'] = $this->default_monospaced_font;
}
if (($dom[$key]['value']{0} == 'h') AND (intval($dom[$key]['value']{1}) > 0) AND (intval($dom[$key]['value']{1}) < 7)) {
$headsize = (4 - intval($dom[$key]['value']{1})) * 2;
$dom[$key]['fontsize'] = $dom[0]['fontsize'] + $headsize;
$dom[$key]['fontstyle'] .= 'B';
}
if (($dom[$key]['value'] == 'table')) {
$dom[$key]['rows'] = 0; // number of rows
$dom[$key]['trids'] = array(); // IDs of TR elements
$dom[$key]['thead'] = ''; // table header rows
}
if (($dom[$key]['value'] == 'tr')) {
$dom[$key]['cols'] = 0;
// store the number of rows on table element
++$dom[($dom[$key]['parent'])]['rows'];
// store the TR elements IDs on table element
array_push($dom[($dom[$key]['parent'])]['trids'], $key);
if ($thead) {
$dom[$key]['thead'] = true;
} else {
$dom[$key]['thead'] = false;
}
}
if (($dom[$key]['value'] == 'th') OR ($dom[$key]['value'] == 'td')) {
if (isset($dom[$key]['attribute']['colspan'])) {
$colspan = intval($dom[$key]['attribute']['colspan']);
} else {
$colspan = 1;
}
$dom[$key]['attribute']['colspan'] = $colspan;
$dom[($dom[$key]['parent'])]['cols'] += $colspan;
}
// set foreground color attribute
if (isset($dom[$key]['attribute']['color']) AND (!$this->empty_string($dom[$key]['attribute']['color']))) {
$dom[$key]['fgcolor'] = $this->convertHTMLColorToDec($dom[$key]['attribute']['color']);
}
// set background color attribute
if (isset($dom[$key]['attribute']['bgcolor']) AND (!$this->empty_string($dom[$key]['attribute']['bgcolor']))) {
$dom[$key]['bgcolor'] = $this->convertHTMLColorToDec($dom[$key]['attribute']['bgcolor']);
}
// check for width attribute
if (isset($dom[$key]['attribute']['width'])) {
$dom[$key]['width'] = $dom[$key]['attribute']['width'];
}
// check for height attribute
if (isset($dom[$key]['attribute']['height'])) {
$dom[$key]['height'] = $dom[$key]['attribute']['height'];
}
// check for text alignment
if (isset($dom[$key]['attribute']['align']) AND (!$this->empty_string($dom[$key]['attribute']['align'])) AND ($dom[$key]['value'] !== 'img')) {
$dom[$key]['align'] = strtoupper($dom[$key]['attribute']['align']{0});
}
} // end opening tag
} else {
// text
$dom[$key]['tag'] = false;
$dom[$key]['value'] = stripslashes($this->unhtmlentities($element));
$dom[$key]['parent'] = end($level);
}
++$elkey;
++$key;
}
return $dom;
}
/**
* Allows to preserve some HTML formatting (limited support).
* IMPORTANT: The HTML must be well formatted - try to clean-up it using an application like HTML-Tidy before submitting.
* Supported tags are: a, b, blockquote, br, dd, del, div, dl, dt, em, font, h1, h2, h3, h4, h5, h6, hr, i, img, li, ol, p, small, span, strong, sub, sup, table, td, th, tr, u, ul,
* @param string $html text to display
* @param boolean $ln if true add a new line after text (default = true)
* @param int $fill Indicates if the background must be painted (true) or transparent (false).
* @param boolean $reseth if true reset the last cell height (default false).
* @param boolean $cell if true add the default cMargin space to each Write (default false).
* @param string $align Allows to center or align the text. Possible values are:- L : left align
- C : center
- R : right align
- '' : empty string : left for LTR or right for RTL
* @access public
*/
public function writeHTML($html, $ln=true, $fill=false, $reseth=false, $cell=false, $align='') {
$gvars = $this->getGraphicVars();
// store current values
$prevPage = $this->page;
$prevlMargin = $this->lMargin;
$prevrMargin = $this->rMargin;
$curfontname = $this->FontFamily;
$curfontstyle = $this->FontStyle;
$curfontsize = $this->FontSizePt;
$this->newline = true;
$minstartliney = $this->y;
$yshift = 0;
$startlinepage = $this->page;
$newline = true;
$loop = 0;
$curpos = 0;
$blocktags = array('blockquote','br','dd','div','dt','h1','h2','h3','h4','h5','h6','hr','li','ol','p','ul');
$this->premode = false;
if (isset($this->PageAnnots[$this->page])) {
$pask = count($this->PageAnnots[$this->page]);
} else {
$pask = 0;
}
if (isset($this->footerlen[$this->page])) {
$this->footerpos[$this->page] = $this->pagelen[$this->page] - $this->footerlen[$this->page];
} else {
$this->footerpos[$this->page] = $this->pagelen[$this->page];
}
$startlinepos = $this->footerpos[$this->page];
$lalign = $align;
$plalign = $align;
if ($this->rtl) {
$w = $this->x - $this->lMargin;
} else {
$w = $this->w - $this->rMargin - $this->x;
}
$w -= (2 * $this->cMargin);
if ($cell) {
if ($this->rtl) {
$this->x -= $this->cMargin;
} else {
$this->x += $this->cMargin;
}
}
if ($this->customlistindent >= 0) {
$this->listindent = $this->customlistindent;
} else {
$this->listindent = $this->GetStringWidth('0000');
}
$this->listnum = 0;
if (($this->empty_string($this->lasth)) OR ($reseth)) {
//set row height
$this->lasth = $this->FontSize * $this->cell_height_ratio;
}
$dom = $this->getHtmlDomArray($html);
$maxel = count($dom);
$key = 0;
while ($key < $maxel) {
if ($dom[$key]['tag'] OR ($key == 0)) {
if ((($dom[$key]['value'] == 'table') OR ($dom[$key]['value'] == 'tr')) AND (isset($dom[$key]['align']))) {
$dom[$key]['align'] = ($this->rtl) ? 'R' : 'L';
}
// vertically align image in line
if ((!$this->newline)
AND ($dom[$key]['value'] == 'img')
AND (isset($dom[$key]['attribute']['height']))
AND ($dom[$key]['attribute']['height'] > 0)
AND (!((($this->y + $this->getHTMLUnitToUnits($dom[$key]['attribute']['height'], $this->lasth, 'px')) > $this->PageBreakTrigger)
AND (!$this->InFooter)
AND $this->AcceptPageBreak()))
) {
if ($this->page > $startlinepage) {
// fix lines splitted over two pages
if (isset($this->footerlen[$startlinepage])) {
$curpos = $this->pagelen[$startlinepage] - $this->footerlen[$startlinepage];
}
// line to be moved one page forward
$pagebuff = $this->getPageBuffer($startlinepage);
$linebeg = substr($pagebuff, $startlinepos, ($curpos - $startlinepos));
$tstart = substr($pagebuff, 0, $startlinepos);
$tend = substr($this->getPageBuffer($startlinepage), $curpos);
// remove line start from previous page
$this->setPageBuffer($startlinepage, $tstart.''.$tend);
$pagebuff = $this->getPageBuffer($this->page);
$tstart = substr($pagebuff, 0, $this->intmrk[$this->page]);
$tend = substr($pagebuff, $this->intmrk[$this->page]);
// add line start to current page
$yshift = $minstartliney - $this->y;
$try = sprintf('1 0 0 1 0 %.3F cm', ($yshift * $this->k));
$this->setPageBuffer($this->page, $tstart."\nq\n".$try."\n".$linebeg."\nQ\n".$tend);
// shift the annotations and links
if (isset($this->PageAnnots[$startlinepage])) {
foreach ($this->PageAnnots[$startlinepage] as $pak => $pac) {
if ($pak >= $pask) {
$this->PageAnnots[$this->page][] = $pac;
unset($this->PageAnnots[$startlinepage][$pak]);
$npak = count($this->PageAnnots[$this->page]) - 1;
$this->PageAnnots[$this->page][$npak]['y'] -= $yshift;
}
}
}
}
$this->y += (($curfontsize / $this->k) - $this->getHTMLUnitToUnits($dom[$key]['attribute']['height'], $this->lasth, 'px'));
$minstartliney = min($this->y, $minstartliney);
} elseif (isset($dom[$key]['fontname']) OR isset($dom[$key]['fontstyle']) OR isset($dom[$key]['fontsize'])) {
// account for different font size
$pfontname = $curfontname;
$pfontstyle = $curfontstyle;
$pfontsize = $curfontsize;
$fontname = isset($dom[$key]['fontname']) ? $dom[$key]['fontname'] : $curfontname;
$fontstyle = isset($dom[$key]['fontstyle']) ? $dom[$key]['fontstyle'] : $curfontstyle;
$fontsize = isset($dom[$key]['fontsize']) ? $dom[$key]['fontsize'] : $curfontsize;
if (($fontname != $curfontname) OR ($fontstyle != $curfontstyle) OR ($fontsize != $curfontsize)) {
$this->SetFont($fontname, $fontstyle, $fontsize);
$this->lasth = $this->FontSize * $this->cell_height_ratio;
if (is_numeric($fontsize) AND ($fontsize > 0)
AND is_numeric($curfontsize) AND ($curfontsize > 0)
AND ($fontsize != $curfontsize) AND (!$this->newline)
AND ($key < ($maxel - 1))
) {
if ((!$this->newline) AND ($this->page > $startlinepage)) {
// fix lines splitted over two pages
if (isset($this->footerlen[$startlinepage])) {
$curpos = $this->pagelen[$startlinepage] - $this->footerlen[$startlinepage];
}
// line to be moved one page forward
$pagebuff = $this->getPageBuffer($startlinepage);
$linebeg = substr($pagebuff, $startlinepos, ($curpos - $startlinepos));
$tstart = substr($pagebuff, 0, $startlinepos);
$tend = substr($this->getPageBuffer($startlinepage), $curpos);
// remove line start from previous page
$this->setPageBuffer($startlinepage, $tstart.''.$tend);
$pagebuff = $this->getPageBuffer($this->page);
$tstart = substr($pagebuff, 0, $this->intmrk[$this->page]);
$tend = substr($pagebuff, $this->intmrk[$this->page]);
// add line start to current page
$yshift = $minstartliney - $this->y;
$try = sprintf('1 0 0 1 0 %.3F cm', ($yshift * $this->k));
$this->setPageBuffer($this->page, $tstart."\nq\n".$try."\n".$linebeg."\nQ\n".$tend);
// shift the annotations and links
if (isset($this->PageAnnots[$startlinepage])) {
foreach ($this->PageAnnots[$startlinepage] as $pak => $pac) {
if ($pak >= $pask) {
$this->PageAnnots[$this->page][] = $pac;
unset($this->PageAnnots[$startlinepage][$pak]);
$npak = count($this->PageAnnots[$this->page]) - 1;
$this->PageAnnots[$this->page][$npak]['y'] -= $yshift;
}
}
}
}
$this->y += (($curfontsize - $fontsize) / $this->k);
$minstartliney = min($this->y, $minstartliney);
}
$curfontname = $fontname;
$curfontstyle = $fontstyle;
$curfontsize = $fontsize;
}
}
if (($plalign == 'J') AND (in_array($dom[$key]['value'], $blocktags))) {
$plalign = '';
}
// get current position on page buffer
$curpos = $this->pagelen[$startlinepage];
if (isset($dom[$key]['bgcolor']) AND ($dom[$key]['bgcolor'] !== false)) {
$this->SetFillColorArray($dom[$key]['bgcolor']);
$wfill = true;
} else {
$wfill = $fill | false;
}
if (isset($dom[$key]['fgcolor']) AND ($dom[$key]['fgcolor'] !== false)) {
$this->SetTextColorArray($dom[$key]['fgcolor']);
}
if (isset($dom[$key]['align'])) {
$lalign = $dom[$key]['align'];
}
if ($this->empty_string($lalign)) {
$lalign = $align;
}
}
// align lines
if ($this->newline AND (strlen($dom[$key]['value']) > 0) AND ($dom[$key]['value'] != 'td') AND ($dom[$key]['value'] != 'th')) {
$newline = true;
// we are at the beginning of a new line
if (isset($startlinex)) {
$yshift = $minstartliney - $startliney;
if (($yshift > 0) OR ($this->page > $startlinepage)) {
$yshift = 0;
}
if ((isset($plalign) AND ((($plalign == 'C') OR ($plalign == 'J') OR (($plalign == 'R') AND (!$this->rtl)) OR (($plalign == 'L') AND ($this->rtl))))) OR ($yshift < 0)) {
// the last line must be shifted to be aligned as requested
$linew = abs($this->endlinex - $startlinex);
$pstart = substr($this->getPageBuffer($startlinepage), 0, $startlinepos);
if (isset($opentagpos) AND isset($this->footerlen[$startlinepage])) {
$this->footerpos[$startlinepage] = $this->pagelen[$startlinepage] - $this->footerlen[$startlinepage];
$midpos = min($opentagpos, $this->footerpos[$startlinepage]);
} elseif (isset($opentagpos)) {
$midpos = $opentagpos;
} elseif (isset($this->footerlen[$startlinepage])) {
$this->footerpos[$startlinepage] = $this->pagelen[$startlinepage] - $this->footerlen[$startlinepage];
$midpos = $this->footerpos[$startlinepage];
} else {
$midpos = 0;
}
if ($midpos > 0) {
$pmid = substr($this->getPageBuffer($startlinepage), $startlinepos, ($midpos - $startlinepos));
$pend = substr($this->getPageBuffer($startlinepage), $midpos);
} else {
$pmid = substr($this->getPageBuffer($startlinepage), $startlinepos);
$pend = '';
}
// calculate shifting amount
$tw = $w;
if ($this->lMargin != $prevlMargin) {
$tw += ($prevlMargin - $this->lMargin);
}
if ($this->rMargin != $prevrMargin) {
$tw += ($prevrMargin - $this->rMargin);
}
$mdiff = abs($tw - $linew);
$t_x = 0;
if ($plalign == 'C') {
if ($this->rtl) {
$t_x = -($mdiff / 2);
} else {
$t_x = ($mdiff / 2);
}
} elseif (($plalign == 'R') AND (!$this->rtl)) {
// right alignment on LTR document
$t_x = $mdiff;
} elseif (($plalign == 'L') AND ($this->rtl)) {
// left alignment on RTL document
$t_x = -$mdiff;
} elseif (($plalign == 'J') AND ($plalign == $lalign)) {
// Justification
if ($this->rtl OR $this->tmprtl) {
$t_x = $this->lMargin - $this->endlinex;
}
$no = 0;
$ns = 0;
$pmidtemp = $pmid;
// escape special characters
$pmidtemp = preg_replace('/[\\\][\(]/x', '\\#!#OP#!#', $pmidtemp);
$pmidtemp = preg_replace('/[\\\][\)]/x', '\\#!#CP#!#', $pmidtemp);
// search spaces
if (preg_match_all('/\[\(([^\)]*)\)\]/x', $pmidtemp, $lnstring, PREG_PATTERN_ORDER)) {
$maxkk = count($lnstring[1]) - 1;
//foreach ($lnstring[1] as $kk => $value) {
for ($kk=0; $kk <= $maxkk; ++$kk) {
// restore special characters
$lnstring[1][$kk] = str_replace('#!#OP#!#', '(', $lnstring[1][$kk]);
$lnstring[1][$kk] = str_replace('#!#CP#!#', ')', $lnstring[1][$kk]);
if ($kk == $maxkk) {
if ($this->rtl OR $this->tmprtl) {
$tvalue = ltrim($lnstring[1][$kk]);
} else {
$tvalue = rtrim($lnstring[1][$kk]);
}
} else {
$tvalue = $lnstring[1][$kk];
}
// count spaces on line
$no += substr_count($lnstring[1][$kk], chr(32));
$ns += substr_count($tvalue, chr(32));
}
if ($this->rtl OR $this->tmprtl) {
$t_x = $this->lMargin - $this->endlinex - (($no - $ns - 1) * $this->GetStringWidth(chr(32)));
}
// calculate additional space to add to each space
$spacewidth = (($tw - $linew + (($no - $ns) * $this->GetStringWidth(chr(32)))) / ($ns?$ns:1)) * $this->k;
$spacewidthu = ($tw - $linew + ($no * $this->GetStringWidth(chr(32)))) / ($ns?$ns:1) / $this->FontSize / $this->k;
$nsmax = $ns;
$ns = 0;
reset($lnstring);
$offset = 0;
$strcount = 0;
$prev_epsposbeg = 0;
global $spacew;
while (preg_match('/([0-9\.\+\-]*)[\s](Td|cm|m|l|c|re)[\s]/x', $pmid, $strpiece, PREG_OFFSET_CAPTURE, $offset) == 1) {
if ($this->rtl OR $this->tmprtl) {
$spacew = ($spacewidth * ($nsmax - $ns));
} else {
$spacew = ($spacewidth * $ns);
}
$offset = $strpiece[2][1] + strlen($strpiece[2][0]);
$epsposbeg = strpos($pmid, 'q'.$this->epsmarker, $offset);
$epsposend = strpos($pmid, $this->epsmarker.'Q', $offset) + strlen($this->epsmarker.'Q');
if ((($epsposbeg > 0) AND ($epsposend > 0) AND ($offset > $epsposbeg) AND ($offset < $epsposend))
OR (($epsposbeg === false) AND ($epsposend > 0) AND ($offset < $epsposend))) {
// shift EPS images
$trx = sprintf('1 0 0 1 %.3F 0 cm', $spacew);
$epsposbeg = strpos($pmid, 'q'.$this->epsmarker, ($prev_epsposbeg - 6));
$pmid_b = substr($pmid, 0, $epsposbeg);
$pmid_m = substr($pmid, $epsposbeg, ($epsposend - $epsposbeg));
$pmid_e = substr($pmid, $epsposend);
$pmid = $pmid_b."\nq\n".$trx."\n".$pmid_m."\nQ\n".$pmid_e;
$offset = $epsposend;
continue;
}
$prev_epsposbeg = $epsposbeg;
$currentxpos = 0;
// shift blocks of code
switch ($strpiece[2][0]) {
case 'Td':
case 'cm':
case 'm':
case 'l': {
// get current X position
preg_match('/([0-9\.\+\-]*)[\s]('.$strpiece[1][0].')[\s]('.$strpiece[2][0].')([\s]*)/x', $pmid, $xmatches);
$currentxpos = $xmatches[1];
if (($strcount <= $maxkk) AND ($strpiece[2][0] == 'Td')) {
if ($strcount == $maxkk) {
if ($this->rtl OR $this->tmprtl) {
$tvalue = $lnstring[1][$strcount];
} else {
$tvalue = rtrim($lnstring[1][$strcount]);
}
} else {
$tvalue = $lnstring[1][$strcount];
}
$ns += substr_count($tvalue, chr(32));
++$strcount;
}
if ($this->rtl OR $this->tmprtl) {
$spacew = ($spacewidth * ($nsmax - $ns));
}
// justify block
$pmid = preg_replace_callback('/([0-9\.\+\-]*)[\s]('.$strpiece[1][0].')[\s]('.$strpiece[2][0].')([\s]*)/x',
create_function('$matches', 'global $spacew;
$newx = sprintf("%.2F",(floatval($matches[1]) + $spacew));
return "".$newx." ".$matches[2]." x*#!#*x".$matches[3].$matches[4];'), $pmid, 1);
break;
}
case 're': {
// get current X position
preg_match('/([0-9\.\+\-]*)[\s]([0-9\.\+\-]*)[\s]([0-9\.\+\-]*)[\s]('.$strpiece[1][0].')[\s]('.$strpiece[2][0].')([\s]*)/x', $pmid, $xmatches);
$currentxpos = $xmatches[1];
// justify block
$pmid = preg_replace_callback('/([0-9\.\+\-]*)[\s]([0-9\.\+\-]*)[\s]([0-9\.\+\-]*)[\s]('.$strpiece[1][0].')[\s]('.$strpiece[2][0].')([\s]*)/x',
create_function('$matches', 'global $spacew;
$newx = sprintf("%.2F",(floatval($matches[1]) + $spacew));
return "".$newx." ".$matches[2]." ".$matches[3]." ".$matches[4]." x*#!#*x".$matches[5].$matches[6];'), $pmid, 1);
break;
}
case 'c': {
// get current X position
preg_match('/([0-9\.\+\-]*)[\s]([0-9\.\+\-]*)[\s]([0-9\.\+\-]*)[\s]([0-9\.\+\-]*)[\s]([0-9\.\+\-]*)[\s]('.$strpiece[1][0].')[\s]('.$strpiece[2][0].')([\s]*)/x', $pmid, $xmatches);
$currentxpos = $xmatches[1];
// justify block
$pmid = preg_replace_callback('/([0-9\.\+\-]*)[\s]([0-9\.\+\-]*)[\s]([0-9\.\+\-]*)[\s]([0-9\.\+\-]*)[\s]([0-9\.\+\-]*)[\s]('.$strpiece[1][0].')[\s]('.$strpiece[2][0].')([\s]*)/x',
create_function('$matches', 'global $spacew;
$newx1 = sprintf("%.3F",(floatval($matches[1]) + $spacew));
$newx2 = sprintf("%.3F",(floatval($matches[3]) + $spacew));
$newx3 = sprintf("%.3F",(floatval($matches[5]) + $spacew));
return "".$newx1." ".$matches[2]." ".$newx2." ".$matches[4]." ".$newx3." ".$matches[6]." x*#!#*x".$matches[7].$matches[8];'), $pmid, 1);
break;
}
}
// shift the annotations and links
if (isset($this->PageAnnots[$this->page])) {
foreach ($this->PageAnnots[$this->page] as $pak => $pac) {
if (($pac['y'] >= $minstartliney) AND (($pac['x'] * $this->k) >= ($currentxpos - $this->feps)) AND (($pac['x'] * $this->k) <= ($currentxpos + $this->feps))) {
$this->PageAnnots[$this->page][$pak]['x'] += ($spacew / $this->k);
$this->PageAnnots[$this->page][$pak]['w'] += (($spacewidth * $pac['numspaces']) / $this->k);
break;
}
}
}
} // end of while
// remove markers
$pmid = str_replace('x*#!#*x', '', $pmid);
if (($this->CurrentFont['type'] == 'TrueTypeUnicode') OR ($this->CurrentFont['type'] == 'cidfont0')) {
// multibyte characters
$spacew = $spacewidthu;
$pmidtemp = $pmid;
// escape special characters
$pmidtemp = preg_replace('/[\\\][\(]/x', '\\#!#OP#!#', $pmidtemp);
$pmidtemp = preg_replace('/[\\\][\)]/x', '\\#!#CP#!#', $pmidtemp);
$pmid = preg_replace_callback("/\[\(([^\)]*)\)\]/x",
create_function('$matches', 'global $spacew;
$matches[1] = str_replace("#!#OP#!#", "(", $matches[1]);
$matches[1] = str_replace("#!#CP#!#", ")", $matches[1]);
return "[(".str_replace(chr(0).chr(32), ") ".(-2830 * $spacew)." (", $matches[1]).")]";'), $pmidtemp);
$this->setPageBuffer($startlinepage, $pstart."\n".$pmid."\n".$pend);
$endlinepos = strlen($pstart."\n".$pmid."\n");
} else {
// non-unicode (single-byte characters)
$rs = sprintf("%.3F Tw", $spacewidth);
$pmid = preg_replace("/\[\(/x", $rs.' [(', $pmid);
$this->setPageBuffer($startlinepage, $pstart."\n".$pmid."\nBT 0 Tw ET\n".$pend);
$endlinepos = strlen($pstart."\n".$pmid."\nBT 0 Tw ET\n");
}
}
} // end of J
if (($t_x != 0) OR ($yshift < 0)) {
// shift the line
$trx = sprintf('1 0 0 1 %.3F %.3F cm', ($t_x * $this->k), ($yshift * $this->k));
$this->setPageBuffer($startlinepage, $pstart."\nq\n".$trx."\n".$pmid."\nQ\n".$pend);
$endlinepos = strlen($pstart."\nq\n".$trx."\n".$pmid."\nQ\n");
// shift the annotations and links
if (isset($this->PageAnnots[$this->page])) {
foreach ($this->PageAnnots[$this->page] as $pak => $pac) {
if ($pak >= $pask) {
$this->PageAnnots[$this->page][$pak]['x'] += $t_x;
$this->PageAnnots[$this->page][$pak]['y'] -= $yshift;
}
}
}
$this->y -= $yshift;
}
}
}
$this->newline = false;
$pbrk = $this->checkPageBreak($this->lasth);
$this->SetFont($fontname, $fontstyle, $fontsize);
if ($wfill) {
$this->SetFillColorArray($this->bgcolor);
}
$startlinex = $this->x;
$startliney = $this->y;
$minstartliney = $this->y;
$startlinepage = $this->page;
if (isset($endlinepos) AND (!$pbrk)) {
$startlinepos = $endlinepos;
unset($endlinepos);
} else {
if (isset($this->footerlen[$this->page])) {
$this->footerpos[$this->page] = $this->pagelen[$this->page] - $this->footerlen[$this->page];
} else {
$this->footerpos[$this->page] = $this->pagelen[$this->page];
}
$startlinepos = $this->footerpos[$this->page];
}
$plalign = $lalign;
if (isset($this->PageAnnots[$this->page])) {
$pask = count($this->PageAnnots[$this->page]);
} else {
$pask = 0;
}
}
if (isset($opentagpos)) {
unset($opentagpos);
}
if ($dom[$key]['tag']) {
if ($dom[$key]['opening']) {
if ($dom[$key]['value'] == 'table') {
if ($this->rtl) {
$wtmp = $this->x - $this->lMargin;
} else {
$wtmp = $this->w - $this->rMargin - $this->x;
}
$wtmp -= (2 * $this->cMargin);
// calculate cell width
if (isset($dom[$key]['width'])) {
$table_width = $this->getHTMLUnitToUnits($dom[$key]['width'], $wtmp, 'px');
} else {
$table_width = $wtmp;
}
}
// table content is handled in a special way
if (($dom[$key]['value'] == 'td') OR ($dom[$key]['value'] == 'th')) {
$trid = $dom[$key]['parent'];
$table_el = $dom[$trid]['parent'];
if (!isset($dom[$table_el]['cols'])) {
$dom[$table_el]['cols'] = $trid['cols'];
}
$oldmargin = $this->cMargin;
if (isset($dom[($dom[$trid]['parent'])]['attribute']['cellpadding'])) {
$currentcmargin = $this->getHTMLUnitToUnits($dom[($dom[$trid]['parent'])]['attribute']['cellpadding'], 1, 'px');
} else {
$currentcmargin = 0;
}
$this->cMargin = $currentcmargin;
if (isset($dom[($dom[$trid]['parent'])]['attribute']['cellspacing'])) {
$cellspacing = $this->getHTMLUnitToUnits($dom[($dom[$trid]['parent'])]['attribute']['cellspacing'], 1, 'px');
} else {
$cellspacing = 0;
}
if ($this->rtl) {
$cellspacingx = -$cellspacing;
} else {
$cellspacingx = $cellspacing;
}
$colspan = $dom[$key]['attribute']['colspan'];
$wtmp = ($colspan * ($table_width / $dom[$table_el]['cols']));
if (isset($dom[$key]['width'])) {
$cellw = $this->getHTMLUnitToUnits($dom[$key]['width'], $wtmp, 'px');
} else {
$cellw = $wtmp;
}
if (isset($dom[$key]['height'])) {
// minimum cell height
$cellh = $this->getHTMLUnitToUnits($dom[$key]['height'], 0, 'px');
} else {
$cellh = 0;
}
$cellw -= $cellspacing;
if (isset($dom[$key]['content'])) {
$cell_content = $dom[$key]['content'];
} else {
$cell_content = ' ';
}
$tagtype = $dom[$key]['value'];
$parentid = $key;
while (($key < $maxel) AND (!(($dom[$key]['tag']) AND (!$dom[$key]['opening']) AND ($dom[$key]['value'] == $tagtype) AND ($dom[$key]['parent'] == $parentid)))) {
// move $key index forward
++$key;
}
if (!isset($dom[$trid]['startpage'])) {
$dom[$trid]['startpage'] = $this->page;
} else {
$this->setPage($dom[$trid]['startpage']);
}
if (!isset($dom[$trid]['starty'])) {
$dom[$trid]['starty'] = $this->y;
} else {
$this->y = $dom[$trid]['starty'];
}
if (!isset($dom[$trid]['startx'])) {
$dom[$trid]['startx'] = $this->x;
}
$this->x += ($cellspacingx / 2);
if (isset($dom[$parentid]['attribute']['rowspan'])) {
$rowspan = intval($dom[$parentid]['attribute']['rowspan']);
} else {
$rowspan = 1;
}
// skip row-spanned cells started on the previous rows
if (isset($dom[$table_el]['rowspans'])) {
$rsk = 0;
$rskmax = count($dom[$table_el]['rowspans']);
while ($rsk < $rskmax) {
$trwsp = $dom[$table_el]['rowspans'][$rsk];
$rsstartx = $trwsp['startx'];
$rsendx = $trwsp['endx'];
// account for margin changes
if ($trwsp['startpage'] < $this->page) {
if (($this->rtl) AND ($this->pagedim[$this->page]['orm'] != $this->pagedim[$trwsp['startpage']]['orm'])) {
$dl = ($this->pagedim[$this->page]['orm'] - $this->pagedim[$trwsp['startpage']]['orm']);
$rsstartx -= $dl;
$rsendx -= $dl;
} elseif ((!$this->rtl) AND ($this->pagedim[$this->page]['olm'] != $this->pagedim[$trwsp['startpage']]['olm'])) {
$dl = ($this->pagedim[$this->page]['olm'] - $this->pagedim[$trwsp['startpage']]['olm']);
$rsstartx += $dl;
$rsendx += $dl;
}
}
if (($trwsp['rowspan'] > 0)
AND ($rsstartx > ($this->x - $cellspacing - $currentcmargin - $this->feps))
AND ($rsstartx < ($this->x + $cellspacing + $currentcmargin + $this->feps))
AND (($trwsp['starty'] < ($this->y - $this->feps)) OR ($trwsp['startpage'] < $this->page))) {
// set the starting X position of the current cell
$this->x = $rsendx + $cellspacingx;
if (($trwsp['rowspan'] == 1)
AND (isset($dom[$trid]['endy']))
AND (isset($dom[$trid]['endpage']))
AND ($trwsp['endpage'] == $dom[$trid]['endpage'])) {
// set ending Y position for row
$dom[$table_el]['rowspans'][$rsk]['endy'] = max($dom[$trid]['endy'], $trwsp['endy']);
$dom[$trid]['endy'] = $dom[$table_el]['rowspans'][$rsk]['endy'];
}
$rsk = 0;
} else {
++$rsk;
}
}
}
// add rowspan information to table element
if ($rowspan > 1) {
if (isset($this->footerlen[$this->page])) {
$this->footerpos[$this->page] = $this->pagelen[$this->page] - $this->footerlen[$this->page];
} else {
$this->footerpos[$this->page] = $this->pagelen[$this->page];
}
$trintmrkpos = $this->footerpos[$this->page];
$trsid = array_push($dom[$table_el]['rowspans'], array('trid' => $trid, 'rowspan' => $rowspan, 'mrowspan' => $rowspan, 'colspan' => $colspan, 'startpage' => $this->page, 'startx' => $this->x, 'starty' => $this->y, 'intmrkpos' => $trintmrkpos));
}
$cellid = array_push($dom[$trid]['cellpos'], array('startx' => $this->x));
if ($rowspan > 1) {
$dom[$trid]['cellpos'][($cellid - 1)]['rowspanid'] = ($trsid - 1);
}
// push background colors
if (isset($dom[$parentid]['bgcolor']) AND ($dom[$parentid]['bgcolor'] !== false)) {
$dom[$trid]['cellpos'][($cellid - 1)]['bgcolor'] = $dom[$parentid]['bgcolor'];
}
$prevLastH = $this->lasth;
// ****** write the cell content ******
$this->MultiCell($cellw, $cellh, $cell_content, false, $lalign, false, 2, '', '', true, 0, true);
$this->lasth = $prevLastH;
$this->cMargin = $oldmargin;
$dom[$trid]['cellpos'][($cellid - 1)]['endx'] = $this->x;
// update the end of row position
if ($rowspan <= 1) {
if (isset($dom[$trid]['endy'])) {
if ($this->page == $dom[$trid]['endpage']) {
$dom[$trid]['endy'] = max($this->y, $dom[$trid]['endy']);
} elseif ($this->page > $dom[$trid]['endpage']) {
$dom[$trid]['endy'] = $this->y;
}
} else {
$dom[$trid]['endy'] = $this->y;
}
if (isset($dom[$trid]['endpage'])) {
$dom[$trid]['endpage'] = max($this->page, $dom[$trid]['endpage']);
} else {
$dom[$trid]['endpage'] = $this->page;
}
} else {
// account for row-spanned cells
$dom[$table_el]['rowspans'][($trsid - 1)]['endx'] = $this->x;
$dom[$table_el]['rowspans'][($trsid - 1)]['endy'] = $this->y;
$dom[$table_el]['rowspans'][($trsid - 1)]['endpage'] = $this->page;
}
if (isset($dom[$table_el]['rowspans'])) {
// update endy and endpage on rowspanned cells
foreach ($dom[$table_el]['rowspans'] as $k => $trwsp) {
if ($trwsp['rowspan'] > 0) {
if (isset($dom[$trid]['endpage'])) {
if ($trwsp['endpage'] == $dom[$trid]['endpage']) {
$dom[$table_el]['rowspans'][$k]['endy'] = max($dom[$trid]['endy'], $trwsp['endy']);
} elseif ($trwsp['endpage'] < $dom[$trid]['endpage']) {
$dom[$table_el]['rowspans'][$k]['endy'] = $dom[$trid]['endy'];
$dom[$table_el]['rowspans'][$k]['endpage'] = $dom[$trid]['endpage'];
} else {
$dom[$trid]['endy'] = $this->pagedim[$dom[$trid]['endpage']]['hk'] - $this->pagedim[$dom[$trid]['endpage']]['bm'];
}
}
}
}
}
$this->x += ($cellspacingx / 2);
} else {
// opening tag (or self-closing tag)
if (!isset($opentagpos)) {
if (!$this->InFooter) {
if (isset($this->footerlen[$this->page])) {
$this->footerpos[$this->page] = $this->pagelen[$this->page] - $this->footerlen[$this->page];
} else {
$this->footerpos[$this->page] = $this->pagelen[$this->page];
}
}
$opentagpos = $this->footerpos[$this->page];
}
$this->openHTMLTagHandler($dom, $key, $cell);
}
} else {
// closing tag
$this->closeHTMLTagHandler($dom, $key, $cell);
}
} elseif (strlen($dom[$key]['value']) > 0) {
// print list-item
if (!$this->empty_string($this->lispacer)) {
$this->SetFont($pfontname, $pfontstyle, $pfontsize);
$this->lasth = $this->FontSize * $this->cell_height_ratio;
$minstartliney = $this->y;
$this->putHtmlListBullet($this->listnum, $this->lispacer, $pfontsize);
$this->SetFont($curfontname, $curfontstyle, $curfontsize);
$this->lasth = $this->FontSize * $this->cell_height_ratio;
if (is_numeric($pfontsize) AND ($pfontsize > 0) AND is_numeric($curfontsize) AND ($curfontsize > 0) AND ($pfontsize != $curfontsize)) {
$this->y += (($pfontsize - $curfontsize) / $this->k);
$minstartliney = min($this->y, $minstartliney);
}
}
// text
$this->htmlvspace = 0;
if ((!$this->premode) AND ($this->rtl OR $this->tmprtl)) {
// reverse spaces order
$len1 = strlen($dom[$key]['value']);
$lsp = $len1 - strlen(ltrim($dom[$key]['value']));
$rsp = $len1 - strlen(rtrim($dom[$key]['value']));
$tmpstr = '';
if ($rsp > 0) {
$tmpstr .= substr($dom[$key]['value'], -$rsp);
}
$tmpstr .= trim($dom[$key]['value']);
if ($lsp > 0) {
$tmpstr .= substr($dom[$key]['value'], 0, $lsp);
}
$dom[$key]['value'] = $tmpstr;
}
if ($newline) {
if (!$this->premode) {
if (($this->rtl OR $this->tmprtl)) {
$dom[$key]['value'] = rtrim($dom[$key]['value']);
} else {
$dom[$key]['value'] = ltrim($dom[$key]['value']);
}
}
$newline = false;
$firstblock = true;
} else {
$firstblock = false;
}
$strrest = '';
if (!empty($this->HREF)) {
// HTML Link
$strrest = $this->addHtmlLink($this->HREF['url'], $dom[$key]['value'], $wfill, true, $this->HREF['color'], $this->HREF['style']);
} else {
$ctmpmargin = $this->cMargin;
$this->cMargin = 0;
// ****** write only until the end of the line and get the rest ******
$strrest = $this->Write($this->lasth, $dom[$key]['value'], '', $wfill, '', false, 0, true, $firstblock);
$this->cMargin = $ctmpmargin;
}
if (strlen($strrest) > 0) {
// store the remaining string on the previous $key position
$this->newline = true;
if ($cell) {
if ($this->rtl) {
$this->x -= $this->cMargin;
} else {
$this->x += $this->cMargin;
}
}
if ($strrest == $dom[$key]['value']) {
// used to avoid infinite loop
++$loop;
} else {
$loop = 0;
}
$dom[$key]['value'] = ltrim($strrest);
if ($loop < 3) {
--$key;
}
} else {
$loop = 0;
}
}
++$key;
} // end for each $key
// align the last line
if (isset($startlinex)) {
$yshift = $minstartliney - $startliney;
if (($yshift > 0) OR ($this->page > $startlinepage)) {
$yshift = 0;
}
if ((isset($plalign) AND ((($plalign == 'C') OR ($plalign == 'J') OR (($plalign == 'R') AND (!$this->rtl)) OR (($plalign == 'L') AND ($this->rtl))))) OR ($yshift < 0)) {
// the last line must be shifted to be aligned as requested
$linew = abs($this->endlinex - $startlinex);
$pstart = substr($this->getPageBuffer($startlinepage), 0, $startlinepos);
if (isset($opentagpos) AND isset($this->footerlen[$startlinepage])) {
$this->footerpos[$startlinepage] = $this->pagelen[$startlinepage] - $this->footerlen[$startlinepage];
$midpos = min($opentagpos, $this->footerpos[$startlinepage]);
} elseif (isset($opentagpos)) {
$midpos = $opentagpos;
} elseif (isset($this->footerlen[$startlinepage])) {
$this->footerpos[$startlinepage] = $this->pagelen[$startlinepage] - $this->footerlen[$startlinepage];
$midpos = $this->footerpos[$startlinepage];
} else {
$midpos = 0;
}
if ($midpos > 0) {
$pmid = substr($this->getPageBuffer($startlinepage), $startlinepos, ($midpos - $startlinepos));
$pend = substr($this->getPageBuffer($startlinepage), $midpos);
} else {
$pmid = substr($this->getPageBuffer($startlinepage), $startlinepos);
$pend = '';
}
// calculate shifting amount
$tw = $w;
if ($this->lMargin != $prevlMargin) {
$tw += ($prevlMargin - $this->lMargin);
}
if ($this->rMargin != $prevrMargin) {
$tw += ($prevrMargin - $this->rMargin);
}
$mdiff = abs($tw - $linew);
if ($plalign == 'C') {
if ($this->rtl) {
$t_x = -($mdiff / 2);
} else {
$t_x = ($mdiff / 2);
}
} elseif (($plalign == 'R') AND (!$this->rtl)) {
// right alignment on LTR document
$t_x = $mdiff;
} elseif (($plalign == 'L') AND ($this->rtl)) {
// left alignment on RTL document
$t_x = -$mdiff;
} else {
$t_x = 0;
}
if (($t_x != 0) OR ($yshift < 0)) {
// shift the line
$trx = sprintf('1 0 0 1 %.3F %.3F cm', ($t_x * $this->k), ($yshift * $this->k));
$this->setPageBuffer($startlinepage, $pstart."\nq\n".$trx."\n".$pmid."\nQ\n".$pend);
$endlinepos = strlen($pstart."\nq\n".$trx."\n".$pmid."\nQ\n");
// shift the annotations and links
if (isset($this->PageAnnots[$this->page])) {
foreach ($this->PageAnnots[$this->page] as $pak => $pac) {
if ($pak >= $pask) {
$this->PageAnnots[$this->page][$pak]['x'] += $t_x;
$this->PageAnnots[$this->page][$pak]['y'] -= $yshift;
}
}
}
$this->y -= $yshift;
}
}
}
if ($ln AND (!($cell AND ($dom[$key-1]['value'] == 'table')))) {
$this->Ln($this->lasth);
}
// restore previous values
$this->setGraphicVars($gvars);
if ($this->page > $prevPage) {
$this->lMargin = $this->pagedim[$this->page]['olm'];
$this->rMargin = $this->pagedim[$this->page]['orm'];
}
unset($dom);
}
/**
* Process opening tags.
* @param array $dom html dom array
* @param int $key current element id
* @param boolean $cell if true add the default cMargin space to each new line (default false).
* @access protected
*/
protected function openHTMLTagHandler(&$dom, $key, $cell=false) {
$tag = $dom[$key];
$parent = $dom[($dom[$key]['parent'])];
$firstorlast = ($key == 1);
// check for text direction attribute
if (isset($tag['attribute']['dir'])) {
$this->tmprtl = $tag['attribute']['dir'] == 'rtl' ? 'R' : 'L';
} else {
$this->tmprtl = false;
}
//Opening tag
switch($tag['value']) {
case 'table': {
$cp = 0;
$cs = 0;
$dom[$key]['rowspans'] = array();
if (!$this->empty_string($dom[$key]['thead'])) {
// set table header
$this->thead = $dom[$key]['thead'];
}
if (isset($tag['attribute']['cellpadding'])) {
$cp = $this->getHTMLUnitToUnits($tag['attribute']['cellpadding'], 1, 'px');
$this->oldcMargin = $this->cMargin;
$this->cMargin = $cp;
}
if (isset($tag['attribute']['cellspacing'])) {
$cs = $this->getHTMLUnitToUnits($tag['attribute']['cellspacing'], 1, 'px');
}
$this->checkPageBreak((2 * $cp) + (2 * $cs) + $this->lasth);
break;
}
case 'tr': {
// array of columns positions
$dom[$key]['cellpos'] = array();
break;
}
case 'hr': {
$this->addHTMLVertSpace(1, $cell, '', $firstorlast, $tag['value'], false);
$this->htmlvspace = 0;
$wtmp = $this->w - $this->lMargin - $this->rMargin;
if ((isset($tag['attribute']['width'])) AND ($tag['attribute']['width'] != '')) {
$hrWidth = $this->getHTMLUnitToUnits($tag['attribute']['width'], $wtmp, 'px');
} else {
$hrWidth = $wtmp;
}
$x = $this->GetX();
$y = $this->GetY();
$prevlinewidth = $this->GetLineWidth();
$this->Line($x, $y, $x + $hrWidth, $y);
$this->SetLineWidth($prevlinewidth);
$this->addHTMLVertSpace(1, $cell, '', !isset($dom[($key + 1)]), $tag['value'], false);
break;
}
case 'a': {
if (array_key_exists('href', $tag['attribute'])) {
$this->HREF['url'] = $tag['attribute']['href'];
}
$this->HREF['color'] = $this->htmlLinkColorArray;
$this->HREF['style'] = $this->htmlLinkFontStyle;
if (array_key_exists('style', $tag['attribute'])) {
// get style attributes
preg_match_all('/([^;:\s]*):([^;]*)/', $tag['attribute']['style'], $style_array, PREG_PATTERN_ORDER);
$astyle = array();
while (list($id, $name) = each($style_array[1])) {
$name = strtolower($name);
$astyle[$name] = trim($style_array[2][$id]);
}
if (isset($astyle['color'])) {
$this->HREF['color'] = $this->convertHTMLColorToDec($astyle['color']);
}
if (isset($astyle['text-decoration'])) {
$this->HREF['style'] = '';
$decors = explode(' ', strtolower($astyle['text-decoration']));
foreach ($decors as $dec) {
$dec = trim($dec);
if (!$this->empty_string($dec)) {
if ($dec{0} == 'u') {
$this->HREF['style'] .= 'U';
} elseif ($dec{0} == 'l') {
$this->HREF['style'] .= 'D';
}
}
}
}
}
break;
}
case 'img': {
if (isset($tag['attribute']['src'])) {
// replace relative path with real server path
if ($tag['attribute']['src'][0] == '/') {
$tag['attribute']['src'] = $_SERVER['DOCUMENT_ROOT'].$tag['attribute']['src'];
}
$tag['attribute']['src'] = urldecode($tag['attribute']['src']);
$tag['attribute']['src'] = str_replace(K_PATH_URL, K_PATH_MAIN, $tag['attribute']['src']);
if (!isset($tag['attribute']['width'])) {
$tag['attribute']['width'] = 0;
}
if (!isset($tag['attribute']['height'])) {
$tag['attribute']['height'] = 0;
}
//if (!isset($tag['attribute']['align'])) {
// the only alignment supported is "bottom"
// further development is required for other modes.
$tag['attribute']['align'] = 'bottom';
//}
switch($tag['attribute']['align']) {
case 'top': {
$align = 'T';
break;
}
case 'middle': {
$align = 'M';
break;
}
case 'bottom': {
$align = 'B';
break;
}
default: {
$align = 'B';
break;
}
}
$fileinfo = pathinfo($tag['attribute']['src']);
if (isset($fileinfo['extension']) AND (!$this->empty_string($fileinfo['extension']))) {
$type = strtolower($fileinfo['extension']);
}
$prevy = $this->y;
$xpos = $this->GetX();
if (isset($dom[($key - 1)]) AND ($dom[($key - 1)]['value'] == ' ')) {
if ($this->rtl) {
$xpos += $this->GetStringWidth(' ');
} else {
$xpos -= $this->GetStringWidth(' ');
}
}
$imglink = '';
if (isset($this->HREF['url']) AND !$this->empty_string($this->HREF['url'])) {
$imglink = $this->HREF['url'];
if ($imglink{0} == '#') {
// convert url to internal link
$page = intval(substr($imglink, 1));
$imglink = $this->AddLink();
$this->SetLink($imglink, 0, $page);
}
}
$border = 0;
if (isset($tag['attribute']['border']) AND !empty($tag['attribute']['border'])) {
// currently only support 1 (frame) or a combination of 'LTRB'
$border = $tag['attribute']['border'];
}
if (isset($tag['attribute']['width'])) {
$iw = $this->getHTMLUnitToUnits($tag['attribute']['width'], 1, 'px', false);
}
if (isset($tag['attribute']['height'])) {
$ih = $this->getHTMLUnitToUnits($tag['attribute']['height'], 1, 'px', false);
}
if (($type == 'eps') OR ($type == 'ai')) {
$this->ImageEps($tag['attribute']['src'], $xpos, $this->GetY(), $iw, $ih, $imglink, true, $align, '', $border);
} else {
$this->Image($tag['attribute']['src'], $xpos, $this->GetY(), $iw, $ih, '', $imglink, $align, false, 300, '', false, false, $border);
}
switch($align) {
case 'T': {
$this->y = $prevy;
break;
}
case 'M': {
$this->y = (($this->img_rb_y + $prevy - ($tag['fontsize'] / $this->k)) / 2) ;
break;
}
case 'B': {
$this->y = $this->img_rb_y - ($tag['fontsize'] / $this->k);
break;
}
}
}
break;
}
case 'dl': {
++$this->listnum;
$this->addHTMLVertSpace(0, $cell, '', $firstorlast, $tag['value'], false);
break;
}
case 'dt': {
$this->addHTMLVertSpace(1, $cell, '', $firstorlast, $tag['value'], false);
break;
}
case 'dd': {
if ($this->rtl) {
$this->rMargin += $this->listindent;
} else {
$this->lMargin += $this->listindent;
}
$this->addHTMLVertSpace(1, $cell, '', $firstorlast, $tag['value'], false);
break;
}
case 'ul':
case 'ol': {
$this->addHTMLVertSpace(0, $cell, '', $firstorlast, $tag['value'], false);
$this->htmlvspace = 0;
++$this->listnum;
if ($tag['value'] == 'ol') {
$this->listordered[$this->listnum] = true;
} else {
$this->listordered[$this->listnum] = false;
}
if (isset($tag['attribute']['start'])) {
$this->listcount[$this->listnum] = intval($tag['attribute']['start']) - 1;
} else {
$this->listcount[$this->listnum] = 0;
}
if ($this->rtl) {
$this->rMargin += $this->listindent;
} else {
$this->lMargin += $this->listindent;
}
$this->addHTMLVertSpace(0, $cell, '', $firstorlast, $tag['value'], false);
$this->htmlvspace = 0;
break;
}
case 'li': {
$this->addHTMLVertSpace(1, $cell, '', $firstorlast, $tag['value'], false);
if ($this->listordered[$this->listnum]) {
// ordered item
if (isset($parent['attribute']['type']) AND !$this->empty_string($parent['attribute']['type'])) {
$this->lispacer = $parent['attribute']['type'];
} elseif (isset($parent['listtype']) AND !$this->empty_string($parent['listtype'])) {
$this->lispacer = $parent['listtype'];
} elseif (isset($this->lisymbol) AND !$this->empty_string($this->lisymbol)) {
$this->lispacer = $this->lisymbol;
} else {
$this->lispacer = '#';
}
++$this->listcount[$this->listnum];
if (isset($tag['attribute']['value'])) {
$this->listcount[$this->listnum] = intval($tag['attribute']['value']);
}
} else {
// unordered item
if (isset($parent['attribute']['type']) AND !$this->empty_string($parent['attribute']['type'])) {
$this->lispacer = $parent['attribute']['type'];
} elseif (isset($parent['listtype']) AND !$this->empty_string($parent['listtype'])) {
$this->lispacer = $parent['listtype'];
} elseif (isset($this->lisymbol) AND !$this->empty_string($this->lisymbol)) {
$this->lispacer = $this->lisymbol;
} else {
$this->lispacer = '!';
}
}
break;
}
case 'blockquote': {
if ($this->rtl) {
$this->rMargin += $this->listindent;
} else {
$this->lMargin += $this->listindent;
}
$this->addHTMLVertSpace(2, $cell, '', $firstorlast, $tag['value'], false);
break;
}
case 'br': {
$this->Ln('', $cell);
break;
}
case 'div': {
$this->addHTMLVertSpace(1, $cell, '', $firstorlast, $tag['value'], false);
break;
}
case 'p': {
$this->addHTMLVertSpace(2, $cell, '', $firstorlast, $tag['value'], false);
break;
}
case 'pre': {
$this->addHTMLVertSpace(1, $cell, '', $firstorlast, $tag['value'], false);
$this->premode = true;
break;
}
case 'sup': {
$this->SetXY($this->GetX(), $this->GetY() - ((0.7 * $this->FontSizePt) / $this->k));
break;
}
case 'sub': {
$this->SetXY($this->GetX(), $this->GetY() + ((0.3 * $this->FontSizePt) / $this->k));
break;
}
case 'h1':
case 'h2':
case 'h3':
case 'h4':
case 'h5':
case 'h6': {
$this->addHTMLVertSpace(1, $cell, ($tag['fontsize'] * 1.5) / $this->k, $firstorlast, $tag['value'], false);
break;
}
case 'tcpdf': {
// NOT HTML: used to call TCPDF methods
if (isset($tag['attribute']['method'])) {
$tcpdf_method = $tag['attribute']['method'];
if (method_exists($this, $tcpdf_method)) {
if (isset($tag['attribute']['params']) AND (!empty($tag['attribute']['params']))) {
eval('$params = array('.$tag['attribute']['params'].');');
call_user_func_array(array($this, $tcpdf_method), $params);
} else {
$this->$tcpdf_method();
}
$this->newline = true;
}
}
}
default: {
break;
}
}
}
/**
* Process closing tags.
* @param array $dom html dom array
* @param int $key current element id
* @param boolean $cell if true add the default cMargin space to each new line (default false).
* @access protected
*/
protected function closeHTMLTagHandler(&$dom, $key, $cell=false) {
$tag = $dom[$key];
$parent = $dom[($dom[$key]['parent'])];
$firstorlast = ((!isset($dom[($key + 1)])) OR ((!isset($dom[($key + 2)])) AND ($dom[($key + 1)]['value'] == 'marker')));
//Closing tag
switch($tag['value']) {
case 'tr': {
$table_el = $dom[($dom[$key]['parent'])]['parent'];
if(!isset($parent['endy'])) {
$dom[($dom[$key]['parent'])]['endy'] = $this->y;
$parent['endy'] = $this->y;
}
if(!isset($parent['endpage'])) {
$dom[($dom[$key]['parent'])]['endpage'] = $this->page;
$parent['endpage'] = $this->page;
}
// update row-spanned cells
if (isset($dom[$table_el]['rowspans'])) {
foreach ($dom[$table_el]['rowspans'] as $k => $trwsp) {
$dom[$table_el]['rowspans'][$k]['rowspan'] -= 1;
if ($dom[$table_el]['rowspans'][$k]['rowspan'] == 0) {
if ($dom[$table_el]['rowspans'][$k]['endpage'] == $parent['endpage']) {
$dom[($dom[$key]['parent'])]['endy'] = max($dom[$table_el]['rowspans'][$k]['endy'], $parent['endy']);
} elseif ($dom[$table_el]['rowspans'][$k]['endpage'] > $parent['endpage']) {
$dom[($dom[$key]['parent'])]['endy'] = $dom[$table_el]['rowspans'][$k]['endy'];
$dom[($dom[$key]['parent'])]['endpage'] = $dom[$table_el]['rowspans'][$k]['endpage'];
}
}
}
// report new endy and endpage to the rowspanned cells
foreach ($dom[$table_el]['rowspans'] as $k => $trwsp) {
if ($dom[$table_el]['rowspans'][$k]['rowspan'] == 0) {
$dom[$table_el]['rowspans'][$k]['endpage'] = max($dom[$table_el]['rowspans'][$k]['endpage'], $dom[($dom[$key]['parent'])]['endpage']);
$dom[($dom[$key]['parent'])]['endpage'] = $dom[$table_el]['rowspans'][$k]['endpage'];
$dom[$table_el]['rowspans'][$k]['endy'] = max($dom[$table_el]['rowspans'][$k]['endy'], $dom[($dom[$key]['parent'])]['endy']);
$dom[($dom[$key]['parent'])]['endy'] = $dom[$table_el]['rowspans'][$k]['endy'];
}
}
// update remaining rowspanned cells
foreach ($dom[$table_el]['rowspans'] as $k => $trwsp) {
if ($dom[$table_el]['rowspans'][$k]['rowspan'] == 0) {
$dom[$table_el]['rowspans'][$k]['endpage'] = $dom[($dom[$key]['parent'])]['endpage'];
$dom[$table_el]['rowspans'][$k]['endy'] = $dom[($dom[$key]['parent'])]['endy'];
}
}
}
$this->setPage($dom[($dom[$key]['parent'])]['endpage']);
$this->y = $dom[($dom[$key]['parent'])]['endy'];
if (isset($dom[$table_el]['attribute']['cellspacing'])) {
$cellspacing = $this->getHTMLUnitToUnits($dom[$table_el]['attribute']['cellspacing'], 1, 'px');
$this->y += $cellspacing;
}
$this->Ln(0, $cell);
$this->x = $parent['startx'];
// account for booklet mode
if ($this->page > $parent['startpage']) {
if (($this->rtl) AND ($this->pagedim[$this->page]['orm'] != $this->pagedim[$parent['startpage']]['orm'])) {
$this->x += ($this->pagedim[$this->page]['orm'] - $this->pagedim[$parent['startpage']]['orm']);
} elseif ((!$this->rtl) AND ($this->pagedim[$this->page]['olm'] != $this->pagedim[$parent['startpage']]['olm'])) {
$this->x += ($this->pagedim[$this->page]['olm'] - $this->pagedim[$parent['startpage']]['olm']);
}
}
break;
}
case 'table': {
// draw borders
$table_el = $parent;
if ((isset($table_el['attribute']['border']) AND ($table_el['attribute']['border'] > 0))
OR (isset($table_el['style']['border']) AND ($table_el['style']['border'] > 0))) {
$border = 1;
} else {
$border = 0;
}
// fix bottom line alignment of last line before page break
foreach ($dom[($dom[$key]['parent'])]['trids'] as $j => $trkey) {
// update row-spanned cells
if (isset($dom[($dom[$key]['parent'])]['rowspans'])) {
foreach ($dom[($dom[$key]['parent'])]['rowspans'] as $k => $trwsp) {
if ($trwsp['trid'] == $trkey) {
$dom[($dom[$key]['parent'])]['rowspans'][$k]['mrowspan'] -= 1;
}
if (isset($prevtrkey) AND ($trwsp['trid'] == $prevtrkey) AND ($trwsp['mrowspan'] >= 0)) {
$dom[($dom[$key]['parent'])]['rowspans'][$k]['trid'] = $trkey;
}
}
}
if (isset($prevtrkey) AND ($dom[$trkey]['startpage'] > $dom[$prevtrkey]['endpage'])) {
$pgendy = $this->pagedim[$dom[$prevtrkey]['endpage']]['hk'] - $this->pagedim[$dom[$prevtrkey]['endpage']]['bm'];
$dom[$prevtrkey]['endy'] = $pgendy;
// update row-spanned cells
if (isset($dom[($dom[$key]['parent'])]['rowspans'])) {
foreach ($dom[($dom[$key]['parent'])]['rowspans'] as $k => $trwsp) {
if (($trwsp['trid'] == $trkey) AND ($trwsp['mrowspan'] == 1) AND ($trwsp['endpage'] == $dom[$prevtrkey]['endpage'])) {
$dom[($dom[$key]['parent'])]['rowspans'][$k]['endy'] = $pgendy;
$dom[($dom[$key]['parent'])]['rowspans'][$k]['mrowspan'] = -1;
}
}
}
}
$prevtrkey = $trkey;
$table_el = $dom[($dom[$key]['parent'])];
}
// for each row
foreach ($table_el['trids'] as $j => $trkey) {
$parent = $dom[$trkey];
// for each cell on the row
foreach ($parent['cellpos'] as $k => $cellpos) {
if (isset($cellpos['rowspanid']) AND ($cellpos['rowspanid'] >= 0)) {
$cellpos['startx'] = $table_el['rowspans'][($cellpos['rowspanid'])]['startx'];
$cellpos['endx'] = $table_el['rowspans'][($cellpos['rowspanid'])]['endx'];
$endy = $table_el['rowspans'][($cellpos['rowspanid'])]['endy'];
$startpage = $table_el['rowspans'][($cellpos['rowspanid'])]['startpage'];
$endpage = $table_el['rowspans'][($cellpos['rowspanid'])]['endpage'];
} else {
$endy = $parent['endy'];
$startpage = $parent['startpage'];
$endpage = $parent['endpage'];
}
if ($endpage > $startpage) {
// design borders around HTML cells.
for ($page=$startpage; $page <= $endpage; ++$page) {
$this->setPage($page);
if ($page == $startpage) {
$this->y = $parent['starty']; // put cursor at the beginning of row on the first page
$ch = $this->getPageHeight() - $parent['starty'] - $this->getBreakMargin();
$cborder = $this->getBorderMode($border, $position='start');
} elseif ($page == $endpage) {
$this->y = $this->tMargin; // put cursor at the beginning of last page
$ch = $endy - $this->tMargin;
$cborder = $this->getBorderMode($border, $position='end');
} else {
$this->y = $this->tMargin; // put cursor at the beginning of the current page
$ch = $this->getPageHeight() - $this->tMargin - $this->getBreakMargin();
$cborder = $this->getBorderMode($border, $position='middle');
}
if (isset($cellpos['bgcolor']) AND ($cellpos['bgcolor']) !== false) {
$this->SetFillColorArray($cellpos['bgcolor']);
$fill = true;
} else {
$fill = false;
}
$cw = abs($cellpos['endx'] - $cellpos['startx']);
$this->x = $cellpos['startx'];
// account for margin changes
if ($page > $startpage) {
if (($this->rtl) AND ($this->pagedim[$page]['orm'] != $this->pagedim[$startpage]['orm'])) {
$this->x -= ($this->pagedim[$page]['orm'] - $this->pagedim[$startpage]['orm']);
} elseif ((!$this->rtl) AND ($this->pagedim[$page]['lm'] != $this->pagedim[$startpage]['olm'])) {
$this->x += ($this->pagedim[$page]['olm'] - $this->pagedim[$startpage]['olm']);
}
}
// design a cell around the text
$ccode = $this->FillColor."\n".$this->getCellCode($cw, $ch, '', $cborder, 1, '', $fill, '', 0, true);
if ($cborder OR $fill) {
$pagebuff = $this->getPageBuffer($this->page);
$pstart = substr($pagebuff, 0, $this->intmrk[$this->page]);
$pend = substr($pagebuff, $this->intmrk[$this->page]);
$this->setPageBuffer($this->page, $pstart.$ccode."\n".$pend);
$this->intmrk[$this->page] += strlen($ccode."\n");
}
}
} else {
$this->setPage($startpage);
if (isset($cellpos['bgcolor']) AND ($cellpos['bgcolor']) !== false) {
$this->SetFillColorArray($cellpos['bgcolor']);
$fill = true;
} else {
$fill = false;
}
$this->x = $cellpos['startx'];
$this->y = $parent['starty'];
$cw = abs($cellpos['endx'] - $cellpos['startx']);
$ch = $endy - $parent['starty'];
// design a cell around the text
$ccode = $this->FillColor."\n".$this->getCellCode($cw, $ch, '', $border, 1, '', $fill, '', 0, true);
if ($border OR $fill) {
if (end($this->transfmrk[$this->page]) !== false) {
$pagemarkkey = key($this->transfmrk[$this->page]);
$pagemark = &$this->transfmrk[$this->page][$pagemarkkey];
} elseif ($this->InFooter) {
$pagemark = &$this->footerpos[$this->page];
} else {
$pagemark = &$this->intmrk[$this->page];
}
$pagebuff = $this->getPageBuffer($this->page);
$pstart = substr($pagebuff, 0, $pagemark);
$pend = substr($pagebuff, $pagemark);
$this->setPageBuffer($this->page, $pstart.$ccode."\n".$pend);
$pagemark += strlen($ccode."\n");
}
}
}
if (isset($table_el['attribute']['cellspacing'])) {
$cellspacing = $this->getHTMLUnitToUnits($table_el['attribute']['cellspacing'], 1, 'px');
$this->y += $cellspacing;
}
$this->Ln(0, $cell);
$this->x = $parent['startx'];
if ($endpage > $startpage) {
if (($this->rtl) AND ($this->pagedim[$endpage]['orm'] != $this->pagedim[$startpage]['orm'])) {
$this->x += ($this->pagedim[$endpage]['orm'] - $this->pagedim[$startpage]['orm']);
} elseif ((!$this->rtl) AND ($this->pagedim[$endpage]['olm'] != $this->pagedim[$startpage]['olm'])) {
$this->x += ($this->pagedim[$endpage]['olm'] - $this->pagedim[$startpage]['olm']);
}
}
}
if (isset($parent['cellpadding'])) {
$this->cMargin = $this->oldcMargin;
}
$this->lasth = $this->FontSize * $this->cell_height_ratio;
if (!$this->empty_string($table_el['thead']) AND !$this->empty_string($this->theadMargin)) {
// reset table header
$this->thead = '';
// restore top margin
$this->tMargin = $this->theadMargin;
$this->pagedim[$this->page]['tm'] = $this->theadMargin;
$this->theadMargin = '';
}
break;
}
case 'a': {
$this->HREF = '';
break;
}
case 'sup': {
$this->SetXY($this->GetX(), $this->GetY() + ((0.7 * $parent['fontsize']) / $this->k));
break;
}
case 'sub': {
$this->SetXY($this->GetX(), $this->GetY() - ((0.3 * $parent['fontsize'])/$this->k));
break;
}
case 'div': {
$this->addHTMLVertSpace(1, $cell, '', $firstorlast, $tag['value'], true);
break;
}
case 'blockquote': {
if ($this->rtl) {
$this->rMargin -= $this->listindent;
} else {
$this->lMargin -= $this->listindent;
}
$this->addHTMLVertSpace(2, $cell, '', $firstorlast, $tag['value'], true);
break;
}
case 'p': {
$this->addHTMLVertSpace(2, $cell, '', $firstorlast, $tag['value'], true);
break;
}
case 'pre': {
$this->addHTMLVertSpace(1, $cell, '', $firstorlast, $tag['value'], true);
$this->premode = false;
break;
}
case 'dl': {
--$this->listnum;
if ($this->listnum <= 0) {
$this->listnum = 0;
$this->addHTMLVertSpace(2, $cell, '', $firstorlast, $tag['value'], true);
}
break;
}
case 'dt': {
$this->lispacer = '';
$this->addHTMLVertSpace(0, $cell, '', $firstorlast, $tag['value'], true);
break;
}
case 'dd': {
$this->lispacer = '';
if ($this->rtl) {
$this->rMargin -= $this->listindent;
} else {
$this->lMargin -= $this->listindent;
}
$this->addHTMLVertSpace(0, $cell, '', $firstorlast, $tag['value'], true);
break;
}
case 'ul':
case 'ol': {
--$this->listnum;
$this->lispacer = '';
if ($this->rtl) {
$this->rMargin -= $this->listindent;
} else {
$this->lMargin -= $this->listindent;
}
if ($this->listnum <= 0) {
$this->listnum = 0;
$this->addHTMLVertSpace(2, $cell, '', $firstorlast, $tag['value'], true);
}
$this->lasth = $this->FontSize * $this->cell_height_ratio;
break;
}
case 'li': {
$this->lispacer = '';
$this->addHTMLVertSpace(0, $cell, '', $firstorlast, $tag['value'], true);
break;
}
case 'h1':
case 'h2':
case 'h3':
case 'h4':
case 'h5':
case 'h6': {
$this->addHTMLVertSpace(1, $cell, ($parent['fontsize'] * 1.5) / $this->k, $firstorlast, $tag['value'], true);
break;
}
default : {
break;
}
}
$this->tmprtl = false;
}
/**
* Add vertical spaces if needed.
* @param int $n number of spaces to add
* @param boolean $cell if true add the default cMargin space to each new line (default false).
* @param string $h The height of the break. By default, the value equals the height of the last printed cell.
* @param boolean $firstorlast if true do not print additional empty lines.
* @param string $tag HTML tag to which this space will be applied
* @param boolean $closing true if this space will be applied to a closing tag, false otherwise
* @access protected
*/
protected function addHTMLVertSpace($n, $cell=false, $h='', $firstorlast=false, $tag='', $closing=false) {
if ($firstorlast) {
$this->Ln(0, $cell);
$this->htmlvspace = 0;
return;
}
if (isset($this->tagvspaces[$tag][intval($closing)]['n'])) {
$n = $this->tagvspaces[$tag][intval($closing)]['n'];
}
if (isset($this->tagvspaces[$tag][intval($closing)]['h'])) {
$h = $this->tagvspaces[$tag][intval($closing)]['h'];
}
if (is_string($h)) {
$vsize = $n * $this->lasth;
} else {
$vsize = $n * $h;
}
if ($vsize > $this->htmlvspace) {
$this->Ln(($vsize - $this->htmlvspace), $cell);
$this->htmlvspace = $vsize;
}
}
/**
* Set the default bullet to be used as LI bullet symbol
* @param string $symbol character or string to be used (legal values are: '' = automatic, '!' = auto bullet, '#' = auto numbering, 'disc', 'disc', 'circle', 'square', '1', 'decimal', 'decimal-leading-zero', 'i', 'lower-roman', 'I', 'upper-roman', 'a', 'lower-alpha', 'lower-latin', 'A', 'upper-alpha', 'upper-latin', 'lower-greek')
* @access public
* @since 4.0.028 (2008-09-26)
*/
public function setLIsymbol($symbol='!') {
$symbol = strtolower($symbol);
switch ($symbol) {
case '!' :
case '#' :
case 'disc' :
case 'disc' :
case 'circle' :
case 'square' :
case '1':
case 'decimal':
case 'decimal-leading-zero':
case 'i':
case 'lower-roman':
case 'I':
case 'upper-roman':
case 'a':
case 'lower-alpha':
case 'lower-latin':
case 'A':
case 'upper-alpha':
case 'upper-latin':
case 'lower-greek': {
$this->lisymbol = $symbol;
break;
}
default : {
$this->lisymbol = '';
}
}
}
/**
* Set the booklet mode for double-sided pages.
* @param boolean $booklet true set the booklet mode on, fals eotherwise.
* @param float $inner Inner page margin.
* @param float $outer Outer page margin.
* @access public
* @since 4.2.000 (2008-10-29)
*/
public function SetBooklet($booklet=true, $inner=-1, $outer=-1) {
$this->booklet = $booklet;
if ($inner >= 0) {
$this->lMargin = $inner;
}
if ($outer >= 0) {
$this->rMargin = $outer;
}
}
/**
* Swap the left and right margins.
* @param boolean $reverse if true swap left and right margins.
* @access protected
* @since 4.2.000 (2008-10-29)
*/
protected function swapMargins($reverse=true) {
if ($reverse) {
// swap left and right margins
$mtemp = $this->original_lMargin;
$this->original_lMargin = $this->original_rMargin;
$this->original_rMargin = $mtemp;
$deltam = $this->original_lMargin - $this->original_rMargin;
$this->lMargin += $deltam;
$this->rMargin -= $deltam;
}
}
/**
* Set the vertical spaces for HTML tags.
* The array must have the following structure (example):
* $tagvs = array('h1' => array(0 => array('h' => '', 'n' => 2), 1 => array('h' => 1.3, 'n' => 1)));
* The first array level contains the tag names,
* the second level contains 0 for opening tags or 1 for closing tags,
* the third level contains the vertical space unit (h) and the number spaces to add (n).
* If the h parameter is not specified, default values are used.
* @param array $tagvs array of tags and relative vertical spaces.
* @access public
* @since 4.2.001 (2008-10-30)
*/
public function setHtmlVSpace($tagvs) {
$this->tagvspaces = $tagvs;
}
/**
* Set custom width for list indentation.
* @param float $width width of the indentation. Use negative value to disable it.
* @access public
* @since 4.2.007 (2008-11-12)
*/
public function setListIndentWidth($width) {
return $this->customlistindent = floatval($width);
}
/**
* Set the top/bottom cell sides to be open or closed when the cell cross the page.
* @param boolean $isopen if true keeps the top/bottom border open for the cell sides that cross the page.
* @access public
* @since 4.2.010 (2008-11-14)
*/
public function setOpenCell($isopen) {
$this->opencell = $isopen;
}
/**
* Set the color and font style for HTML links.
* @param array $color RGB array of colors
* @param string $fontstyle additional font styles to add
* @access public
* @since 4.4.003 (2008-12-09)
*/
public function setHtmlLinksStyle($color=array(0,0,255), $fontstyle='U') {
$this->htmlLinkColorArray = $color;
$this->htmlLinkFontStyle = $fontstyle;
}
/**
* convert html string containing value and unit of measure to user's units or points.
* @param string $htmlval string containing values and unit
* @param string $refsize reference value in points
* @param string $defaultunit default unit (can be one of the following: %, em, ex, px, in, mm, pc, pt).
* @param boolean $point if true returns points, otherwise returns value in user's units
* @return float value in user's unit or point if $points=true
* @access public
* @since 4.4.004 (2008-12-10)
*/
public function getHTMLUnitToUnits($htmlval, $refsize=1, $defaultunit='px', $points=false) {
$supportedunits = array('%', 'em', 'ex', 'px', 'in', 'cm', 'mm', 'pc', 'pt');
$retval = 0;
$value = 0;
$unit = 'px';
$k = $this->k;
if ($points) {
$k = 1;
}
if (in_array($defaultunit, $supportedunits)) {
$unit = $defaultunit;
}
if (is_numeric($htmlval)) {
$value = floatval($htmlval);
} elseif (preg_match('/([0-9\.]+)/', $htmlval, $mnum)) {
$value = floatval($mnum[1]);
if (preg_match('/([a-z%]+)/', $htmlval, $munit)) {
if (in_array($munit[1], $supportedunits)) {
$unit = $munit[1];
}
}
}
switch ($unit) {
// percentage
case '%': {
$retval = (($value * $refsize) / 100);
break;
}
// relative-size
case 'em': {
$retval = ($value * $refsize);
break;
}
case 'ex': {
$retval = $value * ($refsize / 2);
break;
}
// absolute-size
case 'in': {
$retval = ($value * $this->dpi) / $k;
break;
}
case 'cm': {
$retval = ($value / 2.54 * $this->dpi) / $k;
break;
}
case 'mm': {
$retval = ($value / 25.4 * $this->dpi) / $k;
break;
}
case 'pc': {
// one pica is 12 points
$retval = ($value * 12) / $k;
break;
}
case 'pt': {
$retval = $value / $k;
break;
}
case 'px': {
$retval = $this->pixelsToUnits($value);
break;
}
}
return $retval;
}
/**
* Returns the Roman representation of an integer number
* @param int number to convert
* @return string roman representation of the specified number
* @access public
* @since 4.4.004 (2008-12-10)
*/
public function intToRoman($number) {
$roman = '';
while ($number >= 1000) {
$roman .= 'M';
$number -= 1000;
}
while ($number >= 900) {
$roman .= 'CM';
$number -= 900;
}
while ($number >= 500) {
$roman .= 'D';
$number -= 500;
}
while ($number >= 400) {
$roman .= 'CD';
$number -= 400;
}
while ($number >= 100) {
$roman .= 'C';
$number -= 100;
}
while ($number >= 90) {
$roman .= 'XC';
$number -= 90;
}
while ($number >= 50) {
$roman .= 'L';
$number -= 50;
}
while ($number >= 40) {
$roman .= 'XL';
$number -= 40;
}
while ($number >= 10) {
$roman .= 'X';
$number -= 10;
}
while ($number >= 9) {
$roman .= 'IX';
$number -= 9;
}
while ($number >= 5) {
$roman .= 'V';
$number -= 5;
}
while ($number >= 4) {
$roman .= 'IV';
$number -= 4;
}
while ($number >= 1) {
$roman .= 'I';
--$number;
}
return $roman;
}
/**
* Output an HTML list bullet or ordered item symbol
* @param int $listdepth list nesting level
* @param string $listtype type of list
* @param float $size current font size
* @access protected
* @since 4.4.004 (2008-12-10)
*/
protected function putHtmlListBullet($listdepth, $listtype='', $size=10) {
$size /= $this->k;
$fill = '';
$color = $this->fgcolor;
$width = 0;
$textitem = '';
$tmpx = $this->x;
$lspace = $this->GetStringWidth(' ');
if ($listtype == '!') {
// set default list type for unordered list
$deftypes = array('disc', 'circle', 'square');
$listtype = $deftypes[($listdepth - 1) % 3];
} elseif ($listtype == '#') {
// set default list type for ordered list
$listtype = 'decimal';
}
switch ($listtype) {
// unordered types
case 'none': {
break;
}
case 'disc': {
$fill = 'F';
}
case 'circle': {
$fill .= 'D';
$r = $size / 6;
$lspace += (2 * $r);
if ($this->rtl) {
$this->x += $lspace;
} else {
$this->x -= $lspace;
}
$this->Circle(($this->x + $r), ($this->y + ($this->lasth / 2)), $r, 0, 360, $fill, array('color'=>$color), $color, 8);
break;
}
case 'square': {
$l = $size / 3;
$lspace += $l;
if ($this->rtl) {
$this->x += $lspace;
} else {
$this->x -= $lspace;
}
$this->Rect($this->x, ($this->y + (($this->lasth - $l)/ 2)), $l, $l, 'F', array(), $color);
break;
}
// ordered types
// $this->listcount[$this->listnum];
// $textitem
case '1':
case 'decimal': {
$textitem = $this->listcount[$this->listnum];
break;
}
case 'decimal-leading-zero': {
$textitem = sprintf("%02d", $this->listcount[$this->listnum]);
break;
}
case 'i':
case 'lower-roman': {
$textitem = strtolower($this->intToRoman($this->listcount[$this->listnum]));
break;
}
case 'I':
case 'upper-roman': {
$textitem = $this->intToRoman($this->listcount[$this->listnum]);
break;
}
case 'a':
case 'lower-alpha':
case 'lower-latin': {
$textitem = chr(97 + $this->listcount[$this->listnum] - 1);
break;
}
case 'A':
case 'upper-alpha':
case 'upper-latin': {
$textitem = chr(65 + $this->listcount[$this->listnum] - 1);
break;
}
case 'lower-greek': {
$textitem = $this->unichr(945 + $this->listcount[$this->listnum] - 1);
break;
}
/*
// Types to be implemented (special handling)
case 'hebrew': {
break;
}
case 'armenian': {
break;
}
case 'georgian': {
break;
}
case 'cjk-ideographic': {
break;
}
case 'hiragana': {
break;
}
case 'katakana': {
break;
}
case 'hiragana-iroha': {
break;
}
case 'katakana-iroha': {
break;
}
*/
default: {
$textitem = $this->listcount[$this->listnum];
}
}
if (!$this->empty_string($textitem)) {
// print ordered item
if ($this->rtl) {
$textitem = '.'.$textitem;
} else {
$textitem = $textitem.'.';
}
$lspace += $this->GetStringWidth($textitem);
if ($this->rtl) {
$this->x += $lspace;
} else {
$this->x -= $lspace;
}
$this->Write($this->lasth, $textitem, '', false, '', false, 0, false);
}
$this->x = $tmpx;
$this->lispacer = '';
}
/**
* Returns current graphic variables as array.
* @return array graphic variables
* @access protected
* @since 4.2.010 (2008-11-14)
*/
protected function getGraphicVars() {
$grapvars = array(
'FontFamily' => $this->FontFamily,
'FontStyle' => $this->FontStyle,
'FontSizePt' => $this->FontSizePt,
'rMargin' => $this->rMargin,
'lMargin' => $this->lMargin,
'cMargin' => $this->cMargin,
'LineWidth' => $this->LineWidth,
'linestyleWidth' => $this->linestyleWidth,
'linestyleCap' => $this->linestyleCap,
'linestyleJoin' => $this->linestyleJoin,
'linestyleDash' => $this->linestyleDash,
'DrawColor' => $this->DrawColor,
'FillColor' => $this->FillColor,
'TextColor' => $this->TextColor,
'ColorFlag' => $this->ColorFlag,
'bgcolor' => $this->bgcolor,
'fgcolor' => $this->fgcolor,
'htmlvspace' => $this->htmlvspace,
'lasth' => $this->lasth
);
return $grapvars;
}
/**
* Set graphic variables.
* @param $gvars array graphic variables
* @access protected
* @since 4.2.010 (2008-11-14)
*/
protected function setGraphicVars($gvars) {
$this->FontFamily = $gvars['FontFamily'];
$this->FontStyle = $gvars['FontStyle'];
$this->FontSizePt = $gvars['FontSizePt'];
$this->rMargin = $gvars['rMargin'];
$this->lMargin = $gvars['lMargin'];
$this->cMargin = $gvars['cMargin'];
$this->LineWidth = $gvars['LineWidth'];
$this->linestyleWidth = $gvars['linestyleWidth'];
$this->linestyleCap = $gvars['linestyleCap'];
$this->linestyleJoin = $gvars['linestyleJoin'];
$this->linestyleDash = $gvars['linestyleDash'];
$this->DrawColor = $gvars['DrawColor'];
$this->FillColor = $gvars['FillColor'];
$this->TextColor = $gvars['TextColor'];
$this->ColorFlag = $gvars['ColorFlag'];
$this->bgcolor = $gvars['bgcolor'];
$this->fgcolor = $gvars['fgcolor'];
$this->htmlvspace = $gvars['htmlvspace'];
//$this->lasth = $gvars['lasth'];
$this->_out(''.$this->linestyleWidth.' '.$this->linestyleCap.' '.$this->linestyleJoin.' '.$this->linestyleDash.' '.$this->DrawColor.' '.$this->FillColor.'');
if (!$this->empty_string($this->FontFamily)) {
$this->SetFont($this->FontFamily, $this->FontStyle, $this->FontSizePt);
}
}
/**
* Returns a temporary filename for caching object on filesystem.
* @param string $prefix prefix to add to filename
* return string filename.
* @access protected
* @since 4.5.000 (2008-12-31)
*/
protected function getObjFilename($name) {
return tempnam(K_PATH_CACHE, $name.'_');
}
/**
* Writes data to a temporary file on filesystem.
* @param string $file file name
* @param mixed $data data to write on file
* @param boolean $append if true append data, false replace.
* @access protected
* @since 4.5.000 (2008-12-31)
*/
protected function writeDiskCache($filename, $data, $append=false) {
if ($append) {
$fmode = 'ab+';
} else {
$fmode = 'wb+';
}
$f = @fopen($filename, $fmode);
if (!$f) {
$this->Error('Unable to write cache file: '.$filename);
} else {
fwrite($f, $data);
fclose($f);
}
// update file lenght (needed for transactions)
if (!isset($this->cache_file_lenght['_'.$filename])) {
$this->cache_file_lenght['_'.$filename] = strlen($data);
} else {
$this->cache_file_lenght['_'.$filename] += strlen($data);
}
}
/**
* Read data from a temporary file on filesystem.
* @param string $file file name
* @return mixed retrieved data
* @access protected
* @since 4.5.000 (2008-12-31)
*/
protected function readDiskCache($filename) {
return file_get_contents($filename);
}
/**
* Set buffer content (always append data).
* @param string $data data
* @access protected
* @since 4.5.000 (2009-01-02)
*/
protected function setBuffer($data) {
$this->bufferlen += strlen($data);
if ($this->diskcache) {
if (!isset($this->buffer) OR $this->empty_string($this->buffer)) {
$this->buffer = $this->getObjFilename('buffer');
}
$this->writeDiskCache($this->buffer, $data, true);
} else {
$this->buffer .= $data;
}
}
/**
* Get buffer content.
* @return string buffer content
* @access protected
* @since 4.5.000 (2009-01-02)
*/
protected function getBuffer() {
if ($this->diskcache) {
return $this->readDiskCache($this->buffer);
} else {
return $this->buffer;
}
}
/**
* Set page buffer content.
* @param int $page page number
* @param string $data page data
* @param boolean $append if true append data, false replace.
* @access protected
* @since 4.5.000 (2008-12-31)
*/
protected function setPageBuffer($page, $data, $append=false) {
if ($this->diskcache) {
if (!isset($this->pages[$page])) {
$this->pages[$page] = $this->getObjFilename('page'.$page);
}
$this->writeDiskCache($this->pages[$page], $data, $append);
} else {
if ($append) {
$this->pages[$page] .= $data;
} else {
$this->pages[$page] = $data;
}
}
if ($append AND isset($this->pagelen[$page])) {
$this->pagelen[$page] += strlen($data);
} else {
$this->pagelen[$page] = strlen($data);
}
}
/**
* Get page buffer content.
* @param int $page page number
* @return string page buffer content or false in case of error
* @access protected
* @since 4.5.000 (2008-12-31)
*/
protected function getPageBuffer($page) {
if ($this->diskcache) {
return $this->readDiskCache($this->pages[$page]);
} elseif (isset($this->pages[$page])) {
return $this->pages[$page];
}
return false;
}
/**
* Set image buffer content.
* @param string $image image key
* @param array $data image data
* @access protected
* @since 4.5.000 (2008-12-31)
*/
protected function setImageBuffer($image, $data) {
if ($this->diskcache) {
if (!isset($this->images[$image])) {
$this->images[$image] = $this->getObjFilename('image'.$image);
}
$this->writeDiskCache($this->images[$image], serialize($data));
} else {
$this->images[$image] = $data;
}
if (!in_array($image, $this->imagekeys)) {
$this->imagekeys[] = $image;
}
++$this->numimages;
}
/**
* Set image buffer content.
* @param string $image image key
* @param string $key image sub-key
* @param array $data image data
* @access protected
* @since 4.5.000 (2008-12-31)
*/
protected function setImageSubBuffer($image, $key, $data) {
if (!isset($this->images[$image])) {
$this->setImageBuffer($image, array());
}
if ($this->diskcache) {
$tmpimg = $this->getImageBuffer($image);
$tmpimg[$key] = $data;
$this->writeDiskCache($this->images[$image], serialize($tmpimg));
} else {
$this->images[$image][$key] = $data;
}
}
/**
* Get page buffer content.
* @param string $image image key
* @return string image buffer content or false in case of error
* @access protected
* @since 4.5.000 (2008-12-31)
*/
protected function getImageBuffer($image) {
if ($this->diskcache AND isset($this->images[$image])) {
return unserialize($this->readDiskCache($this->images[$image]));
} elseif (isset($this->images[$image])) {
return $this->images[$image];
}
return false;
}
/**
* Set font buffer content.
* @param string $font font key
* @param array $data font data
* @access protected
* @since 4.5.000 (2009-01-02)
*/
protected function setFontBuffer($font, $data) {
if ($this->diskcache) {
if (!isset($this->fonts[$font])) {
$this->fonts[$font] = $this->getObjFilename('font');
}
$this->writeDiskCache($this->fonts[$font], serialize($data));
} else {
$this->fonts[$font] = $data;
}
if (!in_array($font, $this->fontkeys)) {
$this->fontkeys[] = $font;
}
}
/**
* Set font buffer content.
* @param string $font font key
* @param string $key font sub-key
* @param array $data font data
* @access protected
* @since 4.5.000 (2009-01-02)
*/
protected function setFontSubBuffer($font, $key, $data) {
if (!isset($this->fonts[$font])) {
$this->setFontBuffer($font, array());
}
if ($this->diskcache) {
$tmpfont = $this->getFontBuffer($font);
$tmpfont[$key] = $data;
$this->writeDiskCache($this->fonts[$font], serialize($tmpfont));
} else {
$this->fonts[$font][$key] = $data;
}
}
/**
* Get font buffer content.
* @param string $font font key
* @return string font buffer content or false in case of error
* @access protected
* @since 4.5.000 (2009-01-02)
*/
protected function getFontBuffer($font) {
if ($this->diskcache AND isset($this->fonts[$font])) {
return unserialize($this->readDiskCache($this->fonts[$font]));
} elseif (isset($this->fonts[$font])) {
return $this->fonts[$font];
}
return false;
}
/**
* Move a page to a previous position.
* @param int $frompage number of the source page
* @param int $topage number of the destination page (must be less than $frompage)
* @return true in case of success, false in case of error.
* @access public
* @since 4.5.000 (2009-01-02)
*/
public function movePage($frompage, $topage) {
if (($frompage > $this->numpages) OR ($frompage <= $topage)) {
return false;
}
if ($frompage == $this->page) {
// close the page before moving it
$this->endPage();
}
// move all page-related states
$tmppage = $this->pages[$frompage];
$tmppagedim = $this->pagedim[$frompage];
$tmppagelen = $this->pagelen[$frompage];
$tmpintmrk = $this->intmrk[$frompage];
if (isset($this->footerpos[$frompage])) {
$tmpfooterpos = $this->footerpos[$frompage];
}
if (isset($this->footerlen[$frompage])) {
$tmpfooterlen = $this->footerlen[$frompage];
}
if (isset($this->transfmrk[$frompage])) {
$tmptransfmrk = $this->transfmrk[$frompage];
}
if (isset($this->PageAnnots[$frompage])) {
$tmpannots = $this->PageAnnots[$frompage];
}
if (isset($this->newpagegroup[$frompage])) {
$tmpnewpagegroup = $this->newpagegroup[$frompage];
}
for ($i = $frompage; $i > $topage; --$i) {
$j = $i - 1;
// shift pages down
$this->pages[$i] = $this->pages[$j];
$this->pagedim[$i] = $this->pagedim[$j];
$this->pagelen[$i] = $this->pagelen[$j];
$this->intmrk[$i] = $this->intmrk[$j];
if (isset($this->footerpos[$j])) {
$this->footerpos[$i] = $this->footerpos[$j];
} elseif (isset($this->footerpos[$i])) {
unset($this->footerpos[$i]);
}
if (isset($this->footerlen[$j])) {
$this->footerlen[$i] = $this->footerlen[$j];
} elseif (isset($this->footerlen[$i])) {
unset($this->footerlen[$i]);
}
if (isset($this->transfmrk[$j])) {
$this->transfmrk[$i] = $this->transfmrk[$j];
} elseif (isset($this->transfmrk[$i])) {
unset($this->transfmrk[$i]);
}
if (isset($this->PageAnnots[$j])) {
$this->PageAnnots[$i] = $this->PageAnnots[$j];
} elseif (isset($this->PageAnnots[$i])) {
unset($this->PageAnnots[$i]);
}
if (isset($this->newpagegroup[$j])) {
$this->newpagegroup[$i] = $this->newpagegroup[$j];
} elseif (isset($this->newpagegroup[$i])) {
unset($this->newpagegroup[$i]);
}
}
$this->pages[$topage] = $tmppage;
$this->pagedim[$topage] = $tmppagedim;
$this->pagelen[$topage] = $tmppagelen;
$this->intmrk[$topage] = $tmpintmrk;
if (isset($tmpfooterpos)) {
$this->footerpos[$topage] = $tmpfooterpos;
} elseif (isset($this->footerpos[$topage])) {
unset($this->footerpos[$topage]);
}
if (isset($tmpfooterlen)) {
$this->footerlen[$topage] = $tmpfooterlen;
} elseif (isset($this->footerlen[$topage])) {
unset($this->footerlen[$topage]);
}
if (isset($tmptransfmrk)) {
$this->transfmrk[$topage] = $tmptransfmrk;
} elseif (isset($this->transfmrk[$topage])) {
unset($this->transfmrk[$topage]);
}
if (isset($tmpannots)) {
$this->PageAnnots[$topage] = $tmpannots;
} elseif (isset($this->PageAnnots[$topage])) {
unset($this->PageAnnots[$topage]);
}
if (isset($tmpnewpagegroup)) {
$this->newpagegroup[$topage] = $tmpnewpagegroup;
} elseif (isset($this->newpagegroup[$topage])) {
unset($this->newpagegroup[$topage]);
}
// adjust outlines
$tmpoutlines = $this->outlines;
foreach ($tmpoutlines as $key => $outline) {
if (($outline['p'] >= $topage) AND ($outline['p'] < $frompage)) {
$this->outlines[$key]['p'] = $outline['p'] + 1;
} elseif ($outline['p'] == $frompage) {
$this->outlines[$key]['p'] = $topage;
}
}
// adjust links
$tmplinks = $this->links;
foreach ($tmplinks as $key => $link) {
if (($link[0] >= $topage) AND ($link[0] < $frompage)) {
$this->links[$key][0] = $link[0] + 1;
} elseif ($link[0] == $frompage) {
$this->links[$key][0] = $topage;
}
}
// adjust javascript
$tmpjavascript = $this->javascript;
global $jfrompage, $jtopage;
$jfrompage = $frompage;
$jtopage = $topage;
$this->javascript = preg_replace_callback('/this\.addField\(\'([^\']*)\',\'([^\']*)\',([0-9]+)/',
create_function('$matches', 'global $jfrompage, $jtopage;
$pagenum = intval($matches[3]) + 1;
if (($pagenum >= $jtopage) AND ($pagenum < $jfrompage)) {
$newpage = ($pagenum + 1);
} elseif ($pagenum == $jfrompage) {
$newpage = $jtopage;
} else {
$newpage = $pagenum;
}
--$newpage;
return "this.addField(\'".$matches[1]."\',\'".$matches[2]."\',".$newpage."";'), $tmpjavascript);
// return to last page
$this->lastPage(true);
return true;
}
/**
* Remove the specified page.
* @param int $page page to remove
* @return true in case of success, false in case of error.
* @access public
* @since 4.6.004 (2009-04-23)
*/
public function deletePage($page) {
if ($page > $this->numpages) {
return false;
}
// delete current page
unset($this->pages[$page]);
unset($this->pagedim[$page]);
unset($this->pagelen[$page]);
unset($this->intmrk[$page]);
if (isset($this->footerpos[$page])) {
unset($this->footerpos[$page]);
}
if (isset($this->footerlen[$page])) {
unset($this->footerlen[$page]);
}
if (isset($this->transfmrk[$page])) {
unset($this->transfmrk[$page]);
}
if (isset($this->PageAnnots[$page])) {
unset($this->PageAnnots[$page]);
}
if (isset($this->newpagegroup[$page])) {
unset($this->newpagegroup[$page]);
}
if (isset($this->pageopen[$page])) {
unset($this->pageopen[$page]);
}
// update remaining pages
for ($i = $page; $i < $this->numpages; ++$i) {
$j = $i + 1;
// shift pages
$this->pages[$i] = $this->pages[$j];
$this->pagedim[$i] = $this->pagedim[$j];
$this->pagelen[$i] = $this->pagelen[$j];
$this->intmrk[$i] = $this->intmrk[$j];
if (isset($this->footerpos[$j])) {
$this->footerpos[$i] = $this->footerpos[$j];
} elseif (isset($this->footerpos[$i])) {
unset($this->footerpos[$i]);
}
if (isset($this->footerlen[$j])) {
$this->footerlen[$i] = $this->footerlen[$j];
} elseif (isset($this->footerlen[$i])) {
unset($this->footerlen[$i]);
}
if (isset($this->transfmrk[$j])) {
$this->transfmrk[$i] = $this->transfmrk[$j];
} elseif (isset($this->transfmrk[$i])) {
unset($this->transfmrk[$i]);
}
if (isset($this->PageAnnots[$j])) {
$this->PageAnnots[$i] = $this->PageAnnots[$j];
} elseif (isset($this->PageAnnots[$i])) {
unset($this->PageAnnots[$i]);
}
if (isset($this->newpagegroup[$j])) {
$this->newpagegroup[$i] = $this->newpagegroup[$j];
} elseif (isset($this->newpagegroup[$i])) {
unset($this->newpagegroup[$i]);
}
if (isset($this->pageopen[$j])) {
$this->pageopen[$i] = $this->pageopen[$j];
} elseif (isset($this->pageopen[$i])) {
unset($this->pageopen[$i]);
}
}
// remove last page
unset($this->pages[$this->numpages]);
unset($this->pagedim[$this->numpages]);
unset($this->pagelen[$this->numpages]);
unset($this->intmrk[$this->numpages]);
if (isset($this->footerpos[$this->numpages])) {
unset($this->footerpos[$this->numpages]);
}
if (isset($this->footerlen[$this->numpages])) {
unset($this->footerlen[$this->numpages]);
}
if (isset($this->transfmrk[$this->numpages])) {
unset($this->transfmrk[$this->numpages]);
}
if (isset($this->PageAnnots[$this->numpages])) {
unset($this->PageAnnots[$this->numpages]);
}
if (isset($this->newpagegroup[$this->numpages])) {
unset($this->newpagegroup[$this->numpages]);
}
if (isset($this->pageopen[$this->numpages])) {
unset($this->pageopen[$this->numpages]);
}
--$this->numpages;
$this->page = $this->numpages;
// adjust outlines
$tmpoutlines = $this->outlines;
foreach ($tmpoutlines as $key => $outline) {
if ($outline['p'] > $page) {
$this->outlines[$key]['p'] = $outline['p'] - 1;
} elseif ($outline['p'] == $page) {
unset($this->outlines[$key]);
}
}
// adjust links
$tmplinks = $this->links;
foreach ($tmplinks as $key => $link) {
if ($link[0] > $page) {
$this->links[$key][0] = $link[0] - 1;
} elseif ($link[0] == $page) {
unset($this->links[$key]);
}
}
// adjust javascript
$tmpjavascript = $this->javascript;
global $jpage;
$jpage = $page;
$this->javascript = preg_replace_callback('/this\.addField\(\'([^\']*)\',\'([^\']*)\',([0-9]+)/',
create_function('$matches', 'global $jpage;
$pagenum = intval($matches[3]) + 1;
if ($pagenum >= $jpage) {
$newpage = ($pagenum - 1);
} elseif ($pagenum == $jpage) {
$newpage = 1;
} else {
$newpage = $pagenum;
}
--$newpage;
return "this.addField(\'".$matches[1]."\',\'".$matches[2]."\',".$newpage."";'), $tmpjavascript);
// return to last page
$this->lastPage(true);
return true;
}
/**
* Output a Table of Content Index (TOC).
* You can override this method to achieve different styles.
* @param int $page page number where this TOC should be inserted (leave empty for current page).
* @param string $numbersfont set the font for page numbers (please use monospaced font for better alignment).
* @param string $filler string used to fill the space between text and page number.
* @access public
* @author Nicola Asuni
* @since 4.5.000 (2009-01-02)
*/
public function addTOC($page='', $numbersfont='', $filler='.') {
$fontsize = $this->FontSizePt;
$fontfamily = $this->FontFamily;
$fontstyle = $this->FontStyle;
$w = $this->w - $this->lMargin - $this->rMargin;
$spacer = $this->GetStringWidth(' ') * 4;
$page_first = $this->getPage();
$lmargin = $this->lMargin;
$rmargin = $this->rMargin;
$x_start = $this->GetX();
if ($this->empty_string($numbersfont)) {
$numbersfont = $this->default_monospaced_font;
}
if ($this->empty_string($filler)) {
$filler = ' ';
}
if ($this->empty_string($page)) {
$gap = ' ';
} else {
$gap = '';
}
foreach ($this->outlines as $key => $outline) {
if ($this->rtl) {
$aligntext = 'R';
$alignnum = 'L';
} else {
$aligntext = 'L';
$alignnum = 'R';
}
if ($outline['l'] == 0) {
$this->SetFont($fontfamily, $fontstyle.'B', $fontsize);
} else {
$this->SetFont($fontfamily, $fontstyle, $fontsize - $outline['l']);
}
$indent = ($spacer * $outline['l']);
if ($this->rtl) {
$this->rMargin += $indent;
$this->x -= $indent;
} else {
$this->lMargin += $indent;
$this->x += $indent;
}
$link = $this->AddLink();
$this->SetLink($link, 0, $outline['p']);
// write the text
$this->Write(0, $outline['t'], $link, 0, $aligntext, false, 0, false, false, 0);
$this->SetFont($numbersfont, $fontstyle, $fontsize);
if ($this->empty_string($page)) {
$pagenum = $outline['p'];
} else {
// placemark to be replaced with the correct number
$pagenum = '{#'.($outline['p']).'}';
if (($this->CurrentFont['type'] == 'TrueTypeUnicode') OR ($this->CurrentFont['type'] == 'cidfont0')) {
$pagenum = '{'.$pagenum.'}';
}
}
$numwidth = $this->GetStringWidth($pagenum);
if ($this->rtl) {
$tw = $this->x - $this->lMargin;
} else {
$tw = $this->w - $this->rMargin - $this->x;
}
$fw = $tw - $numwidth - $this->GetStringWidth(' ');
$numfills = floor($fw / $this->GetStringWidth($filler));
if ($numfills > 0) {
$rowfill = str_repeat($filler, $numfills);
} else {
$rowfill = '';
}
if ($this->rtl) {
$pagenum = $pagenum.$gap.$rowfill.' ';
} else {
$pagenum = ' '.$rowfill.$gap.$pagenum;
}
// write the number
//$this->SetX($x_start);
$this->Cell($tw, 0, $pagenum, 0, 1, $alignnum, 0, $link, 0);
$this->SetX($x_start);
$this->lMargin = $lmargin;
$this->rMargin = $rmargin;
}
$page_last = $this->getPage();
$numpages = $page_last - $page_first + 1;
if (!$this->empty_string($page)) {
for($p = $page_first; $p <= $page_last; ++$p) {
// get page data
$temppage = $this->getPageBuffer($p);
for($n = 1; $n <= $this->numpages; ++$n) {
// update page numbers
$k = '{#'.$n.'}';
$ku = '{'.$k.'}';
$alias_a = $this->_escape($k);
$alias_au = $this->_escape('{'.$k.'}');
if ($this->isunicode) {
$alias_b = $this->_escape($this->UTF8ToLatin1($k));
$alias_bu = $this->_escape($this->UTF8ToLatin1($ku));
$alias_c = $this->_escape($this->utf8StrRev($k, false, $this->tmprtl));
$alias_cu = $this->_escape($this->utf8StrRev($ku, false, $this->tmprtl));
}
if ($n >= $page) {
$np = $n + $numpages;
} else {
$np = $n;
}
$ns = $this->formatTOCPageNumber($np);
$nu = $ns;
$sdiff = strlen($k) - strlen($ns) - 1;
$sdiffu = strlen($ku) - strlen($ns) - 1;
$sfill = str_repeat($filler, $sdiff);
$sfillu = str_repeat($filler, $sdiffu);
if ($this->rtl) {
$ns = $ns.' '.$sfill;
$nu = $nu.' '.$sfillu;
} else {
$ns = $sfill.' '.$ns;
$nu = $sfillu.' '.$nu;
}
$nu = $this->UTF8ToUTF16BE($nu, false);
$temppage = str_replace($alias_au, $nu, $temppage);
if ($this->isunicode) {
$temppage = str_replace($alias_bu, $nu, $temppage);
$temppage = str_replace($alias_cu, $nu, $temppage);
$temppage = str_replace($alias_b, $ns, $temppage);
$temppage = str_replace($alias_c, $ns, $temppage);
}
$temppage = str_replace($alias_a, $ns, $temppage);
}
// save changes
$this->setPageBuffer($p, $temppage);
}
// move pages
for ($i = 0; $i < $numpages; ++$i) {
$this->movePage($page_last, $page);
}
}
$this->SetFont($fontfamily, $fontstyle, $fontsize);
}
/**
* Stores a copy of the current TCPDF object used for undo operation.
* @access public
* @since 4.5.029 (2009-03-19)
*/
public function startTransaction() {
if (isset($this->objcopy)) {
// remove previous copy
$this->commitTransaction();
}
// clone current object
$this->objcopy = $this->objclone($this);
}
/**
* Delete the copy of the current TCPDF object used for undo operation.
* @access public
* @since 4.5.029 (2009-03-19)
*/
public function commitTransaction() {
if (isset($this->objcopy)) {
$this->objcopy->_destroy(true, true);
unset($this->objcopy);
}
}
/**
* This method allows to undo the latest transaction by returning the latest saved TCPDF object with startTransaction().
* @return TCPDF object.
* @access public
* @since 4.5.029 (2009-03-19)
*/
public function rollbackTransaction() {
if (isset($this->objcopy)) {
if (isset($this->objcopy->diskcache) AND $this->objcopy->diskcache) {
// truncate files to previous values
foreach ($this->objcopy->cache_file_lenght as $file => $lenght) {
$file = substr($file, 1);
$handle = fopen($file, 'r+');
ftruncate($handle, $lenght);
}
}
$this->_destroy(true, true);
return $this->objcopy;
}
return $this;
}
/**
* Creates a copy of a class object
* @param object $object class object to be cloned
* @return cloned object
* @access public
* @since 4.5.029 (2009-03-19)
*/
public function objclone($object) {
return @clone($object);
}
/**
* Determine whether a string is empty.
* @param srting $str string to be checked
* @return boolean true if string is empty
* @access public
* @since 4.5.044 (2009-04-16)
*/
public function empty_string($str) {
return (is_null($str) OR (is_string($str) AND (strlen($str) == 0)));
}
} // END OF TCPDF CLASS
}
//============================================================+
// END OF FILE
//============================================================+
?>