egroupware/phpgwapi/inc/fpdf/pdml.php

1066 lines
40 KiB
PHP
Executable File

<?php
class PDML extends FPDF {
var $parserState=0;
var $final; // final PDF output.
var $inPage = false; // are we in a page yet?
var $anchors = array(); // map anchor names to internal ids.
var $href = array(); // stack of current URLs to link to. (shift/unshift)
var $href_style = array(); // should links be underlined blue? 0/1
var $font_color = array("000000"); // current text color
var $font_size = array("10"); // current font size
var $font_face = array("Helvetica"); // current font name
var $font_mask = array(); // keep track of stuff so that </font> works right.
var $B = 0;
var $I = 0;
var $U = 0;
var $left_margin = array( 28.35 ); // 1cm
var $right_margin = array( 28.35 ); // 1cm
var $bottom_margin = array( 28.35 ); // 1cm
var $div_x = array();
var $div_y = array();
var $cell_info; // stuff to keep around until a </cell> shows up
var $cell_text; // text to put in a cell.
var $script; // stuff to put in our script.
var $header='';
var $footer='';
var $parserBreak; // when you want to break parsing, put a stop word here.
var $multicol = array(); // stack of columns. you never know.
/* Rotation extension. Should go away with 1.6 */
var $angle=0;
function Rotate($angle,$x=-1,$y=-1)
{
if($x==-1)
$x=$this->x;
if($y==-1)
$y=$this->y;
if($this->angle!=0)
$this->_out('Q');
$this->angle=$angle;
if($angle!=0)
{
$angle*=M_PI/180;
$c=cos($angle);
$s=sin($angle);
$cx=$x*$this->k;
$cy=($this->h-$y)*$this->k;
$this->_out(sprintf('q %.5f %.5f %.5f %.5f %.2f %.2f cm 1 0 0 1 %.2f %.2f cm',$c, $s,-$s,$c,$cx,$cy,-$cx,-$cy));
}
}
function _endpage()
{
if($this->angle!=0)
{
$this->angle=0;
$this->_out('Q');
}
parent::_endpage();
}
/* End of Rotation Extension */
/* Ellipse extension. Should go away with 1.6 */
function Circle($x,$y,$r,$style='') {
$this->Ellipse($x,$y,$r,$r,$style);
}
function Ellipse($x,$y,$rx,$ry,$style='D') {
if($style=='F')
$op='f';
elseif($style=='FD' or $style=='DF')
$op='B';
else
$op='S';
$lx=4/3*(M_SQRT2-1)*$rx;
$ly=4/3*(M_SQRT2-1)*$ry;
$k=$this->k;
$h=$this->h;
$this->_out(sprintf('%.2f %.2f m %.2f %.2f %.2f %.2f %.2f %.2f c',
($x+$rx)*$k,($h-$y)*$k,
($x+$rx)*$k,($h-($y-$ly))*$k,
($x+$lx)*$k,($h-($y-$ry))*$k,
$x*$k,($h-($y-$ry))*$k));
$this->_out(sprintf('%.2f %.2f %.2f %.2f %.2f %.2f c',
($x-$lx)*$k,($h-($y-$ry))*$k,
($x-$rx)*$k,($h-($y-$ly))*$k,
($x-$rx)*$k,($h-$y)*$k));
$this->_out(sprintf('%.2f %.2f %.2f %.2f %.2f %.2f c',
($x-$rx)*$k,($h-($y+$ly))*$k,
($x-$lx)*$k,($h-($y+$ry))*$k,
$x*$k,($h-($y+$ry))*$k));
$this->_out(sprintf('%.2f %.2f %.2f %.2f %.2f %.2f c %s',
($x+$lx)*$k,($h-($y+$ry))*$k,
($x+$rx)*$k,($h-($y+$ly))*$k,
($x+$rx)*$k,($h-$y)*$k,
$op));
}
/* End of Ellipse Extension */
/* Javascript extension. That may stick here a while. */
var $javascript;
var $n_js;
function IncludeJS($script) {
$this->javascript.=$script;
}
function _putjavascript() {
$this->_newobj();
$this->n_js=$this->n;
$this->_out('<<');
$this->_out('/Names [(EmbeddedJS) '.($this->n+1).' 0 R ]');
$this->_out('>>');
$this->_out('endobj');
$this->_newobj();
$this->_out('<<');
$this->_out('/S /JavaScript');
$this->_out('/JS '.$this->_textstring($this->javascript));
$this->_out('>>');
$this->_out('endobj');
}
function _putresources() {
parent::_putresources();
if (!empty($this->javascript)) {
$this->_putjavascript();
}
$this->_putbookmarks();
}
function _putcatalog() {
parent::_putcatalog();
if (isset($this->javascript)) {
$this->_out('/Names <</JavaScript '.($this->n_js).' 0 R>>');
}
if(count($this->outlines)>0)
{
$this->_out('/Outlines '.$this->OutlineRoot.' 0 R');
$this->_out('/PageMode /UseOutlines');
}
}
/* End of Javascript Extension */
/* Bookmark Extension. Should go away with 1.6 */
var $outlines=array();
var $OutlineRoot;
function Bookmark($txt,$level=0,$y=0)
{
if($y==-1)
$y=$this->GetY();
$this->outlines[]=array('t'=>$txt,'l'=>$level,'y'=>$y,'p'=>$this->PageNo());
}
function _putbookmarks()
{
$nb=count($this->outlines);
if($nb==0)
return;
$lru=array();
$level=0;
foreach($this->outlines as $i=>$o)
{
if($o['l']>0)
{
$parent=$lru[$o['l']-1];
//Set parent and last pointers
$this->outlines[$i]['parent']=$parent;
$this->outlines[$parent]['last']=$i;
if($o['l']>$level)
{
//Level increasing: set first pointer
$this->outlines[$parent]['first']=$i;
}
}
else
$this->outlines[$i]['parent']=$nb;
if($o['l']<=$level and $i>0)
{
//Set prev and next pointers
$prev=$lru[$o['l']];
$this->outlines[$prev]['next']=$i;
$this->outlines[$i]['prev']=$prev;
}
$lru[$o['l']]=$i;
$level=$o['l'];
}
//Outline items
$n=$this->n+1;
foreach($this->outlines as $i=>$o)
{
$this->_newobj();
$this->_out('<</Title '.$this->_textstring($o['t']));
$this->_out('/Parent '.($n+$o['parent']).' 0 R');
if(isset($o['prev']))
$this->_out('/Prev '.($n+$o['prev']).' 0 R');
if(isset($o['next']))
$this->_out('/Next '.($n+$o['next']).' 0 R');
if(isset($o['first']))
$this->_out('/First '.($n+$o['first']).' 0 R');
if(isset($o['last']))
$this->_out('/Last '.($n+$o['last']).' 0 R');
$this->_out(sprintf('/Dest [%d 0 R /XYZ 0 %.2f null]',1+2*$o['p'],($this->h-$o['y'])*$this->k));
$this->_out('/Count 0>>');
$this->_out('endobj');
}
//Outline root
$this->_newobj();
$this->OutlineRoot=$this->n;
$this->_out('<</Type /Outlines /First '.$n.' 0 R');
$this->_out('/Last '.($n+$lru[0]).' 0 R>>');
$this->_out('endobj');
}
/* End of Bookmark Extension */
function ParsePDML($pdml) {
// default font.
$this->SetFont($this->font_face[0],'',$this->font_size[0]);
// apply margins
$this->SetRightMargin($this->right_margin[0]);
$this->SetLeftMargin($this->left_margin[0]);
// bottom margin
$this->SetAutoPageBreak(true, $this->bottom_margin[0]);
$this->AliasNbPages('&pagecount;');
$this->_parsePDML($pdml);
//return $this->final;
}
function Header() {
$this->_parsePDML($this->header);
}
function Footer() {
$this->_parsePDML($this->footer);
}
function AcceptPageBreak() {
if (count($this->multicol>0)) {
// we need: starting y0, col_width, col_spacing, columns, height, break=page/line
list($x0, $y0, $width, $height, $spacing, $break, $cols, $current) = $this->multicol[0];
if ($current<$cols-1) {
// next column
$current++;
$this->multicol[0][7] = $current;
$x = $x0 + $current * $width;
$this->SetLeftMargin($x);
$this->SetX($x);
$this->SetY($y0);
return false;
} else {
// ok. we need to break.
$this->SetLeftMargin($x0);
$this->SetX($x0);
$this->multicol[0][7] = 0; // $current
if ($break=="line") {
$y0 += $spacing + $height; // y0
$this->multicol[0][1] = $y0;
$this->SetAutoPageBreak(true, $this->hPt - ( $y0 + $height));
$this->SetY($y0);
//$this->Write(10,"This sux0rs.");
return false;
} else {
// page break.
return true;
}
}
} else {
// no multi-column tag. do the normal thing.
return true;
}
}
function _parsePDML($pdml) {
$a = preg_split('/<([^<]*)\/?>/U',$pdml,-1,PREG_SPLIT_DELIM_CAPTURE);
foreach ($a as $i=>$e) {
if ($this->parserBreak) {
if ($i%2==0) {
$this->ProcessText($e);
continue;
}
if (strcasecmp($e,$this->parserBreak)) {
$this->ProcessText('<'.$e.'>');
continue;
}
}
if ($i%2==0) {
// text
$this->ProcessText(pdml_entity_decode(preg_replace(
array(
'/\s+/',
'/&pagenumber;/',
'/&title;/',
'/&author;/',
'/&subject;/',
'/&creator;/'
),
array(
' ',
$this->PageNo(),
$this->title,
$this->author,
$this->subject,
$this->creator
) ,$e)));
} else {
// tag
if ($e{0}=='/') {
$this->CloseTag(strtoupper(substr($e,1)));
} else {
$a2 = explode(' ',$e,2);
$tag = strtoupper(array_shift($a2));
$e = substr($e, strlen($tag)+1);
// stolen from http://www.cs.sfu.ca/~cameron/REX.html
// bugified into uselessness. It's the intent that counts. right?
$NameStrt = "[A-Za-z_:]|[^\\x00-\\x7F]";
$NameChar = "[A-Za-z0-9_:.-]|[^\\x00-\\x7F]";
$Name = "(?:$NameStrt)(?:$NameChar)*";
$S = "[ \\n\\t\\r]+";
$AttValSE = "\"[^\"]*\"|'[^']*'|[^ \\n\\t\\r]+";
$ElemTagCE = "($Name)(?:$S)?=(?:$S)?($AttValSE)";
$attr = array();
preg_match_all("/$ElemTagCE/", $e, $matches, PREG_SET_ORDER);
for ($i=0;$i<count($matches);$i++) {
$val = $matches[$i][2];
if ((($val{0}=='"') and (substr($val,-1)=='"')) or
(($val{0}=="'") and (substr($val,-1)=="'")) ){
$val = substr($val, 1, strlen($val)-2);
}
$attr[strtoupper($matches[$i][1])] = $val;
}
$this->OpenTag($tag,$attr);
}
}
}
}
function ProcessText($text) {
switch ($this->parserState) {
case 0:
case 1:
case 2:
// ignore text/whitespace in there.
break;
case 3:
$this->SetTitle($text);
break;
case 4:
$this->SetSubject($text);
break;
case 5:
$this->SetAuthor($text);
break;
case 6:
$this->SetKeywords($text);
break;
case 51:
$this->cell_text .= $text;
break;
case 10:
$this->script .= $text;
break;
case 63:
$this->header .= $text;
break;
case 64:
$this->footer .= $text;
break;
default:
// ignore pure whitespace
if (preg_match("/^[ \\n\\t\\r]*$/",$text)) break;
// auto-create a page if needed.
if (!$this->inPage) {
$this->inPage = true;
$this->AddPage();
}
// write stuff.
// do we have a link to use?
if (sizeof($this->href)>0) {
if ($this->href_style[0]) {
$this->SetTextColor(0,0,255);
$this->_setStyle('U',true, true);
}
$this->Write($this->font_size[0],$text,$this->href[0]);
if ($this->href_style[0]) {
$this->_setStyle('U', $this->U>0, true);
$this->_setFontColor($this->font_color[0]);
}
} else {
$this->Write($this->font_size[0],$text);
}
}
}
function OpenTag($tag, $attr) {
switch ($tag) {
case "PDML":
$this->_enforceState(0,1);
break;
case "HEAD":
$this->_enforceState(1,2);
break;
case "TITLE":
$this->_enforceState(2,3);
break;
case "SUBJECT":
$this->_enforceState(2,4);
break;
case "AUTHOR":
$this->_enforceState(2,5);
break;
case "KEYWORDS":
$this->_enforceState(2,6);
break;
case "SCRIPT":
$this->_enforceState(2,10);
$this->script='';
$this->parserBreak="/script";
break;
case "BODY":
$this->_enforceState(1,50);
break;
case "PAGE":
$this->_enforceState(50,50);
$o = "P";
if (isset($attr["ORIENTATION"])) {
if (strcasecmp($attr["ORIENTATION"],"LANDSCAPE")==0) {
$o = "L";
}
}
$this->inPage=true;
$this->AddPage($o);
break;
case "BR":
// no enforcement.
if ($this->parserState==51) {
$this->cell_text.="\n";
break;
}
if (isset($attr["HEIGHT"])) {
$h=$this->_getUnit($attr["HEIGHT"], $this->font_size[0]);
$this->Ln($h);
} else {
$this->Ln($this->font_size[0]);
}
break;
case "A":
$this->_enforceState(50,50);
// name=
if (isset($attr["NAME"])) {
// local anchor
$name = $attr["NAME"];
if (!isset($this->anchors[$name])) {
$this->anchors[$name] = $this->AddLink();
}
$this->SetLink($this->anchors[$name], -1);
}
// href=
if (isset($attr["HREF"])) {
$href = $attr["HREF"];
if ($href[0]=='#') {
// local anchor
$href = substr($href,1);
if (!isset($this->anchors[$href])) {
$this->anchors[$href] = $this->AddLink();
}
array_unshift ($this->href, $this->anchors[$href]);
} else {
array_unshift ($this->href, $href);
}
// we should set style to underlined blue. XXX
array_unshift ($this->href_style, isset($attr["HIDDEN"])?0:1);
}
break;
case "B":
case "I":
case "U":
$this->_enforceState(50,50);
$this->_setStyle($tag, true);
break;
case "FONT":
$this->_enforceState(50,50);
$mask = 0;
if (isset($attr["COLOR"])) {
// hex-encoded color. no space for long color name list.
$color = $attr["COLOR"];
if ($color[0]=="#") { $color = substr($color,1); }
array_unshift($this->font_color, $color);
$this->_setFontColor($color);
$mask |= 1;
}
if (isset($attr["SIZE"])) {
$size = $this->_getUnit($attr["SIZE"], $this->font_size[0]);
array_unshift($this->font_size, $size);
$this->SetFontSize($size);
$mask |= 2;
}
if (isset($attr["FACE"])) {
$face = $attr["FACE"];
array_unshift($this->font_face, $face);
$this->_setFontFace($face);
$mask |= 4;
}
array_unshift($this->font_mask, $mask);
break;
case "IMG":
$this->_enforceState(50,50);
if (!isset($attr["SRC"])) break;
$src = $attr["SRC"];
$x = $this->GetX();
if (isset($attr["LEFT"])) {
$x = $this->_getUnit($attr["LEFT"], $this->wPt);
}
$y = $this->GetY();
if (isset($attr["TOP"])) {
$y = $this->_getUnit($attr["TOP"], $this->hPt);
}
$width = 0;
if (isset($attr["WIDTH"])) {
$width = $this->_getUnit($attr["WIDTH"], $this->wPt);
}
$height = 0;
if (isset($attr["HEIGHT"])) {
$height = $this->_getUnit($attr["HEIGHT"], $this->hPt);
}
// try to resolve src a bit if necessary.
if (!file_exists($src)) {
$src1 = getenv("DOCUMENT_ROOT")."/".$src;
$src2 = dirname(getenv("SCRIPT_FILENAME"))."/".$src;
if (file_exists($src1)) {
$src = $src1;
} elseif (file_exists($src2)) {
$src = $src2;
}
}
if (sizeof($this->href)>0) {
$this->Image($src, $x, $y, $width, $height, '', $this->href[0]);
} else {
$this->Image($src, $x, $y, $width, $height);
}
break;
case "LINE":
$this->_enforceState(50,50);
$x1 = $this->GetX();
$y1 = $this->GetY();
if (isset($attr["FROM"])) {
list($x1,$y1) = explode(',',$attr["FROM"]);
$x1 = $this->_getUnit($x1, $this->wPt);
$y1 = $this->_getUnit($y1, $this->hPt);
}
$x2 = $this->wPt;
$y2 = $y1;
if (isset($attr["TO"])) {
list($x2,$y2) = explode(',',$attr["TO"]);
$x2 = $this->_getUnit($x2, $this->wPt);
$y2 = $this->_getUnit($y2, $this->hPt);
}
$color = "000000";
if (isset($attr["COLOR"])) {
$color = $attr["COLOR"];
if ($color[0]=="#") { $color = substr($color,1); }
}
$lwidth = $this->_getUnit("0.2mm");
if (isset($attr["WIDTH"])) {
$lwidth = $this->_getUnit($attr["WIDTH"], $lwidth);
}
$this->_setLineColor($color);
$this->SetLineWidth($lwidth);
$this->Line($x1,$y1,$x2,$y2);
break;
case "RECT":
$this->_enforceState(50,50);
$x1 = $this->GetX();
$y1 = $this->GetY();
if (isset($attr["FROM"])) {
list($x1,$y1) = explode(',',$attr["FROM"]);
$x1 = $this->_getUnit($x1, $this->wPt);
$y1 = $this->_getUnit($y1, $this->hPt);
}
if (isset($attr["LEFT"])) {
$x1 = $this->_getUnit($attr["LEFT"], $this->wPt);
}
if (isset($attr["TOP"])) {
$y1 = $this->_getUnit($attr["TOP"], $this->hPt);
}
$width= 144;
$height= 36;
if (isset($attr["TO"])) {
list($x2,$y2) = explode(',',$attr["TO"]);
$x2 = $this->_getUnit($x2, $this->wPt);
$y2 = $this->_getUnit($y2, $this->hPt);
$width = $x2-$x1+1;
$height = $y2-$y1+1;
}
if (isset($attr["WIDTH"])) {
$width = $this->_getUnit($attr["WIDTH"], $this->wPt);
}
if (isset($attr["HEIGHT"])) {
$height = $this->_getUnit($attr["HEIGHT"], $this->hPt);
}
$style="";
$color = "000000";
if (isset($attr["COLOR"])) {
$color = $attr["COLOR"];
if ($color[0]=="#") { $color = substr($color,1); }
$style.="D";
}
$fill = "000000";
if (isset($attr["FILLCOLOR"])) {
$fill = $attr["FILLCOLOR"];
if ($fill[0]=="#") { $fill = substr($fill,1); }
$style.="F";
}
$border = $this->_getUnit("0.2mm");
if (isset($attr["BORDER"])) {
$border = $this->_getUnit($attr["BORDER"], $border);
}
$this->_setLineColor($color);
$this->SetLineWidth($border);
$this->_setRectColor($fill);
$this->Rect($x1,$y1,$width,$height,$style);
break;
case "CIRCLE":
case "ELLIPSE":
$this->_enforceState(50,50);
$x1 = $this->GetX();
$y1 = $this->GetY();
if (isset($attr["FROM"])) {
list($x1,$y1) = explode(',',$attr["FROM"]);
$x1 = $this->_getUnit($x1, $this->wPt);
$y1 = $this->_getUnit($y1, $this->hPt);
}
$radius = $this->_getAttrUnit($this->font_size[0], $attr, "RADIUS", $this->font_size[0]);
$xradius = $this->_getAttrUnit($radius, $attr, "XRADIUS", $this->font_size[0]);
$yradius = $this->_getAttrUnit($radius, $attr, "YRADIUS", $this->font_size[0]);
$style="";
$color = "000000";
if (isset($attr["COLOR"])) {
$color = $attr["COLOR"];
if ($color[0]=="#") { $color = substr($color,1); }
$style.="D";
}
$fill = "000000";
if (isset($attr["FILLCOLOR"])) {
$fill = $attr["FILLCOLOR"];
if ($fill[0]=="#") { $fill = substr($fill,1); }
$style.="F";
}
$border = $this->_getUnit("0.2mm");
if (isset($attr["BORDER"])) {
$border = $this->_getUnit($attr["BORDER"], $border);
}
$this->_setLineColor($color);
$this->SetLineWidth($border);
$this->_setRectColor($fill);
$this->Ellipse($x1, $y1, $xradius, $yradius, $style);
break;
case "DIV":
$this->_enforceState(50,50);
$save_x = $this->GetX();
$x = $this->_getAttrUnit($save_x, $attr, "LEFT", $this->wPt);
$save_y = $this->GetY();
$y = $this->_getAttrUnit($save_y, $attr, "TOP", $this->hPt);
$width = $this->_getAttrUnit($this->wPt-$x, $attr, "WIDTH", $this->wPt);
$height = $this->_getAttrUnit($this->hPt-$y, $attr, "HEIGHT", $this->hPt);
if ($x == $save_x) { $save_x+=$width; }
array_unshift($this->left_margin, $x);
array_unshift($this->right_margin, $this->wPt-$width-$x);
array_unshift($this->div_x, $save_x);
array_unshift($this->div_y, $save_y);
// draw a rect, just to debug. XXX
$style="";
$color = "000000";
if (isset($attr["COLOR"])) {
$color = $attr["COLOR"];
if ($color[0]=="#") { $color = substr($color,1); }
$style.="D";
}
$fill = "000000";
if (isset($attr["FILLCOLOR"])) {
$fill = $attr["FILLCOLOR"];
if ($fill[0]=="#") { $fill = substr($fill,1); }
$style.="F";
}
$border = $this->_getUnit("0.2mm");
if (isset($attr["BORDER"])) {
$border = $this->_getUnit($attr["BORDER"], $border);
}
$this->_setLineColor($color);
$this->SetLineWidth($border);
$this->_setRectColor($fill);
if ($style) {
$this->Rect($x,$y,$width,$height,$style);
}
$this->SetLeftMargin($this->left_margin[0]);
$this->SetRightMargin($this->right_margin[0]);
$this->SetXY($x,$y);
break;
case "MULTICELL":
case "CELL":
$this->_enforceState(50,51);
$save_x = $this->GetX();
$x = $this->_getAttrUnit($save_x, $attr, "LEFT", $this->wPt);
$save_y = $this->GetY();
$y = $this->_getAttrUnit($save_y, $attr, "TOP", $this->hPt);
$width = $this->_getAttrUnit($this->wPt-$x, $attr, "WIDTH", $this->wPt);
// used by multicell only
$inter = $this->_getAttrUnit($this->font_size[0], $attr, "INTER", $this->font_size[0]);
// used by cell only.
$height = $this->_getAttrUnit($this->font_size[0], $attr, "HEIGHT", $this->font_size[0]);
$next = 0;
if (isset($attr["NEXT"])) {
$n = strtolower($attr["NEXT"]);
switch ($n) {
case "right": $next =0; break;
case "bottom": case "down": $next=2; break;
case "break": $next = 1; break;
}
}
$style="";
$color = "000000";
if (isset($attr["COLOR"])) {
$color = $attr["COLOR"];
if ($color[0]=="#") { $color = substr($color,1); }
$style.="D";
}
$fillflag = 0;
$fill = "000000";
if (isset($attr["FILLCOLOR"])) {
$fill = $attr["FILLCOLOR"];
if ($fill[0]=="#") { $fill = substr($fill,1); }
$fillflag=1;
}
$borderflag=0;
$border = $this->_getUnit("0.2mm");
if (isset($attr["BORDER"])) {
$border = $this->_getUnit($attr["BORDER"], $border);
$borderflag=1;
}
$align = ($tag=="CELL")?"L":"J";
if (isset($attr["ALIGN"])) {
$al = strtolower($attr["ALIGN"]);
switch ($al){
case "left": $align="L"; break;
case "center": $align="C"; break;
case "right": $align="R"; break;
case "justify": $align="J"; break;
}
}
$this->_setLineColor($color);
$this->SetLineWidth($border);
$this->_setRectColor($fill);
$this->SetXY($x,$y);
$this->cell_info = array($width, $inter, $height, $borderflag, $align, $fillflag, $next);
$this->cell_text = '';
break;
case "ROTATE":
$angle=45;
if (isset($attr["ANGLE"])) {
$angle = $attr["ANGLE"];
}
$x=-1;
$y=-1;
if (isset($attr["CENTER"])) {
list($x,$y) = explode(',',$attr["CENTER"]);
$x = $this->_getUnit($x, $this->wPt);
$y = $this->_getUnit($y, $this->hPt);
}
$this->rotate($angle, $x, $y);
break;
case "BOOKMARK":
if (!isset($attr["TITLE"])) break;
$title = $attr["TITLE"];
$level = 0;
if (isset($attr["LEVEL"])) {
$level = $attr["LEVEL"];
}
$top = -1;
if (isset($attr["TOP"])) {
$top = $this->_getUnit($attr["TOP"], $this->hPt);
}
$this->Bookmark($title, $level, $top);
break;
case "HEADER":
$this->_enforceState(50,63);
$this->header='';
$this->parserBreak='/header';
break;
case "FOOTER":
$this->_enforceState(50,64);
$this->footer='';
$this->parserBreak='/footer';
break;
case "COLUMN":
$this->_enforceState(50,50);
$save_x = $this->GetX();
$x = $this->_getAttrUnit($save_x, $attr, "LEFT", $this->wPt);
$save_y = $this->GetY();
$y = $this->_getAttrUnit($save_y, $attr, "TOP", $this->hPt);
$count = 2;
if (isset($attr["COUNT"])) {
$count = (int)$attr["COUNT"];
}
$width = $this->_getAttrUnit(($this->wPt-$x)/$count, $attr, "WIDTH", $this->wPt);
$height = $this->_getAttrUnit($this->hPt-$y, $attr, "HEIGHT", $this->hPt);
$spacing = $this->_getAttrUnit($this->font_size[0], $attr, "SPACING", $this->font_size[0]);
$break = "page";
if (isset($attr["BREAK"]) and (strtolower($attr["BREAK"])=="line")) {
$break = "line";
}
// store stuff for acceptPageBreak to make sense of, and stuff we're saving
array_unshift($this->multicol, array($x,$y,$width,$height,$spacing, $break, $count, 0, ));
array_unshift($this->left_margin, $x);
array_unshift($this->bottom_margin, $this->hPt-($y+$height));
// set margins to make things work.
$this->SetLeftMargin($this->left_margin[0]);
$this->SetAutoPageBreak(true, $this->bottom_margin[0]);
break;
}
}
function CloseTag($tag) {
switch ($tag) {
case "PDML":
$this->_enforceState(1,0);
//$this->final = $this->Output("","S");
break;
case "HEAD":
$this->_enforceState(2,1);
break;
case "TITLE":
$this->_enforceState(3,2);
break;
case "SUBJECT":
$this->_enforceState(4,2);
break;
case "AUTHOR":
$this->_enforceState(5,2);
break;
case "KEYWORDS":
$this->_enforceState(6,2);
break;
case "SCRIPT":
$this->_enforceState(10,2);
$this->IncludeJS($this->script);
$this->parserBreak='';
break;
case "BODY":
$this->Close();
$this->_enforceState(50,1);
break;
case "A":
array_shift ($this->href);
array_shift ($this->href_style);
// we should remove underline + blue.
break;
case "B":
case "I":
case "U":
$this->_setStyle($tag, false);
break;
case "FONT":
if (sizeof($this->font_mask)>0) {
$mask = array_shift($this->font_mask);
}
if (($mask&1)==1) {
array_shift($this->font_color);
$this->_setFontColor($this->font_color[0]);
}
if (($mask&2)==2) {
array_shift($this->font_size);
$this->SetFontSize($this->font_size[0]);
}
if (($mask&4)==4) {
array_shift($this->font_face);
$this->_setFontFace($this->font_face[0]);
}
break;
case "DIV":
if (sizeof($this->div_x)<1) break;
array_shift($this->left_margin);
array_shift($this->right_margin);
$this->SetLeftMargin($this->left_margin[0]);
$this->SetRightMargin($this->right_margin[0]);
$this->SetXY($this->div_x[0],$this->div_y[0]);
array_shift($this->div_x);
array_shift($this->div_y);
break;
case "MULTICELL":
$this->_enforceState(51,50);
// auto-create a page if needed.
if (!$this->inPage) {
$this->inPage = true;
$this->AddPage();
}
$this->MultiCell(
$this->cell_info[0],
$this->cell_info[1],
$this->cell_text,
$this->cell_info[3],
$this->cell_info[4],
$this->cell_info[5]);
break;
case "CELL":
$this->_enforceState(51,50);
// auto-create a page if needed.
if (!$this->inPage) {
$this->inPage = true;
$this->AddPage();
}
// redo the link logic here. blah.
if (sizeof($this->href)>0) {
if ($this->href_style[0]) {
$this->SetTextColor(0,0,255);
$this->_setStyle('U',true, true);
}
$this->Cell(
$this->cell_info[0],
$this->cell_info[2],
$this->cell_text,
$this->cell_info[3],
$this->cell_info[6],
$this->cell_info[4],
$this->cell_info[5],
$this->href[0]);
if ($this->href_style[0]) {
$this->_setStyle('U', $this->U>0, true);
$this->_setFontColor($this->font_color[0]);
}
} else {
$this->Cell(
$this->cell_info[0],
$this->cell_info[2],
$this->cell_text,
$this->cell_info[3],
$this->cell_info[6],
$this->cell_info[4],
$this->cell_info[5]);
}
break;
case "ROTATE":
$this->rotate(0);
break;
case "HEADER":
$this->_enforceState(63,50);
$this->parserBreak='';
break;
case "FOOTER":
$this->_enforceState(64,50);
$this->parserBreak='';
break;
case "COLUMN":
$this->_enforceState(50,50);
array_shift($this->multicol);
array_shift($this->left_margin);
array_shift($this->bottom_margin);
$this->SetLeftMargin($this->left_margin[0]);
$this->SetAutoPageBreak(true, $this->bottom_margin[0]);
break;
}
}
function _enforceState($from, $to) {
if ($this->parserState!=$from) {
error_log("unexpected tag (from $from to $to, but state=".$this->parserState.")");
//$this->Write("[unexpected tag (from $from to $to)]");
}
$this->parserState=$to;
}
// default is pt. works good for fonts, so yeah.
function _getUnit($str, $max=100) {
$str=rtrim($str);
$v=(float)$str;
if (substr($str,-1)=='%') {
return $max * $v / 100;
}
$u=substr($str,-2);
switch ($u) {
default:
case "pt": $m=1; break;
case "mm": $m=72/25.4; break;
case "cm": $m=72/2.54; break;
case "in": $m=72; break;
}
return $v * $m;
}
function _getAttrUnit($default, $attr, $name, $ref) {
if (isset($attr[$name])) {
return $this->_getUnit($attr[$name], $ref);
} else {
return $default;
}
}
function _setStyle($tag, $enable, $forget=0) {
$this->$tag+=($enable ? 1: -1);
$style='';
foreach(array('B','I','U') as $s) {
if ($this->$s>0) {
$style.=$s;
}
}
$this->SetFont('',$style);
if ($forget) {
$this->$tag-=($enable ? 1: -1);
}
}
function _setFontFace($face) {
$style='';
foreach(array('B','I','U') as $s) {
if ($this->$s>0) {
$style.=$s;
}
}
$this->SetFont($face,$style);
}
function _setFontColor($hex) {
$this->SetTextColor(
hexdec(substr($hex,0,2)),
hexdec(substr($hex,2,2)),
hexdec(substr($hex,4,2)));
}
function _setLineColor($hex) {
$this->SetDrawColor(
hexdec(substr($hex,0,2)),
hexdec(substr($hex,2,2)),
hexdec(substr($hex,4,2)));
}
function _setRectColor($hex) {
$this->SetFillColor(
hexdec(substr($hex,0,2)),
hexdec(substr($hex,2,2)),
hexdec(substr($hex,4,2)));
}
}
function ob_pdml($buffer) {
$pdml = new PDML('P','pt','A4'); // P and A4 should be customizable. XXX
$pdml->compress=0;
$pdml->ParsePDML($buffer);
$s = $pdml->Output("","S");
Header('Content-Type: application/pdf');
Header('Content-Length: '.strlen($s));
Header('Content-disposition: inline; filename=doc.pdf');
return $s;
}
function pdml_entity_decode( $given_html, $quote_style = ENT_QUOTES ) {
$trans_table = array_flip(array_merge(
get_html_translation_table( HTML_SPECIALCHARS, $quote_style ),
get_html_translation_table( HTML_ENTITIES, $quote_style) ));
$trans_table['&#39;'] = "'";
return ( strtr( $given_html, $trans_table ) );
}
//ob_start("ob_pdml");
?>