mirror of
https://github.com/EGroupware/egroupware.git
synced 2024-11-15 20:44:28 +01:00
1066 lines
40 KiB
PHP
Executable File
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['''] = "'";
|
|
return ( strtr( $given_html, $trans_table ) );
|
|
}
|
|
|
|
|
|
//ob_start("ob_pdml");
|
|
|
|
?>
|