<?
require_once 'Pdf/FontCollection.php';
require_once 'Pdf/Objects.php';
require_once 'Pdf/Document.php';
require_once 'Pdf/Text.php';
define('PDF_O_DIVIDER'," ");
class Pdf {
var $objects;
var $document;
var $fonts;
var $messages;
var $text;
/**
* a flag to say if a document is to be encrypted or not
*/
var $encrypted=0;
/**
* the ancryption key for the encryption of all the document content (structure is not encrypted)
*/
var $encryptionKey='';
/**
* store the stack for the transaction commands, each item in here is a record of the values of all the
* variables within the class, so that the user can rollback at will (from each 'start' command)
* note that this includes the objects array, so these can be large.
*/
var $checkpoint = '';
function Pdf ($pageSize=array(0,0,612,792)) {
$this->objects = &new PdfObjects();
$this->document = &new PdfDocument($this->objects,$pageSize);
$this->fonts = &new PdfFontCollection($this->objects);
// also initialize the font families that are known about already
$this->fonts->setFontFamily('init');
$this->text = &new PdfText($this->fonts,$this->objects,$this);
}
/**
* used to add messages for use in debugging
*/
function addMessage($message){
$this->messages .= $message."\n";
}
/**
* set the encryption of the document
* can be used to turn it on and/or set the passwords which it will have.
* also the functions that the user will have are set here, such as print, modify, add
*/
function setEncryption($userPass='',$ownerPass='',$pc=array()){
$p=bindec(11000000);
$options = array(
'print'=>4
,'modify'=>8
,'copy'=>16
,'add'=>32
);
foreach($pc as $k=>$v){
if ($v && isset($options[$k])){
$p+=$options[$k];
} else if (isset($options[$v])){
$p+=$options[$v];
}
}
// implement encryption on the document
if ($this->objects->arc4_objnum == 0){
// then the block does not exist already, add it.
if (strlen($ownerPass)==0){
$ownerPass=$userPass;
}
$this->objects->createObject('PdfObjectEncryption', array('user'=>$userPass,'owner'=>$ownerPass,'p'=>$p));
}
}
/**
* return the pdf stream as a string returned from the function
*/
function output($debug=0){
if ($debug){
// turn compression off
$this->options['compression']=false;
}
if (isset($this->objects->arc4_objnum) && $this->objects->arc4_objnum>0){
$this->ARC4_init($this->objects->encryptionKey);
}
// $this->checkAllHere();
$xref=array();
$content="%PDF-1.3\n%òóÏÓ\n";
// $content="%PDF-1.3\n";
$pos=strlen($content);
unset($this->objects->objects[0]);
$root = $this->objects->catalogId->getId();
foreach($this->objects->objects as $k=>$v){
$c = (boolean)@$this->options['compression'];
if (is_object($v)) {
$cont = $v->out($c);
$content .= $cont;
}
}
array_unshift($this->objects->xref,$pos);
$content.="\nxref\n0 ".(sizeof($this->objects->xref))."\n0000000000 65535 f \n";
$pos = 0;
foreach($this->objects->xref as $p){
$pos += $p;
$content .= str_pad($pos, 10, "0", STR_PAD_LEFT)." 00000 n \n";
}
$content.="\ntrailer\n << /Size ".(sizeof($this->objects->xref))."\n /Root ".$root." 0 R\n /Info ".$this->objects->infoObject->getId()." 0 R\n";
// if encryption has been applied to this document then add the marker for this dictionary
if (isset($this->objects->arc4_objnum) && $this->objects->arc4_objnum > 0){
$content .= "/Encrypt ".$this->objects->arc4_objnum." 0 R\n";
}
/*
* comment it now....
if (strlen($this->fileIdentifier)){
$content .= "/ID[<".$this->fileIdentifier."><".$this->fileIdentifier.">]\n";
}
*/
$content .= " >>\nstartxref\n".$pos."\n%%EOF\n";
return $content;
}
/**
* output the pdf code, streaming it to the browser
* the relevant headers are set so that hopefully the browser will recognise it
*/
function stream($options=''){
// setting the options allows the adjustment of the headers
// values at the moment are:
// 'Content-Disposition'=>'filename' - sets the filename, though not too sure how well this will
// work as in my trial the browser seems to use the filename of the php file with .pdf on the end
// 'Accept-Ranges'=>1 or 0 - if this is not set to 1, then this header is not included, off by default
// this header seems to have caused some problems despite tha fact that it is supposed to solve
// them, so I am leaving it off by default.
// 'compress'=> 1 or 0 - apply content stream compression, this is on (1) by default
if (!is_array($options)){
$options=array();
}
if ( isset($options['compress']) && $options['compress']==0){
$tmp = $this->output(1);
} else {
$tmp = $this->output();
}
header("Content-type: application/pdf");
header("Content-Length: ".strlen(ltrim($tmp)));
$fileName = (isset($options['Content-Disposition'])?$options['Content-Disposition']:"file.pdf");
header("Content-Disposition: inline; filename=".$fileName);
if (isset($options['Accept-Ranges']) && $options['Accept-Ranges']==1){
header("Accept-Ranges: ".strlen(ltrim($tmp)));
}
echo ltrim($tmp);
}
/**
* a few functions which should allow the document to be treated transactionally.
*/
function transaction($action){
switch ($action){
case 'start':
// store all the data away into the checkpoint variable
$data = get_object_vars($this);
$this->checkpoint = $data;
unset($data);
break;
case 'commit':
if (is_array($this->checkpoint) && isset($this->checkpoint['checkpoint'])){
$tmp = $this->checkpoint['checkpoint'];
$this->checkpoint = $tmp;
unset($tmp);
} else {
$this->checkpoint='';
}
break;
case 'rewind':
// do not destroy the current checkpoint, but move us back to the state then, so that we can try again
if (is_array($this->checkpoint)){
// can only abort if were inside a checkpoint
$tmp = $this->checkpoint;
foreach ($tmp as $k=>$v){
if ($k != 'checkpoint'){
$this->$k=$v;
}
}
unset($tmp);
}
break;
case 'abort':
if (is_array($this->checkpoint)){
// can only abort if were inside a checkpoint
$tmp = $this->checkpoint;
foreach ($tmp as $k=>$v){
$this->$k=$v;
}
unset($tmp);
}
break;
}
}
/**
*
* Interface for PdfText;
*
**/
function addText($x,$y,$size,$text,$angle=0,$wordSpaceAdjust=0){
$this->text->addText($x,$y,$size,$text,$angle,$wordSpaceAdjust);
}
function getTextWidth($size,$text){
return $this->text->getTextWidth($size,$text);
}
function addTextWrap($x,$y,$width,$size,$text,$justification='left',$angle=0,$test=0){
return $this->text->addTextWrap($x,$y,$width,$size,$text,$justification,$angle,$test);
}
/**
*
* Interface for PdfFontCollection;
*
**/
function selectFont($font,$options='') {
return $this->fonts->select($font,$options);
}
function setCurrentFont($textState=false) {
return $this->fonts->setCurrentFont($textState=false);
}
function getFontHeight($size){
return $this->fonts->getFontHeight($size);
}
function getFontDecender($size){
return $this->fonts->getFontDecender($size);
}
/**
*
* Interface for PdfObjects;
*
**/
function addObject($id,$options='add'){
return $this->objects->addObject($id,$options);
}
function openObject () {
return $this->objects->openObject();
}
function reopenObject($id){
return $this->objects->reopenObject($id);
}
function closeObject(){
return $this->objects->closeObject();
}
function stopObject($id){
return $this->objects->stopObject($id);
}
function addContent($content){
$this->objects->addContent($content);
}
/**
*
* Interface for PdfDocument;
*
**/
function addLink($url,$x0,$y0,$x1,$y1){
$this->document->addLink($url,$x0,$y0,$x1,$y1);
}
function addInternalLink($label,$x0,$y0,$x1,$y1){
$this->document->addInternalLink($label,$x0,$y0,$x1,$y1);
}
function addDestination($label,$style,$a=0,$b=0,$c=0){
$this->document->addDestination($label,$style,$a,$b,$c);
}
function openHere($style,$a=0,$b=0,$c=0){
$this->document->openHere($style,$a,$b,$c);
}
function newPage($insert=false,$id=0,$pos='after'){
return $this->document->newPage($insert,$id,$pos);
}
function saveState () {
$this->document->saveState();
}
function restoreState () {
$this->document->restoreState();
}
function setColor ($r,$g,$b,$force=false) {
$this->document->styles->setColor($r,$g,$b,$force);
}
function setStrokeColor ($r,$g,$b,$force=false) {
$this->document->styles->setStrokeColor($r,$g,$b,$force);
}
function setLineStyle ($w=1,$c='',$j='',$d='',$p=0) {
$this->document->styles->setLine($w,$c,$j,$d,$p);
}
function addInfo($label,$value=0) {
$this->document->addInfo($label,$value);
}
function setPreferences($label,$value=0){
$this->document->setPreferences($label,$value);
}
/**
* Adds image using callbacks
*
* @param string filename can be either local or remote file or image contents
* @param int x position
* @param int y position
* @param int width
* @param int height
* @param mixed options
* @param string forced type, valid image parser should exists
* @param bolean img is file or image stream
* @return ref image object
* @access public
*/
function &addImage ($img,$x,$y,$w=0,$h=0,$options=array(),$fType=false,$isFile=true){
$options['x'] = $x;
$options['y'] = $y;
$options['w'] = $w;
$options['h'] = $h;
return $this->objects->currentContents->addImage($img,$options,$fType=false,$isFile=true);
}
function &addImageGd (&$img,$x,$y,$w=0,$h=0,$quality=100,$options=array()){
$options['x'] = $x;
$options['y'] = $y;
$options['w'] = $w;
$options['h'] = $h;
$options['quality'] = $quality;
return $this->objects->currentContents->addImage(&$img,$options,$fType='GD',$isFile=false);
}
function addJpegFromFile($img,$x,$y,$w=0,$h=0){
$this->addImage($img,$x,$y,$w,$h);
}
function addPngFromFile($img,$x,$y,$w=0,$h=0){
$this->addImage($img,$x,$y,$w,$h);
}
/**
*
* Interface for PdfDocument/PdfGeometry;
*
**/
function line ($x1,$y1,$x2,$y2){
$this->document->geometry->line($x1,$y1,$x2,$y2);
}
function curve($x0,$y0,$x1,$y1,$x2,$y2,$x3,$y3) {
$this->document->geometry->curve($x0,$y0,$x1,$y1,$x2,$y2,$x3,$y3);
}
function partEllipse($x0,$y0,$astart,$afinish,$r1,$r2=0,$angle=0,$nSeg=8){
$this->document->geometry->partEllipse($x0,$y0,$astart,$afinish,$r1,$r2,$angle,$nSeg);
}
function filledEllipse($x0,$y0,$r1,$r2=0,$angle=0,$nSeg=8,$astart=0,$afinish=360){
$this->document->geometry->filledEllipse($x0,$y0,$r1,$r2,$angle,$nSeg,$astart,$afinish);
}
function ellipse($x0,$y0,$r1,$r2=0,$angle=0,$nSeg=8,$astart=0,$afinish=360,$close=1,$fill=0){
$this->document->geometry->ellipse($x0,$y0,$r1,$r2,$angle,$nSeg,$astart,$afinish,$close,$fill);
}
function polygon($p,$np,$f=0){
$this->document->geometry->polygon($p,$np,$f);
}
function filledRectangle($x1,$y1,$width,$height){
$this->document->geometry->filledRectangle($x1,$y1,$width,$height);
}
function rectangle($x1,$y1,$width,$height){
$this->document->geometry->filledRectangle($x1,$y1,$width,$height);
}
}
?>