diff --git a/htdocs/includes/fpdf/fpdf/fpdf_tpl.php b/htdocs/includes/fpdf/fpdf/fpdf_tpl.php index 86b74ccc492..3ff5b4eb0b3 100644 --- a/htdocs/includes/fpdf/fpdf/fpdf_tpl.php +++ b/htdocs/includes/fpdf/fpdf/fpdf_tpl.php @@ -1,446 +1,446 @@ -page <= 0) - $this->error("You have to add a page to fpdf first!"); - - // Save settings - $this->tpl++; - $this->tpls[$this->tpl]['o_x'] = $this->x; - $this->tpls[$this->tpl]['o_y'] = $this->y; - $this->tpls[$this->tpl]['o_AutoPageBreak'] = $this->AutoPageBreak; - $this->tpls[$this->tpl]['o_bMargin'] = $this->bMargin; - $this->tpls[$this->tpl]['o_tMargin'] = $this->tMargin; - $this->tpls[$this->tpl]['o_lMargin'] = $this->lMargin; - $this->tpls[$this->tpl]['o_rMargin'] = $this->rMargin; - $this->tpls[$this->tpl]['o_h'] = $this->h; - $this->tpls[$this->tpl]['o_w'] = $this->w; - - $this->SetAutoPageBreak(false); - - if ($x == null) - $x = 0; - if ($y == null) - $y = 0; - if ($w == null) - $w = $this->w; - if ($h == null) - $h = $this->h; - - // Define own high and width to calculate possitions correct - $this->h = $h; - $this->w = $w; - - $this->tpls[$this->tpl]['buffer'] = ""; - $this->tpls[$this->tpl]['x'] = $x; - $this->tpls[$this->tpl]['y'] = $y; - $this->tpls[$this->tpl]['w'] = $w; - $this->tpls[$this->tpl]['h'] = $h; - - $this->intpl = true; - $this->SetXY($x+$this->lMargin,$y+$this->tMargin); - $this->SetRightMargin($this->w-$w+$this->rMargin); - - return $this->tpl; - } - - /** - * End Template - * - * This method ends a template and reset initiated variables on beginTemplate. - * - * @return mixed If a template is opened, the ID is returned. If not a false is returned. - */ - function endTemplate() { - if ($this->intpl) { - $this->intpl = false; - $this->SetAutoPageBreak($this->tpls[$this->tpl]['o_AutoPageBreak'],$this->tpls[$this->tpl]['o_bMargin']); - $this->SetXY($this->tpls[$this->tpl]['o_x'],$this->tpls[$this->tpl]['o_y']); - $this->tMargin = $this->tpls[$this->tpl]['o_tMargin']; - $this->lMargin = $this->tpls[$this->tpl]['o_lMargin']; - $this->rMargin = $this->tpls[$this->tpl]['o_rMargin']; - $this->h = $this->tpls[$this->tpl]['o_h']; - $this->w = $this->tpls[$this->tpl]['o_w']; - return $this->tpl; - } else { - return false; - } - } - - /** - * Use a Template in current Page or other Template - * - * You can use a template in a page or in another template. - * You can give the used template a new size like you use the Image()-method. - * All parameters are optional. The width or height is calculated automaticaly - * if one is given. If no parameter is given the origin size as defined in - * beginTemplate() is used. - * The calculated or used width and height are returned as an array. - * - * @param int $tplidx A valid template-Id - * @param int $_x The x-position - * @param int $_y The y-position - * @param int $_w The new width of the template - * @param int $_h The new height of the template - * @retrun array The height and width of the template - */ - function useTemplate($tplidx, $_x=null, $_y=null, $_w=0, $_h=0) { - if ($this->page <= 0) - $this->error("You have to add a page to fpdf first!"); - - if (!$this->tpls[$tplidx]) - $this->error("Template does not exist!"); - - if ($this->intpl) { - $this->res['tpl'][$this->tpl]['tpls'][$tplidx] =& $this->tpls[$tplidx]; - } - extract($this->tpls[$tplidx]); - - if ($_x == null) - $_x = $x; - if ($_y == null) - $_y = $y; - $wh = $this->getTemplateSize($tplidx,$_w,$_h); - $_w = $wh['w']; - $_h = $wh['h']; - - $this->_out(sprintf("q %.4f 0 0 %.4f %.2f %.2f cm", ($_w/$w), ($_h/$h), $_x*$this->k, ($this->h-($_y+$_h))*$this->k)); // Translate - $this->_out($this->tplprefix.$tplidx." Do Q"); - - return array("w" => $_w, "h" => $_h); - } - - /** - * Get The calculated Size of a Template - * - * If one size is given, this method calculates the other one. - * - * @param int $tplidx A valid template-Id - * @param int $_w The width of the template - * @param int $_h The height of the template - * @return array The height and width of the template - */ - function getTemplateSize($tplidx, $_w=0, $_h=0) { - if (!$this->tpls[$tplidx]) - return false; - - extract($this->tpls[$tplidx]); - if ($_w == 0 and $_h == 0) { - $_w = $w; - $_h = $h; - } - - if($_w==0) - $_w=$_h*$w/$h; - if($_h==0) - $_h=$_w*$h/$w; - - return array("w" => $_w, "h" => $_h); - } - - /** - * See FPDF-Documentation ;-) - */ - function SetFont($family,$style='',$size=0) { - //Select a font; size given in points - global $fpdf_charwidths; - - $family=strtolower($family); - if($family=='') - $family=$this->FontFamily; - if($family=='arial') - $family='helvetica'; - elseif($family=='symbol' or $family=='zapfdingbats') - $style=''; - $style=strtoupper($style); - if(is_int(strpos($style,'U'))) - { - $this->underline=true; - $style=str_replace('U','',$style); - } - else - $this->underline=false; - if($style=='IB') - $style='BI'; - if($size==0) - $size=$this->FontSizePt; - //Test if font is already selected - if($this->FontFamily==$family and $this->FontStyle==$style and $this->FontSizePt==$size and !$this->intpl) - return; - //Test if used for the first time - $fontkey=$family.$style; - if(!isset($this->fonts[$fontkey])) - { - //Check if one of the standard fonts - if(isset($this->CoreFonts[$fontkey])) - { - if(!isset($fpdf_charwidths[$fontkey])) - { - //Load metric file - $file=$family; - if($family=='times' or $family=='helvetica') - $file.=strtolower($style); - $file.='.php'; - if(defined('FPDF_FONTPATH')) - $file=FPDF_FONTPATH.$file; - include($file); - if(!isset($fpdf_charwidths[$fontkey])) - $this->Error('Could not include font metric file'); - } - $i = $this->findNextAvailFont(); - $this->fonts[$fontkey]=array('i'=>$i,'type'=>'core','name'=>$this->CoreFonts[$fontkey],'up'=>-100,'ut'=>50,'cw'=>$fpdf_charwidths[$fontkey]); - } - else - $this->Error('Undefined font: '.$family.' '.$style); - } - //Select it - $this->FontFamily=$family; - $this->FontStyle=$style; - $this->FontSizePt=$size; - $this->FontSize=$size/$this->k; - $this->CurrentFont=&$this->fonts[$fontkey]; - if($this->page>0) - $this->_out(sprintf('BT '.$this->fontprefix.'%d %.2f Tf ET',$this->CurrentFont['i'],$this->FontSizePt)); - - - if ($this->intpl) { - $this->res['tpl'][$this->tpl]['fonts'][$fontkey] =& $this->fonts[$fontkey]; - } else { - $this->res['page'][$this->page]['fonts'][$fontkey] =& $this->fonts[$fontkey]; - } - } - - /** - * Find the next available Font-No. - * - * @return int - */ - function findNextAvailFont() { - return count($this->fonts)+1; - } - - /** - * See FPDF-Documentation ;-) - */ - function Image($file,$x,$y,$w=0,$h=0,$type='',$link='') { - parent::Image($file,$x,$y,$w,$h,$type,$link); - if ($this->intpl) { - $this->res['tpl'][$this->tpl]['images'][$file] =& $this->images[$file]; - } else { - $this->res['page'][$this->page]['images'][$file] =& $this->images[$file]; - } - } - - /** - * See FPDF-Documentation ;-) - * - * AddPage is not available when you're "in" a template. - */ - function AddPage($orientation='') { - if ($this->intpl) - $this->Error('Adding pages in templates isn\'t possible!'); - parent::AddPage($orientation); - } - - /** - * Preserve adding Links in Templates ...won't work - */ - function Link($x,$y,$w,$h,$link) { - if ($this->intpl) - $this->Error('Using links in templates aren\'t possible!'); - parent::Link($x,$y,$w,$h,$link); - } - - function AddLink() { - if ($this->intpl) - $this->Error('Adding links in templates aren\'t possible!'); - return parent::AddLink(); - } - - function SetLink($link,$y=0,$page=-1) { - if ($this->intpl) - $this->Error('Setting links in templates aren\'t possible!'); - parent::SetLink($link,$y,$page); - } - - /** - * Private Method that writes the Resources-Objects - */ - function _puttemplates() { - $filter=($this->compress) ? '/Filter /FlateDecode ' : ''; - reset($this->tpls); - foreach($this->tpls AS $tplidx => $tpl) { - - $p=($this->compress) ? gzcompress($tpl['buffer']) : $tpl['buffer']; - $this->_newobj(); - $this->tpls[$tplidx]['n'] = $this->n; - $this->_out('<<'.$filter.'/Type /XObject'); - $this->_out('/Subtype /Form'); - $this->_out('/FormType 1'); - $this->_out(sprintf('/BBox [%.2f %.2f %.2f %.2f]',$tpl['x']*$this->k, ($tpl['h']-$tpl['y'])*$this->k, $tpl['w']*$this->k, ($tpl['h']-$tpl['y']-$tpl['h'])*$this->k)); // ($this->h-$tpl['y'])*$this->k - $this->_out('/Resources '); - - $this->_out('<res['tpl'][$tplidx]['fonts'])) { - $this->_out('/Font <<'); - foreach($this->res['tpl'][$tplidx]['fonts'] as $font) - $this->_out($this->fontprefix.$font['i'].' '.$font['n'].' 0 R'); - $this->_out('>>'); - } - if(count($this->res['tpl'][$tplidx]['images']) || count($this->res['tpl'][$tplidx]['tpls'])) - { - $this->_out('/XObject <<'); - if (count($this->res['tpl'][$tplidx]['images'])) { - foreach($this->res['tpl'][$tplidx]['images'] as $image) - $this->_out('/I'.$image['i'].' '.$image['n'].' 0 R'); - } - if (count($this->res['tpl'][$tplidx]['tpls'])) { - foreach($this->res['tpl'][$tplidx]['tpls'] as $i => $tpl) - $this->_out($this->tplprefix.$i.' '.$tpl['n'].' 0 R'); - } - $this->_out('>>'); - } - $this->_out('>>'); - - $this->_out('/Length '.strlen($p).' >>'); - $this->_putstream($p); - $this->_out('endobj'); - } - } - - /** - * Private Method - */ - function _putresources() { - $this->_putfonts(); - $this->_putimages(); - $this->_puttemplates(); - //Resource dictionary - $this->offsets[2]=strlen($this->buffer); - $this->_out('2 0 obj'); - $this->_out('<_out('/Font <<'); - foreach($this->fonts as $font) - $this->_out($this->fontprefix.$font['i'].' '.$font['n'].' 0 R'); - $this->_out('>>'); - if(count($this->images) || count($this->tpls)) - { - $this->_out('/XObject <<'); - if (count($this->images)) { - foreach($this->images as $image) - $this->_out('/I'.$image['i'].' '.$image['n'].' 0 R'); - } - if (count($this->tpls)) { - foreach($this->tpls as $tplidx => $tpl) - $this->_out($this->tplprefix.$tplidx.' '.$tpl['n'].' 0 R'); - } - $this->_out('>>'); - } - $this->_out('>>'); - $this->_out('endobj'); - } - - - /** - * Private Method - */ - function _out($s) { - //Add a line to the document - if ($this->state==2) { - if (!$this->intpl) - $this->pages[$this->page].=$s."\n"; - else - $this->tpls[$this->tpl]['buffer'] .= $s."\n"; - } else { - $this->buffer.=$s."\n"; - } - } -} - +page <= 0) + $this->error("You have to add a page to fpdf first!"); + + // Save settings + $this->tpl++; + $this->tpls[$this->tpl]['o_x'] = $this->x; + $this->tpls[$this->tpl]['o_y'] = $this->y; + $this->tpls[$this->tpl]['o_AutoPageBreak'] = $this->AutoPageBreak; + $this->tpls[$this->tpl]['o_bMargin'] = $this->bMargin; + $this->tpls[$this->tpl]['o_tMargin'] = $this->tMargin; + $this->tpls[$this->tpl]['o_lMargin'] = $this->lMargin; + $this->tpls[$this->tpl]['o_rMargin'] = $this->rMargin; + $this->tpls[$this->tpl]['o_h'] = $this->h; + $this->tpls[$this->tpl]['o_w'] = $this->w; + + $this->SetAutoPageBreak(false); + + if ($x == null) + $x = 0; + if ($y == null) + $y = 0; + if ($w == null) + $w = $this->w; + if ($h == null) + $h = $this->h; + + // Define own high and width to calculate possitions correct + $this->h = $h; + $this->w = $w; + + $this->tpls[$this->tpl]['buffer'] = ""; + $this->tpls[$this->tpl]['x'] = $x; + $this->tpls[$this->tpl]['y'] = $y; + $this->tpls[$this->tpl]['w'] = $w; + $this->tpls[$this->tpl]['h'] = $h; + + $this->intpl = true; + $this->SetXY($x+$this->lMargin,$y+$this->tMargin); + $this->SetRightMargin($this->w-$w+$this->rMargin); + + return $this->tpl; + } + + /** + * End Template + * + * This method ends a template and reset initiated variables on beginTemplate. + * + * @return mixed If a template is opened, the ID is returned. If not a false is returned. + */ + function endTemplate() { + if ($this->intpl) { + $this->intpl = false; + $this->SetAutoPageBreak($this->tpls[$this->tpl]['o_AutoPageBreak'],$this->tpls[$this->tpl]['o_bMargin']); + $this->SetXY($this->tpls[$this->tpl]['o_x'],$this->tpls[$this->tpl]['o_y']); + $this->tMargin = $this->tpls[$this->tpl]['o_tMargin']; + $this->lMargin = $this->tpls[$this->tpl]['o_lMargin']; + $this->rMargin = $this->tpls[$this->tpl]['o_rMargin']; + $this->h = $this->tpls[$this->tpl]['o_h']; + $this->w = $this->tpls[$this->tpl]['o_w']; + return $this->tpl; + } else { + return false; + } + } + + /** + * Use a Template in current Page or other Template + * + * You can use a template in a page or in another template. + * You can give the used template a new size like you use the Image()-method. + * All parameters are optional. The width or height is calculated automaticaly + * if one is given. If no parameter is given the origin size as defined in + * beginTemplate() is used. + * The calculated or used width and height are returned as an array. + * + * @param int $tplidx A valid template-Id + * @param int $_x The x-position + * @param int $_y The y-position + * @param int $_w The new width of the template + * @param int $_h The new height of the template + * @retrun array The height and width of the template + */ + function useTemplate($tplidx, $_x=null, $_y=null, $_w=0, $_h=0) { + if ($this->page <= 0) + $this->error("You have to add a page to fpdf first!"); + + if (!$this->tpls[$tplidx]) + $this->error("Template does not exist!"); + + if ($this->intpl) { + $this->res['tpl'][$this->tpl]['tpls'][$tplidx] =& $this->tpls[$tplidx]; + } + extract($this->tpls[$tplidx]); + + if ($_x == null) + $_x = $x; + if ($_y == null) + $_y = $y; + $wh = $this->getTemplateSize($tplidx,$_w,$_h); + $_w = $wh['w']; + $_h = $wh['h']; + + $this->_out(sprintf("q %.4f 0 0 %.4f %.2f %.2f cm", ($_w/$w), ($_h/$h), $_x*$this->k, ($this->h-($_y+$_h))*$this->k)); // Translate + $this->_out($this->tplprefix.$tplidx." Do Q"); + + return array("w" => $_w, "h" => $_h); + } + + /** + * Get The calculated Size of a Template + * + * If one size is given, this method calculates the other one. + * + * @param int $tplidx A valid template-Id + * @param int $_w The width of the template + * @param int $_h The height of the template + * @return array The height and width of the template + */ + function getTemplateSize($tplidx, $_w=0, $_h=0) { + if (!$this->tpls[$tplidx]) + return false; + + extract($this->tpls[$tplidx]); + if ($_w == 0 and $_h == 0) { + $_w = $w; + $_h = $h; + } + + if($_w==0) + $_w=$_h*$w/$h; + if($_h==0) + $_h=$_w*$h/$w; + + return array("w" => $_w, "h" => $_h); + } + + /** + * See FPDF-Documentation ;-) + */ + function SetFont($family,$style='',$size=0) { + //Select a font; size given in points + global $fpdf_charwidths; + + $family=strtolower($family); + if($family=='') + $family=$this->FontFamily; + if($family=='arial') + $family='helvetica'; + elseif($family=='symbol' or $family=='zapfdingbats') + $style=''; + $style=strtoupper($style); + if(is_int(strpos($style,'U'))) + { + $this->underline=true; + $style=str_replace('U','',$style); + } + else + $this->underline=false; + if($style=='IB') + $style='BI'; + if($size==0) + $size=$this->FontSizePt; + //Test if font is already selected + if($this->FontFamily==$family and $this->FontStyle==$style and $this->FontSizePt==$size and !$this->intpl) + return; + //Test if used for the first time + $fontkey=$family.$style; + if(!isset($this->fonts[$fontkey])) + { + //Check if one of the standard fonts + if(isset($this->CoreFonts[$fontkey])) + { + if(!isset($fpdf_charwidths[$fontkey])) + { + //Load metric file + $file=$family; + if($family=='times' or $family=='helvetica') + $file.=strtolower($style); + $file.='.php'; + if(defined('FPDF_FONTPATH')) + $file=FPDF_FONTPATH.$file; + include($file); + if(!isset($fpdf_charwidths[$fontkey])) + $this->Error('Could not include font metric file'); + } + $i = $this->findNextAvailFont(); + $this->fonts[$fontkey]=array('i'=>$i,'type'=>'core','name'=>$this->CoreFonts[$fontkey],'up'=>-100,'ut'=>50,'cw'=>$fpdf_charwidths[$fontkey]); + } + else + $this->Error('Undefined font: '.$family.' '.$style); + } + //Select it + $this->FontFamily=$family; + $this->FontStyle=$style; + $this->FontSizePt=$size; + $this->FontSize=$size/$this->k; + $this->CurrentFont=&$this->fonts[$fontkey]; + if($this->page>0) + $this->_out(sprintf('BT '.$this->fontprefix.'%d %.2f Tf ET',$this->CurrentFont['i'],$this->FontSizePt)); + + + if ($this->intpl) { + $this->res['tpl'][$this->tpl]['fonts'][$fontkey] =& $this->fonts[$fontkey]; + } else { + $this->res['page'][$this->page]['fonts'][$fontkey] =& $this->fonts[$fontkey]; + } + } + + /** + * Find the next available Font-No. + * + * @return int + */ + function findNextAvailFont() { + return count($this->fonts)+1; + } + + /** + * See FPDF-Documentation ;-) + */ + function Image($file,$x,$y,$w=0,$h=0,$type='',$link='') { + parent::Image($file,$x,$y,$w,$h,$type,$link); + if ($this->intpl) { + $this->res['tpl'][$this->tpl]['images'][$file] =& $this->images[$file]; + } else { + $this->res['page'][$this->page]['images'][$file] =& $this->images[$file]; + } + } + + /** + * See FPDF-Documentation ;-) + * + * AddPage is not available when you're "in" a template. + */ + function AddPage($orientation='') { + if ($this->intpl) + $this->Error('Adding pages in templates isn\'t possible!'); + parent::AddPage($orientation); + } + + /** + * Preserve adding Links in Templates ...won't work + */ + function Link($x,$y,$w,$h,$link) { + if ($this->intpl) + $this->Error('Using links in templates aren\'t possible!'); + parent::Link($x,$y,$w,$h,$link); + } + + function AddLink() { + if ($this->intpl) + $this->Error('Adding links in templates aren\'t possible!'); + return parent::AddLink(); + } + + function SetLink($link,$y=0,$page=-1) { + if ($this->intpl) + $this->Error('Setting links in templates aren\'t possible!'); + parent::SetLink($link,$y,$page); + } + + /** + * Private Method that writes the Resources-Objects + */ + function _puttemplates() { + $filter=($this->compress) ? '/Filter /FlateDecode ' : ''; + reset($this->tpls); + foreach($this->tpls AS $tplidx => $tpl) { + + $p=($this->compress) ? gzcompress($tpl['buffer']) : $tpl['buffer']; + $this->_newobj(); + $this->tpls[$tplidx]['n'] = $this->n; + $this->_out('<<'.$filter.'/Type /XObject'); + $this->_out('/Subtype /Form'); + $this->_out('/FormType 1'); + $this->_out(sprintf('/BBox [%.2f %.2f %.2f %.2f]',$tpl['x']*$this->k, ($tpl['h']-$tpl['y'])*$this->k, $tpl['w']*$this->k, ($tpl['h']-$tpl['y']-$tpl['h'])*$this->k)); // ($this->h-$tpl['y'])*$this->k + $this->_out('/Resources '); + + $this->_out('<res['tpl'][$tplidx]['fonts'])) { + $this->_out('/Font <<'); + foreach($this->res['tpl'][$tplidx]['fonts'] as $font) + $this->_out($this->fontprefix.$font['i'].' '.$font['n'].' 0 R'); + $this->_out('>>'); + } + if(count($this->res['tpl'][$tplidx]['images']) || count($this->res['tpl'][$tplidx]['tpls'])) + { + $this->_out('/XObject <<'); + if (count($this->res['tpl'][$tplidx]['images'])) { + foreach($this->res['tpl'][$tplidx]['images'] as $image) + $this->_out('/I'.$image['i'].' '.$image['n'].' 0 R'); + } + if (count($this->res['tpl'][$tplidx]['tpls'])) { + foreach($this->res['tpl'][$tplidx]['tpls'] as $i => $tpl) + $this->_out($this->tplprefix.$i.' '.$tpl['n'].' 0 R'); + } + $this->_out('>>'); + } + $this->_out('>>'); + + $this->_out('/Length '.strlen($p).' >>'); + $this->_putstream($p); + $this->_out('endobj'); + } + } + + /** + * Private Method + */ + function _putresources() { + $this->_putfonts(); + $this->_putimages(); + $this->_puttemplates(); + //Resource dictionary + $this->offsets[2]=strlen($this->buffer); + $this->_out('2 0 obj'); + $this->_out('<_out('/Font <<'); + foreach($this->fonts as $font) + $this->_out($this->fontprefix.$font['i'].' '.$font['n'].' 0 R'); + $this->_out('>>'); + if(count($this->images) || count($this->tpls)) + { + $this->_out('/XObject <<'); + if (count($this->images)) { + foreach($this->images as $image) + $this->_out('/I'.$image['i'].' '.$image['n'].' 0 R'); + } + if (count($this->tpls)) { + foreach($this->tpls as $tplidx => $tpl) + $this->_out($this->tplprefix.$tplidx.' '.$tpl['n'].' 0 R'); + } + $this->_out('>>'); + } + $this->_out('>>'); + $this->_out('endobj'); + } + + + /** + * Private Method + */ + function _out($s) { + //Add a line to the document + if ($this->state==2) { + if (!$this->intpl) + $this->pages[$this->page].=$s."\n"; + else + $this->tpls[$this->tpl]['buffer'] .= $s."\n"; + } else { + $this->buffer.=$s."\n"; + } + } +} + ?> \ No newline at end of file diff --git a/htdocs/includes/fpdf/fpdf/fpdi.php b/htdocs/includes/fpdf/fpdf/fpdi.php index f203c6fef94..6b989c12a95 100644 --- a/htdocs/includes/fpdf/fpdf/fpdi.php +++ b/htdocs/includes/fpdf/fpdf/fpdi.php @@ -1,413 +1,413 @@ -current_filename = $filename; - $fn =& $this->current_filename; - - $this->parsers[$fn] = new fpdi_pdf_parser($fn,$this); - $this->current_parser =& $this->parsers[$fn]; - - return $this->parsers[$fn]->getPageCount(); - } - - /** - * Import a page - * - * @param int $pageno pagenumber - * @return int Index of imported page - to use with fpdf_tpl::useTemplate() - */ - function ImportPage($pageno) { - $fn =& $this->current_filename; - - $this->parsers[$fn]->setPageno($pageno); - - $this->tpl++; - $this->tpls[$this->tpl] = array(); - $this->tpls[$this->tpl]['parser'] =& $this->parsers[$fn]; - $this->tpls[$this->tpl]['resources'] = $this->parsers[$fn]->getPageResources(); - $this->tpls[$this->tpl]['buffer'] = $this->parsers[$fn]->getContent(); - // $mediabox holds the dimensions of the source page - $mediabox = $this->parsers[$fn]->getPageMediaBox($pageno); - - // To build array that can used by pdf_tpl::useTemplate() - $this->tpls[$this->tpl] = array_merge($this->tpls[$this->tpl],$mediabox); - - return $this->tpl; - } - - /** - * Private method, that rebuilds all needed objects of source files - */ - function _putOobjects() { - if (is_array($this->parsers) && count($this->parsers) > 0) { - foreach($this->parsers AS $filename => $p) { - $this->current_parser =& $this->parsers[$filename]; - if (is_array($this->obj_stack[$filename])) { - while($n = key($this->obj_stack[$filename])) { - $nObj = $this->current_parser->pdf_resolve_object($this->current_parser->c,$this->obj_stack[$filename][$n][1]); - - $this->_newobj($this->obj_stack[$filename][$n][0]); - - if ($nObj[0] == PDF_TYPE_STREAM) { - $this->pdf_write_value ($nObj); - } else { - $this->pdf_write_value ($nObj[1]); - } - - $this->_out('endobj'); - $this->obj_stack[$filename][$n] = null; // free memory - unset($this->obj_stack[$filename][$n]); - reset($this->obj_stack[$filename]); - } - } - } - } - } - - /** - * Rewritten for handling own defined PDF-Versions - * only needed by FPDF 1.52 - */ - function _begindoc() { - //Start document - $this->state=1; - } - - /** - * Sets the PDF Version to the highest of imported documents - */ - function setVersion() { - if ($this->importVersion > $this->PDFVersion) - $this->PDFVersion = $this->importVersion; - - if (!method_exists($this, '_putheader')) { - $this->buffer = '%PDF-'.$this->PDFVersion."\n".$this->buffer; - } - } - - /** - * rewritten for handling higher PDF Versions - */ - function _enddoc() { - $this->setVersion(); - parent::_enddoc(); - } - - - /** - * Put resources - */ - function _putresources() { - $this->_putfonts(); - $this->_putimages(); - $this->_puttemplates(); - $this->_putOobjects(); - - //Resource dictionary - $this->offsets[2]=strlen($this->buffer); - $this->_out('2 0 obj'); - $this->_out('<_out('/Font <<'); - foreach($this->fonts as $font) - $this->_out($this->fontprefix.$font['i'].' '.$font['n'].' 0 R'); - $this->_out('>>'); - if(count($this->images) || count($this->tpls)) - { - $this->_out('/XObject <<'); - if (count($this->images)) { - foreach($this->images as $image) - $this->_out('/I'.$image['i'].' '.$image['n'].' 0 R'); - } - if (count($this->tpls)) { - foreach($this->tpls as $tplidx => $tpl) - $this->_out($this->tplprefix.$tplidx.' '.$tpl['n'].' 0 R'); - } - $this->_out('>>'); - } - $this->_out('>>'); - $this->_out('endobj'); - } - - /** - * Private Method that writes /XObjects - "Templates" - */ - function _puttemplates() { - $filter=($this->compress) ? '/Filter /FlateDecode ' : ''; - reset($this->tpls); - foreach($this->tpls AS $tplidx => $tpl) { - - $p=($this->compress) ? gzcompress($tpl['buffer']) : $tpl['buffer']; - $this->_newobj(); - $this->tpls[$tplidx]['n'] = $this->n; - $this->_out('<<'.$filter.'/Type /XObject'); - $this->_out('/Subtype /Form'); - $this->_out('/FormType 1'); - $this->_out(sprintf('/BBox [%.2f %.2f %.2f %.2f]',$tpl['x']*$this->k, ($tpl['h']-$tpl['y'])*$this->k, $tpl['w']*$this->k, ($tpl['h']-$tpl['y']-$tpl['h'])*$this->k)); - $this->_out('/Resources '); - - if ($tpl['resources']) { - $this->current_parser =& $tpl['parser']; - $this->pdf_write_value($tpl['resources']); - } else { - $this->_out('<res['tpl'][$tplidx]['fonts'])) { - $this->_out('/Font <<'); - foreach($this->res['tpl'][$tplidx]['fonts'] as $font) - $this->_out($this->fontprefix.$font['i'].' '.$font['n'].' 0 R'); - $this->_out('>>'); - } - if(count($this->res['tpl'][$tplidx]['images']) || count($this->res['tpl'][$tplidx]['tpls'])) - { - $this->_out('/XObject <<'); - if (count($this->res['tpl'][$tplidx]['images'])) { - foreach($this->res['tpl'][$tplidx]['images'] as $image) - $this->_out('/I'.$image['i'].' '.$image['n'].' 0 R'); - } - if (count($this->res['tpl'][$tplidx]['tpls'])) { - foreach($this->res['tpl'][$tplidx]['tpls'] as $i => $tpl) - $this->_out($this->tplprefix.$i.' '.$tpl['n'].' 0 R'); - } - $this->_out('>>'); - } - $this->_out('>>'); - } - - $this->_out('/Length '.strlen($p).' >>'); - $this->_putstream($p); - $this->_out('endobj'); - } - } - - /** - * Rewritten to handle existing own defined objects - */ - function _newobj($obj_id=false,$onlynewobj=false) { - if (!$obj_id) { - $obj_id = ++$this->n; - } - - //Begin a new object - if (!$onlynewobj) { - $this->offsets[$obj_id]=strlen($this->buffer); - $this->_out($obj_id.' 0 obj'); - $this->current_obj_id = $obj_id; // for later use with encryption - } - - } - - /** - * Writes a value - * Needed to rebuild the source document - * - * @param mixed $value A PDF-Value. Structure of values see cases in this method - */ - function pdf_write_value(&$value) - { - - switch ($value[0]) { - - case PDF_TYPE_NUMERIC : - case PDF_TYPE_TOKEN : - // A numeric value or a token. - // Simply output them - $this->_out($value[1]." "); - break; - - case PDF_TYPE_ARRAY : - - // An array. Output the proper - // structure and move on. - - $this->_out("[",false); - for ($i = 0; $i < count($value[1]); $i++) { - $this->pdf_write_value($value[1][$i]); - } - - $this->_out("]"); - break; - - case PDF_TYPE_DICTIONARY : - - // A dictionary. - $this->_out("<<",false); - - reset ($value[1]); - - while (list($k, $v) = each($value[1])) { - $this->_out($k . " ",false); - $this->pdf_write_value($v); - } - - $this->_out(">>"); - break; - - case PDF_TYPE_OBJREF : - - // An indirect object reference - // Fill the object stack if needed - if (!isset($this->don_obj_stack[$this->current_parser->filename][$value[1]])) { - $this->_newobj(false,true); - $this->obj_stack[$this->current_parser->filename][$value[1]] = array($this->n,$value); - $this->don_obj_stack[$this->current_parser->filename][$value[1]] = array($this->n,$value); - } - $objid = $this->don_obj_stack[$this->current_parser->filename][$value[1]][0]; - - $this->_out("{$objid} 0 R"); //{$value[2]} - break; - - case PDF_TYPE_STRING : - - // A string. - $this->_out('(' . $value[1] . ')'); - - break; - - case PDF_TYPE_STREAM : - - // A stream. First, output the - // stream dictionary, then the - // stream data itself. - $this->pdf_write_value($value[1]); - $this->_out("stream"); - $this->_out($value[2][1]); - $this->_out("endstream"); - break; - case PDF_TYPE_HEX : - - $this->_out("<" . $value[1] . ">"); - break; - - case PDF_TYPE_NULL : - // The null object. - - $this->_out("null"); - break; - } - } - - - /** - * Private Method - */ - function _out($s,$ln=true) { - //Add a line to the document - if ($this->state==2) { - if (!$this->intpl) - $this->pages[$this->page].=$s.($ln == true ? "\n" : ''); - else - $this->tpls[$this->tpl]['buffer'] .= $s.($ln == true ? "\n" : ''); - } else { - $this->buffer.=$s.($ln == true ? "\n" : ''); - } - } - - /** - * close all files opened by parsers - */ - function closeParsers() { - foreach ($this->parsers as $parser){ - $parser->closeFile(); - } - } - -} - +current_filename = $filename; + $fn =& $this->current_filename; + + $this->parsers[$fn] = new fpdi_pdf_parser($fn,$this); + $this->current_parser =& $this->parsers[$fn]; + + return $this->parsers[$fn]->getPageCount(); + } + + /** + * Import a page + * + * @param int $pageno pagenumber + * @return int Index of imported page - to use with fpdf_tpl::useTemplate() + */ + function ImportPage($pageno) { + $fn =& $this->current_filename; + + $this->parsers[$fn]->setPageno($pageno); + + $this->tpl++; + $this->tpls[$this->tpl] = array(); + $this->tpls[$this->tpl]['parser'] =& $this->parsers[$fn]; + $this->tpls[$this->tpl]['resources'] = $this->parsers[$fn]->getPageResources(); + $this->tpls[$this->tpl]['buffer'] = $this->parsers[$fn]->getContent(); + // $mediabox holds the dimensions of the source page + $mediabox = $this->parsers[$fn]->getPageMediaBox($pageno); + + // To build array that can used by pdf_tpl::useTemplate() + $this->tpls[$this->tpl] = array_merge($this->tpls[$this->tpl],$mediabox); + + return $this->tpl; + } + + /** + * Private method, that rebuilds all needed objects of source files + */ + function _putOobjects() { + if (is_array($this->parsers) && count($this->parsers) > 0) { + foreach($this->parsers AS $filename => $p) { + $this->current_parser =& $this->parsers[$filename]; + if (is_array($this->obj_stack[$filename])) { + while($n = key($this->obj_stack[$filename])) { + $nObj = $this->current_parser->pdf_resolve_object($this->current_parser->c,$this->obj_stack[$filename][$n][1]); + + $this->_newobj($this->obj_stack[$filename][$n][0]); + + if ($nObj[0] == PDF_TYPE_STREAM) { + $this->pdf_write_value ($nObj); + } else { + $this->pdf_write_value ($nObj[1]); + } + + $this->_out('endobj'); + $this->obj_stack[$filename][$n] = null; // free memory + unset($this->obj_stack[$filename][$n]); + reset($this->obj_stack[$filename]); + } + } + } + } + } + + /** + * Rewritten for handling own defined PDF-Versions + * only needed by FPDF 1.52 + */ + function _begindoc() { + //Start document + $this->state=1; + } + + /** + * Sets the PDF Version to the highest of imported documents + */ + function setVersion() { + if ($this->importVersion > $this->PDFVersion) + $this->PDFVersion = $this->importVersion; + + if (!method_exists($this, '_putheader')) { + $this->buffer = '%PDF-'.$this->PDFVersion."\n".$this->buffer; + } + } + + /** + * rewritten for handling higher PDF Versions + */ + function _enddoc() { + $this->setVersion(); + parent::_enddoc(); + } + + + /** + * Put resources + */ + function _putresources() { + $this->_putfonts(); + $this->_putimages(); + $this->_puttemplates(); + $this->_putOobjects(); + + //Resource dictionary + $this->offsets[2]=strlen($this->buffer); + $this->_out('2 0 obj'); + $this->_out('<_out('/Font <<'); + foreach($this->fonts as $font) + $this->_out($this->fontprefix.$font['i'].' '.$font['n'].' 0 R'); + $this->_out('>>'); + if(count($this->images) || count($this->tpls)) + { + $this->_out('/XObject <<'); + if (count($this->images)) { + foreach($this->images as $image) + $this->_out('/I'.$image['i'].' '.$image['n'].' 0 R'); + } + if (count($this->tpls)) { + foreach($this->tpls as $tplidx => $tpl) + $this->_out($this->tplprefix.$tplidx.' '.$tpl['n'].' 0 R'); + } + $this->_out('>>'); + } + $this->_out('>>'); + $this->_out('endobj'); + } + + /** + * Private Method that writes /XObjects - "Templates" + */ + function _puttemplates() { + $filter=($this->compress) ? '/Filter /FlateDecode ' : ''; + reset($this->tpls); + foreach($this->tpls AS $tplidx => $tpl) { + + $p=($this->compress) ? gzcompress($tpl['buffer']) : $tpl['buffer']; + $this->_newobj(); + $this->tpls[$tplidx]['n'] = $this->n; + $this->_out('<<'.$filter.'/Type /XObject'); + $this->_out('/Subtype /Form'); + $this->_out('/FormType 1'); + $this->_out(sprintf('/BBox [%.2f %.2f %.2f %.2f]',$tpl['x']*$this->k, ($tpl['h']-$tpl['y'])*$this->k, $tpl['w']*$this->k, ($tpl['h']-$tpl['y']-$tpl['h'])*$this->k)); + $this->_out('/Resources '); + + if ($tpl['resources']) { + $this->current_parser =& $tpl['parser']; + $this->pdf_write_value($tpl['resources']); + } else { + $this->_out('<res['tpl'][$tplidx]['fonts'])) { + $this->_out('/Font <<'); + foreach($this->res['tpl'][$tplidx]['fonts'] as $font) + $this->_out($this->fontprefix.$font['i'].' '.$font['n'].' 0 R'); + $this->_out('>>'); + } + if(count($this->res['tpl'][$tplidx]['images']) || count($this->res['tpl'][$tplidx]['tpls'])) + { + $this->_out('/XObject <<'); + if (count($this->res['tpl'][$tplidx]['images'])) { + foreach($this->res['tpl'][$tplidx]['images'] as $image) + $this->_out('/I'.$image['i'].' '.$image['n'].' 0 R'); + } + if (count($this->res['tpl'][$tplidx]['tpls'])) { + foreach($this->res['tpl'][$tplidx]['tpls'] as $i => $tpl) + $this->_out($this->tplprefix.$i.' '.$tpl['n'].' 0 R'); + } + $this->_out('>>'); + } + $this->_out('>>'); + } + + $this->_out('/Length '.strlen($p).' >>'); + $this->_putstream($p); + $this->_out('endobj'); + } + } + + /** + * Rewritten to handle existing own defined objects + */ + function _newobj($obj_id=false,$onlynewobj=false) { + if (!$obj_id) { + $obj_id = ++$this->n; + } + + //Begin a new object + if (!$onlynewobj) { + $this->offsets[$obj_id]=strlen($this->buffer); + $this->_out($obj_id.' 0 obj'); + $this->current_obj_id = $obj_id; // for later use with encryption + } + + } + + /** + * Writes a value + * Needed to rebuild the source document + * + * @param mixed $value A PDF-Value. Structure of values see cases in this method + */ + function pdf_write_value(&$value) + { + + switch ($value[0]) { + + case PDF_TYPE_NUMERIC : + case PDF_TYPE_TOKEN : + // A numeric value or a token. + // Simply output them + $this->_out($value[1]." "); + break; + + case PDF_TYPE_ARRAY : + + // An array. Output the proper + // structure and move on. + + $this->_out("[",false); + for ($i = 0; $i < count($value[1]); $i++) { + $this->pdf_write_value($value[1][$i]); + } + + $this->_out("]"); + break; + + case PDF_TYPE_DICTIONARY : + + // A dictionary. + $this->_out("<<",false); + + reset ($value[1]); + + while (list($k, $v) = each($value[1])) { + $this->_out($k . " ",false); + $this->pdf_write_value($v); + } + + $this->_out(">>"); + break; + + case PDF_TYPE_OBJREF : + + // An indirect object reference + // Fill the object stack if needed + if (!isset($this->don_obj_stack[$this->current_parser->filename][$value[1]])) { + $this->_newobj(false,true); + $this->obj_stack[$this->current_parser->filename][$value[1]] = array($this->n,$value); + $this->don_obj_stack[$this->current_parser->filename][$value[1]] = array($this->n,$value); + } + $objid = $this->don_obj_stack[$this->current_parser->filename][$value[1]][0]; + + $this->_out("{$objid} 0 R"); //{$value[2]} + break; + + case PDF_TYPE_STRING : + + // A string. + $this->_out('(' . $value[1] . ')'); + + break; + + case PDF_TYPE_STREAM : + + // A stream. First, output the + // stream dictionary, then the + // stream data itself. + $this->pdf_write_value($value[1]); + $this->_out("stream"); + $this->_out($value[2][1]); + $this->_out("endstream"); + break; + case PDF_TYPE_HEX : + + $this->_out("<" . $value[1] . ">"); + break; + + case PDF_TYPE_NULL : + // The null object. + + $this->_out("null"); + break; + } + } + + + /** + * Private Method + */ + function _out($s,$ln=true) { + //Add a line to the document + if ($this->state==2) { + if (!$this->intpl) + $this->pages[$this->page].=$s.($ln == true ? "\n" : ''); + else + $this->tpls[$this->tpl]['buffer'] .= $s.($ln == true ? "\n" : ''); + } else { + $this->buffer.=$s.($ln == true ? "\n" : ''); + } + } + + /** + * close all files opened by parsers + */ + function closeParsers() { + foreach ($this->parsers as $parser){ + $parser->closeFile(); + } + } + +} + ?> \ No newline at end of file diff --git a/htdocs/includes/fpdf/fpdf/fpdi_pdf_parser.php b/htdocs/includes/fpdf/fpdf/fpdi_pdf_parser.php index d0016776827..71df28d3ff2 100644 --- a/htdocs/includes/fpdf/fpdf/fpdi_pdf_parser.php +++ b/htdocs/includes/fpdf/fpdf/fpdi_pdf_parser.php @@ -1,482 +1,482 @@ -fpdi =& $fpdi; - $this->filename = $filename; - - parent::pdf_parser($filename); - - // Get Info - $this->getInfo(); - - // resolve Pages-Dictonary - $pages = $this->pdf_resolve_object($this->c, $this->root[1][1]['/Pages']); - - // Read pages - $this->read_pages($this->c, $pages, $this->pages); - - // count pages; - $this->page_count = count($this->pages); - } - - /** - * Overwrite parent::error() - * - * @param string $msg Error-Message - */ - function error($msg) { - $this->fpdi->error($msg); - } - - /** - * Get pagecount from sourcefile - * - * @return int - */ - function getPageCount() { - return $this->page_count; - } - - - /** - * Set pageno - * - * @param int $pageno Pagenumber to use - */ - function setPageno($pageno) { - $pageno-=1; - - if ($pageno < 0 || $pageno >= $this->getPageCount()) { - $this->fpdi->error("Pagenumber is wrong!"); - } - - $this->pageno = $pageno; - } - - /** - * Get page-resources from current page - * - * @return array - */ - function getPageResources() { - return $this->_getPageResources($this->pages[$this->pageno]); - } - - /** - * Get page-resources from /Page - * - * @param array $obj Array of pdf-data - */ - function _getPageResources ($obj) { // $obj = /Page - $obj = $this->pdf_resolve_object($this->c, $obj); - - // If the current object has a resources - // dictionary associated with it, we use - // it. Otherwise, we move back to its - // parent object. - if (isset ($obj[1][1]['/Resources'])) { - $res = $this->pdf_resolve_object($this->c, $obj[1][1]['/Resources']); - if ($res[0] == PDF_TYPE_OBJECT) - return $res[1]; - return $res; - } else { - if (!isset ($obj[1][1]['/Parent'])) { - return false; - } else { - $res = $this->_getPageResources($obj[1][1]['/Parent']); - if ($res[0] == PDF_TYPE_OBJECT) - return $res[1]; - return $res; - } - } - } - - - function getInfo() { - $avail_infos = array("Title", "Author", "Subject", "Keywords", "Creator", "Producer", "CreationDate", "ModDate", "Trapped"); - - $_infos = $this->pdf_resolve_object($this->c,$this->xref['trailer'][1]['/Info']); - $infos = array(); - - foreach ($avail_infos AS $info) { - if (isset($_infos[1][1]["/".$info])) { - if ($_infos[1][1]["/".$info][0] == PDF_TYPE_STRING) { - $infos[$info] = $this->deescapeString($_infos[1][1]["/".$info][1]); - } else if ($_infos[1][1]["/".$info][0] == PDF_TYPE_HEX) { - $infos[$info] = $this->hex2String($_infos[1][1]["/".$info][1]); - } - } - } - $this->infos = $infos; - } - - /** - * Rebuilds a hexstring to string - * - * @param string $hex hexstring - * @return string - */ - function hex2String($hex) { - $endian = false; - - if (preg_match("/^FEFF/",$hex)) { // is utf-16 aka big endian - $i = 4; - $endian = "big"; - } else if (preg_match("/^FFFE/",$hex)) { // is utf-16 aka little endian - $i = 4; - $endian = "little"; - } else { - $i = 0; - } - - $s = ""; - $l = strlen($hex); - for (; $i < $l; $i+=2) { - if (!$endian) { - $s .= chr(hexdec($hex[$i].(isset($hex[$i+1]) ? $hex[$i+1] : '0'))); - } else { - if ($endian == "big") { - $_c = $hex[$i].$hex[$i+1]; - $i+=2; - $c = $hex[$i].$hex[$i+1]; - - if ($_c != "00") { - $s .= "?"; - continue; - } else { - $s .= chr(hexdec($c)); - continue; - } - } else if ($endian == "little") { - $c = $hex[$i].$hex[$i+1]; - $i+=2; - $_c = $hex[$i].$hex[$i+1]; - - if ($_c != "00") { - $s .= "?"; - continue; - } else { - $s .= chr(hexdec($c)); - continue; - } - } - } - } - - return $s; - } - - function deescapeString($s) { - $torepl = array("/\\\(\d{1,3})/e" => "chr(octdec(\\1))", - "/\\\\\(/" => "(", - "/\\\\\)/" => ")"); - return preg_replace(array_keys($torepl),$torepl,$s); - } - - - - /** - * Get content of current page - * - * If more /Contents is an array, the streams are concated - * - * @return string - */ - function getContent() { - $buffer = ""; - - $contents = $this->getPageContent($this->pages[$this->pageno][1][1]['/Contents']); - foreach($contents AS $tmp_content) { - $buffer .= $this->rebuildContentStream($tmp_content); - } - - return $buffer; - } - - - /** - * Resolve all content-objects - * - * @param array $content_ref - * @return array - */ - function getPageContent($content_ref) { - $contents = array(); - - if ($content_ref[0] == PDF_TYPE_OBJREF) { - $content = $this->pdf_resolve_object($this->c, $content_ref); - if ($content[1][0] == PDF_TYPE_ARRAY) { - $contents = $this->getPageContent($content[1]); - } else { - $contents[] = $content; - } - } else if ($content_ref[0] == PDF_TYPE_ARRAY) { - foreach ($content_ref[1] AS $tmp_content_ref) { - $contents = array_merge($contents,$this->getPageContent($tmp_content_ref)); - } - } - - return $contents; - } - - - /** - * Rebuild content-streams - * only non-compressed streams and /FlateDecode are ready! - * - * @param array $obj - * @return string - */ - function rebuildContentStream($obj) { - $filters = array(); - - if (isset($obj[1][1]['/Filter'])) { - $_filter = $obj[1][1]['/Filter']; - - if ($_filter[0] == PDF_TYPE_TOKEN) { - $filters[] = $_filter; - } else if ($_filter[0] == PDF_TYPE_ARRAY) { - $filters = $_filter[1]; - } - } - - $stream = $obj[2][1]; - - foreach ($filters AS $_filter) { - switch ($_filter[1]) { - case "/FlateDecode": - if (function_exists('gzuncompress')) { - $stream = @gzuncompress($stream); - } else { - $this->fpdi->error(sprintf("To handle %s filter, please compile php with zlib support.",$_filter[1])); - } - if ($stream === false) { - $this->fpdi->error("Error while decompressing string."); - } - - break; - case "/LZWDecode": - @include_once("decoders/lzw.php"); - if (class_exists("LZWDecode")) { - $lzwdec = new LZWDecode($this->fpdi); - $stream = $lzwdec->decode($stream); - } else { - $this->fpdi->error(sprintf("Unsupported Filter: %s",$_filter[1])); - } - break; - case "/ASCII85Decode": - @include_once("decoders/ascii85.php"); - if (class_exists("ASCII85Decode")) { - $ascii85 = new ASCII85Decode($this->fpdi); - $stream = $ascii85->decode(trim($stream)); - } else { - $this->fpdi->error(sprintf("Unsupported Filter: %s",$_filter[1])); - } - break; - case null: - $stream = $stream; - break; - default: - $this->fpdi->error(sprintf("Unsupported Filter: %s",$_filter[1])); - } - } - - return $stream; - } - - /** - * Get MediaBox - * - * gets an array that describes the size of a page. - * - * @param integer $pageno - * @return array @see getPageBox() - */ - function getPageMediaBox($pageno) { - return $this->getPageBox($this->pages[$pageno-1],"/MediaBox"); - } - - - /** - * Get a Box from a page - * Arrayformat is same as used by fpdf_tpl - * - * @param array $page a /Page - * @param string $box_index Type of Box @see getPageBoxes() - * @return array - */ - function getPageBox($page, $box_index) { - $page = $this->pdf_resolve_object($this->c,$page); - - $box = null; - if (isset($page[1][1][$box_index])) - $box =& $page[1][1][$box_index]; - - if (!is_null($box) && $box[0] == PDF_TYPE_OBJREF) { - $tmp_box = $this->pdf_resolve_object($this->c,$box); - $box = $tmp_box[1]; - } - - if (!is_null($box) && $box[0] == PDF_TYPE_ARRAY) { - $b =& $box[1]; - return array("x" => $b[0][1]/$this->fpdi->k, - "y" => $b[1][1]/$this->fpdi->k, - "w" => $b[2][1]/$this->fpdi->k, - "h" => $b[3][1]/$this->fpdi->k); - } else if (!isset ($page[1][1]['/Parent'])) { - return false; - } else { - return $this->getPageBox($this->pdf_resolve_object($this->c, $page[1][1]['/Parent']), $box_index); - } - } - - /** - * Get all Boxes from /Page - * - * @param array a /Page - * @return array - */ - function getPageBoxes($page) { - $_boxes = array("/MediaBox","/CropBox","/BleedBox","/TrimBox","/ArtBox"); - $boxes = array(); - - foreach($_boxes AS $box) { - if ($_box = $this->getPageBox($page,$box)) { - $boxes[$box] = $_box; - } - } - - return $boxes; - } - - - /** - * Read all /Page(es) - * - * @param object pdf_context - * @param array /Pages - * @param array the result-array - */ - function read_pages (&$c, &$pages, &$result) { - - // Get the kids dictionary - $kids = $this->pdf_resolve_object ($c, $pages[1][1]['/Kids']); - - if (!is_array($kids)) - $this->fpdi->Error("Cannot find /Kids in current /Page-Dictionary"); - foreach ($kids[1] as $v) { - $pg = $this->pdf_resolve_object ($c, $v); - #print_r($pg); - - if ($pg[1][1]['/Type'][1] === '/Pages') { - // If one of the kids is an embedded - // /Pages array, resolve it as well. - $this->read_pages ($c, $pg, $result); - } else { - $result[] = $pg; - } - } - } - - - - /** - * Get PDF-Version - * - * And reset the PDF Version used in FPDI if needed - */ - function getPDFVersion() { - parent::getPDFVersion(); - - if (isset($this->fpdi->importVersion) && $this->pdfVersion > $this->fpdi->importVersion) { - $this->fpdi->importVersion = $this->pdfVersion; - } - } - -} - +fpdi =& $fpdi; + $this->filename = $filename; + + parent::pdf_parser($filename); + + // Get Info + $this->getInfo(); + + // resolve Pages-Dictonary + $pages = $this->pdf_resolve_object($this->c, $this->root[1][1]['/Pages']); + + // Read pages + $this->read_pages($this->c, $pages, $this->pages); + + // count pages; + $this->page_count = count($this->pages); + } + + /** + * Overwrite parent::error() + * + * @param string $msg Error-Message + */ + function error($msg) { + $this->fpdi->error($msg); + } + + /** + * Get pagecount from sourcefile + * + * @return int + */ + function getPageCount() { + return $this->page_count; + } + + + /** + * Set pageno + * + * @param int $pageno Pagenumber to use + */ + function setPageno($pageno) { + $pageno-=1; + + if ($pageno < 0 || $pageno >= $this->getPageCount()) { + $this->fpdi->error("Pagenumber is wrong!"); + } + + $this->pageno = $pageno; + } + + /** + * Get page-resources from current page + * + * @return array + */ + function getPageResources() { + return $this->_getPageResources($this->pages[$this->pageno]); + } + + /** + * Get page-resources from /Page + * + * @param array $obj Array of pdf-data + */ + function _getPageResources ($obj) { // $obj = /Page + $obj = $this->pdf_resolve_object($this->c, $obj); + + // If the current object has a resources + // dictionary associated with it, we use + // it. Otherwise, we move back to its + // parent object. + if (isset ($obj[1][1]['/Resources'])) { + $res = $this->pdf_resolve_object($this->c, $obj[1][1]['/Resources']); + if ($res[0] == PDF_TYPE_OBJECT) + return $res[1]; + return $res; + } else { + if (!isset ($obj[1][1]['/Parent'])) { + return false; + } else { + $res = $this->_getPageResources($obj[1][1]['/Parent']); + if ($res[0] == PDF_TYPE_OBJECT) + return $res[1]; + return $res; + } + } + } + + + function getInfo() { + $avail_infos = array("Title", "Author", "Subject", "Keywords", "Creator", "Producer", "CreationDate", "ModDate", "Trapped"); + + $_infos = $this->pdf_resolve_object($this->c,$this->xref['trailer'][1]['/Info']); + $infos = array(); + + foreach ($avail_infos AS $info) { + if (isset($_infos[1][1]["/".$info])) { + if ($_infos[1][1]["/".$info][0] == PDF_TYPE_STRING) { + $infos[$info] = $this->deescapeString($_infos[1][1]["/".$info][1]); + } else if ($_infos[1][1]["/".$info][0] == PDF_TYPE_HEX) { + $infos[$info] = $this->hex2String($_infos[1][1]["/".$info][1]); + } + } + } + $this->infos = $infos; + } + + /** + * Rebuilds a hexstring to string + * + * @param string $hex hexstring + * @return string + */ + function hex2String($hex) { + $endian = false; + + if (preg_match("/^FEFF/",$hex)) { // is utf-16 aka big endian + $i = 4; + $endian = "big"; + } else if (preg_match("/^FFFE/",$hex)) { // is utf-16 aka little endian + $i = 4; + $endian = "little"; + } else { + $i = 0; + } + + $s = ""; + $l = strlen($hex); + for (; $i < $l; $i+=2) { + if (!$endian) { + $s .= chr(hexdec($hex[$i].(isset($hex[$i+1]) ? $hex[$i+1] : '0'))); + } else { + if ($endian == "big") { + $_c = $hex[$i].$hex[$i+1]; + $i+=2; + $c = $hex[$i].$hex[$i+1]; + + if ($_c != "00") { + $s .= "?"; + continue; + } else { + $s .= chr(hexdec($c)); + continue; + } + } else if ($endian == "little") { + $c = $hex[$i].$hex[$i+1]; + $i+=2; + $_c = $hex[$i].$hex[$i+1]; + + if ($_c != "00") { + $s .= "?"; + continue; + } else { + $s .= chr(hexdec($c)); + continue; + } + } + } + } + + return $s; + } + + function deescapeString($s) { + $torepl = array("/\\\(\d{1,3})/e" => "chr(octdec(\\1))", + "/\\\\\(/" => "(", + "/\\\\\)/" => ")"); + return preg_replace(array_keys($torepl),$torepl,$s); + } + + + + /** + * Get content of current page + * + * If more /Contents is an array, the streams are concated + * + * @return string + */ + function getContent() { + $buffer = ""; + + $contents = $this->getPageContent($this->pages[$this->pageno][1][1]['/Contents']); + foreach($contents AS $tmp_content) { + $buffer .= $this->rebuildContentStream($tmp_content); + } + + return $buffer; + } + + + /** + * Resolve all content-objects + * + * @param array $content_ref + * @return array + */ + function getPageContent($content_ref) { + $contents = array(); + + if ($content_ref[0] == PDF_TYPE_OBJREF) { + $content = $this->pdf_resolve_object($this->c, $content_ref); + if ($content[1][0] == PDF_TYPE_ARRAY) { + $contents = $this->getPageContent($content[1]); + } else { + $contents[] = $content; + } + } else if ($content_ref[0] == PDF_TYPE_ARRAY) { + foreach ($content_ref[1] AS $tmp_content_ref) { + $contents = array_merge($contents,$this->getPageContent($tmp_content_ref)); + } + } + + return $contents; + } + + + /** + * Rebuild content-streams + * only non-compressed streams and /FlateDecode are ready! + * + * @param array $obj + * @return string + */ + function rebuildContentStream($obj) { + $filters = array(); + + if (isset($obj[1][1]['/Filter'])) { + $_filter = $obj[1][1]['/Filter']; + + if ($_filter[0] == PDF_TYPE_TOKEN) { + $filters[] = $_filter; + } else if ($_filter[0] == PDF_TYPE_ARRAY) { + $filters = $_filter[1]; + } + } + + $stream = $obj[2][1]; + + foreach ($filters AS $_filter) { + switch ($_filter[1]) { + case "/FlateDecode": + if (function_exists('gzuncompress')) { + $stream = @gzuncompress($stream); + } else { + $this->fpdi->error(sprintf("To handle %s filter, please compile php with zlib support.",$_filter[1])); + } + if ($stream === false) { + $this->fpdi->error("Error while decompressing string."); + } + + break; + case "/LZWDecode": + @include_once("decoders/lzw.php"); + if (class_exists("LZWDecode")) { + $lzwdec = new LZWDecode($this->fpdi); + $stream = $lzwdec->decode($stream); + } else { + $this->fpdi->error(sprintf("Unsupported Filter: %s",$_filter[1])); + } + break; + case "/ASCII85Decode": + @include_once("decoders/ascii85.php"); + if (class_exists("ASCII85Decode")) { + $ascii85 = new ASCII85Decode($this->fpdi); + $stream = $ascii85->decode(trim($stream)); + } else { + $this->fpdi->error(sprintf("Unsupported Filter: %s",$_filter[1])); + } + break; + case null: + $stream = $stream; + break; + default: + $this->fpdi->error(sprintf("Unsupported Filter: %s",$_filter[1])); + } + } + + return $stream; + } + + /** + * Get MediaBox + * + * gets an array that describes the size of a page. + * + * @param integer $pageno + * @return array @see getPageBox() + */ + function getPageMediaBox($pageno) { + return $this->getPageBox($this->pages[$pageno-1],"/MediaBox"); + } + + + /** + * Get a Box from a page + * Arrayformat is same as used by fpdf_tpl + * + * @param array $page a /Page + * @param string $box_index Type of Box @see getPageBoxes() + * @return array + */ + function getPageBox($page, $box_index) { + $page = $this->pdf_resolve_object($this->c,$page); + + $box = null; + if (isset($page[1][1][$box_index])) + $box =& $page[1][1][$box_index]; + + if (!is_null($box) && $box[0] == PDF_TYPE_OBJREF) { + $tmp_box = $this->pdf_resolve_object($this->c,$box); + $box = $tmp_box[1]; + } + + if (!is_null($box) && $box[0] == PDF_TYPE_ARRAY) { + $b =& $box[1]; + return array("x" => $b[0][1]/$this->fpdi->k, + "y" => $b[1][1]/$this->fpdi->k, + "w" => $b[2][1]/$this->fpdi->k, + "h" => $b[3][1]/$this->fpdi->k); + } else if (!isset ($page[1][1]['/Parent'])) { + return false; + } else { + return $this->getPageBox($this->pdf_resolve_object($this->c, $page[1][1]['/Parent']), $box_index); + } + } + + /** + * Get all Boxes from /Page + * + * @param array a /Page + * @return array + */ + function getPageBoxes($page) { + $_boxes = array("/MediaBox","/CropBox","/BleedBox","/TrimBox","/ArtBox"); + $boxes = array(); + + foreach($_boxes AS $box) { + if ($_box = $this->getPageBox($page,$box)) { + $boxes[$box] = $_box; + } + } + + return $boxes; + } + + + /** + * Read all /Page(es) + * + * @param object pdf_context + * @param array /Pages + * @param array the result-array + */ + function read_pages (&$c, &$pages, &$result) { + + // Get the kids dictionary + $kids = $this->pdf_resolve_object ($c, $pages[1][1]['/Kids']); + + if (!is_array($kids)) + $this->fpdi->Error("Cannot find /Kids in current /Page-Dictionary"); + foreach ($kids[1] as $v) { + $pg = $this->pdf_resolve_object ($c, $v); + #print_r($pg); + + if ($pg[1][1]['/Type'][1] === '/Pages') { + // If one of the kids is an embedded + // /Pages array, resolve it as well. + $this->read_pages ($c, $pg, $result); + } else { + $result[] = $pg; + } + } + } + + + + /** + * Get PDF-Version + * + * And reset the PDF Version used in FPDI if needed + */ + function getPDFVersion() { + parent::getPDFVersion(); + + if (isset($this->fpdi->importVersion) && $this->pdfVersion > $this->fpdi->importVersion) { + $this->fpdi->importVersion = $this->pdfVersion; + } + } + +} + ?> \ No newline at end of file diff --git a/htdocs/includes/fpdf/fpdf/fpdi_protection.php b/htdocs/includes/fpdf/fpdf/fpdi_protection.php index 08b0a78d75c..ba19796b1cd 100644 --- a/htdocs/includes/fpdf/fpdf/fpdi_protection.php +++ b/htdocs/includes/fpdf/fpdf/fpdi_protection.php @@ -20,7 +20,7 @@ * * ****************************************************************************/ -require_once("fpdi.php"); +require_once(FPDF_PATH.'fpdi.php'); class FPDI_Protection extends fpdi { diff --git a/htdocs/includes/fpdf/fpdf/pdf_parser.php b/htdocs/includes/fpdf/fpdf/pdf_parser.php index b525ffdfed6..f7125370ef5 100644 --- a/htdocs/includes/fpdf/fpdf/pdf_parser.php +++ b/htdocs/includes/fpdf/fpdf/pdf_parser.php @@ -1,634 +1,634 @@ -filename = $filename; - - $this->f = @fopen($this->filename,"rb"); - - if (!$this->f) - $this->error(sprintf("Cannot open %s !",$filename)); - - $this->getPDFVersion(); - - $this->c = new pdf_context($this->f); - // Read xref-Data - $this->pdf_read_xref($this->xref, $this->pdf_find_xref()); - - // Check for Encryption - $this->getEncryption(); - - // Read root - $this->pdf_read_root(); - } - - /** - * Close the opened file - */ - function closeFile() { - if (isset($this->f)) { - fclose($this->f); - } - } - - /** - * Print Error and die - * - * @param string $msg Error-Message - */ - function error($msg) { - die("PDF-Parser Error: ".$msg); - } - - /** - * Check Trailer for Encryption - */ - function getEncryption() { - if (isset($this->xref['trailer'][1]['/Encrypt'])) { - $this->error("File is encrypted!"); - } - } - - /** - * Find/Return /Root - * - * @return array - */ - function pdf_find_root() { - if ($this->xref['trailer'][1]['/Root'][0] != PDF_TYPE_OBJREF) { - $this->Error("Wrong Type of Root-Element! Must be an indirect reference"); - } - return $this->xref['trailer'][1]['/Root']; - } - - /** - * Read the /Root - */ - function pdf_read_root() { - // read root - $this->root = $this->pdf_resolve_object($this->c, $this->pdf_find_root()); - } - - /** - * Get PDF-Version - * - * And reset the PDF Version used in FPDI if needed - */ - function getPDFVersion() { - fseek($this->f, 0); - preg_match("/\d\.\d/",fread($this->f,16),$m); - $this->pdfVersion = $m[0]; - } - - /** - * Find the xref-Table - */ - function pdf_find_xref() { - fseek ($this->f, -50, SEEK_END); - $data = fread($this->f, 50); - - if (!preg_match('/startxref\s*(\d+)\s*%%EOF\s*$/', $data, $matches)) { - $this->error("Unable to find pointer to xref table"); - } - - return (int) $matches[1]; - } - - /** - * Read xref-table - * - * @param array $result Array of xref-table - * @param integer $offset of xref-table - * @param integer $start start-position in xref-table - * @param integer $end end-position in xref-table - */ - function pdf_read_xref(&$result, $offset, $start = null, $end = null) { - if (is_null ($start) || is_null ($end)) { - fseek($this->f, $o_pos = $offset); - $data = trim(fgets($this->f)); - - if ($data !== 'xref') { - fseek($this->f, $o_pos); - $data = trim(_fgets($this->f, true)); - - if ($data !== 'xref') { - $this->error("Unable to find xref table - Maybe a Problem with 'auto_detect_line_endings'"); - } - } - - $o_pos = ftell($this->f); - $data = explode(' ', trim(fgets($this->f))); - if (count($data) != 2) { - fseek($this->f, $o_pos); - $data = explode(' ', trim(_fgets($this->f, true))); - - if (count($data) != 2) - $this->error("Unexpected header in xref table"); - } - $start = $data[0]; - $end = $start + $data[1]; - } - - if (!isset($result['xref_location'])) { - $result['xref_location'] = $offset; - } - - if (!isset($result['max_object']) || $end > $result['max_object']) { - $result['max_object'] = $end; - } - - for (; $start < $end; $start++) { - $data = fread($this->f, 20); // Spezifications says: 20 bytes including newlines - $offset = substr($data, 0, 10); - $generation = substr($data, 11, 5); - - if (!isset ($result['xref'][$start][(int) $generation])) { - $result['xref'][$start][(int) $generation] = (int) $offset; - } - } - - $o_pos = ftell($this->f); - $data = fgets($this->f); - - if (preg_match("/trailer/",$data)) { - if (preg_match("/(.*trailer[ \n\r]+)/",$data,$m)) { - fseek($this->f, $o_pos+strlen($m[1])); - } - - $c =& new pdf_context($this->f); - $trailer = $this->pdf_read_value($c); - - if (isset($trailer[1]['/Prev'])) { - $this->pdf_read_xref($result, $trailer[1]['/Prev'][1]); - $result['trailer'][1] = array_merge($result['trailer'][1], $trailer[1]); - } else { - $result['trailer'] = $trailer; - } - } else { - $data = explode(' ', trim($data)); - - if (count($data) != 2) { - fseek($this->f, $o_pos); - $data = explode(' ', trim (_fgets ($this->f, true))); - - if (count($data) != 2) { - $this->error("Unexpected data in xref table"); - } - } - - $this->pdf_read_xref($result, null, (int) $data[0], (int) $data[0] + (int) $data[1]); - } - } - - - /** - * Reads an Value - * - * @param object $c pdf_context - * @param string $token a Token - * @return mixed - */ - function pdf_read_value(&$c, $token = null) { - if (is_null($token)) { - $token = $this->pdf_read_token($c); - } - - if ($token === false) { - return false; - } - - switch ($token) { - case '<': - // This is a hex string. - // Read the value, then the terminator - - $pos = $c->offset; - - while(1) { - - $match = strpos ($c->buffer, '>', $pos); - - // If you can't find it, try - // reading more data from the stream - - if ($match === false) { - if (!$c->increase_length()) { - return false; - } else { - continue; - } - } - - $result = substr ($c->buffer, $c->offset, $match - $c->offset); - $c->offset = $match+1; - - return array (PDF_TYPE_HEX, $result); - } - - break; - case '<<': - // This is a dictionary. - - $result = array(); - - // Recurse into this function until we reach - // the end of the dictionary. - while (($key = $this->pdf_read_token($c)) !== '>>') { - if ($key === false) { - return false; - } - - if (($value = $this->pdf_read_value($c)) === false) { - return false; - } - $result[$key] = $value; - } - - return array (PDF_TYPE_DICTIONARY, $result); - - case '[': - // This is an array. - - $result = array(); - - // Recurse into this function until we reach - // the end of the array. - while (($token = $this->pdf_read_token($c)) !== ']') { - if ($token === false) { - return false; - } - - if (($value = $this->pdf_read_value($c, $token)) === false) { - return false; - } - - $result[] = $value; - } - - return array (PDF_TYPE_ARRAY, $result); - - case '(' : - // This is a string - - $pos = $c->offset; - - while(1) { - - // Start by finding the next closed - // parenthesis - - $match = strpos ($c->buffer, ')', $pos); - - // If you can't find it, try - // reading more data from the stream - - if ($match === false) { - if (!$c->increase_length()) { - return false; - } else { - continue; - } - } - - // Make sure that there is no backslash - // before the parenthesis. If there is, - // move on. Otherwise, return the string. - - if (isset($c->buffer[$match - 1]) && $c->buffer[$match - 1] !== '\\' || - isset($c->buffer[$match - 1]) && $c->buffer[$match - 1] === '\\' && isset($c->buffer[$match - 2]) && $c->buffer[$match - 2] === '\\') { - $result = substr ($c->buffer, $c->offset, $match - $c->offset); - $c->offset = $match + 1; - return array (PDF_TYPE_STRING, $result); - } else { - $pos = $match + 1; - - if ($pos > $c->offset + $c->length) { - $c->increase_length(); - } - } - } - - case "stream": - $o_pos = ftell($c->file)-strlen($c->buffer); - $o_offset = $c->offset; - - $c->reset($startpos = $o_pos + $o_offset); - - $e = 0; // ensure line breaks in front of the stream - if ($c->buffer[0] == chr(10) || $c->buffer[0] == chr(13)) - $e++; - if ($c->buffer[1] == chr(10) && $c->buffer[0] != chr(10)) - $e++; - - if ($this->actual_obj[1][1]['/Length'][0] == PDF_TYPE_OBJREF) { - $tmp_c = new pdf_context($this->f); - $tmp_length = $this->pdf_resolve_object($tmp_c,$this->actual_obj[1][1]['/Length']); - $length = $tmp_length[1][1]; - } else { - $length = $this->actual_obj[1][1]['/Length'][1]; - } - - $c->reset($startpos+$e,$length); - $v = $c->buffer; - $c->reset($startpos+$e+$length+strlen("endstream")); - - return array(PDF_TYPE_STREAM, $v); - - default : - if (is_numeric ($token)) { - // A numeric token. Make sure that - // it is not part of something else. - if (($tok2 = $this->pdf_read_token ($c)) !== false) { - if (is_numeric ($tok2)) { - - // Two numeric tokens in a row. - // In this case, we're probably in - // front of either an object reference - // or an object specification. - // Determine the case and return the data - if (($tok3 = $this->pdf_read_token ($c)) !== false) { - switch ($tok3) { - case 'obj' : - return array (PDF_TYPE_OBJDEC, (int) $token, (int) $tok2); - case 'R' : - return array (PDF_TYPE_OBJREF, (int) $token, (int) $tok2); - } - // If we get to this point, that numeric value up - // there was just a numeric value. Push the extra - // tokens back into the stack and return the value. - array_push ($c->stack, $tok3); - } - } - - array_push ($c->stack, $tok2); - } - - return array (PDF_TYPE_NUMERIC, $token); - } else { - - // Just a token. Return it. - return array (PDF_TYPE_TOKEN, $token); - } - - } - } - - /** - * Resolve an object - * - * @param object $c pdf_context - * @param array $obj_spec The object-data - * @param boolean $encapsulate Must set to true, cause the parsing and fpdi use this method only without this para - */ - function pdf_resolve_object(&$c, $obj_spec, $encapsulate = true) { - // Exit if we get invalid data - if (!is_array($obj_spec)) { - return false; - } - - if ($obj_spec[0] == PDF_TYPE_OBJREF) { - - // This is a reference, resolve it - if (isset($this->xref['xref'][$obj_spec[1]][$obj_spec[2]])) { - - // Save current file position - // This is needed if you want to resolve - // references while you're reading another object - // (e.g.: if you need to determine the length - // of a stream) - - $old_pos = ftell($c->file); - - // Reposition the file pointer and - // load the object header. - - $c->reset($this->xref['xref'][$obj_spec[1]][$obj_spec[2]]); - - $header = $this->pdf_read_value($c,null,true); - - if ($header[0] != PDF_TYPE_OBJDEC || $header[1] != $obj_spec[1] || $header[2] != $obj_spec[2]) { - $this->error("Unable to find object ({$obj_spec[1]}, {$obj_spec[2]}) at expected location"); - } - - // If we're being asked to store all the information - // about the object, we add the object ID and generation - // number for later use - $this->actual_obj =& $result; - if ($encapsulate) { - $result = array ( - PDF_TYPE_OBJECT, - 'obj' => $obj_spec[1], - 'gen' => $obj_spec[2] - ); - } else { - $result = array(); - } - - // Now simply read the object data until - // we encounter an end-of-object marker - while(1) { - $value = $this->pdf_read_value($c); - if ($value === false || count($result) > 4) { - // in this case the parser coudn't find an endobj so we break here - break; - } - - if ($value[0] == PDF_TYPE_TOKEN && $value[1] === 'endobj') { - break; - } - - $result[] = $value; - } - - $c->reset($old_pos); - - if (isset($result[2][0]) && $result[2][0] == PDF_TYPE_STREAM) { - $result[0] = PDF_TYPE_STREAM; - } - - return $result; - } - } else { - return $obj_spec; - } - } - - - - /** - * Reads a token from the file - * - * @param object $c pdf_context - * @return mixed - */ - function pdf_read_token(&$c) - { - // If there is a token available - // on the stack, pop it out and - // return it. - - if (count($c->stack)) { - return array_pop($c->stack); - } - - // Strip away any whitespace - - do { - if (!$c->ensure_content()) { - return false; - } - $c->offset += _strspn($c->buffer, " \n\r", $c->offset); - } while ($c->offset >= $c->length - 1); - - // Get the first character in the stream - - $char = $c->buffer[$c->offset++]; - - switch ($char) { - - case '[' : - case ']' : - case '(' : - case ')' : - - // This is either an array or literal string - // delimiter, Return it - - return $char; - - case '<' : - case '>' : - - // This could either be a hex string or - // dictionary delimiter. Determine the - // appropriate case and return the token - - if ($c->buffer[$c->offset] == $char) { - if (!$c->ensure_content()) { - return false; - } - $c->offset++; - return $char . $char; - } else { - return $char; - } - - default : - - // This is "another" type of token (probably - // a dictionary entry or a numeric value) - // Find the end and return it. - - if (!$c->ensure_content()) { - return false; - } - - while(1) { - - // Determine the length of the token - - $pos = _strcspn($c->buffer, " []<>()\r\n\t/", $c->offset); - - if ($c->offset + $pos <= $c->length - 1) { - break; - } else { - // If the script reaches this point, - // the token may span beyond the end - // of the current buffer. Therefore, - // we increase the size of the buffer - // and try again--just to be safe. - - $c->increase_length(); - } - } - - $result = substr($c->buffer, $c->offset - 1, $pos + 1); - - $c->offset += $pos; - return $result; - } - } - - -} - +filename = $filename; + + $this->f = @fopen($this->filename,"rb"); + + if (!$this->f) + $this->error(sprintf("Cannot open %s !",$filename)); + + $this->getPDFVersion(); + + $this->c = new pdf_context($this->f); + // Read xref-Data + $this->pdf_read_xref($this->xref, $this->pdf_find_xref()); + + // Check for Encryption + $this->getEncryption(); + + // Read root + $this->pdf_read_root(); + } + + /** + * Close the opened file + */ + function closeFile() { + if (isset($this->f)) { + fclose($this->f); + } + } + + /** + * Print Error and die + * + * @param string $msg Error-Message + */ + function error($msg) { + die("PDF-Parser Error: ".$msg); + } + + /** + * Check Trailer for Encryption + */ + function getEncryption() { + if (isset($this->xref['trailer'][1]['/Encrypt'])) { + $this->error("File is encrypted!"); + } + } + + /** + * Find/Return /Root + * + * @return array + */ + function pdf_find_root() { + if ($this->xref['trailer'][1]['/Root'][0] != PDF_TYPE_OBJREF) { + $this->Error("Wrong Type of Root-Element! Must be an indirect reference"); + } + return $this->xref['trailer'][1]['/Root']; + } + + /** + * Read the /Root + */ + function pdf_read_root() { + // read root + $this->root = $this->pdf_resolve_object($this->c, $this->pdf_find_root()); + } + + /** + * Get PDF-Version + * + * And reset the PDF Version used in FPDI if needed + */ + function getPDFVersion() { + fseek($this->f, 0); + preg_match("/\d\.\d/",fread($this->f,16),$m); + $this->pdfVersion = $m[0]; + } + + /** + * Find the xref-Table + */ + function pdf_find_xref() { + fseek ($this->f, -50, SEEK_END); + $data = fread($this->f, 50); + + if (!preg_match('/startxref\s*(\d+)\s*%%EOF\s*$/', $data, $matches)) { + $this->error("Unable to find pointer to xref table"); + } + + return (int) $matches[1]; + } + + /** + * Read xref-table + * + * @param array $result Array of xref-table + * @param integer $offset of xref-table + * @param integer $start start-position in xref-table + * @param integer $end end-position in xref-table + */ + function pdf_read_xref(&$result, $offset, $start = null, $end = null) { + if (is_null ($start) || is_null ($end)) { + fseek($this->f, $o_pos = $offset); + $data = trim(fgets($this->f)); + + if ($data !== 'xref') { + fseek($this->f, $o_pos); + $data = trim(_fgets($this->f, true)); + + if ($data !== 'xref') { + $this->error("Unable to find xref table - Maybe a Problem with 'auto_detect_line_endings'"); + } + } + + $o_pos = ftell($this->f); + $data = explode(' ', trim(fgets($this->f))); + if (count($data) != 2) { + fseek($this->f, $o_pos); + $data = explode(' ', trim(_fgets($this->f, true))); + + if (count($data) != 2) + $this->error("Unexpected header in xref table"); + } + $start = $data[0]; + $end = $start + $data[1]; + } + + if (!isset($result['xref_location'])) { + $result['xref_location'] = $offset; + } + + if (!isset($result['max_object']) || $end > $result['max_object']) { + $result['max_object'] = $end; + } + + for (; $start < $end; $start++) { + $data = fread($this->f, 20); // Spezifications says: 20 bytes including newlines + $offset = substr($data, 0, 10); + $generation = substr($data, 11, 5); + + if (!isset ($result['xref'][$start][(int) $generation])) { + $result['xref'][$start][(int) $generation] = (int) $offset; + } + } + + $o_pos = ftell($this->f); + $data = fgets($this->f); + + if (preg_match("/trailer/",$data)) { + if (preg_match("/(.*trailer[ \n\r]+)/",$data,$m)) { + fseek($this->f, $o_pos+strlen($m[1])); + } + + $c =& new pdf_context($this->f); + $trailer = $this->pdf_read_value($c); + + if (isset($trailer[1]['/Prev'])) { + $this->pdf_read_xref($result, $trailer[1]['/Prev'][1]); + $result['trailer'][1] = array_merge($result['trailer'][1], $trailer[1]); + } else { + $result['trailer'] = $trailer; + } + } else { + $data = explode(' ', trim($data)); + + if (count($data) != 2) { + fseek($this->f, $o_pos); + $data = explode(' ', trim (_fgets ($this->f, true))); + + if (count($data) != 2) { + $this->error("Unexpected data in xref table"); + } + } + + $this->pdf_read_xref($result, null, (int) $data[0], (int) $data[0] + (int) $data[1]); + } + } + + + /** + * Reads an Value + * + * @param object $c pdf_context + * @param string $token a Token + * @return mixed + */ + function pdf_read_value(&$c, $token = null) { + if (is_null($token)) { + $token = $this->pdf_read_token($c); + } + + if ($token === false) { + return false; + } + + switch ($token) { + case '<': + // This is a hex string. + // Read the value, then the terminator + + $pos = $c->offset; + + while(1) { + + $match = strpos ($c->buffer, '>', $pos); + + // If you can't find it, try + // reading more data from the stream + + if ($match === false) { + if (!$c->increase_length()) { + return false; + } else { + continue; + } + } + + $result = substr ($c->buffer, $c->offset, $match - $c->offset); + $c->offset = $match+1; + + return array (PDF_TYPE_HEX, $result); + } + + break; + case '<<': + // This is a dictionary. + + $result = array(); + + // Recurse into this function until we reach + // the end of the dictionary. + while (($key = $this->pdf_read_token($c)) !== '>>') { + if ($key === false) { + return false; + } + + if (($value = $this->pdf_read_value($c)) === false) { + return false; + } + $result[$key] = $value; + } + + return array (PDF_TYPE_DICTIONARY, $result); + + case '[': + // This is an array. + + $result = array(); + + // Recurse into this function until we reach + // the end of the array. + while (($token = $this->pdf_read_token($c)) !== ']') { + if ($token === false) { + return false; + } + + if (($value = $this->pdf_read_value($c, $token)) === false) { + return false; + } + + $result[] = $value; + } + + return array (PDF_TYPE_ARRAY, $result); + + case '(' : + // This is a string + + $pos = $c->offset; + + while(1) { + + // Start by finding the next closed + // parenthesis + + $match = strpos ($c->buffer, ')', $pos); + + // If you can't find it, try + // reading more data from the stream + + if ($match === false) { + if (!$c->increase_length()) { + return false; + } else { + continue; + } + } + + // Make sure that there is no backslash + // before the parenthesis. If there is, + // move on. Otherwise, return the string. + + if (isset($c->buffer[$match - 1]) && $c->buffer[$match - 1] !== '\\' || + isset($c->buffer[$match - 1]) && $c->buffer[$match - 1] === '\\' && isset($c->buffer[$match - 2]) && $c->buffer[$match - 2] === '\\') { + $result = substr ($c->buffer, $c->offset, $match - $c->offset); + $c->offset = $match + 1; + return array (PDF_TYPE_STRING, $result); + } else { + $pos = $match + 1; + + if ($pos > $c->offset + $c->length) { + $c->increase_length(); + } + } + } + + case "stream": + $o_pos = ftell($c->file)-strlen($c->buffer); + $o_offset = $c->offset; + + $c->reset($startpos = $o_pos + $o_offset); + + $e = 0; // ensure line breaks in front of the stream + if ($c->buffer[0] == chr(10) || $c->buffer[0] == chr(13)) + $e++; + if ($c->buffer[1] == chr(10) && $c->buffer[0] != chr(10)) + $e++; + + if ($this->actual_obj[1][1]['/Length'][0] == PDF_TYPE_OBJREF) { + $tmp_c = new pdf_context($this->f); + $tmp_length = $this->pdf_resolve_object($tmp_c,$this->actual_obj[1][1]['/Length']); + $length = $tmp_length[1][1]; + } else { + $length = $this->actual_obj[1][1]['/Length'][1]; + } + + $c->reset($startpos+$e,$length); + $v = $c->buffer; + $c->reset($startpos+$e+$length+strlen("endstream")); + + return array(PDF_TYPE_STREAM, $v); + + default : + if (is_numeric ($token)) { + // A numeric token. Make sure that + // it is not part of something else. + if (($tok2 = $this->pdf_read_token ($c)) !== false) { + if (is_numeric ($tok2)) { + + // Two numeric tokens in a row. + // In this case, we're probably in + // front of either an object reference + // or an object specification. + // Determine the case and return the data + if (($tok3 = $this->pdf_read_token ($c)) !== false) { + switch ($tok3) { + case 'obj' : + return array (PDF_TYPE_OBJDEC, (int) $token, (int) $tok2); + case 'R' : + return array (PDF_TYPE_OBJREF, (int) $token, (int) $tok2); + } + // If we get to this point, that numeric value up + // there was just a numeric value. Push the extra + // tokens back into the stack and return the value. + array_push ($c->stack, $tok3); + } + } + + array_push ($c->stack, $tok2); + } + + return array (PDF_TYPE_NUMERIC, $token); + } else { + + // Just a token. Return it. + return array (PDF_TYPE_TOKEN, $token); + } + + } + } + + /** + * Resolve an object + * + * @param object $c pdf_context + * @param array $obj_spec The object-data + * @param boolean $encapsulate Must set to true, cause the parsing and fpdi use this method only without this para + */ + function pdf_resolve_object(&$c, $obj_spec, $encapsulate = true) { + // Exit if we get invalid data + if (!is_array($obj_spec)) { + return false; + } + + if ($obj_spec[0] == PDF_TYPE_OBJREF) { + + // This is a reference, resolve it + if (isset($this->xref['xref'][$obj_spec[1]][$obj_spec[2]])) { + + // Save current file position + // This is needed if you want to resolve + // references while you're reading another object + // (e.g.: if you need to determine the length + // of a stream) + + $old_pos = ftell($c->file); + + // Reposition the file pointer and + // load the object header. + + $c->reset($this->xref['xref'][$obj_spec[1]][$obj_spec[2]]); + + $header = $this->pdf_read_value($c,null,true); + + if ($header[0] != PDF_TYPE_OBJDEC || $header[1] != $obj_spec[1] || $header[2] != $obj_spec[2]) { + $this->error("Unable to find object ({$obj_spec[1]}, {$obj_spec[2]}) at expected location"); + } + + // If we're being asked to store all the information + // about the object, we add the object ID and generation + // number for later use + $this->actual_obj =& $result; + if ($encapsulate) { + $result = array ( + PDF_TYPE_OBJECT, + 'obj' => $obj_spec[1], + 'gen' => $obj_spec[2] + ); + } else { + $result = array(); + } + + // Now simply read the object data until + // we encounter an end-of-object marker + while(1) { + $value = $this->pdf_read_value($c); + if ($value === false || count($result) > 4) { + // in this case the parser coudn't find an endobj so we break here + break; + } + + if ($value[0] == PDF_TYPE_TOKEN && $value[1] === 'endobj') { + break; + } + + $result[] = $value; + } + + $c->reset($old_pos); + + if (isset($result[2][0]) && $result[2][0] == PDF_TYPE_STREAM) { + $result[0] = PDF_TYPE_STREAM; + } + + return $result; + } + } else { + return $obj_spec; + } + } + + + + /** + * Reads a token from the file + * + * @param object $c pdf_context + * @return mixed + */ + function pdf_read_token(&$c) + { + // If there is a token available + // on the stack, pop it out and + // return it. + + if (count($c->stack)) { + return array_pop($c->stack); + } + + // Strip away any whitespace + + do { + if (!$c->ensure_content()) { + return false; + } + $c->offset += _strspn($c->buffer, " \n\r", $c->offset); + } while ($c->offset >= $c->length - 1); + + // Get the first character in the stream + + $char = $c->buffer[$c->offset++]; + + switch ($char) { + + case '[' : + case ']' : + case '(' : + case ')' : + + // This is either an array or literal string + // delimiter, Return it + + return $char; + + case '<' : + case '>' : + + // This could either be a hex string or + // dictionary delimiter. Determine the + // appropriate case and return the token + + if ($c->buffer[$c->offset] == $char) { + if (!$c->ensure_content()) { + return false; + } + $c->offset++; + return $char . $char; + } else { + return $char; + } + + default : + + // This is "another" type of token (probably + // a dictionary entry or a numeric value) + // Find the end and return it. + + if (!$c->ensure_content()) { + return false; + } + + while(1) { + + // Determine the length of the token + + $pos = _strcspn($c->buffer, " []<>()\r\n\t/", $c->offset); + + if ($c->offset + $pos <= $c->length - 1) { + break; + } else { + // If the script reaches this point, + // the token may span beyond the end + // of the current buffer. Therefore, + // we increase the size of the buffer + // and try again--just to be safe. + + $c->increase_length(); + } + } + + $result = substr($c->buffer, $c->offset - 1, $pos + 1); + + $c->offset += $pos; + return $result; + } + } + + +} + ?> \ No newline at end of file