\nGlobal\n";
print_r($this->subs);
foreach ($this->blocksubs as $key=>$val) {
print "Block: $key\n";
print_r($val);
}
print "";
}
//Assign variables
// ie. Assign(array('key'=>'val'));
// or Assign("key","val");
function Assign($key,$val=NULL) {
if (is_array($key)) {
foreach($key as $t_key=>$t_val) {
$this->DebugPrint("Assigning $t_key=>$t_val");
$this->cmnAssign(&$this->subs["keys"],&$this->subs["vals"],$t_key,$t_val);
}
} else {
$this->DebugPrint("Assigning $key=>$val");
$this->cmnAssign(&$this->subs["keys"],&$this->subs["vals"],$key,$val);
}
}
// $block is the name associated with the block.
// ie. AssignBlock("block",array('key'=>'val'));
// or AssignBlock("block","key","val");
function AssignBlock($block,$key,$val=NULL) {
if (!isset($this->blocksubs[$block])) {
$this->blocksubs[$block]["keys"][0]=array();
$this->blocksubs[$block]["vals"][0]=array();
$this->blocksubs[$block]["current"]=0;
$this->cmnAssign(
&$this->blocksubs[$block]["keys"][$this->blocksubs[$block]["current"]],
&$this->blocksubs[$block]["vals"][$this->blocksubs[$block]["current"]],
"DEFAULTS.BLOCK",$block);
$this->cmnAssign(
&$this->blocksubs[$block]["keys"][$this->blocksubs[$block]["current"]],
&$this->blocksubs[$block]["vals"][$this->blocksubs[$block]["current"]],
"DEFAULTS.ITERATION",1);
}
if (is_array($key)) { //assiciative array passed
foreach($key as $t_key=>$t_val) {
$this->DebugPrint("Assigning \"$block\" $t_key=>$t_val");
$this->cmnAssign(
&$this->blocksubs[$block]["keys"][$this->blocksubs[$block]["current"]],
&$this->blocksubs[$block]["vals"][$this->blocksubs[$block]["current"]],
".$t_key",$t_val);
}
} else { //plain old strings were passed
$this->DebugPrint("Assigning \"$block\" $key=>$val");
$this->cmnAssign(
&$this->blocksubs[$block]["keys"][$this->blocksubs[$block]["current"]],
&$this->blocksubs[$block]["vals"][$this->blocksubs[$block]["current"]],
".$key",$val);
}
}
//incremenmnt to next block iteration
function NextBlock($block) {
if (isset($this->blocksubs[$block])) {
$this->blocksubs[$block]["keys"][++$this->blocksubs[$block]["current"]]=array();
$this->blocksubs[$block]["vals"][$this->blocksubs[$block]["current"]]=array();
$this->cmnAssign(
&$this->blocksubs[$block]["keys"][$this->blocksubs[$block]["current"]],
&$this->blocksubs[$block]["vals"][$this->blocksubs[$block]["current"]],
"DEFAULTS.BLOCK",$block);
$this->cmnAssign(
&$this->blocksubs[$block]["keys"][$this->blocksubs[$block]["current"]],
&$this->blocksubs[$block]["vals"][$this->blocksubs[$block]["current"]],
"DEFAULTS.ITERATION",$this->blocksubs[$block]["current"]+1);
}
}
//Close PDF and finish flushing output to client
function Close() {
if ($this->debug)
ob_start();
$this->pdf->close();
if ($this->debug)
ob_end_clean();
}
//Parse through the XML once document and generate PDF (can be called multiple times)
//Returns XML Error messages if bad XML. otherwise false.
function Parse() {
$this->DebugAssign();
$error = XMLParseFile (&$this->parser, "pdf.xml", 0, "", 1,"UTF-8");
if (strcmp ($error, "")) {
return $error;
} else {
$this->WalkXML ("0"); //&$this->parser->structure, &$this->parser->positions);
return false;
}
}
//END OF use Public functions.. The rest are "internal use only" functions
//Recursive funtion to "WALK" the XML tree and call rendering routines
function WalkXML ($path) {
if (is_array($this->parser->structure[$path])) {
//Beginning Tag
$this->startElement($path);
//Check for looping
$count=1;
if (strcmp ($this->parser->structure[$path]["Tag"], "BLOCK") == 0) {
$this->page["block"]["name"]=$this->parser->structure[$path]["Attributes"]["NAME"];
for ($this->page["block"]["current"]=0;
$this->page["block"]["current"]<=$this->blocksubs[$this->page["block"]["name"]]["current"];
$this->page["block"]["current"]++) {
for ($element = 0; $element < $this->parser->structure[$path]["Elements"];$element++)
$this->WalkXML($path.",$element");
}
$this->page["block"]["name"]=""; //Clear out block;
} else { //not in a block. Normal parsing
//walk sub tags/content
for ($element = 0; $element < $this->parser->structure[$path]["Elements"];$element++)
$this->WalkXML($path.",$element");
}
//End Tag
$this->endElement($path);
} else {
//Content
//Find parent path
$parentpath = substr($path,0,strrpos($path,","));
$this->DebugPrint("PATH=".$path."-".strrpos($path,",")."-".$parentpath);
$data = trim(preg_replace("/(\ +|\n)/"," ",$this->parser->structure[$path]));
if (strlen($data)>0) {
$this->characterData($this->parser->structure[$parentpath]["Tag"]
,$this->parser->structure[$parentpath]["Attributes"]
,$data);
}
}
}
//set a font. $index of the font in the font stack (-1 for latest). if $force is true then
// this font's height will be forced for line height otherwise the max of the current
// lineheight and the fonts will be used.
function setfont($index=-1,$force=false) {
if ($index<0) {
$index = count($this->fontstack["Font"])-1;
}
//line height
if ($force) {
$this->page["fontlead"] = $this->fontstack["Size"][$index]*1.5;
} else {
$this->page["fontlead"] = max($this->page["fontlead"],$this->fontstack["Size"][$index]*1.5);
}
$this->DebugPrint ("fontlead=".$this->page["fontlead"]);
$this->pdf->setfont($this->fontstack["Font"][$index],
$this->fontstack["Size"][$index]);
}
//Add font to the font stack $fontname is the name of the registered font. $size is the point size
//if either parameter is null("" or 0) the previous fonts value will be used.
function addfont($fontname="",$size=0) {
array_push($this->fontstack["Font"],(
($fontname=="")
? $this->fontstack["Font"][count($this->fontstack["Size"])-1]
: $fontname)
);
array_push($this->fontstack["Size"],(
($size<1)
? $this->fontstack["Size"][count($this->fontstack["Size"])-1]
: $size)
);
return count($this->fontstack["Font"])-1;
}
//returns an indexed array of the Font name and Font size of the specified font in the index
function getfont($index=-1) {
if ($index<0) {
$index = count($this->fontstack["Font"])-1;
}
return array($this->fontstack["Font"][$index],$this->fontstack["Size"][$index]);
}
//removes the last font from the font stack
function removefont() {
array_pop($this->fontstack["Font"]);
array_pop($this->fontstack["Size"]);
}
//finds the bold version of the current (or specified) font and returns the name of the font
function getbold($index=-1) {
$font = $this->getfont($index);
$bolds = array(
'Helvetica'=>"Helvetica-Bold",
'Courier'=>"Courier-Bold",
'Times-Roman'=>"Times-Roman-Bold",
'Helvetica-Oblique'=>"Helvetica-BoldOblique",
'Courier-Oblique'=>"Courier-BoldOblique",
'Time-Roman-Italic'=>"Times-Roman-BoldItalic",
);
return (empty($bolds[$font[0]])?"":$bolds[$font[0]]);
}
//finds the italic version of the current (or specified) font and returns the name of the font
function getitalic($index=-1) {
$font = $this->getfont($index);
$italics = array(
'Helvetica'=>"Helvetica-Oblique",
'Courier'=>"Courier-Oblique",
'Times-Roman'=>"Times-Roman-Italic",
'Helvetica-Bold'=>"Helvetica-BoldOblique",
'Courier-Bold'=>"Courier-BoldOblique",
'Time-Roman-Bold'=>"Times-Roman-BoldItalic",
);
return (empty($italics[$font[0]])?"":$italics[$font[0]]);
}
//add (and replace) key/value pair in substitution arrays
function cmnAssign(&$keys,&$vals,$key,$val) {
$i=array_search("{".$key."}",$keys);
if ( ($i!==FALSE) && ($i!==NUll)) {
$this->DebugPrint("previous=".$i);
$keys[$i] = "{".$key."}";
$vals[$i] = $val;
} else {
array_push($keys,"{".$key."}");
array_push($vals,$val);
}
}
//Ends the last page
function cmnEndPage() {
if (!$this->page["closed"]) {
if($this->debug)
ob_start();
$this->pdf->endpage();
if ($this->debug)
ob_end_clean();
$this->page["closed"]=true;
}
}
//Ends last page (if one exists) and Begins a new page and resets curX and curY. sets font info.
function cmnNewPage() {
$this->cmnEndPage(); //End previous page if exists
//Current Position of cursor
$this->page["curY"] = $this->page["height"]-$this->page["margin"]; //Current Y position
$this->page["curX"] = $this->page["margin"]; //Current X position
//Begin the page
$this->DebugPrint("newpage=".$this->page["width"].",".$this->page["height"]);
$this->pdf->beginpage($this->page["width"],$this->page["height"]);
$this->page["closed"]=false;
if ($this->page["ticks"]) {
$this->cmnDrawTicks();
} else {
$this->setfont();
}
}
//Draw ticks on sides of page
function cmnDrawTicks() {
//Generate debuging ticks;
$c=0;
$this->pdf->setfont("Helvetica",8);
//left side
/* for ($i=$this->page["height"]; $i>0;$i-=10) {
if (!($c % 5)) {
$this->pdf->drawtext_xy($this->page["height"]-$i,10,$i-3);
}
if (!($c % 5)) {
$this->pdf->line(0,$i,10,$i);
} else {
$this->pdf->line(0,$i,7,$i);
}
$c++;
}*/
for ($i=0; $i<$this->page["height"]; $i+=10) {
if (!($c % 5)) {
$this->pdf->drawtext_xy($i,10,$i-3);
}
if (!($c % 5)) {
$this->pdf->line(0,$i,10,$i);
} else {
$this->pdf->line(0,$i,7,$i);
}
$c++;
}
//top edge
$c=0;
for ($i=0; $i<$this->page["width"]; $i+=10) {
if (!($c % 5)) {
$this->pdf->drawtext_xy($i,$i-6,$this->page["height"]-18);
}
if (!($c % 5)) {
$this->pdf->line($i,$this->page["height"],$i,$this->page["height"]-10);
} else {
$this->pdf->line($i,$this->page["height"],$i,$this->page["height"]-7);
}
$c++;
}
$this->setfont();
}
//handles the "beginning" of a tag and sets parameters appropriatly
function startElement($path) {
$attribs = &$this->parser->structure[$path]["Attributes"];
switch ($this->parser->structure[$path]["Tag"]) {
case 'PDF':
$this->DebugPrint("Begining of file");
$this->page["closed"]=true;
break;
case 'PAGE':
$this->page["fontlead"]=0;
$this->page["tab"] = 36; //A single 'tab'. For paragraph formatting.
//Margin spacing Default = 36 (half inch);
$this->page["margin"]=(empty($attribs["MARGIN"])?36:$attribs["MARGIN"]*72);
//Default Width
$this->page["width"]=(empty($attribs["WIDTH"])?612:$attribs["WIDTH"]*72);
//Default Height
$this->page["height"]=(empty($attribs["HEIGHT"])?792:$attribs["HEIGHT"]*72);
$this->page["ticks"]=($attribs["TICKS"]==1?true:false);
//Make new page
$this->cmnNewPage();
if (!empty($attribs["TOPMARGIN"])) {
$this->page["curY"]=$this->page["height"]-$attribs["TOPMARGIN"]*72;
}
break;
case 'PARA':
if (!empty($attribs["INDENT"])) {
$this->page["curX"]+=$this->page["tab"];
}
if (!empty($attribs["TAB"])) {
$this->page["left"]=$this->page["margin"]+$attribs["TAB"]*72;
$this->page["curX"]+=$attribs["TAB"]*72;
} else {
$this->page["left"]=$this->page["margin"];
}
$this->page["align"]=(empty($attribs["ALIGN"])?"left":strtolower($attribs["ALIGN"]));
break;
case 'BOLD':
$this->setfont($this->addfont($this->getbold()));
break;
case 'ITALIC':
$this->setfont($this->addfont($this->getitalic()));
break;
/*case 'FONTDEF':
$this->DebugPrint(
"face=".$attribs["FACE"]
." afm=".$attribs["AFM"]
." pfm=".$attribs["PFM"]
." outline=".$attribs["OUTLINE"]);
PDF_set_parameter($this->pdf,"FontAFM",$attribs["FACE"]."=".$attribs["AFM"]);
PDF_set_parameter($this->pdf,"FontOutline",$attribs["FACE"]."=".$attribs["OUTLINE"]);
break;*/
case 'FONT':
$this->DebugPrint("face=".$attribs["FACE"]." size=".$attribs["SIZE"]);
$this->setfont($this->addfont($attribs["FACE"],$attribs["SIZE"]));
break;
case 'TAB':
$this->page["curX"]=72 * $attribs["TAB"];
break;
case 'BR':
$this->page["curX"]=$this->page["left"];
$this->page["curY"]-=$this->page["fontlead"];
break;
case 'BREAK':
$this->cmnNewPage();
break;
default:
break;
}
}
//handles the "end" of a tag and (un)sets parameters appropriatly
function endElement($path) {
$attribs = &$this->parser->structure[$path]["Attributes"];
switch ($this->parser->structure[$path]["Tag"]) {
case 'PDF':
$this->DebugPrint("End of document");
$this->cmnEndPage();
break;
case 'PAGE':
//End the page and push to client.
// PDF_end_page($this->pdf);
break;
case 'PARA':
$this->page["curY"]-=$this->page["fontlead"]; //goto next line.
$this->setfont(-1,true); //reset font and fontlead (line height)
$this->page["curX"]=$this->page["margin"]; //Back to the left of the line
if (empty($attribs["NOBREAK"])) {
$this->page["curY"]-=$this->page["fontlead"]; //insert space between paragraphs
}
//$this->setfont(); //Set Default Font
break;
case 'FONT':
case 'ITALIC':
case 'BOLD':
$this->removefont(); //Remove Last Font
$this->setfont(); //Set Previous Font
break;
default:
break;
}
} //end Element
//handles the data between tags (the actual text)
function characterData($tag,$attribs,$data) {
$this->DebugPrint("CharData tag=$tag");
switch ($tag) {
case 'FONT': //Displays text in different font. Formatting done in beginElement
case 'BOLD': //Displays bold text. Formating done in beginElement
case 'ITALIC': //Displays italic text. Formating done in beginElement
//case 'LOOP': //incase loop tag around plain text in a para. (not preferred)
case 'NOSUB': //Do not substitute variables
case 'PARA': //Displays a paragraph
//Substitute variables
if (strcmp($tag,'NOSUB')<>0) {
$data = str_replace($this->subs["keys"],$this->subs["vals"],$data);
if (!empty($this->page["block"]["name"])) {
$this->DebugPrint("blocksub=".$this->page["block"]["name"]."-".$this->page["block"]["current"]);
$data = str_replace(
$this->blocksubs[$this->page["block"]["name"]]["keys"][$this->page["block"]["current"]],
$this->blocksubs[$this->page["block"]["name"]]["vals"][$this->page["block"]["current"]],
$data);
}
}
while (strlen($data)>0) {
//Check to see if we are past the bottom of the page.
// It's backward login due to PDF's 0 coord is at the bottom
if ($this->page["curY"] < ($this->page["margin"]+$this->page["fontlead"]) ) {
$this->DebugPrint("Ending Current Page");
$this->cmnNewPage();
$this->DebugPrint("Starting New Page");
}
$extra = $this->pdf->drawtext($data,
$this->page["curX"], //Left
$this->page["curY"], //Top
$this->page["width"]-$this->page["curX"]-$this->page["margin"], //Width
$this->page["fontlead"], //Height (one line)
$this->page["align"]); //Justification
$printed_num = strlen($data) - $extra;
$printed_text = substr($data, 0, $printed_num);
$printed_size = $this->pdf->textwidth($printed_text);
$this->DebugPrint(
"X=".$this->page["curX"]
." Y=".$this->page["curY"]
." extra=".$extra
." end=".$printed_size
." W=".$printed_size);
$this->DebugPrint("text=".$printed_text);
$printed_size+=$this->page["curX"];
if (method_exists($this->pdf, "get_textX")) {
$this->DebugPrint("textx=".$this->pdf->get_textX()
." PS=".$printed_size);
$printed_size = $this->pdf->get_textX();
}
if ($this->pdf->textwidth($data)
> ($this->page["width"]-$this->page["margin"]-$this->page["curX"])) { //Text wider than page
$this->page["curX"]=$this->page["left"]; //go back to beginning of line
$this->page["curY"]-=$this->page["fontlead"]; //Go down one line
$this->setfont(-1,true); //Reset line height (also resets fontlead)
} else { //fits on one line get current "X" position
$this->page["curX"]=$printed_size;
}
//update $data with unprinted text
//if ($extra>0) {
$data = substr($data,(strlen($data)-$extra));
//};
} //while
break;
default:
break;
}
}
} //End Class PDFTemplate