📄 class.pdf.php
字号:
if ($set && isset($this->fonts[$fontName])){
// so if for some reason the font was not set in the last one then it will not be selected
$this->currentBaseFont=$fontName;
// the next line means that if a new font is selected, then the current text state will be
// applied to it as well.
$this->setCurrentFont();
}
return $this->currentFontNum;
}
/**
* sets up the current font, based on the font families, and the current text state
* note that this system is quite flexible, a <b><i> font can be completely different to a
* <i><b> font, and even <b><b> will have to be defined within the family to have meaning
* This function is to be called whenever the currentTextState is changed, it will update
* the currentFont setting to whatever the appropriatte family one is.
* If the user calls selectFont themselves then that will reset the currentBaseFont, and the currentFont
* This function will change the currentFont to whatever it should be, but will not change the
* currentBaseFont.
*
* @access private
*/
function setCurrentFont(){
if (strlen($this->currentBaseFont)==0){
// then assume an initial font
$this->selectFont('./fonts/Helvetica.afm');
}
$cf = substr($this->currentBaseFont,strrpos($this->currentBaseFont,'/')+1);
if (strlen($this->currentTextState)
&& isset($this->fontFamilies[$cf])
&& isset($this->fontFamilies[$cf][$this->currentTextState])){
// then we are in some state or another
// and this font has a family, and the current setting exists within it
// select the font, then return it
$nf = substr($this->currentBaseFont,0,strrpos($this->currentBaseFont,'/')+1).$this->fontFamilies[$cf][$this->currentTextState];
$this->selectFont($nf,'',0);
$this->currentFont = $nf;
$this->currentFontNum = $this->fonts[$nf]['fontNum'];
} else {
// the this font must not have the right family member for the current state
// simply assume the base font
$this->currentFont = $this->currentBaseFont;
$this->currentFontNum = $this->fonts[$this->currentFont]['fontNum'];
}
}
/**
* function for the user to find out what the ID is of the first page that was created during
* startup - useful if they wish to add something to it later.
*/
function getFirstPageId(){
return $this->firstPageId;
}
/**
* add content to the currently active object
*
* @access private
*/
function addContent($content){
$this->objects[$this->currentContents]['c'].=$content;
}
/**
* sets the colour for fill operations
*/
function setColor($r,$g,$b,$force=0){
if ($r>=0 && ($force || $r!=$this->currentColour['r'] || $g!=$this->currentColour['g'] || $b!=$this->currentColour['b'])){
$this->objects[$this->currentContents]['c'].="\n".sprintf('%.3f',$r).' '.sprintf('%.3f',$g).' '.sprintf('%.3f',$b).' rg';
$this->currentColour=array('r'=>$r,'g'=>$g,'b'=>$b);
}
}
/**
* sets the colour for stroke operations
*/
function setStrokeColor($r,$g,$b,$force=0){
if ($r>=0 && ($force || $r!=$this->currentStrokeColour['r'] || $g!=$this->currentStrokeColour['g'] || $b!=$this->currentStrokeColour['b'])){
$this->objects[$this->currentContents]['c'].="\n".sprintf('%.3f',$r).' '.sprintf('%.3f',$g).' '.sprintf('%.3f',$b).' RG';
$this->currentStrokeColour=array('r'=>$r,'g'=>$g,'b'=>$b);
}
}
/**
* draw a line from one set of coordinates to another
*/
function line($x1,$y1,$x2,$y2){
$this->objects[$this->currentContents]['c'].="\n".sprintf('%.3f',$x1).' '.sprintf('%.3f',$y1).' m '.sprintf('%.3f',$x2).' '.sprintf('%.3f',$y2).' l S';
}
/**
* draw a bezier curve based on 4 control points
*/
function curve($x0,$y0,$x1,$y1,$x2,$y2,$x3,$y3){
// in the current line style, draw a bezier curve from (x0,y0) to (x3,y3) using the other two points
// as the control points for the curve.
$this->objects[$this->currentContents]['c'].="\n".sprintf('%.3f',$x0).' '.sprintf('%.3f',$y0).' m '.sprintf('%.3f',$x1).' '.sprintf('%.3f',$y1);
$this->objects[$this->currentContents]['c'].= ' '.sprintf('%.3f',$x2).' '.sprintf('%.3f',$y2).' '.sprintf('%.3f',$x3).' '.sprintf('%.3f',$y3).' c S';
}
/**
* draw a part of an ellipse
*/
function partEllipse($x0,$y0,$astart,$afinish,$r1,$r2=0,$angle=0,$nSeg=8){
$this->ellipse($x0,$y0,$r1,$r2,$angle,$nSeg,$astart,$afinish,0);
}
/**
* draw a filled ellipse
*/
function filledEllipse($x0,$y0,$r1,$r2=0,$angle=0,$nSeg=8,$astart=0,$afinish=360){
return $this->ellipse($x0,$y0,$r1,$r2=0,$angle,$nSeg,$astart,$afinish,1,1);
}
/**
* draw an ellipse
* note that the part and filled ellipse are just special cases of this function
*
* draws an ellipse in the current line style
* centered at $x0,$y0, radii $r1,$r2
* if $r2 is not set, then a circle is drawn
* nSeg is not allowed to be less than 2, as this will simply draw a line (and will even draw a
* pretty crappy shape at 2, as we are approximating with bezier curves.
*/
function ellipse($x0,$y0,$r1,$r2=0,$angle=0,$nSeg=8,$astart=0,$afinish=360,$close=1,$fill=0){
if ($r1==0){
return;
}
if ($r2==0){
$r2=$r1;
}
if ($nSeg<2){
$nSeg=2;
}
$astart = deg2rad((float)$astart);
$afinish = deg2rad((float)$afinish);
$totalAngle =$afinish-$astart;
$dt = $totalAngle/$nSeg;
$dtm = $dt/3;
if ($angle != 0){
$a = -1*deg2rad((float)$angle);
$tmp = "\n q ";
$tmp .= sprintf('%.3f',cos($a)).' '.sprintf('%.3f',(-1.0*sin($a))).' '.sprintf('%.3f',sin($a)).' '.sprintf('%.3f',cos($a)).' ';
$tmp .= sprintf('%.3f',$x0).' '.sprintf('%.3f',$y0).' cm';
$this->objects[$this->currentContents]['c'].= $tmp;
$x0=0;
$y0=0;
}
$t1 = $astart;
$a0 = $x0+$r1*cos($t1);
$b0 = $y0+$r2*sin($t1);
$c0 = -$r1*sin($t1);
$d0 = $r2*cos($t1);
$this->objects[$this->currentContents]['c'].="\n".sprintf('%.3f',$a0).' '.sprintf('%.3f',$b0).' m ';
for ($i=1;$i<=$nSeg;$i++){
// draw this bit of the total curve
$t1 = $i*$dt+$astart;
$a1 = $x0+$r1*cos($t1);
$b1 = $y0+$r2*sin($t1);
$c1 = -$r1*sin($t1);
$d1 = $r2*cos($t1);
$this->objects[$this->currentContents]['c'].="\n".sprintf('%.3f',($a0+$c0*$dtm)).' '.sprintf('%.3f',($b0+$d0*$dtm));
$this->objects[$this->currentContents]['c'].= ' '.sprintf('%.3f',($a1-$c1*$dtm)).' '.sprintf('%.3f',($b1-$d1*$dtm)).' '.sprintf('%.3f',$a1).' '.sprintf('%.3f',$b1).' c';
$a0=$a1;
$b0=$b1;
$c0=$c1;
$d0=$d1;
}
if ($fill){
$this->objects[$this->currentContents]['c'].=' f';
} else {
if ($close){
$this->objects[$this->currentContents]['c'].=' s'; // small 's' signifies closing the path as well
} else {
$this->objects[$this->currentContents]['c'].=' S';
}
}
if ($angle !=0){
$this->objects[$this->currentContents]['c'].=' Q';
}
}
/**
* this sets the line drawing style.
* width, is the thickness of the line in user units
* cap is the type of cap to put on the line, values can be 'butt','round','square'
* where the diffference between 'square' and 'butt' is that 'square' projects a flat end past the
* end of the line.
* join can be 'miter', 'round', 'bevel'
* dash is an array which sets the dash pattern, is a series of length values, which are the lengths of the
* on and off dashes.
* (2) represents 2 on, 2 off, 2 on , 2 off ...
* (2,1) is 2 on, 1 off, 2 on, 1 off.. etc
* phase is a modifier on the dash pattern which is used to shift the point at which the pattern starts.
*/
function setLineStyle($width=1,$cap='',$join='',$dash='',$phase=0){
// this is quite inefficient in that it sets all the parameters whenever 1 is changed, but will fix another day
$string = '';
if ($width>0){
$string.= $width.' w';
}
$ca = array('butt'=>0,'round'=>1,'square'=>2);
if (isset($ca[$cap])){
$string.= ' '.$ca[$cap].' J';
}
$ja = array('miter'=>0,'round'=>1,'bevel'=>2);
if (isset($ja[$join])){
$string.= ' '.$ja[$join].' j';
}
if (is_array($dash)){
$string.= ' [';
foreach ($dash as $len){
$string.=' '.$len;
}
$string.= ' ] '.$phase.' d';
}
$this->currentLineStyle = $string;
$this->objects[$this->currentContents]['c'].="\n".$string;
}
/**
* draw a polygon, the syntax for this is similar to the GD polygon command
*/
function polygon($p,$np,$f=0){
$this->objects[$this->currentContents]['c'].="\n";
$this->objects[$this->currentContents]['c'].=sprintf('%.3f',$p[0]).' '.sprintf('%.3f',$p[1]).' m ';
for ($i=2;$i<$np*2;$i=$i+2){
$this->objects[$this->currentContents]['c'].= sprintf('%.3f',$p[$i]).' '.sprintf('%.3f',$p[$i+1]).' l ';
}
if ($f==1){
$this->objects[$this->currentContents]['c'].=' f';
} else {
$this->objects[$this->currentContents]['c'].=' S';
}
}
/**
* a filled rectangle, note that it is the width and height of the rectangle which are the secondary paramaters, not
* the coordinates of the upper-right corner
*/
function filledRectangle($x1,$y1,$width,$height){
$this->objects[$this->currentContents]['c'].="\n".sprintf('%.3f',$x1).' '.sprintf('%.3f',$y1).' '.sprintf('%.3f',$width).' '.sprintf('%.3f',$height).' re f';
}
/**
* draw a rectangle, note that it is the width and height of the rectangle which are the secondary paramaters, not
* the coordinates of the upper-right corner
*/
function rectangle($x1,$y1,$width,$height){
$this->objects[$this->currentContents]['c'].="\n".sprintf('%.3f',$x1).' '.sprintf('%.3f',$y1).' '.sprintf('%.3f',$width).' '.sprintf('%.3f',$height).' re S';
}
/**
* add a new page to the document
* this also makes the new page the current active object
*/
function newPage($insert=0,$id=0,$pos='after'){
// if there is a state saved, then go up the stack closing them
// then on the new page, re-open them with the right setings
if ($this->nStateStack){
for ($i=$this->nStateStack;$i>=1;$i--){
$this->restoreState($i);
}
}
$this->numObj++;
if ($insert){
// the id from the ezPdf class is the od of the contents of the page, not the page object itself
// query that object to find the parent
$rid = $this->objects[$id]['onPage'];
$opt= array('rid'=>$rid,'pos'=>$pos);
$this->o_page($this->numObj,'new',$opt);
} else {
$this->o_page($this->numObj,'new');
}
// if there is a stack saved, then put that onto the page
if ($this->nStateStack){
for ($i=1;$i<=$this->nStateStack;$i++){
$this->saveState($i);
}
}
// and if there has been a stroke or fill colour set, then transfer them
if ($this->currentColour['r']>=0){
$this->setColor($this->currentColour['r'],$this->currentColour['g'],$this->currentColour['b'],1);
}
if ($this->currentStrokeColour['r']>=0){
$this->setStrokeColor($this->currentStrokeColour['r'],$this->currentStrokeColour['g'],$this->currentStrokeColour['b'],1);
}
// if there is a line style set, then put this in too
if (strlen($this->currentLineStyle)){
$this->objects[$this->currentContents]['c'].="\n".$this->currentLineStyle;
}
// the call to the o_page object set currentContents to the present page, so this can be returned as the page id
return $this->currentContents;
}
/**
* 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);
}
/**
* return the height in units of the current font in the given size
*/
function getFontHeight($size){
if (!$this->numFonts){
$this->selectFont('./fonts/Helvetica');
}
// for the current font, and the given size, what is the height of the font in user units
$h = $this->fonts[$this->currentFont]['FontBBox'][3]-$this->fonts[$this->currentFont]['FontBBox'][1];
return $size*$h/1000;
}
/**
* return the font decender, this will normally return a negative number
* if you add this number to the baseline, you get the level of the bottom of the font
* it is in the pdf user units
*/
function getFontDecender($size){
// note that this will most likely return a negative value
if (!$this->numFonts){
$this->selectFont('./fonts/Helvetica');
}
$h = $this->fonts[$this->currentFont]['FontBBox'][1];
return $size*$h/1000;
}
/**
* filter the text, this is applied to all text just before being inserted into the pdf document
* it escapes the various things that need to be escaped, and so on
*
* @access private
*/
function filterText($text){
$text = str_replace('\\','\\\\',$text);
$text = str_replace('(','\(',$text);
$text = str_replace(')','\)',$text);
$text = str_replace('<','<',$text);
$text = str_replace('>','>',$text);
$text = str_replace(''','\'',$text);
$text = str_replace('"','"',$text);
$text = str_replace('&','&',$text);
return $text;
}
/**
* given a start position and information about how text is to be laid out, calculate where
* on the page the text will end
*
* @access private
*/
function PRVTgetTextPosition($x,$y,$angle,$size,$wa,$text){
// given this information return an array containing x and y for the end position as elements 0 and 1
$w = $this->getTextWidth($size,$text);
// need to adjust for the number of spaces in this text
$words = explode(' ',$text);
$nspaces=count($words)-1;
$w += $wa*$nspaces;
$a = deg2rad((float)$angle);
r
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -