source-class-Com.Tecnick.Pdf.Output

It appears that you are using AdBlocking software. The cost of running this website is covered by advertisements. If you like it please feel free to a small amount of money to secure the future of this website.
  1: <?php
  2: /**
  3:  * Output.php
  4:  *
  5:  * @since       2002-08-03
  6:  * @category    Library
  7:  * @package     Pdf
  8:  * @author      Nicola Asuni <info@tecnick.com>
  9:  * @copyright   2002-2017 Nicola Asuni - Tecnick.com LTD
 10:  * @license     http://www.gnu.org/copyleft/lesser.html GNU-LGPL v3 (see LICENSE.TXT)
 11:  * @link        https://github.com/tecnickcom/tc-lib-pdf
 12:  *
 13:  * This file is part of tc-lib-pdf software library.
 14:  */
 15: 
 16: namespace Com\Tecnick\Pdf;
 17: 
 18: use \Com\Tecnick\Pdf\Font\Output as OutFont;
 19: 
 20: /**
 21:  * Com\Tecnick\Pdf\Output
 22:  *
 23:  * Output PDF data
 24:  *
 25:  * @since       2002-08-03
 26:  * @category    Library
 27:  * @package     Pdf
 28:  * @author      Nicola Asuni <info@tecnick.com>
 29:  * @copyright   2002-2017 Nicola Asuni - Tecnick.com LTD
 30:  * @license     http://www.gnu.org/copyleft/lesser.html GNU-LGPL v3 (see LICENSE.TXT)
 31:  * @link        https://github.com/tecnickcom/tc-lib-pdf
 32:  *
 33:  * @SuppressWarnings(PHPMD)
 34:  */
 35: abstract class Output
 36: {
 37:     /**
 38:      * Array containing the ID of some PDF objects
 39:      *
 40:      * @var array
 41:      */
 42:     protected $objid = array();
 43: 
 44:     /**
 45:      * Returns the RAW PDF string
 46:      *
 47:      * @return string
 48:      */
 49:     public function getOutPDFString()
 50:     {
 51:         $out = $this->getOutPDFHeader()
 52:             .$this->getOutPDFBody();
 53:         $startxref = strlen($out);
 54:         $offset = $this->getPDFObjectOffsets($out);
 55:         $out .= $this->getOutPDFXref($offset)
 56:             .$this->getOutPDFTrailer()
 57:             .'startxref'."\n"
 58:             .$startxref."\n"
 59:             .'%%EOF'."\n";
 60:         // @TODO: sign the document ...
 61:         return $out;
 62:     }
 63: 
 64:     /**
 65:      * Returns the PDF document header
 66:      *
 67:      * @return string
 68:      */
 69:     protected function getOutPDFHeader()
 70:     {
 71:         return '%PDF-'.$this->pdfver."\n"
 72:             ."%\xE2\xE3\xCF\xD3\n";
 73:     }
 74: 
 75:     /**
 76:      * Returns the raw PDF Body section
 77:      *
 78:      * @return string
 79:      */
 80:     protected function getOutPDFBody()
 81:     {
 82:         $out = $this->page->getPdfPages($this->pon);
 83:         $out .= $this->graph->getOutExtGState($this->pon);
 84:         $this->pon = $this->graph->getObjectNumber();
 85:         $out .= $this->getOutOCG();
 86:         $outfont = new OutFont(
 87:             $this->font->getFonts(),
 88:             $this->pon,
 89:             $this->encrypt
 90:         );
 91:         $out .= $outfont->getFontsBlock();
 92:         $this->pon = $outfont->getObjectNumber();
 93:         $out .= $this->image->getOutImagesBlock($this->pon);
 94:         $this->pon = $outfont->getObjectNumber();
 95:         $out .= $this->color->getPdfSpotObjects($this->pon);
 96:         $out .= $this->graph->getOutGradientShaders($this->pon);
 97:         $this->pon = $this->graph->getObjectNumber();
 98:         $out .= $this->getOutXObjects();
 99:         $out .= $this->getOutResourcesDict();
100:         $out .= $this->getOutDestinations();
101:         $out .= $this->getOutEmbeddedFiles();
102:         $out .= $this->getOutAnnotations();
103:         $out .= $this->getOutJavascript();
104:         $out .= $this->getOutBookmarks();
105:         $enc = $this->encrypt->getEncryptionData();
106:         if ($enc['encrypted']) {
107:             $out .= $this->encrypt->getPdfEncryptionObj($this->pon);
108:         }
109:         $out .= $this->getOutSignatureFields();
110:         $out .= $this->getOutSignature();
111:         $out .= $this->getOutMetaInfo();
112:         $out .= $this->getOutXMP();
113:         $out .= $this->getOutICC();
114:         $out .= $this->getOutCatalog();
115:         return $out;
116:     }
117: 
118:     /**
119:      * Returns the ordered offset array for each object
120:      *
121:      * @param string $data Raw PDF data
122:      *
123:      * @return array
124:      */
125:     protected function getPDFObjectOffsets($data)
126:     {
127:         preg_match_all('/(([0-9]+)[\s][0-9]+[\s]obj[\n])/i', $data, $matches, PREG_SET_ORDER|PREG_OFFSET_CAPTURE);
128:         $offset = array();
129:         foreach ($matches as $item) {
130:             $offset[($item[2][0])] = $item[2][1];
131:         }
132:         ksort($offset);
133:         return $offset;
134:     }
135: 
136:     /**
137:      * Returns the PDF XREF section
138:      *
139:      * @param array $offset Ordered offset array for each PDF object
140:      *
141:      * @return string
142:      */
143:     protected function getOutPDFXref($offset)
144:     {
145:         $out = 'xref'."\n"
146:             .'0 '.($this->pon + 1)."\n"
147:             .'0000000000 65535 f '."\n";
148:         $freegen = ($this->pon + 2);
149:         end($offset);
150:         $lastobj = key($offset);
151:         for ($idx = 1; $idx <= $lastobj; ++$idx) {
152:             if (isset($offset[$idx])) {
153:                 $out .= sprintf('%010d 00000 n '."\n", $offset[$idx]);
154:             } else {
155:                 $out .= sprintf('0000000000 %05d f '."\n", $freegen);
156:                 ++$freegen;
157:             }
158:         }
159:         return $out;
160:     }
161: 
162:     /**
163:      * Returns the PDF Trailer section
164:      *
165:      * @param array $offset Ordered offset array for each PDF object
166:      *
167:      * @return string
168:      */
169:     protected function getOutPDFTrailer()
170:     {
171:         $out = 'trailer'."\n"
172:             .'<<'
173:             .' /Size '.($this->pon + 1)
174:             .' /Root '.$this->objid['catalog'].' 0 R'
175:             .' /Info '.$this->objid['info'].' 0 R';
176:         $enc = $this->encrypt->getEncryptionData();
177:         if (!empty($enc['objid'])) {
178:             $out .= ' /Encrypt '.$enc['objid'].' 0 R';
179:         }
180:         $out .= ' /ID [ <'.$this->fileid.'> <'.$this->fileid.'> ]'
181:             .' >>'."\n";
182:         return $out;
183:     }
184: 
185:     /**
186:      * Returns the PDF object to include a standard sRGB_IEC61966-2.1 blackscaled ICC colour profile
187:      *
188:      * @return string
189:      */
190:     protected function getOutICC()
191:     {
192:         if (!$this->pdfa && !$this->sRGB) {
193:             return '';
194:         }
195:         
196:         $oid = ++$this->pon;
197:         $this->objid['srgbicc'] = $oid;
198:         $out = $oid.' 0 obj'."\n";
199:         $icc = file_get_contents(dirname(__FILE__).'/include/sRGB.icc.z');
200:         $icc = $this->encrypt->encryptString($icc, $oid);
201:         $out .= '<<'
202:             .'/N 3'
203:             .' /Filter /FlateDecode'
204:             .' /Length '.strlen($icc)
205:             .'>>'
206:             .' stream'."\n"
207:             .$icc."\n"
208:             .'endstream'."\n"
209:             .'endobj'."\n";
210:         return $out;
211:     }
212: 
213:     /**
214:      * Get OutputIntents for sRGB IEC61966-2.1 if required
215:      *
216:      * @return string
217:      */
218:     protected function getOutputIntentsSrgb()
219:     {
220:         if (empty($this->objid['srgbicc'])) {
221:             return '';
222:         }
223:         $oid = $this->objid['catalog'];
224:         $out = ' /OutputIntents [<<'
225:             .' /Type /OutputIntent'
226:             .' /S /GTS_PDFA1'
227:             .' /OutputCondition '.$this->getOutTextString('sRGB IEC61966-2.1', $oid)
228:             .' /OutputConditionIdentifier '.$this->getOutTextString('sRGB IEC61966-2.1', $oid)
229:             .' /RegistryName '.$this->getOutTextString('http://www.color.org', $oid)
230:             .' /Info '.$this->getOutTextString('sRGB IEC61966-2.1', $oid)
231:             .' /DestOutputProfile '.$this->objid['srgbicc'].' 0 R'
232:             .' >>]';
233:         return $out;
234:     }
235: 
236:     /**
237:      * Get OutputIntents for PDF-X if required
238:      *
239:      * @return string
240:      */
241:     protected function getOutputIntentsPdfX()
242:     {
243:         $oid = $this->objid['catalog'];
244:         $out = ' /OutputIntents [<<'
245:             .' /Type /OutputIntent'
246:             .' /S /GTS_PDFX'
247:             .' /OutputConditionIdentifier '.$this->getOutTextString('OFCOM_PO_P1_F60_95', $oid)
248:             .' /RegistryName '.$this->getOutTextString('http://www.color.org', $oid)
249:             .' /Info '.$this->getOutTextString('OFCOM_PO_P1_F60_95', $oid)
250:             .' >>]';
251:         return $out;
252:     }
253: 
254:     /**
255:      * Set OutputIntents
256:      *
257:      * @return string
258:      */
259:     protected function getOutputIntents()
260:     {
261:         if (empty($this->objid['catalog'])) {
262:             return '';
263:         }
264:         if ($this->pdfx) {
265:             $this->getOutputIntentsPdfX();
266:         }
267:         return $this->getOutputIntentsSrgb();
268:     }
269: 
270:     /**
271:      * Get the PDF layers
272:      *
273:      * @return string
274:      */
275:     protected function getPDFLayers()
276:     {
277:         if (empty($this->pdflayer) || empty($this->objid['catalog'])) {
278:             return '';
279:         }
280:         $oid = $this->objid['catalog'];
281:         $lyrobjs = '';
282:         $lyrobjs_off = '';
283:         $lyrobjs_lock = '';
284:         foreach ($this->pdflayer as $layer) {
285:             $layer_obj_ref = ' '.$layer['objid'].' 0 R';
286:             $lyrobjs .= $layer_obj_ref;
287:             if ($layer['view'] === false) {
288:                 $lyrobjs_off .= $layer_obj_ref;
289:             }
290:             if ($layer['lock']) {
291:                 $lyrobjs_lock .= $layer_obj_ref;
292:             }
293:         }
294:         $out = ' /OCProperties << /OCGs ['.$lyrobjs.' ]'
295:             .' /D <<'
296:             .' /Name '.$this->getOutTextString('Layers', $oid)
297:             .' /Creator '.$this->getOutTextString($this->creator, $oid)
298:             .' /BaseState /ON'
299:             .' /OFF ['.$lyrobjs_off.']'
300:             .' /Locked ['.$lyrobjs_lock.']'
301:             .' /Intent /View'
302:             .' /AS ['
303:             .' << /Event /Print /OCGs ['.$lyrobjs.'] /Category [/Print] >>'
304:             .' << /Event /View /OCGs ['.$lyrobjs.'] /Category [/View] >>'
305:             .' ]'
306:             .' /Order ['.$lyrobjs.']'
307:             .' /ListMode /AllPages'
308:             //.' /RBGroups ['..']'
309:             //.' /Locked ['..']'
310:             .' >>'
311:             .' >>';
312:         return $out;
313:     }
314: 
315:     /**
316:      * Returns the PDF Catalog entry
317:      *
318:      * @return string
319:      */
320:     protected function getOutCatalog()
321:     {
322:         // @TODO
323:         $oid = ++$this->pon;
324:         $this->objid['catalog'] = $oid;
325:         $out = $oid.' 0 obj'."\n"
326:             .'<<'
327:             .' /Type /Catalog'
328:             .' /Version /'.$this->pdfver
329:             //.' /Extensions <<>>'
330:             .' /Pages 1 0 R'
331:             //.' /PageLabels ' //...
332:             .' /Names <<';
333:         if (!$this->pdfa && !empty($this->objid['javascript'])) {
334:             $out .= ' /JavaScript '.$this->objid['javascript'];
335:         }
336:         if (!empty($this->efnames)) {
337:             $out .= ' /EmbeddedFiles << /Names [';
338:             foreach ($this->efnames as $fn => $fref) {
339:                 $out .= ' '.$this->getOutTextString($fn, $oid).' '.$fref;
340:             }
341:             $out .= ' ] >>';
342:         }
343:         $out .= ' >>';
344: 
345:         if (!empty($this->objid['dests'])) {
346:             $out .= ' /Dests '.($this->objid['dests']).' 0 R';
347:         }
348: 
349:         $out .= $this->getOutViewerPref();
350: 
351:         if (!empty($this->display['layout'])) {
352:             $out .= ' /PageLayout /'.$this->display['layout'];
353:         }
354:         if (!empty($this->display['mode'])) {
355:             $out .= ' /PageMode /'.$this->display['mode'];
356:         }
357:         if (!empty($this->outlines)) {
358:             $out .= ' /Outlines '.$this->OutlineRoot.' 0 R';
359:             $out .= ' /PageMode /UseOutlines';
360:         }
361: 
362:         //$out .= ' /Threads []';
363: 
364:         $firstpage = $this->page->getPage(0);
365:         $fpo = $firstpage['n'];
366:         if ($this->display['zoom'] == 'fullpage') {
367:             $out .= ' /OpenAction ['.$fpo.' 0 R /Fit]';
368:         } elseif ($this->display['zoom'] == 'fullwidth') {
369:             $out .= ' /OpenAction ['.$fpo.' 0 R /FitH null]';
370:         } elseif ($this->display['zoom'] == 'real') {
371:             $out .= ' /OpenAction ['.$fpo.' 0 R /XYZ null null 1]';
372:         } elseif (!is_string($this->display['zoom'])) {
373:             $out .= sprintf(' /OpenAction ['.$fpo.' 0 R /XYZ null null %F]', ($this->display['zoom'] / 100));
374:         }
375: 
376:         //$out .= ' /AA <<>>';
377:         //$out .= ' /URI <<>>';
378:         $out .= ' /Metadata '.$this->objid['xmp'].' 0 R';
379:         //$out .= ' /StructTreeRoot <<>>';
380:         //$out .= ' /MarkInfo <<>>';
381: 
382:         if (!empty($this->l['a_meta_language'])) {
383:             $out .= ' /Lang '.$this->getOutTextString($this->l['a_meta_language'], $oid);
384:         }
385: 
386:         //$out .= ' /SpiderInfo <<>>';
387:         $out .= $this->getOutputIntents();
388:         //$out .= ' /PieceInfo <<>>';
389:         $out .= $this->getPDFLayers();
390: 
391:         /*
392:         // AcroForm
393:         if (!empty($this->form_obj_id)
394:             OR ($this->sign AND isset($this->signature_data['cert_type']))
395:             OR !empty($this->empty_signature_appearance)) {
396:             $out .= ' /AcroForm <<';
397:             $objrefs = '';
398:             if ($this->sign AND isset($this->signature_data['cert_type'])) {
399:                 // set reference for signature object
400:                 $objrefs .= $this->sig_obj_id.' 0 R';
401:             }
402:             if (!empty($this->empty_signature_appearance)) {
403:                 foreach ($this->empty_signature_appearance as $esa) {
404:                     // set reference for empty signature objects
405:                     $objrefs .= ' '.$esa['objid'].' 0 R';
406:                 }
407:             }
408:             if (!empty($this->form_obj_id)) {
409:                 foreach($this->form_obj_id as $objid) {
410:                     $objrefs .= ' '.$objid.' 0 R';
411:                 }
412:             }
413:             $out .= ' /Fields ['.$objrefs.']';
414:             // It's better to turn off this value and set the appearance stream for 
415:             // each annotation (/AP) to avoid conflicts with signature fields.
416:             if (empty($this->signature_data['approval']) OR ($this->signature_data['approval'] != 'A')) {
417:                 $out .= ' /NeedAppearances false';
418:             }
419:             if ($this->sign AND isset($this->signature_data['cert_type'])) {
420:                 if ($this->signature_data['cert_type'] > 0) {
421:                     $out .= ' /SigFlags 3';
422:                 } else {
423:                     $out .= ' /SigFlags 1';
424:                 }
425:             }
426:             //$out .= ' /CO ';
427:             if (isset($this->annotation_fonts) AND !empty($this->annotation_fonts)) {
428:                 $out .= ' /DR <<';
429:                 $out .= ' /Font <<';
430:                 foreach ($this->annotation_fonts as $fontkey => $fontid) {
431:                     $out .= ' /F'.$fontid.' '.$this->font_obj_ids[$fontkey].' 0 R';
432:                 }
433:                 $out .= ' >> >>';
434:             }
435:             $font = $this->getFontBuffer('helvetica');
436:             $out .= ' /DA (/F'.$font['i'].' 0 Tf 0 g)';
437:             $out .= ' /Q '.(($this->rtl)?'2':'0');
438:             //$out .= ' /XFA ';
439:             $out .= ' >>';
440:             // signatures
441:             if ($this->sign AND isset($this->signature_data['cert_type']) 
442:                 AND (empty($this->signature_data['approval']) OR ($this->signature_data['approval'] != 'A'))) {
443:                 if ($this->signature_data['cert_type'] > 0) {
444:                     $out .= ' /Perms << /DocMDP '.($this->sig_obj_id + 1).' 0 R >>';
445:                 } else {
446:                     $out .= ' /Perms << /UR3 '.($this->sig_obj_id + 1).' 0 R >>';
447:                 }
448:             }
449:         }
450:         */
451: 
452:         //$out .= ' /Legal <<>>';
453:         //$out .= ' /Requirements []';
454:         //$out .= ' /Collection <<>>';
455:         //$out .= ' /NeedsRendering true';
456: 
457:         $out .= ' >>'."\n"
458:             .'endobj'."\n";
459:         return $out;
460:     }
461: 
462:     /**
463:      * Returns the PDF OCG entry
464:      *
465:      * @return string
466:      */
467:     protected function getOutOCG()
468:     {
469:         if (empty($this->pdflayer)) {
470:             return '';
471:         }
472:         $out = '';
473:         foreach ($this->pdflayer as $key => $layer) {
474:             $oid = ++$this->pon;
475:             $this->pdflayer[$key]['objid'] = $oid;
476:             $out .= $oid.' 0 obj'."\n";
477:             $out .= '<< '
478:                 .' /Type /OCG'
479:                 .' /Name '.$this->getOutTextString($layer['name'], $oid)
480:                 .' /Usage <<';
481:             if (isset($layer['print']) && ($layer['print'] !== null)) {
482:                 $out .= ' /Print <</PrintState /'.$this->getOnOff($layer['print']).'>>';
483:             }
484:             $out .= ' /View <</ViewState /'.$this->getOnOff($layer['view']).'>>'
485:                 .' >>'
486:                 .' >>'."\n"
487:                 .'endobj'."\n";
488:         }
489:         return $out;
490:     }
491: 
492:     /**
493:      * Returns the PDF XObjects entry
494:      *
495:      * @return string
496:      */
497:     protected function getOutXObjects()
498:     {
499:         // @TODO
500:         return '';
501:     }
502: 
503:     /**
504:      * Returns the PDF Resources Dictionary entry
505:      *
506:      * @return string
507:      */
508:     protected function getOutResourcesDict()
509:     {
510:         $this->objid['resdic'] = $this->page->getResourceDictObjID();
511:         $out = $this->objid['resdic'].' 0 obj'."\n"
512:             .'<<'
513:             .' /ProcSet [/PDF /Text /ImageB /ImageC /ImageI]'
514:             .$this->getOutFontDic()
515:             .$this->getXObjectDic()
516:             .$this->getLayerDic()
517:             .$this->graph->getOutExtGStateResources()
518:             .$this->graph->getOutGradientResources()
519:             .$this->color->getPdfSpotResources()
520:             .' >>'."\n"
521:             .'endobj'."\n";
522:         return $out;
523:     }
524: 
525:     /**
526:      * Returns the PDF Destinations entry
527:      *
528:      * @return string
529:      */
530:     protected function getOutDestinations()
531:     {
532:         // @TODO
533:         return '';
534:     }
535: 
536:     /**
537:      * Returns the PDF Embedded Files entry
538:      *
539:      * @return string
540:      */
541:     protected function getOutEmbeddedFiles()
542:     {
543:         // @TODO
544:         return '';
545:     }
546: 
547:     /**
548:      * Returns the PDF Annotations entry
549:      *
550:      * @return string
551:      */
552:     protected function getOutAnnotations()
553:     {
554:         // @TODO
555:         return '';
556:     }
557: 
558:     /**
559:      * Returns the PDF Javascript entry
560:      *
561:      * @return string
562:      */
563:     protected function getOutJavascript()
564:     {
565:         // @TODO
566:         return '';
567:     }
568: 
569:     /**
570:      * Returns the PDF Bookmarks entry
571:      *
572:      * @return string
573:      */
574:     protected function getOutBookmarks()
575:     {
576:         // @TODO
577:         return '';
578:     }
579: 
580:     /**
581:      * Returns the PDF Signature Fields entry
582:      *
583:      * @return string
584:      */
585:     protected function getOutSignatureFields()
586:     {
587:         // @TODO
588:         return '';
589:     }
590: 
591:     /**
592:      * Returns the PDF signarure entry
593:      *
594:      * @return string
595:      */
596:     protected function getOutSignature()
597:     {
598:         // @TODO
599:         return '';
600:     }
601: 
602:     /**
603:      * Get the PDF output string for Font resources dictionary
604:      *
605:      * return string
606:      */
607:     protected function getOutFontDic()
608:     {
609:         $fonts = $this->font->getFonts();
610:         if (empty($fonts)) {
611:             return '';
612:         }
613:         $out = ' /Font <<';
614:         foreach ($fonts as $font) {
615:             $out .= ' /F'.$font['i'].' '.$font['n'].' 0 R';
616:         }
617:         $out .= ' >>';
618:         return $out;
619:     }
620: 
621:     /**
622:      * Get the PDF output string for XObject resources dictionary
623:      *
624:      * return string
625:      */
626:     protected function getXObjectDic()
627:     {
628:         if (empty($this->xobject)) {
629:             return '';
630:         }
631:         $out = ' /XObject <<';
632:         foreach ($this->xobject as $id => $oid) {
633:             $out .= ' /'.$id.' '.$oid['n'].' 0 R';
634:         }
635:         $out .= ' >>';
636:         return $out;
637:     }
638: 
639:     /**
640:      * Get the PDF output string for Layer resources dictionary
641:      *
642:      * return string
643:      */
644:     protected function getLayerDic()
645:     {
646:         if (empty($this->pdflayer)) {
647:             return '';
648:         }
649:         $out = ' /Properties <<';
650:         foreach ($this->pdflayer as $layer) {
651:             $out .= ' /'.$layer['layer'].' '.$layer['objid'].' 0 R';
652:         }
653:         $out .= ' >>';
654:         return $out;
655:     }
656: 
657:     /**
658:      * Returns 'ON' if $val is true, 'OFF' otherwise
659:      *
660:      * return string
661:      */
662:     protected function getOnOff($val)
663:     {
664:         if (bool($val)) {
665:             return 'ON';
666:         }
667:         return 'OFF';
668:     }
669: }
670: 
 

© 2004-2018 – Nicola Asuni - Tecnick.com - All rights reserved.
about - disclaimer - privacy