📄 class.pdf.php
字号:
<?php
/**
* Cpdf
*
* http://www.ros.co.nz/pdf
*
* A PHP class to provide the basic functionality to create a pdf document without
* any requirement for additional modules.
*
* Note that they companion class CezPdf can be used to extend this class and dramatically
* simplify the creation of documents.
*
* IMPORTANT NOTE
* there is no warranty, implied or otherwise with this software.
*
* LICENCE
* This code has been placed in the Public Domain for all to enjoy.
*
* @author Wayne Munro <pdf@ros.co.nz>
* @version 009
* @package Cpdf
*/
class Cpdf {
/**
* the current number of pdf objects in the document
*/
var $numObj=0;
/**
* this array contains all of the pdf objects, ready for final assembly
*/
var $objects = array();
/**
* the objectId (number within the objects array) of the document catalog
*/
var $catalogId;
/**
* array carrying information about the fonts that the system currently knows about
* used to ensure that a font is not loaded twice, among other things
*/
var $fonts=array();
/**
* a record of the current font
*/
var $currentFont='';
/**
* the current base font
*/
var $currentBaseFont='';
/**
* the number of the current font within the font array
*/
var $currentFontNum=0;
/**
*
*/
var $currentNode;
/**
* object number of the current page
*/
var $currentPage;
/**
* object number of the currently active contents block
*/
var $currentContents;
/**
* number of fonts within the system
*/
var $numFonts=0;
/**
* current colour for fill operations, defaults to inactive value, all three components should be between 0 and 1 inclusive when active
*/
var $currentColour=array('r'=>-1,'g'=>-1,'b'=>-1);
/**
* current colour for stroke operations (lines etc.)
*/
var $currentStrokeColour=array('r'=>-1,'g'=>-1,'b'=>-1);
/**
* current style that lines are drawn in
*/
var $currentLineStyle='';
/**
* an array which is used to save the state of the document, mainly the colours and styles
* it is used to temporarily change to another state, the change back to what it was before
*/
var $stateStack = array();
/**
* number of elements within the state stack
*/
var $nStateStack = 0;
/**
* number of page objects within the document
*/
var $numPages=0;
/**
* object Id storage stack
*/
var $stack=array();
/**
* number of elements within the object Id storage stack
*/
var $nStack=0;
/**
* an array which contains information about the objects which are not firmly attached to pages
* these have been added with the addObject function
*/
var $looseObjects=array();
/**
* array contains infomation about how the loose objects are to be added to the document
*/
var $addLooseObjects=array();
/**
* the objectId of the information object for the document
* this contains authorship, title etc.
*/
var $infoObject=0;
/**
* number of images being tracked within the document
*/
var $numImages=0;
/**
* an array containing options about the document
* it defaults to turning on the compression of the objects
*/
var $options=array('compression'=>1);
/**
* the objectId of the first page of the document
*/
var $firstPageId;
/**
* used to track the last used value of the inter-word spacing, this is so that it is known
* when the spacing is changed.
*/
var $wordSpaceAdjust=0;
/**
* the object Id of the procset object
*/
var $procsetObjectId;
/**
* store the information about the relationship between font families
* this used so that the code knows which font is the bold version of another font, etc.
* the value of this array is initialised in the constuctor function.
*/
var $fontFamilies = array();
/**
* track if the current font is bolded or italicised
*/
var $currentTextState = '';
/**
* messages are stored here during processing, these can be selected afterwards to give some useful debug information
*/
var $messages='';
/**
* the ancryption array for the document encryption is stored here
*/
var $arc4='';
/**
* the object Id of the encryption information
*/
var $arc4_objnum=0;
/**
* the file identifier, used to uniquely identify a pdf document
*/
var $fileIdentifier='';
/**
* 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='';
/**
* array which forms a stack to keep track of nested callback functions
*/
var $callback = array();
/**
* the number of callback functions in the callback array
*/
var $nCallback = 0;
/**
* store label->id pairs for named destinations, these will be used to replace internal links
* done this way so that destinations can be defined after the location that links to them
*/
var $destinations = array();
/**
* 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 = '';
/**
* class constructor
* this will start a new document
* @var array array of 4 numbers, defining the bottom left and upper right corner of the page. first two are normally zero.
*/
function Cpdf ($pageSize=array(0,0,612,792)){
$this->newDocument($pageSize);
// also initialize the font families that are known about already
$this->setFontFamily('init');
// $this->fileIdentifier = md5('xxxxxxxx'.time());
}
/**
* Document object methods (internal use only)
*
* There is about one object method for each type of object in the pdf document
* Each function has the same call list ($id,$action,$options).
* $id = the object ID of the object, or what it is to be if it is being created
* $action = a string specifying the action to be performed, though ALL must support:
* 'new' - create the object with the id $id
* 'out' - produce the output for the pdf object
* $options = optional, a string or array containing the various parameters for the object
*
* These, in conjunction with the output function are the ONLY way for output to be produced
* within the pdf 'file'.
*/
/**
*destination object, used to specify the location for the user to jump to, presently on opening
*/
function o_destination($id,$action,$options=''){
if ($action!='new'){
$o =& $this->objects[$id];
}
switch($action){
case 'new':
$this->objects[$id]=array('t'=>'destination','info'=>array());
$tmp = '';
switch ($options['type']){
case 'XYZ':
case 'FitR':
$tmp = ' '.$options['p3'].$tmp;
case 'FitH':
case 'FitV':
case 'FitBH':
case 'FitBV':
$tmp = ' '.$options['p1'].' '.$options['p2'].$tmp;
case 'Fit':
case 'FitB':
$tmp = $options['type'].$tmp;
$this->objects[$id]['info']['string']=$tmp;
$this->objects[$id]['info']['page']=$options['page'];
}
break;
case 'out':
$tmp = $o['info'];
$res="\n".$id." 0 obj\n".'['.$tmp['page'].' 0 R /'.$tmp['string']."]\nendobj\n";
return $res;
break;
}
}
/**
* set the viewer preferences
*/
function o_viewerPreferences($id,$action,$options=''){
if ($action!='new'){
$o =& $this->objects[$id];
}
switch ($action){
case 'new':
$this->objects[$id]=array('t'=>'viewerPreferences','info'=>array());
break;
case 'add':
foreach($options as $k=>$v){
switch ($k){
case 'HideToolbar':
case 'HideMenubar':
case 'HideWindowUI':
case 'FitWindow':
case 'CenterWindow':
case 'NonFullScreenPageMode':
case 'Direction':
$o['info'][$k]=$v;
break;
}
}
break;
case 'out':
$res="\n".$id." 0 obj\n".'<< ';
foreach($o['info'] as $k=>$v){
$res.="\n/".$k.' '.$v;
}
$res.="\n>>\n";
return $res;
break;
}
}
/**
* define the document catalog, the overall controller for the document
*/
function o_catalog($id,$action,$options=''){
if ($action!='new'){
$o =& $this->objects[$id];
}
switch ($action){
case 'new':
$this->objects[$id]=array('t'=>'catalog','info'=>array());
$this->catalogId=$id;
break;
case 'outlines':
case 'pages':
case 'openHere':
$o['info'][$action]=$options;
break;
case 'viewerPreferences':
if (!isset($o['info']['viewerPreferences'])){
$this->numObj++;
$this->o_viewerPreferences($this->numObj,'new');
$o['info']['viewerPreferences']=$this->numObj;
}
$vp = $o['info']['viewerPreferences'];
$this->o_viewerPreferences($vp,'add',$options);
break;
case 'out':
$res="\n".$id." 0 obj\n".'<< /Type /Catalog';
foreach($o['info'] as $k=>$v){
switch($k){
case 'outlines':
$res.="\n".'/Outlines '.$v.' 0 R';
break;
case 'pages':
$res.="\n".'/Pages '.$v.' 0 R';
break;
case 'viewerPreferences':
$res.="\n".'/ViewerPreferences '.$o['info']['viewerPreferences'].' 0 R';
break;
case 'openHere':
$res.="\n".'/OpenAction '.$o['info']['openHere'].' 0 R';
break;
}
}
$res.=" >>\nendobj";
return $res;
break;
}
}
/**
* object which is a parent to the pages in the document
*/
function o_pages($id,$action,$options=''){
if ($action!='new'){
$o =& $this->objects[$id];
}
switch ($action){
case 'new':
$this->objects[$id]=array('t'=>'pages','info'=>array());
$this->o_catalog($this->catalogId,'pages',$id);
break;
case 'page':
if (!is_array($options)){
// then it will just be the id of the new page
$o['info']['pages'][]=$options;
} else {
// then it should be an array having 'id','rid','pos', where rid=the page to which this one will be placed relative
// and pos is either 'before' or 'after', saying where this page will fit.
if (isset($options['id']) && isset($options['rid']) && isset($options['pos'])){
$i = array_search($options['rid'],$o['info']['pages']);
if (isset($o['info']['pages'][$i]) && $o['info']['pages'][$i]==$options['rid']){
// then there is a match
// make a space
switch ($options['pos']){
case 'before':
$k = $i;
break;
case 'after':
$k=$i+1;
break;
default:
$k=-1;
break;
}
if ($k>=0){
for ($j=count($o['info']['pages'])-1;$j>=$k;$j--){
$o['info']['pages'][$j+1]=$o['info']['pages'][$j];
}
$o['info']['pages'][$k]=$options['id'];
}
}
}
}
break;
case 'procset':
$o['info']['procset']=$options;
break;
case 'mediaBox':
$o['info']['mediaBox']=$options; // which should be an array of 4 numbers
break;
case 'font':
$o['info']['fonts'][]=array('objNum'=>$options['objNum'],'fontNum'=>$options['fontNum']);
break;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -