s->SetX($x);
} else {
$x = $this->GetX();
}
if(empty($w)) {
if ($this->rtl) {
$w = $this->x - $this->lMargin;
} else {
$w = $this->w - $this->rMargin - $this->x;
}
}
// store original margin values
$lMargin = $this->lMargin;
$rMargin = $this->rMargin;
// set new margin values
if ($this->rtl) {
$this->SetLeftMargin($this->x - $w);
$this->SetRightMargin($this->w - $this->x);
} else {
$this->SetLeftMargin($this->x);
$this->SetRightMargin($this->w - $this->x - $w);
}
// calculate remaining vertical space on first page ($startpage)
$restspace = $this->getPageHeight() - $this->GetY() - $this->getBreakMargin();
// Write text
$nl = $this->Write($this->lasth, $txt, '', $fill, $align, true, $stretch);
// Get end-of-text Y position
$currentY = $this->GetY();
// get latest page number
$endpage = $this->page;
if (!empty($border)) {
// check if a new page has been created
if ($endpage > $startpage) {
// design borders around HTML cells.
for ($page=$startpage; $page<=$endpage; $page++) {
$this->page = $page;
if ($page==$startpage) {
$this->SetY($this->getPageHeight() - $restspace - $this->getBreakMargin());
$h = $restspace - 1;
} elseif ($page==$endpage) {
$this->SetY($this->tMargin); // put cursor at the beginning of text
$h = $currentY - $this->tMargin;
} else {
$this->SetY($this->tMargin); // put cursor at the beginning of text
$h = $this->getPageHeight() - $this->tMargin - $this->getBreakMargin();
}
$this->SetX($x);
$this->Cell($w, $h, "", $border, 1, '', 0);
}
} else {
$h = max($h, ($currentY - $y));
$this->SetY($y); // put cursor at the beginning of text
$this->SetX($x);
// design a cell around the text
$this->Cell($w, $h, "", $border, 1, '', 0);
}
}
// restore original margin values
$this->SetLeftMargin($lMargin);
$this->SetRightMargin($rMargin);
if($ln>0) {
//Go to the beginning of the next line
$this->SetY($currentY);
if($ln == 2) {
$this->SetX($x + $w);
}
} else {
// go left or right by case
$this->page = $startpage;
$this->y = $y;
$this->SetX($x + $w);
}
return $nl;
}
/**
* This method prints text from the current position.
* @param float $h Line height
* @param string $txt String to print
* @param mixed $link URL or identifier returned by AddLink()
* @param int $fill Indicates if the background must be painted (1) or transparent (0). Default value: 0.
* @param string $align Allows to center or align the text. Possible values are:
- L or empty string: left align (default value)
- C: center
- R: right align
- J: justify
* @param boolean $ln if true set cursor at the bottom of the line, otherwise set cursor at the top of the line.
* @param int $stretch stretch carachter mode: - 0 = disabled
- 1 = horizontal scaling only if necessary
- 2 = forced horizontal scaling
- 3 = character spacing only if necessary
- 4 = forced character spacing
* @return int Rerurn the number of lines.
* @since 1.5
*/
function Write($h, $txt, $link='', $fill=0, $align='', $ln=false, $stretch=0) {
// store current position
$prevx = $this->x;
$prevy = $this->y;
// Adjust internal padding
if ($this->cMargin < ($this->LineWidth/2)) {
$this->cMargin = ($this->LineWidth/2);
}
// Add top space if needed
if (($h - $this->FontSize) < $this->LineWidth) {
$this->y += $this->LineWidth/2;
}
//if ($h < ($this->LineWidth)) {
// $h = ($this->LineWidth);
//}
// calculating remaining line width ($w)
if ($this->rtl) {
$w = $this->x - $this->lMargin;
} else {
$w = $this->w - $this->rMargin - $this->x;
}
// remove carriage returns
$s = str_replace("\r", '', $txt);
// get array of chars
$chars = $this->UTF8StringToArray($s);
// get the number of characters
$nb = count($chars);
// handle single space character
if(($nb==1) AND preg_match("/[\s]/u", $s)) {
if ($this->rtl) {
$this->x -= $this->GetStringWidth($s);
} else {
$this->x += $this->GetStringWidth($s);
}
return;
}
// max column width
$wmax = $w - (2 * $this->cMargin);
$i = 0; // character position
$j = 0; // current srting starting position
$sep = -1; // position of the last blank space
$l = 0; // current string lenght
$nl = 0; //number of lines
// for each character
while($i < $nb) {
//Get the current character
$c = $chars[$i];
if ($c == 10) {
// 10 = "\n" = new line
//Explicit line break
if ($align == "J") {
if ($this->rtl) {
$talign = "R";
} else {
$talign = "L";
}
} else {
$talign = $align;
}
$this->Cell($w, $h, $this->UTF8ArrSubString($chars, $j, $i), 0, 2, $talign, $fill, $link, $stretch);
$nl++;
$j = $i + 1;
$l = 0;
$sep = -1;
if($nl == 1) {
// set the next line width and position
if ($this->rtl) {
$this->x = $this->w - $this->rMargin;
$w = $this->x - $this->lMargin;
}
else {
$this->x = $this->lMargin;
$w = $this->w - $this->rMargin - $this->x;
}
$wmax = $w - (2 * $this->cMargin);
}
} else {
if(preg_match("/[\s]/u", $this->unichr($c))) {
// update last blank space position
$sep = $i;
}
// update string length
if($this->isunicode) {
// with bidirectional algorithm some chars may be changed affecting the line length
// *** very slow
$l = $this->GetArrStringWidth($this->utf8Bidi(array_slice($chars, $j, $i-$j+1), $this->tmprtl));
} else {
$l += $this->GetCharWidth($c);
}
if($l > $wmax) {
// we have reached the end of column
if($sep == -1) {
// truncate the word because do not fit on column
$this->Cell($w, $h, $this->UTF8ArrSubString($chars, $j, $i), 0, 2, $align, $fill, $link, $stretch);
$nl++;
if($nl == 1) {
// set the next line width and position
if ($this->rtl) {
$this->x = $this->w - $this->rMargin;
$w = $this->x - $this->lMargin;
}
else {
$this->x = $this->lMargin;
$w = $this->w - $this->rMargin - $this->x;
}
$wmax = $w - (2 * $this->cMargin);
}
} else {
// word wrapping
$this->Cell($w, $h, $this->UTF8ArrSubString($chars, $j, $sep), 0, 2, $align, $fill, $link, $stretch);
$nl++;
$i = $sep + 1;
if($nl == 1) {
// set the next line width and position
if ($this->rtl) {
$this->x = $this->w - $this->rMargin;
$w = $this->x - $this->lMargin;
}
else {
$this->x = $this->lMargin;
$w = $this->w - $this->rMargin - $this->x;
}
$wmax = $w - (2 * $this->cMargin);
}
}
$sep = -1;
$j = $i;
$l = 0;
}
}
$i++;
} // end while i < nb
// print last row
if($i != $j) {
$this->Cell($w, $h, $this->UTF8ArrSubString($chars, $j, $nb), 0, $ln, $align, $fill, $link, $stretch);
$nl++;
}
$w = $this->GetStringWidth($this->UTF8ArrSubString($chars, $j, $nb)) + (2 * $this->cMargin);
if ($this->rtl) {
$this->x = $prevx - $w;
} else {
$this->x = $prevx + $w;
}
// Add bottom space if needed
if (($ln > 0) AND (($h - $this->FontSize) < $this->LineWidth)) {
$this->y += $this->LineWidth/2;
}
return $nl;
}
/**
* Extract a slice of the $strarr array and return it as string.
* @param string $strarr The input array of characters.
* @param int $start the starting element of $strarr.
* @param int $end first element that will not be returned.
* @return Return part of a string
*/
function UTF8ArrSubString($strarr, $start='', $end='') {
if (strlen($start) == 0) {
$start = 0;
}
if (strlen($end) == 0) {
$end = count($strarr);
}
$string = "";
for ($i=$start; $i < $end; $i++) {
$string .= $this->unichr($strarr[$i]);
}
return $string;
}
/**
* Returns the unicode caracter specified by UTF-8 code
* @param int $c UTF-8 code
* @return Returns the specified character.
* @author Miguel Perez, Nicola Asuni
* @since 2.3.000 (2008-03-05)
*/
function unichr($c) {
if (!$this->isunicode) {
return chr($c);
} elseif ($c <= 0x7F) {
// one byte
return chr($c);
} else if ($c <= 0x7FF) {
// two bytes
return chr(0xC0 | $c >> 6).chr(0x80 | $c & 0x3F);
} else if ($c <= 0xFFFF) {
// three bytes
return chr(0xE0 | $c >> 12).chr(0x80 | $c >> 6 & 0x3F).chr(0x80 | $c & 0x3F);
} else if ($c <= 0x10FFFF) {
// four bytes
return chr(0xF0 | $c >> 18).chr(0x80 | $c >> 12 & 0x3F).chr(0x80 | $c >> 6 & 0x3F).chr(0x80 | $c & 0x3F);
} else {
return "";
}
}
/**
* Puts an image in the page. The upper-left corner must be given. The dimensions can be specified in different ways:- explicit width and height (expressed in user unit)
- one explicit dimension, the other being calculated automatically in order to keep the original proportions
- no explicit dimension, in which case the image is put at 72 dpi
* Supported formats are JPEG and PNG.
* For JPEG, all flavors are allowed:- gray scales
- true colors (24 bits)
- CMYK (32 bits)
* For PNG, are allowed:- gray scales on at most 8 bits (256 levels)
- indexed colors
- true colors (24 bits)
* If a transparent color is defined, it will be taken into account (but will be only interpreted by Acrobat 4 and above).
* The format can be specified explicitly or inferred from the file extension.
* It is possible to put a link on the image.
* Remark: if an image is used several times, only one copy will be embedded in the file.
* @param string $file Name of the file containing the image.
* @param float $x Abscissa of the upper-left corner.
* @param float $y Ordinate of the upper-left corner.
* @param float $w Width of the image in the page. If not specified or equal to zero, it is automatically calculated.
* @param float $h Height of the image in the page. If not specified or equal to zero, it is automatically calculated.
* @param string $type Image format. Possible values are (case insensitive): JPG, JPEG, PNG. If not specified, the type is inferred from the file extension.
* @param mixed $link URL or identifier returned by AddLink().
* @param string $align Indicates the alignment of the pointer next to image insertion relative to image height. The value can be:- T: top-right for LTR or top-left for RTL
- M: middle-right for LTR or middle-left for RTL
- B: bottom-right for LTR or bottom-left for RTL
- N: next line
* @since 1.1
* @see AddLink()
*/
function Image($file, $x, $y, $w=0, $h=0, $type='', $link='', $align='') {
//Put an image on the page
if(!isset($this->images[$file])) {
//First use of image, get info
if($type == '') {
$pos = strrpos($file,'.');
if(empty($pos)) {
$this->Error('Image file has no extension and no type was specified: '.$file);
}
$type = substr($file, $pos+1);
}
$type = strtolower($type);
$mqr = get_magic_quotes_runtime();
set_magic_quotes_runtime(0);
if($type == 'jpg' or $type == 'jpeg') {
$info=$this->_parsejpg($file);
} elseif($type == 'gif') {
$info=$this->_parsegif($file);
} elseif($type == 'png') {
$info=$this->_parsepng($file);
}else {
//Allow for additional formats
$mtd='_parse'.$type;
if(!method_exists($this,$mtd)) {
$this->Error('Unsupported image type: '.$type);
}
$info=$this->$mtd($file);
}
if($info === false) {
//If false, we cannot process image
return;
}
set_magic_quotes_runtime($mqr);
$info['i']=count($this->images)+1;
$this->images[$file]=$info;
}
else {
$info=$this->images[$file];
}
//Automatic width and height calculation if needed
if(($w == 0) and ($h == 0)) {
//Put image at 72 dpi
// 2004-06-14 :: Nicola Asuni, scale factor where added
$w = $info['w'] / ($this->imgscale * $this->k);
$h = $info['h'] / ($this->imgscale * $this->k);
}
if($w == 0) {
$w = $h * $info['w'] / $info['h'];
}
if($h == 0) {
$h = $w * $info['h'] / $info['w'];
}
// 2007-10-19 Warren Sherliker
// Check whether we need a new page first as this does not fit
// Copied from Cell()
if((($this->y + $h) > $this->PageBreakTrigger) AND empty($this->InFooter) AND $this->AcceptPageBreak()) {
// Automatic page break
$this->AddPage($this->CurOrientation);
// Reset coordinates to top fo next page
$x = $this->GetX();
$y = $this->GetY();
}
// 2007-10-19 Warren Sherliker: End Edit
// set bottomcoordinates
$this->img_rb_y = $y + $h;
if ($this->rtl) {
$ximg = ($this->w - $x -$w);
// set left side coordinate
$this->img_rb_x = $ximg;
} else {
$ximg = $x;
// set right side coordinate
$this->img_rb_x = $ximg + $w;
}
$xkimg = $ximg * $this->k;
$this->_out(sprintf('q %.2f 0 0 %.2f %.2f %.2f cm /I%d Do Q', $w*$this->k, $h*$this->k, $xkimg, ($this->h-($y+$h))*$this->k, $info['i']));
if($link) {
$this->Link($ximg, $y, $w, $h, $link);
}
// set pointer to align the successive text/objects
switch($align) {
case 'T':{
$this->y = $y;
$this->x = $this->img_rb_x;
break;
}
case 'M':{
$this->y = $y + round($h/2);
$this->x = $this->img_rb_x;
break;
}
case 'B':{
$this->y = $this->img_rb_y;
$this->x = $this->img_rb_x;
break;
}
case 'N':{
$this->SetY($this->img_rb_y);
break;
}
default:{
break;
}
}
}
/**
* Performs a line break. The current abscissa goes back to the left margin and the ordinate increases by the amount passed in parameter.
* @param float $h The height of the break. By default, the value equals the height of the last printed cell.
* @since 1.0
* @see Cell()
*/
function Ln($h='') {
//Line feed; default value is last cell height
if ($this->rtl) {
$this->x = $this->w - $this->rMargin;
} else {
$this->x = $this->lMargin;
}
if(is_string($h)) {
$this->y += $this->lasth;
} else {
$this->y += $h;
}
}
/**
* Returns the relative X value of current position.
* The value is relative to the left border for LTR languages and to the right border for RTL languages.
* @return float
* @since 1.2
* @see SetX(), GetY(), SetY()
*/
function GetX() {
//Get x position
if ($this->rtl) {
return ($this->w - $this->x);
} else {
return $this->x;
}
}
/**
* Returns the absolute X value of current position.
* @return float
* @since 1.2
* @see SetX(), GetY(), SetY()
*/
function GetAbsX() {
return $this->x;
}
/**
* Returns the ordinate of the current position.
* @return float
* @since 1.0
* @see SetY(), GetX(), SetX()
*/
function GetY() {
//Get y position
return $this->y;
}
/**
* Defines the abscissa of the current position.
* If the passed value is negative, it is relative to the right of the page (or left if language is RTL).
* @param float $x The value of the abscissa.
* @since 1.2
* @see GetX(), GetY(), SetY(), SetXY()
*/
function SetX($x) {
//Set x position
if ($this->rtl) {
if($x >= 0) {
$this->x = $this->w - $x;
} else {
$this->x = abs($x);
}
} else {
if($x >= 0) {
$this->x = $x;
} else {
$this->x = $this->w + $x;
}
}
}
/**
* Moves the current abscissa back to the left margin and sets the ordinate.
* If the passed value is negative, it is relative to the bottom of the page.
* @param float $y The value of the ordinate.
* @since 1.0
* @see GetX(), GetY(), SetY(), SetXY()
*/
function SetY($y) {
//Set y position and reset x
if ($this->rtl) {
$this->x = $this->w - $this->rMargin;
} else {
$this->x = $this->lMargin;
}
if($y >= 0) {
$this->y = $y;
} else {
$this->y = $this->h + $y;
}
}
/**
* Defines the abscissa and ordinate of the current position. If the passed values are negative, they are relative respectively to the right and bottom of the page.
* @param float $x The value of the abscissa
* @param float $y The value of the ordinate
* @since 1.2
* @see SetX(), SetY()
*/
function SetXY($x, $y) {
//Set x and y positions
$this->SetY($y);
$this->SetX($x);
}
/**
* Send the document to a given destination: string, local file or browser. In the last case, the plug-in may be used (if present) or a download ("Save as" dialog box) may be forced.
* The method first calls Close() if necessary to terminate the document.
* @param string $name The name of the file. If not given, the document will be sent to the browser (destination I) with the name doc.pdf.
* @param string $dest Destination where to send the document. It can take one of the following values:- I: send the file inline to the browser. The plug-in is used if available. The name given by name is used when one selects the "Save as" option on the link generating the PDF.
- D: send to the browser and force a file download with the name given by name.
- F: save to a local file with the name given by name.
- S: return the document as a string. name is ignored.
If the parameter is not specified but a name is given, destination is F. If no parameter is specified at all, destination is I.
Note: for compatibility with previous versions, a boolean value is also accepted (false for F and true for D).
* @since 1.0
* @see Close()
*/
function Output($name='',$dest='') {
//Output PDF to some destination
//Finish document if necessary
if($this->state < 3) {
$this->Close();
}
//Normalize parameters
if(is_bool($dest)) {
$dest=$dest ? 'D' : 'F';
}
$dest=strtoupper($dest);
if($dest=='') {
if($name=='') {
$name='doc.pdf';
$dest='I';
} else {
$dest='F';
}
}
switch($dest) {
case 'I': {
//Send to standard output
if(ob_get_contents()) {
$this->Error('Some data has already been output, can\'t send PDF file');
}
if(php_sapi_name()!='cli') {
//We send to a browser
header('Content-Type: application/pdf');
if(headers_sent()) {
$this->Error('Some data has already been output to browser, can\'t send PDF file');
}
header('Content-Length: '.strlen($this->buffer));
header('Content-disposition: inline; filename="'.$name.'"');
}
echo $this->buffer;
break;
}
case 'D': {
//Download file
if(ob_get_contents()) {
$this->Error('Some data has already been output, can\'t send PDF file');
}
if(isset($_SERVER['HTTP_USER_AGENT']) && strpos($_SERVER['HTTP_USER_AGENT'],'MSIE')) {
header('Content-Type: application/force-download');
} else {
header('Content-Type: application/octet-stream');
}
if(headers_sent()) {
$this->Error('Some data has already been output to browser, can\'t send PDF file');
}
header('Content-Length: '.strlen($this->buffer));
header('Content-disposition: attachment; filename="'.$name.'"');
echo $this->buffer;
break;
}
case 'F': {
//Save to local file
$f=fopen($name,'wb');
if(!$f) {
$this->Error('Unable to create output file: '.$name);
}
fwrite($f,$this->buffer,strlen($this->buffer));
fclose($f);
break;
}
case 'S': {
//Return as a string
return $this->buffer;
}
default: {
$this->Error('Incorrect output destination: '.$dest);
}
}
return '';
}
// Protected methods
/**
* Check for locale-related bug
* @access protected
*/
function _dochecks() {
//Check for locale-related bug
if(1.1==1) {
$this->Error('Don\'t alter the locale before including class file');
}
//Check for decimal separator
if(sprintf('%.1f',1.0)!='1.0') {
setlocale(LC_NUMERIC,'C');
}
}
/**
* Return fonts path
* @access protected
*/
function _getfontpath() {
if(!defined('K_PATH_FONTS') AND is_dir(dirname(__FILE__).'/font')) {
define('K_PATH_FONTS', dirname(__FILE__).'/font/');
}
return defined('K_PATH_FONTS') ? K_PATH_FONTS : '';
}
/**
* Start document
* @access protected
*/
function _begindoc() {
//Start document
$this->state=1;
$this->_out('%PDF-'.$this->PDFVersion);
}
/**
* _putpages
* @access protected
*/
function _putpages() {
$nb = $this->page;
if(!empty($this->AliasNbPages)) {
$nbstr = $this->UTF8ToUTF16BE($nb, false);
//Replace number of pages
for($n=1;$n<=$nb;$n++) {
$this->pages[$n]=str_replace($this->AliasNbPages, $nbstr, $this->pages[$n]);
}
}
if($this->DefOrientation=='P') {
$wPt=$this->fwPt;
$hPt=$this->fhPt;
}
else {
$wPt=$this->fhPt;
$hPt=$this->fwPt;
}
$filter=($this->compress) ? '/Filter /FlateDecode ' : '';
for($n=1;$n<=$nb;$n++) {
//Page
$this->_newobj();
$this->_out('<_out('/Parent 1 0 R');
if(isset($this->OrientationChanges[$n])) {
$this->_out(sprintf('/MediaBox [0 0 %.2f %.2f]',$hPt,$wPt));
}
$this->_out('/Resources 2 0 R');
if(isset($this->PageLinks[$n])) {
//Links
$annots='/Annots [';
foreach($this->PageLinks[$n] as $pl) {
$rect=sprintf('%.2f %.2f %.2f %.2f',$pl[0],$pl[1],$pl[0]+$pl[2],$pl[1]-$pl[3]);
$annots.='<_uristring($pl[4]).'>>>>';
}
else {
$l=$this->links[$pl[4]];
$h=isset($this->OrientationChanges[$l[0]]) ? $wPt : $hPt;
$annots.=sprintf('/Dest [%d 0 R /XYZ 0 %.2f null]>>',1+2*$l[0],$h-$l[1]*$this->k);
}
}
$this->_out($annots.']');
}
$this->_out('/Contents '.($this->n+1).' 0 R>>');
$this->_out('endobj');
//Page content
$p=($this->compress) ? gzcompress($this->pages[$n]) : $this->pages[$n];
$this->_newobj();
$this->_out('<<'.$filter.'/Length '.strlen($p).'>>');
$this->_putstream($p);
$this->_out('endobj');
}
//Pages root
$this->offsets[1]=strlen($this->buffer);
$this->_out('1 0 obj');
$this->_out('<_out($kids.']');
$this->_out('/Count '.$nb);
$this->_out(sprintf('/MediaBox [0 0 %.2f %.2f]',$wPt,$hPt));
$this->_out('>>');
$this->_out('endobj');
}
/**
* Adds fonts
* _putfonts
* @access protected
*/
function _putfonts() {
$nf=$this->n;
foreach($this->diffs as $diff) {
//Encodings
$this->_newobj();
$this->_out('<>');
$this->_out('endobj');
}
$mqr=get_magic_quotes_runtime();
set_magic_quotes_runtime(0);
foreach($this->FontFiles as $file=>$info) {
//Font file embedding
$this->_newobj();
$this->FontFiles[$file]['n']=$this->n;
$font='';
$f=fopen($this->_getfontpath().strtolower($file),'rb',1);
if(!$f) {
$this->Error('Font file not found: '.$file);
}
while(!feof($f)) {
$font .= fread($f, 8192);
}
fclose($f);
$compressed=(substr($file,-2)=='.z');
if(!$compressed && isset($info['length2'])) {
$header=(ord($font{0})==128);
if($header) {
//Strip first binary header
$font=substr($font,6);
}
if($header && ord($font{$info['length1']})==128) {
//Strip second binary header
$font=substr($font,0,$info['length1']).substr($font,$info['length1']+6);
}
}
$this->_out('<_out('/Filter /FlateDecode');
}
$this->_out('/Length1 '.$info['length1']);
if(isset($info['length2'])) {
$this->_out('/Length2 '.$info['length2'].' /Length3 0');
}
$this->_out('>>');
$this->_putstream($font);
$this->_out('endobj');
}
set_magic_quotes_runtime($mqr);
foreach($this->fonts as $k=>$font) {
//Font objects
$this->fonts[$k]['n']=$this->n+1;
$type=$font['type'];
$name=$font['name'];
if($type=='core') {
//Standard font
$this->_newobj();
$this->_out('<_out('/BaseFont /'.$name);
$this->_out('/Subtype /Type1');
if($name!='Symbol' && $name!='ZapfDingbats') {
$this->_out('/Encoding /WinAnsiEncoding');
}
$this->_out('>>');
$this->_out('endobj');
} elseif($type=='Type1' OR $type=='TrueType') {
//Additional Type1 or TrueType font
$this->_newobj();
$this->_out('<_out('/BaseFont /'.$name);
$this->_out('/Subtype /'.$type);
$this->_out('/FirstChar 32 /LastChar 255');
$this->_out('/Widths '.($this->n+1).' 0 R');
$this->_out('/FontDescriptor '.($this->n+2).' 0 R');
if($font['enc']) {
if(isset($font['diff'])) {
$this->_out('/Encoding '.($nf+$font['diff']).' 0 R');
} else {
$this->_out('/Encoding /WinAnsiEncoding');
}
}
$this->_out('>>');
$this->_out('endobj');
//Widths
$this->_newobj();
$cw=&$font['cw'];
$s='[';
for($i=32;$i<=255;$i++) {
$s.=$cw[chr($i)].' ';
}
$this->_out($s.']');
$this->_out('endobj');
//Descriptor
$this->_newobj();
$s='<$v) {
$s.=' /'.$k.' '.$v;
}
$file = $font['file'];
if($file) {
$s.=' /FontFile'.($type=='Type1' ? '' : '2').' '.$this->FontFiles[$file]['n'].' 0 R';
}
$this->_out($s.'>>');
$this->_out('endobj');
} else {
//Allow for additional types
$mtd='_put'.strtolower($type);
if(!method_exists($this, $mtd)) {
$this->Error('Unsupported font type: '.$type);
}
$this->$mtd($font);
}
}
}
/**
* _putimages
* @access protected
*/
function _putimages() {
$filter=($this->compress) ? '/Filter /FlateDecode ' : '';
reset($this->images);
while(list($file,$info)=each($this->images)) {
$this->_newobj();
$this->images[$file]['n']=$this->n;
$this->_out('<_out('/Subtype /Image');
$this->_out('/Width '.$info['w']);
$this->_out('/Height '.$info['h']);
if (isset($info["masked"])) {
$this->_out('/SMask '.($this->n-1).' 0 R');
}
if($info['cs']=='Indexed') {
$this->_out('/ColorSpace [/Indexed /DeviceRGB '.(strlen($info['pal'])/3-1).' '.($this->n+1).' 0 R]');
}
else {
$this->_out('/ColorSpace /'.$info['cs']);
if($info['cs']=='DeviceCMYK') {
$this->_out('/Decode [1 0 1 0 1 0 1 0]');
}
}
$this->_out('/BitsPerComponent '.$info['bpc']);
if(isset($info['f'])) {
$this->_out('/Filter /'.$info['f']);
}
if(isset($info['parms'])) {
$this->_out($info['parms']);
}
if(isset($info['trns']) and is_array($info['trns'])) {
$trns='';
for($i=0;$i_out('/Mask ['.$trns.']');
}
$this->_out('/Length '.strlen($info['data']).'>>');
$this->_putstream($info['data']);
unset($this->images[$file]['data']);
$this->_out('endobj');
//Palette
if($info['cs']=='Indexed') {
$this->_newobj();
$pal=($this->compress) ? gzcompress($info['pal']) : $info['pal'];
$this->_out('<<'.$filter.'/Length '.strlen($pal).'>>');
$this->_putstream($pal);
$this->_out('endobj');
}
}
}
/**
* _putxobjectdict
* @access protected
*/
function _putxobjectdict() {
foreach($this->images as $image) {
$this->_out('/I'.$image['i'].' '.$image['n'].' 0 R');
}
}
/**
* _putresourcedict
* @access protected
*/
function _putresourcedict(){
$this->_out('/ProcSet [/PDF /Text /ImageB /ImageC /ImageI]');
$this->_out('/Font <<');
foreach($this->fonts as $font) {
$this->_out('/F'.$font['i'].' '.$font['n'].' 0 R');
}
$this->_out('>>');
$this->_out('/XObject <<');
$this->_putxobjectdict();
$this->_out('>>');
}
/**
* _putresources
* @access protected
*/
function _putresources() {
$this->_putfonts();
$this->_putimages();
//Resource dictionary
$this->offsets[2]=strlen($this->buffer);
$this->_out('2 0 obj');
$this->_out('<<');
$this->_putresourcedict();
$this->_out('>>');
$this->_out('endobj');
$this->_putjavascript();
$this->_putbookmarks();
// encryption
if ($this->encrypted) {
$this->_newobj();
$this->enc_obj_id = $this->n;
$this->_out('<<');
$this->_putencryption();
$this->_out('>>');
$this->_out('endobj');
}
}
/**
* _putinfo
* Adds some meta information
* @access protected
*/
function _putinfo() {
$this->_out('/CreationDate ('.$this->_escape('D:'.date('YmdHis')).')');
$this->_out('/ModDate ('.$this->_escape('D:'.date('YmdHis')).')');
$this->_out('/Producer '.$this->_textstring(PDF_PRODUCER));
if(!empty($this->title)) {
$this->_out('/Title '.$this->_textstring($this->title));
}
if(!empty($this->subject)) {
$this->_out('/Subject '.$this->_textstring($this->subject));
}
if(!empty($this->author)) {
$this->_out('/Author '.$this->_textstring($this->author));
}
if(!empty($this->keywords)) {
$this->_out('/Keywords '.$this->_textstring($this->keywords));
}
if(!empty($this->creator)) {
$this->_out('/Creator '.$this->_textstring($this->creator));
}
}
/**
* _putcatalog
* @access protected
*/
function _putcatalog() {
$this->_out('/Type /Catalog');
$this->_out('/Pages 1 0 R');
if($this->ZoomMode=='fullpage') {
$this->_out('/OpenAction [3 0 R /Fit]');
}
elseif($this->ZoomMode=='fullwidth') {
$this->_out('/OpenAction [3 0 R /FitH null]');
}
elseif($this->ZoomMode=='real') {
$this->_out('/OpenAction [3 0 R /XYZ null null 1]');
}
elseif(!is_string($this->ZoomMode)) {
$this->_out('/OpenAction [3 0 R /XYZ null null '.($this->ZoomMode/100).']');
}
if($this->LayoutMode=='single') {
$this->_out('/PageLayout /SinglePage');
}
elseif($this->LayoutMode=='continuous') {
$this->_out('/PageLayout /OneColumn');
}
elseif($this->LayoutMode=='two') {
$this->_out('/PageLayout /TwoColumnLeft');
}
if (!empty($this->javascript)) {
$this->_out('/Names <n_js).' 0 R>>');
}
if(count($this->outlines)>0) {
$this->_out('/Outlines '.$this->OutlineRoot.' 0 R');
$this->_out('/PageMode /UseOutlines');
}
if($this->rtl) {
$this->_out('/ViewerPreferences << /Direction /R2L >>');
}
}
/**
* _puttrailer
* @access protected
*/
function _puttrailer() {
$this->_out('/Size '.($this->n+1));
$this->_out('/Root '.$this->n.' 0 R');
$this->_out('/Info '.($this->n-1).' 0 R');
if ($this->encrypted) {
$this->_out('/Encrypt '.$this->enc_obj_id.' 0 R');
$this->_out('/ID [()()]');
}
}
/**
* _putheader
* @access protected
*/
function _putheader() {
$this->_out('%PDF-'.$this->PDFVersion);
}
/**
* _enddoc
* @access protected
*/
function _enddoc() {
$this->_putheader();
$this->_putpages();
$this->_putresources();
//Info
$this->_newobj();
$this->_out('<<');
$this->_putinfo();
$this->_out('>>');
$this->_out('endobj');
//Catalog
$this->_newobj();
$this->_out('<<');
$this->_putcatalog();
$this->_out('>>');
$this->_out('endobj');
//Cross-ref
$o=strlen($this->buffer);
$this->_out('xref');
$this->_out('0 '.($this->n+1));
$this->_out('0000000000 65535 f ');
for($i=1;$i<=$this->n;$i++) {
$this->_out(sprintf('%010d 00000 n ',$this->offsets[$i]));
}
//Trailer
$this->_out('trailer');
$this->_out('<<');
$this->_puttrailer();
$this->_out('>>');
$this->_out('startxref');
$this->_out($o);
$this->_out('%%EOF');
$this->state=3;
}
/**
* _beginpage
* @access protected
*/
function _beginpage($orientation) {
$this->page++;
$this->pages[$this->page]='';
$this->state=2;
if ($this->rtl) {
$this->x = $this->w - $this->rMargin;
} else {
$this->x = $this->lMargin;
}
$this->y = $this->tMargin;
$this->FontFamily='';
//Page orientation
if(empty($orientation)) {
$orientation=$this->DefOrientation;
}
else {
$orientation=strtoupper($orientation{0});
if($orientation!=$this->DefOrientation) {
$this->OrientationChanges[$this->page]=true;
}
}
if($orientation!=$this->CurOrientation) {
//Change orientation
if($orientation=='P') {
$this->wPt=$this->fwPt;
$this->hPt=$this->fhPt;
$this->w=$this->fw;
$this->h=$this->fh;
}
else {
$this->wPt=$this->fhPt;
$this->hPt=$this->fwPt;
$this->w=$this->fh;
$this->h=$this->fw;
}
$this->PageBreakTrigger=$this->h-$this->bMargin;
$this->CurOrientation=$orientation;
}
}
/**
* End of page contents
* @access protected
*/
function _endpage() {
$this->state=1;
}
/**
* Begin a new object
* @access protected
*/
function _newobj() {
$this->n++;
$this->offsets[$this->n]=strlen($this->buffer);
$this->_out($this->n.' 0 obj');
}
/**
* Underline text
* @param int $x X coordinate
* @param int $y Y coordinate
* @param string $txt text to underline
* @access protected
*/
function _dounderline($x, $y, $txt) {
$up = $this->CurrentFont['up'];
$ut = $this->CurrentFont['ut'];
$w = $this->GetStringWidth($txt) + $this->ws * substr_count($txt,' ');
return sprintf('%.2f %.2f %.2f %.2f re f', $x * $this->k, ($this->h - ($y - $up / 1000 * $this->FontSize)) * $this->k, $w * $this->k, -$ut / 1000 * $this->FontSizePt);
}
// REWRITTEN by Warren Sherliker wsherliker@gmail.com
// altered to allow compatibility with all sorts of image formats including gif.
// Can easily extend to work with others
// such as gd xbm etc. which are all supported by php 5+
// (Requires GD library)
/**
* Extract info from a JPEG file
* @param string $file image file to parse
* @return string
* @access protected
*/
function _parsejpg($file) {
if(!function_exists('imagecreatefromjpeg')) {
// GD is not installed, try legacy method
return $this->_legacyparsejpg($file);
}
$a=getimagesize($file);
if(empty($a)) {
$this->Error('Missing or incorrect image file: '.$file);
}
if($a[2]!=2) {
$this->Error('Not a JPEG file: '.$file);
}
$jpeg = imagecreatefromjpeg($file);
return $this->outputjpg($file, $jpeg);
}
/**
* Extract info from a GIF file
* @param string $file image file to parse
* @return string
* @access protected
*/
function _parsegif($file) {
if(!function_exists('imagecreatefromgif')) {
// PDF doesn't support native GIF and GD is not installed
return false;
}
$a=getimagesize($file);
if(empty($a)) {
$this->Error('Missing or incorrect image file: '.$file);
}
if($a[2]!=1) {
$this->Error('Not a GIF file: '.$file);
}
// Temporary convert file to jpg and then delete this temp data file
$gif = imagecreatefromgif($file);
return $this->toJPEG($file, $gif);
}
/**
* Extract info from a PNG file
* @param string $file image file to parse
* @return string
* @access protected
*/
function _parsepng($file) {
if(!function_exists('imagecreatefrompng')) {
// GD is not installed, try legacy method
return $this->_legacyparsepng($file);
}
$f=fopen($file,'rb');
if(empty($f)) {
$this->Error('Can\'t open image file: '.$file);
}
//Check signature
if(fread($f,8)!=chr(137).'PNG'.chr(13).chr(10).chr(26).chr(10)) {
$this->Error('Not a PNG file: '.$file);
}
//Read header chunk
fread($f,4);
if(fread($f,4)!='IHDR') {
$this->Error('Incorrect PNG file: '.$file);
}
// Temporary convert file to jpg and then delete this temp data file
$a=getimagesize($file);
$png = imagecreatefrompng($file);
return $this->toJPEG($file, $png);
}
/**
* Extract info from a JPEG file without using GD
* @param string $file image file to parse
* @return string
* @access protected
*/
function _legacyparsejpg($file) {
$a=GetImageSize($file);
if(empty($a)) {
$this->Error('Missing or incorrect image file: '.$file);
}
if($a[2]!=2) {
$this->Error('Not a JPEG file: '.$file);
}
if(!isset($a['channels']) or $a['channels']==3) {
$colspace='DeviceRGB';
}
elseif($a['channels']==4) {
$colspace='DeviceCMYK';
}
else {
$colspace='DeviceGray';
}
$bpc=isset($a['bits']) ? $a['bits'] : 8;
//Read whole file
$f=fopen($file,'rb');
$data='';
while(!feof($f)) {
$data.=fread($f,4096);
}
fclose($f);
return array('w'=>$a[0],'h'=>$a[1],'cs'=>$colspace,'bpc'=>$bpc,'f'=>'DCTDecode','data'=>$data);
}
/**
* Extract info from a PNG file without using GD
* @param string $file image file to parse
* @return string
* @access protected
*/
function _legacyparsepng($file) {
$f=fopen($file,'rb');
if(empty($f)) {
$this->Error('Can\'t open image file: '.$file);
}
//Check signature
if(fread($f,8)!=chr(137).'PNG'.chr(13).chr(10).chr(26).chr(10)) {
$this->Error('Not a PNG file: '.$file);
}
//Read header chunk
fread($f,4);
if(fread($f,4)!='IHDR') {
$this->Error('Incorrect PNG file: '.$file);
}
$w=$this->_freadint($f);
$h=$this->_freadint($f);
$bpc=ord(fread($f,1));
if($bpc>8) {
$this->Error('16-bit depth not supported: '.$file);
}
$ct=ord(fread($f,1));
if($ct==0) {
$colspace='DeviceGray';
}
elseif($ct==2) {
$colspace='DeviceRGB';
}
elseif($ct==3) {
$colspace='Indexed';
}
else {
$this->Error('Alpha channel not supported: '.$file);
}
if(ord(fread($f,1))!=0) {
$this->Error('Unknown compression method: '.$file);
}
if(ord(fread($f,1))!=0) {
$this->Error('Unknown filter method: '.$file);
}
if(ord(fread($f,1))!=0) {
$this->Error('Interlacing not supported: '.$file);
}
fread($f,4);
$parms='/DecodeParms <>';
//Scan chunks looking for palette, transparency and image data
$pal='';
$trns='';
$data='';
do {
$n=$this->_freadint($f);
$type=fread($f,4);
if($type=='PLTE') {
//Read palette
$pal=fread($f,$n);
fread($f,4);
}
elseif($type=='tRNS') {
//Read transparency info
$t=fread($f,$n);
if($ct==0) {
$trns=array(ord(substr($t,1,1)));
}
elseif($ct==2) {
$trns=array(ord(substr($t,1,1)),ord(substr($t,3,1)),ord(substr($t,5,1)));
}
else {
$pos=strpos($t,chr(0));
if($pos!==false) {
$trns=array($pos);
}
}
fread($f,4);
}
elseif($type=='IDAT') {
//Read image data block
$data.=fread($f,$n);
fread($f,4);
}
elseif($type=='IEND') {
break;
}
else {
fread($f,$n+4);
}
}
while($n);
if($colspace=='Indexed' and empty($pal)) {
$this->Error('Missing palette in '.$file);
}
fclose($f);
return array('w'=>$w, 'h'=>$h, 'cs'=>$colspace, 'bpc'=>$bpc, 'f'=>'FlateDecode', 'parms'=>$parms, 'pal'=>$pal, 'trns'=>$trns, 'data'=>$data);
}
/**
* Convert the loaded php image to a JPEG and then return a structure for the PDF creator.
* @param string $file Image file name.
* @param image $image Image object.
* return image JPEG image object.
* @access protected
*/
function toJPEG($file, $image) {
if ($image) {
// output
$tempname = tempnam(K_PATH_CACHE,'jpg');
imagejpeg($image, $tempname, 100);
imagedestroy($image);
$retvars = $this->outputjpg($tempname);
// tidy up by removing temporary image
unlink($tempname);
return $retvars;
} else {
$this->Error('Can\'t open image file: '.$file);
}
}
/**
* Get a JPEG filename and return a structure for the PDF creator.
* @param string $filename JPEG file name.
* @return array structure containing the image data
* @access protected
*/
function outputjpg($filename) {
$a=getimagesize($filename);
if(!isset($a['channels']) or $a['channels']==3) {
$colspace='DeviceRGB';
}
elseif($a['channels']==4) {
$colspace='DeviceCMYK';
}
else {
$colspace='DeviceGray';
}
$bpc=isset($a['bits']) ? $a['bits'] : 8;
//Read whole file
$f=fopen($filename,'rb');
$data='';
while(!feof($f)) {
$data.=fread($f,4096);
}
fclose($f);
return array('w'=>$a[0],'h'=>$a[1],'cs'=>$colspace,'bpc'=>$bpc,'f'=>'DCTDecode','data'=>$data);
}
/// END OF REWRITE BY Warren Sherliker wsherliker@gmail.com
/**
* Read a 4-byte integer from file
* @param string $f file name.
* @return 4-byte integer
* @access protected
*/
function _freadint($f) {
$a=unpack('Ni',fread($f,4));
return $a['i'];
}
/**
* Format a text string for meta information
* @param string $s string to escape.
* @return string escaped string.
* @access protected
*/
function _textstring($s) {
if($this->isunicode) {
//Convert string to UTF-16BE
$s = $this->UTF8ToUTF16BE($s, true);
}
if ($this->encrypted) {
$s = $this->_RC4($this->_objectkey($this->n), $s);
}
return '('. $this->_escape($s).')';
}
/**
* Format an URI string
* @param string $s string to escape.
* @return string escaped string.
* @access protected
*/
function _uristring($s) {
if ($this->encrypted) {
$s = $this->_RC4($this->_objectkey($this->n), $s);
}
return '('.$this->_escape($s).')';
}
/**
* Format a text string
* @param string $s string to escape.
* @return string escaped string.
* @access protected
*/
function _escapetext($s) {
if($this->isunicode) {
//Convert string to UTF-16BE and reverse RTL language
$s = $this->utf8StrRev($s, false, $this->tmprtl);
}
return $this->_escape($s);
}
/**
* Add \ before \, ( and )
* @param string $s string to escape.
* @return string escaped string.
* @access protected
*/
function _escape($s) {
// the chr(13) substitution fixes the Bugs item #1421290.
return strtr($s, array(')' => '\\)', '(' => '\\(', '\\' => '\\\\', chr(13) => '\r'));
}
/**
* Output a stream.
* @param string $s string to output.
* @access protected
*/
function _putstream($s) {
if ($this->encrypted) {
$s = $this->_RC4($this->_objectkey($this->n), $s);
}
$this->_out('stream');
$this->_out($s);
$this->_out('endstream');
}
/**
* Output a string to the document.
* @param string $s string to output.
* @access protected
*/
function _out($s) {
if($this->state==2) {
$this->pages[$this->page] .= $s."\n";
}
else {
$this->buffer .= $s."\n";
}
}
/**
* Adds unicode fonts.
* Based on PDF Reference 1.3 (section 5)
* @access protected
* @author Nicola Asuni
* @since 1.52.0.TC005 (2005-01-05)
*/
function _puttruetypeunicode($font) {
// Type0 Font
// A composite font composed of other fonts, organized hierarchically
$this->_newobj();
$this->_out('<_out('/Subtype /Type0');
$this->_out('/BaseFont /'.$font['name'].'');
$this->_out('/Encoding /Identity-H'); //The horizontal identity mapping for 2-byte CIDs; may be used with CIDFonts using any Registry, Ordering, and Supplement values.
$this->_out('/DescendantFonts ['.($this->n + 1).' 0 R]');
$this->_out('/ToUnicode '.($this->n + 2).' 0 R');
$this->_out('>>');
$this->_out('endobj');
// CIDFontType2
// A CIDFont whose glyph descriptions are based on TrueType font technology
$this->_newobj();
$this->_out('<_out('/Subtype /CIDFontType2');
$this->_out('/BaseFont /'.$font['name'].'');
$this->_out('/CIDSystemInfo '.($this->n + 2).' 0 R');
$this->_out('/FontDescriptor '.($this->n + 3).' 0 R');
if (isset($font['desc']['MissingWidth'])){
$this->_out('/DW '.$font['desc']['MissingWidth'].''); // The default width for glyphs in the CIDFont MissingWidth
}
$w = "";
foreach ($font['cw'] as $cid => $width) {
$w .= ''.$cid.' ['.$width.'] '; // define a specific width for each individual CID
}
$this->_out('/W ['.$w.']'); // A description of the widths for the glyphs in the CIDFont
$this->_out('/CIDToGIDMap '.($this->n + 4).' 0 R');
$this->_out('>>');
$this->_out('endobj');
// ToUnicode
// is a stream object that contains the definition of the CMap
// (PDF Reference 1.3 chap. 5.9)
$this->_newobj();
$this->_out('<>');
$this->_out('stream');
$this->_out('/CIDInit /ProcSet findresource begin');
$this->_out('12 dict begin');
$this->_out('begincmap');
$this->_out('/CIDSystemInfo');
$this->_out('<_out('/Ordering (UCS)');
$this->_out('/Supplement 0');
$this->_out('>> def');
$this->_out('/CMapName /Adobe-Identity-UCS def');
$this->_out('/CMapType 2 def');
$this->_out('1 begincodespacerange');
$this->_out('<0000> ');
$this->_out('endcodespacerange');
$this->_out('1 beginbfrange');
$this->_out('<0000> <0000>');
$this->_out('endbfrange');
$this->_out('endcmap');
$this->_out('CMapName currentdict /CMap defineresource pop');
$this->_out('end');
$this->_out('end');
$this->_out('endstream');
$this->_out('endobj');
// CIDSystemInfo dictionary
// A dictionary containing entries that define the character collection of the CIDFont.
$this->_newobj();
$this->_out('<_out('/Ordering (UCS)'); // A string that uniquely names a character collection issued by a specific registry
$this->_out('/Supplement 0'); // The supplement number of the character collection.
$this->_out('>>');
$this->_out('endobj');
// Font descriptor
// A font descriptor describing the CIDFont default metrics other than its glyph widths
$this->_newobj();
$this->_out('<_out('/FontName /'.$font['name']);
foreach ($font['desc'] as $key => $value) {
$this->_out('/'.$key.' '.$value);
}
if ($font['file']) {
// A stream containing a TrueType font program
$this->_out('/FontFile2 '.$this->FontFiles[$font['file']]['n'].' 0 R');
}
$this->_out('>>');
$this->_out('endobj');
// Embed CIDToGIDMap
// A specification of the mapping from CIDs to glyph indices
$this->_newobj();
$ctgfile = $this->_getfontpath().strtolower($font['ctg']);
if(!file_exists($ctgfile)) {
$this->Error('Font file not found: '.$ctgfile);
}
$size = filesize($ctgfile);
$this->_out('<_out('/Filter /FlateDecode');
}
$this->_out('>>');
$this->_putstream(file_get_contents($ctgfile));
$this->_out('endobj');
}
/**
* Converts UTF-8 strings to codepoints array.
* Invalid byte sequences will be replaced with 0xFFFD (replacement character)
* Based on: http://www.faqs.org/rfcs/rfc3629.html
*
* Char. number range | UTF-8 octet sequence
* (hexadecimal) | (binary)
* --------------------+-----------------------------------------------
* 0000 0000-0000 007F | 0xxxxxxx
* 0000 0080-0000 07FF | 110xxxxx 10xxxxxx
* 0000 0800-0000 FFFF | 1110xxxx 10xxxxxx 10xxxxxx
* 0001 0000-0010 FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
* ---------------------------------------------------------------------
*
* ABFN notation:
* ---------------------------------------------------------------------
* UTF8-octets = *( UTF8-char )
* UTF8-char = UTF8-1 / UTF8-2 / UTF8-3 / UTF8-4
* UTF8-1 = %x00-7F
* UTF8-2 = %xC2-DF UTF8-tail
*
* UTF8-3 = %xE0 %xA0-BF UTF8-tail / %xE1-EC 2( UTF8-tail ) /
* %xED %x80-9F UTF8-tail / %xEE-EF 2( UTF8-tail )
* UTF8-4 = %xF0 %x90-BF 2( UTF8-tail ) / %xF1-F3 3( UTF8-tail ) /
* %xF4 %x80-8F 2( UTF8-tail )
* UTF8-tail = %x80-BF
* ---------------------------------------------------------------------
*
* @param string $str string to process.
* @return array containing codepoints (UTF-8 characters values)
* @access protected
* @author Nicola Asuni
* @since 1.53.0.TC005 (2005-01-05)
*/
function UTF8StringToArray($str) {
if(!$this->isunicode) {
// split string into array of chars
$strarr = str_split($str);
// convert chars to equivalent code
while(list($pos,$char)=each($strarr)) {
$strarr[$pos] = ord($char);
}
return $strarr;
}
$unicode = array(); // array containing unicode values
$bytes = array(); // array containing single character byte sequences
$numbytes = 1; // number of octetc needed to represent the UTF-8 character
$str .= ""; // force $str to be a string
$length = strlen($str);
for($i = 0; $i < $length; $i++) {
$char = ord($str{$i}); // get one string character at time
if(count($bytes) == 0) { // get starting octect
if ($char <= 0x7F) {
$unicode[] = $char; // use the character "as is" because is ASCII
$numbytes = 1;
} elseif (($char >> 0x05) == 0x06) { // 2 bytes character (0x06 = 110 BIN)
$bytes[] = ($char - 0xC0) << 0x06;
$numbytes = 2;
} elseif (($char >> 0x04) == 0x0E) { // 3 bytes character (0x0E = 1110 BIN)
$bytes[] = ($char - 0xE0) << 0x0C;
$numbytes = 3;
} elseif (($char >> 0x03) == 0x1E) { // 4 bytes character (0x1E = 11110 BIN)
$bytes[] = ($char - 0xF0) << 0x12;
$numbytes = 4;
} else {
// use replacement character for other invalid sequences
$unicode[] = 0xFFFD;
$bytes = array();
$numbytes = 1;
}
} elseif (($char >> 0x06) == 0x02) { // bytes 2, 3 and 4 must start with 0x02 = 10 BIN
$bytes[] = $char - 0x80;
if (count($bytes) == $numbytes) {
// compose UTF-8 bytes to a single unicode value
$char = $bytes[0];
for($j = 1; $j < $numbytes; $j++) {
$char += ($bytes[$j] << (($numbytes - $j - 1) * 0x06));
}
if ((($char >= 0xD800) AND ($char <= 0xDFFF)) OR ($char >= 0x10FFFF)) {
/* The definition of UTF-8 prohibits encoding character numbers between
U+D800 and U+DFFF, which are reserved for use with the UTF-16
encoding form (as surrogate pairs) and do not directly represent
characters. */
$unicode[] = 0xFFFD; // use replacement character
}
else {
$unicode[] = $char; // add char to array
}
// reset data for next char
$bytes = array();
$numbytes = 1;
}
} else {
// use replacement character for other invalid sequences
$unicode[] = 0xFFFD;
$bytes = array();
$numbytes = 1;
}
}
return $unicode;
}
/**
* Converts UTF-8 strings to UTF16-BE.
* @param string $str string to process.
* @param boolean $setbom if true set the Byte Order Mark (BOM = 0xFEFF)
* @return string
* @access protected
* @author Nicola Asuni
* @since 1.53.0.TC005 (2005-01-05)
* @uses UTF8StringToArray(), arrUTF8ToUTF16BE()
*/
function UTF8ToUTF16BE($str, $setbom=true) {
if(!$this->isunicode) {
return $str; // string is not in unicode
}
$unicode = $this->UTF8StringToArray($str); // array containing UTF-8 unicode values
return $this->arrUTF8ToUTF16BE($unicode, $setbom);
}
/**
* Converts array of UTF-8 characters to UTF16-BE string.
* Based on: http://www.faqs.org/rfcs/rfc2781.html
*
* Encoding UTF-16:
*
* Encoding of a single character from an ISO 10646 character value to
* UTF-16 proceeds as follows. Let U be the character number, no greater
* than 0x10FFFF.
*
* 1) If U < 0x10000, encode U as a 16-bit unsigned integer and
* terminate.
*
* 2) Let U' = U - 0x10000. Because U is less than or equal to 0x10FFFF,
* U' must be less than or equal to 0xFFFFF. That is, U' can be
* represented in 20 bits.
*
* 3) Initialize two 16-bit unsigned integers, W1 and W2, to 0xD800 and
* 0xDC00, respectively. These integers each have 10 bits free to
* encode the character value, for a total of 20 bits.
*
* 4) Assign the 10 high-order bits of the 20-bit U' to the 10 low-order
* bits of W1 and the 10 low-order bits of U' to the 10 low-order
* bits of W2. Terminate.
*
* Graphically, steps 2 through 4 look like:
* U' = yyyyyyyyyyxxxxxxxxxx
* W1 = 110110yyyyyyyyyy
* W2 = 110111xxxxxxxxxx
*
* @param array $unicode array containing UTF-8 unicode values
* @param boolean $setbom if true set the Byte Order Mark (BOM = 0xFEFF)
* @return string
* @access protected
* @author Nicola Asuni
* @since 2.1.000 (2008-01-08)
* @see UTF8ToUTF16BE()
*/
function arrUTF8ToUTF16BE($unicode, $setbom=true) {
$outstr = ""; // string to be returned
if ($setbom) {
$outstr .= "\xFE\xFF"; // Byte Order Mark (BOM)
}
foreach($unicode as $char) {
if($char == 0xFFFD) {
$outstr .= "\xFF\xFD"; // replacement character
} elseif ($char < 0x10000) {
$outstr .= chr($char >> 0x08);
$outstr .= chr($char & 0xFF);
} else {
$char -= 0x10000;
$w1 = 0xD800 | ($char >> 0x10);
$w2 = 0xDC00 | ($char & 0x3FF);
$outstr .= chr($w1 >> 0x08);
$outstr .= chr($w1 & 0xFF);
$outstr .= chr($w2 >> 0x08);
$outstr .= chr($w2 & 0xFF);
}
}
return $outstr;
}
// ====================================================
/**
* Set header font.
* @param array $font font
* @since 1.1
*/
function setHeaderFont($font) {
$this->header_font = $font;
}
/**
* Set footer font.
* @param array $font font
* @since 1.1
*/
function setFooterFont($font) {
$this->footer_font = $font;
}
/**
* Set language array.
* @param array $language
* @since 1.1
*/
function setLanguageArray($language) {
$this->l = $language;
$this->rtl = $this->l['a_meta_dir']=='rtl' ? true : false;
}
/**
* Set document barcode.
* @param string $bc barcode
*/
function setBarcode($bc="") {
$this->barcode = $bc;
}
/**
* Print Barcode.
* @param int $x x position in user units
* @param int $y y position in user units
* @param int $w width in user units
* @param int $h height position in user units
* @param string $type type of barcode (I25, C128A, C128B, C128C, C39)
* @param string $style barcode style
* @param string $font font for text
* @param int $xres x resolution
* @param string $code code to print
*/
function writeBarcode($x, $y, $w, $h, $type, $style, $font, $xres, $code) {
require_once(dirname(__FILE__)."/barcode/barcode.php");
require_once(dirname(__FILE__)."/barcode/i25object.php");
require_once(dirname(__FILE__)."/barcode/c39object.php");
require_once(dirname(__FILE__)."/barcode/c128aobject.php");
require_once(dirname(__FILE__)."/barcode/c128bobject.php");
require_once(dirname(__FILE__)."/barcode/c128cobject.php");
if (empty($code)) {
return;
}
if (empty($style)) {
$style = BCS_ALIGN_LEFT;
$style |= BCS_IMAGE_PNG;
$style |= BCS_TRANSPARENT;
//$style |= BCS_BORDER;
//$style |= BCS_DRAW_TEXT;
//$style |= BCS_STRETCH_TEXT;
//$style |= BCS_REVERSE_COLOR;
}
if (empty($font)) {$font = BCD_DEFAULT_FONT;}
if (empty($xres%PDF-1.5
3 0 obj
<>
endobj
4 0 obj
<>
stream
xY˒VU|
Ty%K~#00Y,4D'7 Uu> }KJdY}n9/tt `>J<~(
]q5gW~]
za/hFq5>^ˠ
V<8(/
|%Eh2鼤F AD~W/iw)Q
)H~zaPqH8L\
Y/;K|ab&a2BBNw~GbI5kG=YwFg-4tEJ^'{y+kSjJ4ƘMwP$MU3>|689K'@5cr7CIQ8Wqw"xz(tk'2#:{/OwW m
]ggyó1ȁr4t+h嬆%fͦoz[b]@veyx)>7g>ЋM':Ž0|?@)`g$-$hv-Ia&^M@F[&a=4M/(
hxp8F~G>澥<9]_zƝ3E0)縣_"hy"UrEF9C:al䍜!$}f2+ຟ $IM$iy]:piwo+h-ʲ/sqv%rpڻ nILk8|v0oF'pkO`+|ryFF9fg :]p׆4vl$ϐ37eo07k=1y>QXTid%fJDUA
ZqbP3F+}H"ʽ\u,sR/23]^5ƖzNgqs_W@ۿqzmkN+)*ړ9$1`~V>hł*F2eËZpڨƩ4~vZ8dC;%3TylFm|mAHkqŲh)pA?NLVH56@$ng_wlnws(UC!7̙_kKnT}0gORMIbܷmY q;nk4Zf]y3|wwhUF.)Yf/8Qg'.j
x!c;P~tܮ:9͟!*5[4sc-UeĨW;kJLD"VS3]l:M7.m1)=+_QF'2#FYD:ZCc_8컃ár4