3 // FPDI - Version 1.2.1
5 // Copyright 2004-2008 Setasign - Jan Slabon
7 // Licensed under the Apache License, Version 2.0 (the "License");
8 // you may not use this file except in compliance with the License.
9 // You may obtain a copy of the License at
11 // http://www.apache.org/licenses/LICENSE-2.0
13 // Unless required by applicable law or agreed to in writing, software
14 // distributed under the License is distributed on an "AS IS" BASIS,
15 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 // See the License for the specific language governing permissions and
17 // limitations under the License.
20 require_once("pdf_parser.php");
22 class fpdi_pdf_parser extends pdf_parser {
45 * PDF Version of imported Document
61 var $availableBoxes = array("/MediaBox","/CropBox","/BleedBox","/TrimBox","/ArtBox");
66 * @param string $filename Source-Filename
67 * @param object $fpdi Object of type fpdi
69 function fpdi_pdf_parser($filename,&$fpdi) {
71 $this->filename = $filename;
73 parent::pdf_parser($filename);
75 // resolve Pages-Dictonary
76 $pages = $this->pdf_resolve_object($this->c, $this->root[1][1]['/Pages']);
79 $this->read_pages($this->c, $pages, $this->pages);
82 $this->page_count = count($this->pages);
86 * Overwrite parent::error()
88 * @param string $msg Error-Message
90 function error($msg) {
91 $this->fpdi->error($msg);
95 * Get pagecount from sourcefile
99 function getPageCount() {
100 return $this->page_count;
107 * @param int $pageno Pagenumber to use
109 function setPageno($pageno) {
110 $pageno = ((int) $pageno) - 1;
112 if ($pageno < 0 || $pageno >= $this->getPageCount()) {
113 $this->fpdi->error("Pagenumber is wrong!");
116 $this->pageno = $pageno;
120 * Get page-resources from current page
124 function getPageResources() {
125 return $this->_getPageResources($this->pages[$this->pageno]);
129 * Get page-resources from /Page
131 * @param array $obj Array of pdf-data
133 function _getPageResources ($obj) { // $obj = /Page
134 $obj = $this->pdf_resolve_object($this->c, $obj);
136 // If the current object has a resources
137 // dictionary associated with it, we use
138 // it. Otherwise, we move back to its
140 if (isset ($obj[1][1]['/Resources'])) {
141 $res = $this->pdf_resolve_object($this->c, $obj[1][1]['/Resources']);
142 if ($res[0] == PDF_TYPE_OBJECT)
146 if (!isset ($obj[1][1]['/Parent'])) {
149 $res = $this->_getPageResources($obj[1][1]['/Parent']);
150 if ($res[0] == PDF_TYPE_OBJECT)
159 * Get content of current page
161 * If more /Contents is an array, the streams are concated
165 function getContent() {
168 if (isset($this->pages[$this->pageno][1][1]['/Contents'])) {
169 $contents = $this->_getPageContent($this->pages[$this->pageno][1][1]['/Contents']);
170 foreach($contents AS $tmp_content) {
171 $buffer .= $this->_rebuildContentStream($tmp_content).' ';
180 * Resolve all content-objects
182 * @param array $content_ref
185 function _getPageContent($content_ref) {
188 if ($content_ref[0] == PDF_TYPE_OBJREF) {
189 $content = $this->pdf_resolve_object($this->c, $content_ref);
190 if ($content[1][0] == PDF_TYPE_ARRAY) {
191 $contents = $this->_getPageContent($content[1]);
193 $contents[] = $content;
195 } else if ($content_ref[0] == PDF_TYPE_ARRAY) {
196 foreach ($content_ref[1] AS $tmp_content_ref) {
197 $contents = array_merge($contents,$this->_getPageContent($tmp_content_ref));
206 * Rebuild content-streams
211 function _rebuildContentStream($obj) {
214 if (isset($obj[1][1]['/Filter'])) {
215 $_filter = $obj[1][1]['/Filter'];
217 if ($_filter[0] == PDF_TYPE_TOKEN) {
218 $filters[] = $_filter;
219 } else if ($_filter[0] == PDF_TYPE_ARRAY) {
220 $filters = $_filter[1];
224 $stream = $obj[2][1];
226 foreach ($filters AS $_filter) {
227 switch ($_filter[1]) {
229 if (function_exists('gzuncompress')) {
230 $stream = (strlen($stream) > 0) ? @gzuncompress($stream) : '';
232 $this->fpdi->error(sprintf("To handle %s filter, please compile php with zlib support.",$_filter[1]));
234 if ($stream === false) {
235 $this->fpdi->error("Error while decompressing stream.");
242 if (preg_match("/^\/[a-z85]*$/i", $_filter[1], $filterName) && @include_once('decoders'.$_filter[1].'.php')) {
243 $filterName = substr($_filter[1],1);
244 if (class_exists($filterName)) {
245 $decoder = new $filterName($this->fpdi);
246 $stream = $decoder->decode(trim($stream));
248 $this->fpdi->error(sprintf("Unsupported Filter: %s",$_filter[1]));
251 $this->fpdi->error(sprintf("Unsupported Filter: %s",$_filter[1]));
261 * Get a Box from a page
262 * Arrayformat is same as used by fpdf_tpl
264 * @param array $page a /Page
265 * @param string $box_index Type of Box @see $availableBoxes
268 function getPageBox($page, $box_index) {
269 $page = $this->pdf_resolve_object($this->c,$page);
271 if (isset($page[1][1][$box_index]))
272 $box =& $page[1][1][$box_index];
274 if (!is_null($box) && $box[0] == PDF_TYPE_OBJREF) {
275 $tmp_box = $this->pdf_resolve_object($this->c,$box);
279 if (!is_null($box) && $box[0] == PDF_TYPE_ARRAY) {
281 return array("x" => $b[0][1]/$this->fpdi->k,
282 "y" => $b[1][1]/$this->fpdi->k,
283 "w" => abs($b[0][1]-$b[2][1])/$this->fpdi->k,
284 "h" => abs($b[1][1]-$b[3][1])/$this->fpdi->k);
285 } else if (!isset ($page[1][1]['/Parent'])) {
288 return $this->getPageBox($this->pdf_resolve_object($this->c, $page[1][1]['/Parent']), $box_index);
292 function getPageBoxes($pageno) {
293 return $this->_getPageBoxes($this->pages[$pageno-1]);
297 * Get all Boxes from /Page
299 * @param array a /Page
302 function _getPageBoxes($page) {
305 foreach($this->availableBoxes AS $box) {
306 if ($_box = $this->getPageBox($page,$box)) {
307 $boxes[$box] = $_box;
315 * Get the page rotation by pageno
317 * @param integer $pageno
320 function getPageRotation($pageno) {
321 return $this->_getPageRotation($this->pages[$pageno-1]);
324 function _getPageRotation ($obj) { // $obj = /Page
325 $obj = $this->pdf_resolve_object($this->c, $obj);
326 if (isset ($obj[1][1]['/Rotate'])) {
327 $res = $this->pdf_resolve_object($this->c, $obj[1][1]['/Rotate']);
328 if ($res[0] == PDF_TYPE_OBJECT)
332 if (!isset ($obj[1][1]['/Parent'])) {
335 $res = $this->_getPageRotation($obj[1][1]['/Parent']);
336 if ($res[0] == PDF_TYPE_OBJECT)
346 * @param object pdf_context
347 * @param array /Pages
348 * @param array the result-array
350 function read_pages (&$c, &$pages, &$result) {
351 // Get the kids dictionary
352 $kids = $this->pdf_resolve_object ($c, $pages[1][1]['/Kids']);
354 if (!is_array($kids))
355 $this->fpdi->Error("Cannot find /Kids in current /Page-Dictionary");
356 foreach ($kids[1] as $v) {
357 $pg = $this->pdf_resolve_object ($c, $v);
358 if ($pg[1][1]['/Type'][1] === '/Pages') {
359 // If one of the kids is an embedded
360 // /Pages array, resolve it as well.
361 $this->read_pages ($c, $pg, $result);
373 * And reset the PDF Version used in FPDI if needed
375 function getPDFVersion() {
376 parent::getPDFVersion();
377 $this->fpdi->PDFVersion = max($this->fpdi->PDFVersion, $this->pdfVersion);