| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785 |
- <?php
- /**
- * FPDF_Merge
- * Tool to merge PDFs created by fpdf 1.6
- *
- * @version 1.0
- * @date 2011-02-18
- * @author DEMONTE Jean-Baptiste <jbdemonte@gmail.com>
- * @copyright © Digitick <www.digitick.net> 2011
- * @license GNU Lesser General Public License v3.0
- *
- * Why this tool ?
- *
- * All the library tested (fpdi, ...) produce too heavy pdf
- * because, these are not optimized.
- * This library parses the pages, get the objects included (font, images)
- * generate a hash to store only once these objects or reuse previous stored ones.
- *
- *
- * Notes
- *
- * - links are not supported in this version
- * - all pages are included (because this was what we needed) but update it
- * to create an add(array pages) should be easy
- *
- *
- * I tried to optimize a lot this tool using X-Debug, let me know if you do best :)
- * If you get trouble or want to comment, feel free to send me an email.
- *
- * Use
- *
- * $merge = new FPDF_Merge();
- * $merge->add('/tmp/pdf-1.pdf');
- * $merge->add('/tmp/pdf-2.pdf');
- * $merge->output('/tmp/pdf-merge.pdf'); // or $merge->output(); to open it directly in the browser
- *
- **/
- class FPDF_Merge{
- const TYPE_NULL = 0,
- TYPE_TOKEN = 1,
- TYPE_REFERENCE = 2,
- TYPE_REFERENCE_F= 3,
- TYPE_NUMERIC = 4,
- TYPE_HEX = 5,
- TYPE_BOOL = 6,
- TYPE_STRING = 7,
- TYPE_ARRAY = 8,
- TYPE_DICTIONARY = 9,
- TYPE_STREAM = 10;
-
- private $buffer, $compress, $fonts, $objects, $pages, $ref, $n, $xref;
-
- /**************************************************
- /* CONSTRUCTOR
- /**************************************************/
-
- public function __construct(){
- $this->buffer = '';
- $this->fonts = array();
- $this->objects = array();
- $this->pages = array();
- $this->ref = array();
- $this->xref = array();
- $this->n = 0;
- $this->compress = function_exists('gzcompress');
- }
-
- /**************************************************
- /* PRIVATE
- /**************************************************/
-
-
- private function error($msg){
- throw new Exception($msg);
- die;
- }
-
- //================================================
- // FONCTIONS D'IMPORT
- //================================================
-
- private function parse($buffer, &$len, &$off){
- if ($len === $off) {
- return null;
- }
-
- if (!preg_match('`\s*(.)`', $buffer, $m, PREG_OFFSET_CAPTURE, $off)) return null;
- $off = $m[1][1];
-
- switch($buffer[$off]){
- case '<':
- if ($buffer[$off+1] === '<'){
- // dictionnary
- $v = array();
- $off+=2;
- while(1){
- $key = $this->parse($buffer, $len, $off);
- if ($key === null) break;
- if ($key[0] !== self::TYPE_TOKEN) break;
- $value = $this->parse($buffer, $len, $off);
- $v[$key[1]] = $value;
- }
- $off+=2;
- return array(self::TYPE_DICTIONARY, $v);
- } else {
- // hex
- $p = strpos($buffer, '>', $off);
- if ($p !== false){
- $v = substr($buffer, $off+1, $p - $off - 1);
- $off = $p + 1;
- return array(self::TYPE_HEX, $v);
- }
- }
- break;
- case '(':
- // string
- $p = $off;
- while(1){
- $p++;
- if ($p === $len) break;
- if (($buffer[$p] === ')') && ($buffer[$p-1] !== '\\')) break;
- }
- if ($p < $len){
- $v = substr($buffer, $off+1, $p - $off - 1);
- $off = $p + 1;
- return array(self::TYPE_STRING, $v);
- }
- break;
- case '[':
- $v = array();
- $off++; // jump the [
- while(1){
- $value = $this->parse($buffer, $len, $off);
- if ($value === null) break;
- $v[] = $value;
- }
- $off++; // jump the ]
- return array(self::TYPE_ARRAY, $v);
- break;
- case '>': // dictionnary : end
- case ']': // array : end
- return null;
- break;
- case '%': // comments : jump
- $p = strpos($buffer, "\n", $off);
- if ($p !== false){
- $off = $p + 1;
- return $this->parse($buffer, $len, $off);
- }
-
- break;
- default:
- if (preg_match('`^\s*([0-9]+) 0 R`', substr($buffer, $off, 32), $m)){
- $off += strlen($m[0]);
- return array(self::TYPE_REFERENCE, $m[1]);
- } else {
- $p = strcspn($buffer, " %[]<>()\r\n\t/", $off+1);
- $v = substr($buffer, $off, $p+1);
- $off += $p+1;
- if ( is_numeric($v) ){
- $type = self::TYPE_NUMERIC;
- } else if ( ($v === 'true') || ($v === 'false') ){
- $type = self::TYPE_BOOL;
- } else if ( $v === 'null' ){
- $type = self::TYPE_NULL;
- } else {
- $type = self::TYPE_TOKEN;
- }
- return array($type, $v);
- }
- break;
- }
- return null;
- }
-
- private function getObject($f, $xref, $index, $includeSubObject = false){
-
- $type = self::TYPE_TOKEN;
-
- if (!isset($xref[$index])){
- $this->error('reference d\'object inconnue');
- }
-
- fseek($f, $xref[$index]);
-
- $data = '';
- $len = 0;
- $offset = 0;
- $expLen = 1024;
- do{
- $prev = $len;
- $data .= fread($f, $expLen);
- $len = strlen($data);
- $p = strpos($data, "endobj", $offset);
- if ($p !== false){
- if ( $data[$p-1] !== "\n" ){
- $offset = $p + 6;
- $p = false;
- } else {
- if ($len < $p + 8){
- $data .= fread($f, 1);
- $len = strlen($data);
- }
- if ($data[$p+6] !== "\n"){
- $offset = $p + 6; // not the endobj markup, maybe a string content
- $p = false;
- }
- }
- }
- $expLen *= 2;
- }while( ($p === false) && ($prev !== $len) );
-
- if ($p === false){
- $this->error('object ['.$index.'] non trouve');
- }
-
- $p--;
- $data = substr($data,0, $p);
-
- if (!preg_match('`^([0-9]+ 0 obj)`', $data, $m, PREG_OFFSET_CAPTURE)){
- $this->error('object ['.$index.'] invalide');
- }
-
- $p = $m[0][1] + strlen($m[1][0]) + 1;
- $data = substr($data, $p);
-
- if (substr($data, 0, 2) === '<<') {
- $type = self::TYPE_DICTIONARY;
- $off = 0;
- $len = strlen($data);
- $dictionary = $this->parse($data, $len, $off);
- $off++;
- $data = substr($data, $off);
- if ($data === false) {
- $data = '';
- } else if (substr($data, 0, 7) === "stream\n"){
- $data = substr($data, 7, strlen($data) - 17);
- $type = self::TYPE_STREAM;
- }
- if ( $includeSubObject ){
- $dictionary = $this->_resolveValues($f, $xref, $dictionary);
- }
- } else {
- $dictionary = null;
- }
- return array($type, $dictionary, $data);
- }
-
- private function _resolveValues($f, $xref, $item){
- switch($item[0]){
- case self::TYPE_REFERENCE:
- $object = $this->getObject($f, $xref, $item[1], true);
- if ($object[0] === self::TYPE_TOKEN){
- return array(self::TYPE_TOKEN, $object[2]);
- }
- $ref = $this->storeObject($object);
- return array(self::TYPE_REFERENCE_F, $this->_getObjectType($object), $ref);
- break;
- case self::TYPE_ARRAY:
- case self::TYPE_DICTIONARY:
- $r = array();
- foreach($item[1] as $key => $val){
- if ( ($val[0] == self::TYPE_REFERENCE) ||
- ($val[0] == self::TYPE_ARRAY) ||
- ($val[0] == self::TYPE_DICTIONARY) ){
- $r[$key] = $this->_resolveValues($f, $xref, $val);
- } else {
- $r[$key] = $val;
- }
- }
- return array($item[0], $r);
- break;
- default:
- return $item;
- }
- }
-
- private function getResources($f, $xref, $page){
- if ($page[0] !== self::TYPE_DICTIONARY){
- $this->error('getResources necessite un dictionaire');
- }
- if (isset($page[1]['/Resources'])){
- if ($page[1]['/Resources'][0] === self::TYPE_REFERENCE){
- return $this->getObject($f, $xref, $page[1]['/Resources'][1]);
- } else {
- return array($page[1]['/Resources'][1]);
- }
- } else if (isset($page[1]['/Parent'])){
- return $this->getResources($f, $xref, $page[1]['/Parent']);
- }
- return null;
- }
-
- private function getContent($f, $xref, $page){
- if ($page[0] !== self::TYPE_DICTIONARY){
- $this->error('getContent necessite un dictionaire');
- }
- $stream = '';
- if (isset($page[1]['/Contents'])){
- $stream = $this->_getContent($f, $xref, $page[1]['/Contents']);
- }
- return $stream;
- }
-
- private function _getContent($f, $xref, $content){
- $stream = '';
- if ($content[0] === self::TYPE_REFERENCE){
- $stream .= $this->getStream($f, $xref, $this->getObject($f, $xref, $content[1]));
- } else if ($content[0] === self::TYPE_ARRAY){
- foreach($content[1] as $sub){
- $stream .= $this->_getContent($f, $xref, $sub);
- }
- } else {
- $stream .= $this->getStream($f, $xref, $item);
- }
- return $stream;
- }
-
- private function getCompression($f, $xref, $item){
- if ($item[0] === self::TYPE_TOKEN){
- return array($item[1]);
- } else if ($item[0] === self::TYPE_ARRAY){
- $r = array();
- foreach($item[1] as $sub){
- $r = array_merge($r, $this->getCompression($f, $xref, $sub));
- }
- return $r;
- } else if ($item[0] === self::TYPE_REFERENCE){
- return $this->getCompression($f, $xref, $this->getObject($f, $xref, $item[1]));
- }
- return array();
- }
-
- private function getStream($f, $xref, $item){
- $methods = isset($item[1][1]['/Filter']) ? $this->getCompression($f, $xref, $item[1][1]['/Filter']) : array();
-
- $raw = $item[2];
- foreach($methods as $method){
- switch ($method) {
- case '/FlateDecode':
- if (function_exists('gzuncompress')) {
- $raw = !empty($raw) ? @gzuncompress($raw) : '';
- } else {
- $this->error('gzuncompress necessaire pour decompresser ce stream');
- }
- if ($raw === false) {
- $this->error('erreur de decompression du stream');
- }
- break;
- default:
- $this->error($method . ' necessaire pour decompresser ce stream');
- }
- }
- return $raw;
- }
-
- private function storeObject($item, $type = false){
- $md5 = md5(serialize($item));
- if ($type === '/Font'){
- $array = & $this->fonts;
- $prefix = '/F';
- } else {
- $array = & $this->objects;
- $prefix = '/Obj';
- }
- if (!isset($array[$md5])){
- $index = count($array) + 1;
- $array[$md5] = array(
- 'name' => $prefix . $index,
- 'item' => $item,
- 'type' => $type,
- 'index' => $index
- );
- } else if ($type){
- $array[$md5]['type'] = $type;
- }
- return $array[$md5][$type ? 'name' : 'index'];
- }
-
- //================================================
- // FONCTIONS D'IMPRESSION
- //================================================
-
- private function _out($raw){
- $this->buffer .= $raw . "\n";
- }
-
- private function _strval($value){
- $value+=0;
- if ($value){
- return strval($value);
- }
- return '0';
- }
-
- private function _toStream($item){
- switch($item[0]){
- case self::TYPE_NULL : return 'null';
- case self::TYPE_TOKEN : return $item[1];
- case self::TYPE_REFERENCE : return $this->_strval($item[1]) . ' 0 R';
- case self::TYPE_REFERENCE_F :
- if (!isset($this->ref[ $item[1] ][ $item[2] ])){
- $this->error('reference vers un object non sauve');
- }
- return $this->_strval($this->ref[ $item[1] ][ $item[2] ]) . ' 0 R';
-
- case self::TYPE_NUMERIC : return $this->_strval($item[1]);
- case self::TYPE_HEX : return '<'.strval($item[1]).'>';
- case self::TYPE_BOOL : return $item[1] ? 'true' : 'false';
- case self::TYPE_STRING : return '(' . str_replace(array('\\', '(', ')'), array('\\\\', '\\(', '\\)'), strval($item[1])) . ')';
- case self::TYPE_ARRAY :
- $r = array();
- foreach($item[1] as $val){
- $r[] = $this->_toStream($val);
- }
- return '[' . implode(' ', $r) . ']';
- case self::TYPE_DICTIONARY :
- $r = array();
- foreach($item[1] as $key => $val){
- $val = $this->_toStream($val);
- $r[] = $key . ' ' . $val;
- }
- return '<<' . implode("\n", $r) . '>>';
- break;
- }
- return '';
- }
-
- private function _newobj($n = null){
- if ( ($n === null) || ($n === true) ){
- $this->n++;
- $id = $this->n;
- } else {
- $id = $n;
- }
- if ($n !== true){
- $this->xref[ $id ] = strlen($this->buffer);
- $this->_out($id . ' 0 obj');
- }
- return $id;
- }
-
- private function _addObj($dico = null, $buf = null){
- $ref = $this->_newobj();
- $buf = empty($buf) && ($buf !== 0) && ($buf !== '0') ? null : $buf;
- if (is_array($dico)){
- if ($buf !== null){
- if ($this->compress && !isset($dico['/Filter'])) {
- $buf = gzcompress($buf);
- $dico['/Filter'] = array(self::TYPE_TOKEN, '/FlateDecode');
- }
- $dico['/Length'] = array(self::TYPE_NUMERIC, strlen($buf));
- }
- $this->_out($this->_toStream(array(self::TYPE_DICTIONARY, $dico)));
- }
- if ($buf !== null){
- $this->_out('stream');
- $this->_out($buf);
- $this->_out('endstream');
- }
- $this->_out('endobj');
- return $ref;
- }
-
- private function _getObjectType($object){
- return isset($object['type']) && !empty($object['type']) ? $object['type'] : 'default';
- }
-
- private function _putObject($object){
- $type = $this->_getObjectType($object);
- if (!isset($this->ref[$type])){
- $this->ref[$type] = array();
- }
- $this->ref[$type][ $object['index'] ] = $this->_addObj($object['item'][1][1], $object['item'][2]);
- }
-
- private function _putObjects(){
- foreach($this->objects as $object){
- if ($object['type']) continue;
- $this->_putObject($object);
- }
- foreach($this->objects as $object){
- if (!$object['type']) continue;
- $this->_putObject($object);
- }
- foreach($this->fonts as $object){
- $this->_putObject($object);
- }
- }
-
-
- private function _putResources(){
- $dico = array(
- '/ProcSet' => array(
- self::TYPE_ARRAY,
- array(
- array(self::TYPE_TOKEN, '/PDF'),
- array(self::TYPE_TOKEN, '/Text'),
- array(self::TYPE_TOKEN, '/ImageB'),
- array(self::TYPE_TOKEN, '/ImageC'),
- array(self::TYPE_TOKEN, '/ImageI')
- )
- )
- );
-
- $xObjects = array();
- foreach($this->objects as $index => $object){
- if ($object['type'] === false){
- continue;
- }
- $value = array(
- self::TYPE_TOKEN,
- $this->_toStream(array(self::TYPE_REFERENCE, $this->ref[ $object['type'] ][ $object['index'] ]))
- );
- if ($object['type'] === '/XObject'){
- $xObjects[$object['name']] = $value;
- }
- }
- if (!empty($xObjects)){
- $dico['/XObject'] = array(self::TYPE_DICTIONARY, $xObjects);
- }
-
- $fonts = array();
- foreach($this->fonts as $index => $object){
- $value = array(
- self::TYPE_TOKEN,
- $this->_toStream(array(self::TYPE_REFERENCE, $this->ref[ '/Font' ][ $object['index'] ]))
- );
- $fonts[$object['name']] = $value;
- }
- if (!empty($fonts)){
- $dico['/Font'] = array(self::TYPE_DICTIONARY, $fonts);
- }
- return $this->_addObj($dico);
- }
-
- /**************************************************
- /* PUBLIC
- /**************************************************/
-
- public function add( $filename ){
- $f = @fopen($filename, 'rb');
- if (!$f) {
- $this->error('impossible d\'ouvrir le fichier');
- }
- fseek($f, 0, SEEK_END);
- $fileLength = ftell($f);
-
- // Localisation de xref
- //-------------------------------------------------
-
- fseek($f, -128, SEEK_END);
- $data = fread($f, 128);
- if ($data === false) {
- return $this->error('erreur de lecture dans le fichier');
- }
- $p = strripos($data, 'startxref');
- if ($p === false){
- return $this->error('startxref absent');
- }
- $startxref = substr($data, $p+10, strlen($data) - $p - 17);
- $posStartxref = $fileLength - 128 + $p;
-
- // extraction de xref + trailer
- //-------------------------------------------------
-
- fseek($f, $startxref);
- $data = fread($f, $posStartxref - $startxref);
-
- // extraction du trailer
- //-------------------------------------------------
- $p = stripos($data, 'trailer');
- if ($p === false){
- return $this->error('trailer absent');
- }
- $dataTrailer = substr($data, $p + 8);
- $len = strlen($dataTrailer);
- $off = 0;
- $trailer = $this->parse($dataTrailer, $len, $off);
-
- // extraction du xref
- //-------------------------------------------------
-
- $data = explode("\n", trim(substr($data, 0, $p)));
- array_shift($data); // "xref"
-
- $cnt = 0;
- $xref = array();
-
- foreach($data as $line){
- if (!$cnt) {
- if (preg_match('`^([0-9]+) ([0-9]+)$`', $line, $m)){
- $index = intval($m[1]) - 1;
- $cnt = intval($m[2]);
- } else {
- $this->error('erreur dans xref');
- }
- } else {
- $index++;
- $cnt--;
- if (preg_match('`^([0-9]{10}) [0-9]{5} ([n|f])`', $line, $m)){
- if ($m[2] === 'f') {
- continue;
- }
- $xref[ $index ] = $m[1];
- } else {
- $this->error('erreur dans xref : ' . $line);
- }
- }
- }
-
- // Lecture des pages
- //-------------------------------------------------
-
- $root = $this->getObject($f, $xref, $trailer[1]['/Root'][1]);
- $root = $root[1][1];
-
- $pages = $this->getObject($f, $xref, $root['/Pages'][1]);
- $pages = $pages[1][1];
-
- foreach($pages['/Kids'][1] as $kid){
- $kid = $this->getObject($f, $xref, $kid[1]);
- $kid = $kid[1];
-
- $resources = $this->getResources($f, $xref, $kid);
- $resources = $resources[1][1];
-
- $content = $this->getContent($f, $xref, $kid);
-
- // traitement des fonts
- //-------------------------------------------------
- $newFonts = array();
- if (isset($resources['/Font']) && !empty($resources['/Font'])){
- if (preg_match_all("`(/F[0-9]+)\s+-?[0-9\.]+\s+Tf`", $content, $matches, PREG_OFFSET_CAPTURE)){
- $newContent = '';
- $offset = 0;
- $cnt = count($matches[0]);
- for($i=0; $i<$cnt; $i++){
- $position = $matches[0][$i][1];
- $name = $matches[1][$i][0];
- if (!isset($newFonts[$name])){
- $object = $this->getObject($f, $xref, $resources['/Font'][1][$name][1], true);
- $newFonts[$name] = $this->storeObject($object, '/Font');
- }
- if ($newFonts[$name] !== $name){
- $newContent .= substr($content, $offset, $position - $offset);
- $newContent .= $newFonts[$name];
- $offset = $position + strlen($name);
- }
- }
- $content = $newContent . substr($content, $offset);
- }
- }
-
- // traitement des XObjets
- //-------------------------------------------------
- $newXObjects = array();
- if (isset($resources['/XObject']) && !empty($resources['/XObject'])){
- if (preg_match_all("`(/[^%\[\]<>\(\)\r\n\t/]+) Do`", $content, $matches, PREG_OFFSET_CAPTURE)){
- $newContent = '';
- $offset = 0;
- foreach($matches[1] as $m){
- $name = $m[0];
- $position = $m[1];
- if (!isset($newXObjects[$name])){
- $object = $this->getObject($f, $xref, $resources['/XObject'][1][$name][1], true);
- $newXObjects[$name] = $this->storeObject($object, '/XObject');
- }
- if ($newXObjects[$name] !== $name){
- $newContent .= substr($content, $offset, $position - $offset);
- $newContent .= $newXObjects[$name];
- $offset = $position + strlen($name);
- }
- }
- $content = $newContent . substr($content, $offset);
- }
- }
-
- $mediaBox = isset($kid[1]['/MediaBox']) ? $kid[1]['/MediaBox'] : (isset($pages['/MediaBox']) ? $pages['/MediaBox'] : null);
-
- if ($mediaBox[0] !== self::TYPE_ARRAY){
- $this->error('MediaBox non definie');
- }
-
-
- $this->pages[] = array(
- 'content' => $content,
- '/XObject' => array_values($newXObjects),
- '/Font' => array_values($newFonts),
- '/MediaBox' => $mediaBox
- );
- }
- fclose($f);
- }
-
- public function output($filename = null){
- $this->_out('%PDF-1.6');
-
- $this->_putObjects();
-
- $rsRef = $this->_putResources();
-
- $ptRef = $this->_newobj(true);
-
- $kids = array();
-
- // Ajout des pages
- $n = count($this->pages);
- for($i=0; $i<$n; $i++){
- $ctRef = $this->_addObj(array(), $this->pages[$i]['content']);
- $dico = array(
- '/Type' => array(self::TYPE_TOKEN, '/Page'),
- '/Parent' => array(self::TYPE_REFERENCE, $ptRef),
- '/MediaBox' => $this->pages[$i]['/MediaBox'],
- '/Resources'=> array(self::TYPE_REFERENCE, $rsRef),
- '/Contents' => array(self::TYPE_REFERENCE, $ctRef),
- );
- $kids[] = array(self::TYPE_REFERENCE, $this->_addObj($dico));
- }
-
- // Ajout du page tree
- $ptDico = array(
- self::TYPE_DICTIONARY,
- array(
- '/Type' => array(self::TYPE_TOKEN, '/Pages'),
- '/Kids' => array(self::TYPE_ARRAY, $kids),
- '/Count' => array(self::TYPE_NUMERIC, count($kids))
- )
- );
-
- $this->_newobj($ptRef);
- $this->_out($this->_toStream($ptDico));
- $this->_out('endobj');
-
- // Ajout du catalogue
- $ctDico = array(
- self::TYPE_DICTIONARY,
- array(
- '/Type' => array(self::TYPE_TOKEN, '/Calalog'),
- '/Pages'=> array(self::TYPE_REFERENCE, $ptRef)
- )
- );
- $ctRef = $this->_newobj();
- $this->_out($this->_toStream($ctDico));
- $this->_out('endobj');
-
- // Ajout du xref
- $xrefOffset = strlen($this->buffer);
- $count = count($this->xref);
- $this->_out('xref');
- $this->_out('0 ' . ($count+1));
- $this->_out('0000000000 65535 f ');
- for($i=0; $i<$count; $i++){
- $this->_out(sprintf('%010d 00000 n ',$this->xref[$i+1]));
- }
-
- // Ajout du trailer
- $dico = array(
- '/Size' => array(self::TYPE_NUMERIC, 1+count($this->xref)),
- '/Root' => array(self::TYPE_REFERENCE, $ctRef)
- );
- $this->_out('trailer');
- $this->_out($this->_toStream(array(self::TYPE_DICTIONARY, $dico)));
-
-
- // Ajout du startxref
- $this->_out('startxref');
- $this->_out($xrefOffset);
- $this->_out('%%EOF');
-
- if ($filename === null){
- header('Content-Type: application/pdf');
- header('Content-Length: '.strlen($this->buffer));
- header('Cache-Control: private, max-age=0, must-revalidate');
- header('Pragma: public');
- ini_set('zlib.output_compression','0');
-
- echo $this->buffer;
- die;
- } else {
- file_put_contents($filename, $this->buffer);
- }
- }
- }
- ?>
|