source-class-Com.Tecnick.Pdf.Page.Page

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:  * Page.php
  4:  *
  5:  * @since       2011-05-23
  6:  * @category    Library
  7:  * @package     PdfPage
  8:  * @author      Nicola Asuni <info@tecnick.com>
  9:  * @copyright   2011-2015 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-page
 12:  *
 13:  * This file is part of tc-lib-pdf-page software library.
 14:  */
 15: 
 16: namespace Com\Tecnick\Pdf\Page;
 17: 
 18: use \Com\Tecnick\Color\Pdf as Color;
 19: use \Com\Tecnick\Pdf\Encrypt\Encrypt;
 20: use \Com\Tecnick\Pdf\Page\Exception as PageException;
 21: 
 22: /**
 23:  * Com\Tecnick\Pdf\Page\Page
 24:  *
 25:  * @since       2011-05-23
 26:  * @category    Library
 27:  * @package     PdfPage
 28:  * @author      Nicola Asuni <info@tecnick.com>
 29:  * @copyright   2011-2015 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-page
 32:  */
 33: class Page extends \Com\Tecnick\Pdf\Page\Region
 34: {
 35:     /**
 36:      * Alias for total number of pages in a group
 37:      *
 38:      * @var string
 39:      */
 40:     const PAGE_TOT = '~#PT';
 41:     
 42:     /**
 43:      * Alias for page number
 44:      *
 45:      * @var string
 46:      */
 47:     const PAGE_NUM = '~#PN';
 48: 
 49:     /**
 50:      * Array of pages (stack).
 51:      *
 52:      * @var array
 53:      */
 54:     protected $page = array();
 55: 
 56:     /**
 57:      * Current page ID.
 58:      *
 59:      * @var int
 60:      */
 61:     protected $pageid = -1;
 62: 
 63:     /**
 64:      * Maximum page ID.
 65:      *
 66:      * @var int
 67:      */
 68:     protected $pmaxid = -1;
 69:     
 70:     /**
 71:      * Count pages in each group
 72:      *
 73:      * @var array
 74:      */
 75:     protected $group = array(0 => 0);
 76:     
 77:     /**
 78:      * Unit of measure conversion ratio
 79:      *
 80:      * @var float
 81:      */
 82:     protected $kunit = 1.0;
 83: 
 84:     /**
 85:      * Color object
 86:      *
 87:      * @var Color
 88:      */
 89:     protected $col;
 90: 
 91:     /**
 92:      * Encrypt object
 93:      *
 94:      * @var Encrypt
 95:      */
 96:     protected $enc;
 97: 
 98:     /**
 99:      * True if we are in PDF/A mode.
100:      *
101:      * @var bool
102:      */
103:     protected $pdfa = false;
104: 
105:     /**
106:      * True if the signature approval is enabled (for incremental updates).
107:      *
108:      * @var bool
109:      */
110:     protected $sigapp = false;
111: 
112:     /**
113:      * Reserved Object ID for the resource dictionary.
114:      *
115:      * @var int
116:      */
117:     protected $rdoid = 1;
118: 
119:     /**
120:      * Initialize page data
121:      *
122:      * @param string  $unit   Unit of measure ('pt', 'mm', 'cm', 'in')
123:      * @param Color   $col    Color object
124:      * @param Encrypt $enc    Encrypt object
125:      * @param bool    $pdfa   True if we are in PDF/A mode.
126:      * @param bool    $sigapp True if the signature approval is enabled (for incremental updates).
127:      */
128:     public function __construct($unit, Color $col, Encrypt $enc, $pdfa = false, $sigapp = false)
129:     {
130:         $this->kunit = $this->getUnitRatio($unit);
131:         $this->col = $col;
132:         $this->enc = $enc;
133:         $this->pdfa = (bool) $pdfa;
134:         $this->sigapp = (bool) $sigapp;
135:     }
136: 
137:     /**
138:      * Get the unit ratio
139:      *
140:      * @return float
141:      */
142:     public function getKUnit()
143:     {
144:         return $this->kunit;
145:     }
146: 
147:     /**
148:      * Enable Signature Approval
149:      *
150:      * @param bool $sigapp True if the signature approval is enabled (for incremental updates).
151:      */
152:     public function enableSignatureApproval($sigapp)
153:     {
154:         $this->sigapp = (bool) $sigapp;
155:         return $this;
156:     }
157: 
158:     /**
159:      * Add a new page
160:      *
161:      * @param array $data Page data:
162:      *     time        : UTC page modification time in seconds;
163:      *     group       : page group number;
164:      *     num         : if set overwrites the page number;
165:      *     content     : string containing the raw page content;
166:      *     annotrefs   : array containing the annotation object references;
167:      *     format      : page format name, or alternatively you can set width and height as below;
168:      *     width       : page width;
169:      *     height      : page height;
170:      *     orientation : page orientation ('P' or 'L');
171:      *     rotation    : the number of degrees by which the page shall be rotated clockwise when displayed or printed;
172:      *     box         : array containing page box boundaries and settings (@see setBox);
173:      *     transition  : array containing page transition data (@see getPageTransition);
174:      *     zoom        : preferred zoom (magnification) factor;
175:      *     margin      : page margins:
176:      *                   PL : page left margin measured from the left page edge
177:      *                   PR : page right margin measured from the right page edge
178:      *                   PT : page top or header top measured distance from the top page edge
179:      *                   HB : header bottom measured from the top page edge
180:      *                   CT : content top measured from the top page edge
181:      *                   CB : content bottom (page breaking point) measured from the top page edge
182:      *                   FT : footer top measured from the bottom page edge
183:      *                   PB : page bottom (footer bottom) measured from the bottom page edge
184:      *     columns     : number of equal vertical columns, if set it will automatically populate the region array
185:      *     region      : array containing the ordered list of rectangular areas where it is allowed to write,
186:      *                   each region is defined by:
187:      *                   RX : horizontal coordinate of top-left corner
188:      *                   RY : vertical coordinate of top-left corner
189:      *                   RW : region width
190:      *                   RH : region height
191:      *     autobreak   : true to automatically add a page when the content reaches the breaking point.
192:      *
193:      * NOTE: if $data is empty, then the last page format will be cloned.
194:      *
195:      * @return array Page data
196:      */
197:     public function add(array $data = array())
198:     {
199:         if (empty($data) && ($this->pmaxid >= 0)) {
200:             // clone last page data
201:             $data = $this->page[$this->pmaxid];
202:             unset($data['time'], $data['content'], $data['annotrefs'], $data['pagenum']);
203:         } else {
204:             $this->sanitizeGroup($data);
205:             $this->sanitizeRotation($data);
206:             $this->sanitizeZoom($data);
207:             $this->sanitizePageFormat($data);
208:             $this->sanitizeBoxData($data);
209:             $this->sanitizeTransitions($data);
210:             $this->sanitizeMargins($data);
211:             $this->sanitizeRegions($data);
212:         }
213: 
214:         $this->sanitizeTime($data);
215:         $this->sanitizeContent($data);
216:         $this->sanitizeAnnotRefs($data);
217:         $this->sanitizePageNumber($data);
218:         $data['content_mark'] = array(0);
219:         $data['currentRegion'] = 0;
220: 
221:         $this->pageid = ++$this->pmaxid;
222:         $this->page[$this->pageid] = $data;
223:         if (isset($this->group[$data['group']])) {
224:             $this->group[$data['group']] += 1;
225:         } else {
226:             $this->group[$data['group']] = 1;
227:         }
228: 
229:         return $this->page[$this->pageid];
230:     }
231: 
232:     /**
233:      * Remove the specified page
234:      *
235:      * @param int $idx page index
236:      *
237:      * @return array Removed page
238:      */
239:     public function delete($idx)
240:     {
241:         if (empty($this->page[$idx])) {
242:             throw new PageException('The specified page do not exist');
243:         }
244:         $page = $this->page[$idx];
245:         $this->group[$this->page[$idx]['group']] -= 1;
246:         unset($this->page[$idx]);
247:         $this->page = array_values($this->page); // reindex array
248:         --$this->pmaxid;
249:         return $page;
250:     }
251: 
252:     /**
253:      * Remove and return last page
254:      *
255:      * @return array Removed page
256:      */
257:     public function pop()
258:     {
259:         return $this->delete($this->pmaxid);
260:     }
261: 
262:     /**
263:      * Move a page to a previous position
264:      *
265:      * @param int $from Index of the page to move
266:      * @param int $new  Destination index
267:      */
268:     public function move($from, $new)
269:     {
270:         if (($from <= $new) || ($from > $this->pmaxid)) {
271:             throw new PageException('The new position must be lower than the starting position');
272:         }
273:         $this->page = array_values(
274:             array_merge(
275:                 array_slice($this->page, 0, $new),
276:                 array($this->page[$from]),
277:                 array_slice($this->page, $new, ($from - $new)),
278:                 array_slice($this->page, ($from + 1))
279:             )
280:         );
281:     }
282: 
283:     /**
284:      * Returns the array (stack) containing all pages data.
285:      *
286:      * return array
287:      */
288:     public function getPages()
289:     {
290:         return $this->page;
291:     }
292: 
293:     /**
294:      * Returns the specified page data.
295:      *
296:      * @param int $idx Page ID
297:      *
298:      * return array
299:      */
300:     public function getPage($idx)
301:     {
302:         if (!isset($this->page[$idx])) {
303:             throw new PageException('The page '.$idx.' do not exist.');
304:         }
305:         return $this->page[$idx];
306:     }
307: 
308:     /**
309:      * Set the current page number (move to the specified page)
310:      *
311:      * @param int $pid Page ID number
312:      */
313:     public function setCurrentPage($pid)
314:     {
315:         $this->pageid = min(max(0, intval($pid)), $this->pmaxid);
316:         return $this->page[$this->pageid];
317:     }
318: 
319:     /**
320:      * Returns the last page array
321:      *
322:      * @return array
323:      */
324:     public function getCurrentPage()
325:     {
326:         return $this->page[$this->pageid];
327:     }
328: 
329:     /**
330:      * Add page content
331:      *
332:      * @param array $data Page data
333:      */
334:     public function addContent($content)
335:     {
336:         $this->page[$this->pageid]['content'][] = (string) $content;
337:     }
338: 
339:     /**
340:      * Remove and return last page content
341:      *
342:      * @param array $data Page data
343:      *
344:      * @param string content
345:      */
346:     public function popContent()
347:     {
348:         return array_pop($this->page[$this->pageid]['content']);
349:     }
350: 
351:     /**
352:      * Add page content mark
353:      */
354:     public function addContentMark()
355:     {
356:         $this->page[$this->pageid]['content_mark'][] = count($this->page[$this->pageid]['content']);
357:     }
358: 
359:     /**
360:      * Remove the last marked page content
361:      */
362:     public function popContentToLastMark()
363:     {
364:         $mark = array_pop($this->page[$this->pageid]['content_mark']);
365:         $this->page[$this->pageid]['content'] = array_slice($this->page[$this->pageid]['content'], 0, $mark, true);
366:     }
367: 
368:     /**
369:      * Returns the PDF command to output all page sections
370:      *
371:      * @param int $pon Current PDF object number
372:      *
373:      * @return string PDF command
374:      */
375:     public function getPdfPages(&$pon)
376:     {
377:         $out = $this->getPageRootObj($pon);
378:         $rootobjid = $pon;
379: 
380:         foreach ($this->page as $num => $page) {
381:             if (!isset($page['num'])) {
382:                 if ($num > 0) {
383:                     if ($page['group'] == $this->page[($num - 1)]['group']) {
384:                         $page['num'] = (1 + $this->page[($num - 1)]['num']);
385:                     } else {
386:                         // new page group
387:                         $page['num'] = 1;
388:                     }
389:                 } else {
390:                     $page['num'] = (1 + $num);
391:                 }
392:             }
393:             $this->page[$num]['num'] = $page['num'];
394:             
395:             $content = $this->replacePageTemplates($page);
396:             $out .= $this->getPageContentObj($pon, $content);
397:             $contentobjid = $pon;
398: 
399:             $out .= $page['n'].' 0 obj'."\n"
400:                 .'<<'."\n"
401:                 .'/Type /Page'."\n"
402:                 .'/Parent '.$rootobjid.' 0 R'."\n";
403:             if (!$this->pdfa) {
404:                 $out .= '/Group << /Type /Group /S /Transparency /CS /DeviceRGB >>'."\n";
405:             }
406:             if (!$this->sigapp) {
407:                 $out .= '/LastModified '.$this->enc->getFormattedDate($page['time'], $pon)."\n";
408:             }
409:             $out .= '/Resources '.$this->rdoid.' 0 R'."\n"
410:                 .$this->getBox($page['box'])
411:                 .$this->getBoxColorInfo($page['box'])
412:                 .'/Contents '.$contentobjid.' 0 R'."\n"
413:                 .'/Rotate '.$page['rotation']."\n"
414:                 .'/PZ '.sprintf('%F', $page['zoom'])."\n"
415:                 .$this->getPageTransition($page)
416:                 .$this->getAnnotationRef($page)
417:                 .'>>'."\n"
418:                 .'endobj'."\n";
419:         }
420: 
421:         return $out;
422:     }
423: 
424:     /**
425:      * Returns the reserved Object ID for the Resource dictionary.
426:      *
427:      * return int
428:      */
429:     public function getResourceDictObjID()
430:     {
431:         return $this->rdoid;
432:     }
433: 
434:     /**
435:      * Returns the PDF command to output the page content.
436:      *
437:      * @param int    $pon     Current PDF object number.
438:      * @param string $content Page content.
439:      *
440:      * @return string PDF command
441:      */
442:     protected function getPageTransition($page)
443:     {
444:         if (empty($page['transition'])) {
445:             return '';
446:         }
447:         $entries = array('S', 'D', 'Dm', 'M', 'Di', 'SS', 'B');
448:         $out = '';
449:         if (isset($page['transition']['Dur'])) {
450:             $out .= '/Dur '.sprintf('%F', $page['transition']['Dur'])."\n";
451:         }
452:         $out .= '/Trans <<'."\n"
453:             .'/Type /Trans'."\n";
454:         foreach ($page['transition'] as $key => $val) {
455:             if (in_array($key, $entries)) {
456:                 if (is_float($val)) {
457:                     $val = sprintf('%F', $val);
458:                 }
459:                 $out .= '/'.$key.' /'.$val."\n";
460:             }
461:         }
462:         $out .= '>>'."\n";
463:         return $out;
464:     }
465: 
466:     /**
467:      * Get references to page annotations.
468:      *
469:      * @param array $page Page data
470:      *
471:      * @return string PDF command
472:      */
473:     protected function getAnnotationRef($page)
474:     {
475:         if (empty($page['annotrefs'])) {
476:             return '';
477:         }
478:         $out = '/Annots [ ';
479:         foreach ($page['annotrefs'] as $val) {
480:             $out .= intval($val).' 0 R ';
481:         }
482:         $out .= ']'."\n";
483:         return $out;
484:     }
485: 
486:     /**
487:      * Returns the PDF command to output the page content.
488:      *
489:      * @param int    $pon     Current PDF object number.
490:      * @param string $content Page content.
491:      *
492:      * @return string PDF command
493:      */
494:     protected function getPageContentObj(&$pon, $content = '')
495:     {
496:         $stream = $this->enc->encryptString(gzcompress($content), ++$pon);
497:         $out = $pon.' 0 obj'."\n"
498:             .'<</Filter /FlateDecode /Length '.strlen($stream).'>>'."\n"
499:             .'stream'."\n"
500:             .$stream."\n"
501:             .'endstream'."\n"
502:             .'endobj'."\n";
503:         return $out;
504:     }
505: 
506:     /**
507:      * Returns the PDF command to output the page root object.
508:      *
509:      * @param int $pon Current PDF object number
510:      *
511:      * @return string PDF command
512:      */
513:     protected function getPageRootObj(&$pon)
514:     {
515:         $out = (++$pon).' 0 obj'."\n";
516:         $this->rdoid = ++$pon; // reserve object ID for the resource dictionary
517:         $out .= '<< /Type /Pages /Kids [ ';
518:         $numpages = count($this->page);
519:         for ($idx = 0; $idx < $numpages; ++$idx) {
520:             $this->page[$idx]['n'] = ++$pon;
521:             $out .= $this->page[$idx]['n'].' 0 R ';
522:         }
523:         $out .= '] /Count '.$numpages.' >>'."\n"
524:             .'endobj'."\n";
525:         return $out;
526:     }
527: 
528:     /**
529:      * Replace page templates and numbers
530:      *
531:      * @param array $data Page data
532:      */
533:     protected function replacePageTemplates(array $data)
534:     {
535:         return implode(
536:             '',
537:             str_replace(
538:                 array(self::PAGE_TOT, self::PAGE_NUM),
539:                 array($this->group[$data['group']], $data['num']),
540:                 $data['content']
541:             )
542:         );
543:     }
544: }
545: 
 

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