1
|
|
|
<?php
|
|
|
|
|
2
|
|
|
//
|
3
|
|
|
// FPDI - Version 1.2.1
|
4
|
|
|
//
|
5
|
|
|
// Copyright 2004-2008 Setasign - Jan Slabon
|
6
|
|
|
//
|
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
|
10
|
|
|
//
|
11
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
12
|
|
|
//
|
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.
|
18
|
|
|
//
|
19
|
|
|
|
20
|
|
|
require_once("pdf_parser.php");
|
21
|
|
|
|
22
|
|
|
class fpdi_pdf_parser extends pdf_parser {
|
|
|
|
|
23
|
|
|
|
24
|
|
|
/**
|
25
|
|
|
* Pages
|
26
|
|
|
* Index beginns at 0
|
27
|
|
|
*
|
28
|
|
|
* @var array
|
29
|
|
|
*/
|
30
|
|
|
var $pages;
|
|
|
|
|
31
|
|
|
|
32
|
|
|
/**
|
33
|
|
|
* Page count
|
34
|
|
|
* @var integer
|
35
|
|
|
*/
|
36
|
|
|
var $page_count;
|
|
|
|
|
37
|
|
|
|
38
|
|
|
/**
|
39
|
|
|
* actual page number
|
40
|
|
|
* @var integer
|
41
|
|
|
*/
|
42
|
|
|
var $pageno;
|
|
|
|
|
43
|
|
|
|
44
|
|
|
/**
|
45
|
|
|
* PDF Version of imported Document
|
46
|
|
|
* @var string
|
47
|
|
|
*/
|
48
|
|
|
var $pdfVersion;
|
|
|
|
|
49
|
|
|
|
50
|
|
|
/**
|
51
|
|
|
* FPDI Reference
|
52
|
|
|
* @var object
|
53
|
|
|
*/
|
54
|
|
|
var $fpdi;
|
|
|
|
|
55
|
|
|
|
56
|
|
|
/**
|
57
|
|
|
* Available BoxTypes
|
58
|
|
|
*
|
59
|
|
|
* @var array
|
60
|
|
|
*/
|
61
|
|
|
var $availableBoxes = array("/MediaBox","/CropBox","/BleedBox","/TrimBox","/ArtBox");
|
|
|
|
|
62
|
|
|
|
63
|
|
|
/**
|
64
|
|
|
* Constructor
|
65
|
|
|
*
|
66
|
|
|
* @param string $filename Source-Filename
|
67
|
|
|
* @param object $fpdi Object of type fpdi
|
68
|
|
|
*/
|
69
|
|
|
function fpdi_pdf_parser($filename,&$fpdi) {
|
|
|
|
|
70
|
|
|
$this->fpdi =& $fpdi;
|
71
|
|
|
$this->filename = $filename;
|
|
|
|
|
72
|
|
|
|
73
|
|
|
parent::pdf_parser($filename);
|
|
|
|
|
74
|
|
|
|
75
|
|
|
// resolve Pages-Dictonary
|
76
|
|
|
$pages = $this->pdf_resolve_object($this->c, $this->root[1][1]['/Pages']);
|
|
|
|
|
77
|
|
|
|
78
|
|
|
// Read pages
|
79
|
|
|
$this->read_pages($this->c, $pages, $this->pages);
|
|
|
|
|
80
|
|
|
|
81
|
|
|
// count pages;
|
82
|
|
|
$this->page_count = count($this->pages);
|
83
|
|
|
}
|
84
|
|
|
|
85
|
|
|
/**
|
86
|
|
|
* Overwrite parent::error()
|
87
|
|
|
*
|
88
|
|
|
* @param string $msg Error-Message
|
89
|
|
|
*/
|
90
|
|
|
function error($msg) {
|
|
|
|
|
91
|
|
|
$this->fpdi->error($msg);
|
92
|
|
|
}
|
93
|
|
|
|
94
|
|
|
/**
|
95
|
|
|
* Get pagecount from sourcefile
|
96
|
|
|
*
|
97
|
|
|
* @return int
|
98
|
|
|
*/
|
99
|
|
|
function getPageCount() {
|
|
|
|
|
100
|
|
|
return $this->page_count;
|
101
|
|
|
}
|
102
|
|
|
|
103
|
|
|
|
104
|
|
|
/**
|
105
|
|
|
* Set pageno
|
106
|
|
|
*
|
107
|
|
|
* @param int $pageno Pagenumber to use
|
108
|
|
|
*/
|
109
|
|
|
function setPageno($pageno) {
|
|
|
|
|
110
|
|
|
$pageno = ((int) $pageno) - 1;
|
111
|
|
|
|
112
|
|
|
if ($pageno < 0 || $pageno >= $this->getPageCount()) {
|
113
|
|
|
$this->fpdi->error("Pagenumber is wrong!");
|
114
|
|
|
}
|
115
|
|
|
|
116
|
|
|
$this->pageno = $pageno;
|
117
|
|
|
}
|
118
|
|
|
|
119
|
|
|
/**
|
120
|
|
|
* Get page-resources from current page
|
121
|
|
|
*
|
122
|
|
|
* @return array
|
123
|
|
|
*/
|
124
|
|
|
function getPageResources() {
|
|
|
|
|
125
|
|
|
return $this->_getPageResources($this->pages[$this->pageno]);
|
126
|
|
|
}
|
127
|
|
|
|
128
|
|
|
/**
|
129
|
|
|
* Get page-resources from /Page
|
130
|
|
|
*
|
131
|
|
|
* @param array $obj Array of pdf-data
|
132
|
|
|
*/
|
133
|
|
View Code Duplication |
function _getPageResources ($obj) { // $obj = /Page
|
|
|
|
|
134
|
|
|
$obj = $this->pdf_resolve_object($this->c, $obj);
|
|
|
|
|
135
|
|
|
|
136
|
|
|
// If the current object has a resources
|
137
|
|
|
// dictionary associated with it, we use
|
138
|
|
|
// it. Otherwise, we move back to its
|
139
|
|
|
// parent object.
|
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)
|
143
|
|
|
return $res[1];
|
144
|
|
|
return $res;
|
145
|
|
|
} else {
|
146
|
|
|
if (!isset ($obj[1][1]['/Parent'])) {
|
147
|
|
|
return false;
|
148
|
|
|
} else {
|
149
|
|
|
$res = $this->_getPageResources($obj[1][1]['/Parent']);
|
150
|
|
|
if ($res[0] == PDF_TYPE_OBJECT)
|
151
|
|
|
return $res[1];
|
152
|
|
|
return $res;
|
153
|
|
|
}
|
154
|
|
|
}
|
155
|
|
|
}
|
156
|
|
|
|
157
|
|
|
|
158
|
|
|
/**
|
159
|
|
|
* Get content of current page
|
160
|
|
|
*
|
161
|
|
|
* If more /Contents is an array, the streams are concated
|
162
|
|
|
*
|
163
|
|
|
* @return string
|
164
|
|
|
*/
|
165
|
|
|
function getContent() {
|
|
|
|
|
166
|
|
|
$buffer = "";
|
167
|
|
|
|
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).' ';
|
172
|
|
|
}
|
173
|
|
|
}
|
174
|
|
|
|
175
|
|
|
return $buffer;
|
176
|
|
|
}
|
177
|
|
|
|
178
|
|
|
|
179
|
|
|
/**
|
180
|
|
|
* Resolve all content-objects
|
181
|
|
|
*
|
182
|
|
|
* @param array $content_ref
|
183
|
|
|
* @return array
|
184
|
|
|
*/
|
185
|
|
|
function _getPageContent($content_ref) {
|
|
|
|
|
186
|
|
|
$contents = array();
|
187
|
|
|
|
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]);
|
192
|
|
|
} else {
|
193
|
|
|
$contents[] = $content;
|
194
|
|
|
}
|
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));
|
198
|
|
|
}
|
199
|
|
|
}
|
200
|
|
|
|
201
|
|
|
return $contents;
|
202
|
|
|
}
|
203
|
|
|
|
204
|
|
|
|
205
|
|
|
/**
|
206
|
|
|
* Rebuild content-streams
|
207
|
|
|
*
|
208
|
|
|
* @param array $obj
|
209
|
|
|
* @return string
|
210
|
|
|
*/
|
211
|
|
|
function _rebuildContentStream($obj) {
|
|
|
|
|
212
|
|
|
$filters = array();
|
213
|
|
|
|
214
|
|
|
if (isset($obj[1][1]['/Filter'])) {
|
215
|
|
|
$_filter = $obj[1][1]['/Filter'];
|
216
|
|
|
|
217
|
|
|
if ($_filter[0] == PDF_TYPE_TOKEN) {
|
218
|
|
|
$filters[] = $_filter;
|
219
|
|
|
} else if ($_filter[0] == PDF_TYPE_ARRAY) {
|
220
|
|
|
$filters = $_filter[1];
|
221
|
|
|
}
|
222
|
|
|
}
|
223
|
|
|
|
224
|
|
|
$stream = $obj[2][1];
|
225
|
|
|
|
226
|
|
|
foreach ($filters AS $_filter) {
|
227
|
|
|
switch ($_filter[1]) {
|
228
|
|
|
case "/FlateDecode":
|
229
|
|
|
if (function_exists('gzuncompress')) {
|
230
|
|
|
$stream = (strlen($stream) > 0) ? @gzuncompress($stream) : '';
|
231
|
|
|
} else {
|
232
|
|
|
$this->fpdi->error(sprintf("To handle %s filter, please compile php with zlib support.",$_filter[1]));
|
233
|
|
|
}
|
234
|
|
|
if ($stream === false) {
|
235
|
|
|
$this->fpdi->error("Error while decompressing stream.");
|
236
|
|
|
}
|
237
|
|
|
break;
|
238
|
|
|
case null:
|
239
|
|
|
$stream = $stream;
|
|
|
|
|
240
|
|
|
break;
|
241
|
|
|
default:
|
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));
|
247
|
|
|
} else {
|
248
|
|
|
$this->fpdi->error(sprintf("Unsupported Filter: %s",$_filter[1]));
|
249
|
|
|
}
|
250
|
|
|
} else {
|
251
|
|
|
$this->fpdi->error(sprintf("Unsupported Filter: %s",$_filter[1]));
|
252
|
|
|
}
|
253
|
|
|
}
|
254
|
|
|
}
|
255
|
|
|
|
256
|
|
|
return $stream;
|
257
|
|
|
}
|
258
|
|
|
|
259
|
|
|
|
260
|
|
|
/**
|
261
|
|
|
* Get a Box from a page
|
262
|
|
|
* Arrayformat is same as used by fpdf_tpl
|
263
|
|
|
*
|
264
|
|
|
* @param array $page a /Page
|
265
|
|
|
* @param string $box_index Type of Box @see $availableBoxes
|
266
|
|
|
* @return array
|
267
|
|
|
*/
|
268
|
|
|
function getPageBox($page, $box_index) {
|
|
|
|
|
269
|
|
|
$page = $this->pdf_resolve_object($this->c,$page);
|
|
|
|
|
270
|
|
|
$box = null;
|
271
|
|
|
if (isset($page[1][1][$box_index]))
|
272
|
|
|
$box =& $page[1][1][$box_index];
|
273
|
|
|
|
274
|
|
|
if (!is_null($box) && $box[0] == PDF_TYPE_OBJREF) {
|
275
|
|
|
$tmp_box = $this->pdf_resolve_object($this->c,$box);
|
|
|
|
|
276
|
|
|
$box = $tmp_box[1];
|
277
|
|
|
}
|
278
|
|
|
|
279
|
|
|
if (!is_null($box) && $box[0] == PDF_TYPE_ARRAY) {
|
280
|
|
|
$b =& $box[1];
|
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'])) {
|
286
|
|
|
return false;
|
287
|
|
|
} else {
|
288
|
|
|
return $this->getPageBox($this->pdf_resolve_object($this->c, $page[1][1]['/Parent']), $box_index);
|
|
|
|
|
289
|
|
|
}
|
290
|
|
|
}
|
291
|
|
|
|
292
|
|
|
function getPageBoxes($pageno) {
|
|
|
|
|
293
|
|
|
return $this->_getPageBoxes($this->pages[$pageno-1]);
|
294
|
|
|
}
|
295
|
|
|
|
296
|
|
|
/**
|
297
|
|
|
* Get all Boxes from /Page
|
298
|
|
|
*
|
299
|
|
|
* @param array a /Page
|
300
|
|
|
* @return array
|
301
|
|
|
*/
|
302
|
|
|
function _getPageBoxes($page) {
|
|
|
|
|
303
|
|
|
$boxes = array();
|
304
|
|
|
|
305
|
|
|
foreach($this->availableBoxes AS $box) {
|
306
|
|
|
if ($_box = $this->getPageBox($page,$box)) {
|
307
|
|
|
$boxes[$box] = $_box;
|
308
|
|
|
}
|
309
|
|
|
}
|
310
|
|
|
|
311
|
|
|
return $boxes;
|
312
|
|
|
}
|
313
|
|
|
|
314
|
|
|
/**
|
315
|
|
|
* Get the page rotation by pageno
|
316
|
|
|
*
|
317
|
|
|
* @param integer $pageno
|
318
|
|
|
* @return array
|
319
|
|
|
*/
|
320
|
|
|
function getPageRotation($pageno) {
|
|
|
|
|
321
|
|
|
return $this->_getPageRotation($this->pages[$pageno-1]);
|
322
|
|
|
}
|
323
|
|
|
|
324
|
|
View Code Duplication |
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)
|
329
|
|
|
return $res[1];
|
330
|
|
|
return $res;
|
331
|
|
|
} else {
|
332
|
|
|
if (!isset ($obj[1][1]['/Parent'])) {
|
333
|
|
|
return false;
|
334
|
|
|
} else {
|
335
|
|
|
$res = $this->_getPageRotation($obj[1][1]['/Parent']);
|
336
|
|
|
if ($res[0] == PDF_TYPE_OBJECT)
|
337
|
|
|
return $res[1];
|
338
|
|
|
return $res;
|
339
|
|
|
}
|
340
|
|
|
}
|
341
|
|
|
}
|
342
|
|
|
|
343
|
|
|
/**
|
344
|
|
|
* Read all /Page(es)
|
345
|
|
|
*
|
346
|
|
|
* @param object pdf_context
|
347
|
|
|
* @param array /Pages
|
348
|
|
|
* @param array the result-array
|
349
|
|
|
*/
|
350
|
|
|
function read_pages (&$c, &$pages, &$result) {
|
|
|
|
|
351
|
|
|
// Get the kids dictionary
|
352
|
|
|
$kids = $this->pdf_resolve_object ($c, $pages[1][1]['/Kids']);
|
353
|
|
|
|
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);
|
362
|
|
|
} else {
|
363
|
|
|
$result[] = $pg;
|
364
|
|
|
}
|
365
|
|
|
}
|
366
|
|
|
}
|
367
|
|
|
|
368
|
|
|
|
369
|
|
|
|
370
|
|
|
/**
|
371
|
|
|
* Get PDF-Version
|
372
|
|
|
*
|
373
|
|
|
* And reset the PDF Version used in FPDI if needed
|
374
|
|
|
*/
|
375
|
|
|
function getPDFVersion() {
|
|
|
|
|
376
|
|
|
parent::getPDFVersion();
|
377
|
|
|
$this->fpdi->PDFVersion = max($this->fpdi->PDFVersion, $this->pdfVersion);
|
378
|
|
|
}
|
379
|
|
|
|
380
|
|
|
} |
The PSR-1: Basic Coding Standard recommends that a file should either introduce new symbols, that is classes, functions, constants or similar, or have side effects. Side effects are anything that executes logic, like for example printing output, changing ini settings or writing to a file.
The idea behind this recommendation is that merely auto-loading a class should not change the state of an application. It also promotes a cleaner style of programming and makes your code less prone to errors, because the logic is not spread out all over the place.
To learn more about the PSR-1, please see the PHP-FIG site on the PSR-1.