44 require_once(dirname( __FILE__ ) .
'/include/tcpdf_filters.php');
90 $this->
Error(
'Empty PDF data.');
92 $this->pdfdata = $data;
94 $pdflen = strlen($this->pdfdata);
100 $this->objects = array();
101 foreach ($this->xref[
'xref'] as $obj => $offset) {
102 if (!isset($this->objects[$obj]) AND ($offset > 0)) {
108 unset($this->pdfdata);
119 return array($this->xref, $this->objects);
133 if (preg_match_all(
'/[\r\n]startxref[\s]*[\r\n]+([0-9]+)[\s]*[\r\n]+%%EOF/i', $this->pdfdata, $matches, PREG_SET_ORDER, $offset) == 0) {
134 $this->
Error(
'Unable to find startxref');
136 $matches = array_pop($matches);
137 $startxref = $matches[1];
139 if (preg_match(
'/([0-9]+[\s][0-9]+[\s]obj)/i', $this->pdfdata, $matches, PREG_OFFSET_CAPTURE, $offset)) {
141 $startxref = $offset;
142 } elseif (preg_match(
'/[\r\n]startxref[\s]*[\r\n]+([0-9]+)[\s]*[\r\n]+%%EOF/i', $this->pdfdata, $matches, PREG_OFFSET_CAPTURE, $offset)) {
144 $startxref = $matches[1][0];
146 $this->
Error(
'Unable to find startxref');
150 if (strpos($this->pdfdata,
'xref', $startxref) == $startxref) {
158 $this->
Error(
'Unable to find xref');
173 $xoffset = $startxref + 5;
177 while (preg_match(
'/^([0-9]+)[\s]([0-9]+)[\s]?([nf]?)/im', $this->pdfdata, $matches, PREG_OFFSET_CAPTURE, $offset) > 0) {
178 $offset = (strlen($matches[0][0]) + $matches[0][1]);
179 if ($matches[3][0] ==
'n') {
181 $index = $obj_num.
'_'.intval($matches[2][0]);
183 if (!isset(
$xref[
'xref'][$index])) {
185 $xref[
'xref'][$index] = intval($matches[1][0]);
189 } elseif ($matches[3][0] ==
'f') {
194 $obj_num = intval($matches[1][0]);
198 if (preg_match(
'/trailer[\s]*<<(.*)>>[\s]*[\r\n]+startxref[\s]*[\r\n]+/isU', $this->pdfdata, $matches, PREG_OFFSET_CAPTURE, $xoffset) > 0) {
199 $trailer_data = $matches[1][0];
200 if (!isset(
$xref[
'trailer']) OR empty(
$xref[
'trailer'])) {
202 $xref[
'trailer'] = array();
204 if (preg_match(
'/Size[\s]+([0-9]+)/i', $trailer_data, $matches) > 0) {
205 $xref[
'trailer'][
'size'] = intval($matches[1]);
207 if (preg_match(
'/Root[\s]+([0-9]+)[\s]+([0-9]+)[\s]+R/i', $trailer_data, $matches) > 0) {
208 $xref[
'trailer'][
'root'] = intval($matches[1]).
'_'.intval($matches[2]);
210 if (preg_match(
'/Encrypt[\s]+([0-9]+)[\s]+([0-9]+)[\s]+R/i', $trailer_data, $matches) > 0) {
211 $xref[
'trailer'][
'encrypt'] = intval($matches[1]).
'_'.intval($matches[2]);
213 if (preg_match(
'/Info[\s]+([0-9]+)[\s]+([0-9]+)[\s]+R/i', $trailer_data, $matches) > 0) {
214 $xref[
'trailer'][
'info'] = intval($matches[1]).
'_'.intval($matches[2]);
216 if (preg_match(
'/ID[\s]*[\[][\s]*[<]([^>]*)[>][\s]*[<]([^>]*)[>]/i', $trailer_data, $matches) > 0) {
217 $xref[
'trailer'][
'id'] = array();
218 $xref[
'trailer'][
'id'][0] = $matches[1];
219 $xref[
'trailer'][
'id'][1] = $matches[2];
222 if (preg_match(
'/Prev[\s]+([0-9]+)/i', $trailer_data, $matches) > 0) {
227 $this->
Error(
'Unable to find trailer');
244 if (!isset(
$xref[
'trailer']) OR empty(
$xref[
'trailer'])) {
246 $xref[
'trailer'] = array();
249 $filltrailer =
false;
252 $sarr = $xrefcrs[0][1];
253 foreach ($sarr as $k => $v) {
254 if (($v[0] ==
'/') AND ($v[1] ==
'Type') AND (isset($sarr[($k +1)]) AND ($sarr[($k +1)][0] ==
'/') AND ($sarr[($k +1)][1] ==
'XRef'))) {
256 } elseif (($v[0] ==
'/') AND ($v[1] ==
'Index') AND (isset($sarr[($k +1)]))) {
258 $index_first = intval($sarr[($k +1)][1][0][1]);
260 $index_entries = intval($sarr[($k +1)][1][1][1]);
261 } elseif (($v[0] ==
'/') AND ($v[1] ==
'Prev') AND (isset($sarr[($k +1)]) AND ($sarr[($k +1)][0] ==
'numeric'))) {
263 $prevxref = intval($sarr[($k +1)][1]);
264 } elseif (($v[0] ==
'/') AND ($v[1] ==
'W') AND (isset($sarr[($k +1)]))) {
267 $wb[0] = intval($sarr[($k +1)][1][0][1]);
268 $wb[1] = intval($sarr[($k +1)][1][1][1]);
269 $wb[2] = intval($sarr[($k +1)][1][2][1]);
270 } elseif (($v[0] ==
'/') AND ($v[1] ==
'DecodeParms') AND (isset($sarr[($k +1)][1]))) {
271 $decpar = $sarr[($k +1)][1];
272 foreach ($decpar as $kdc => $vdc) {
273 if (($vdc[0] ==
'/') AND ($vdc[1] ==
'Columns') AND (isset($decpar[($kdc +1)]) AND ($decpar[($kdc +1)][0] ==
'numeric'))) {
274 $columns = intval($decpar[($kdc +1)][1]);
275 } elseif (($vdc[0] ==
'/') AND ($vdc[1] ==
'Predictor') AND (isset($decpar[($kdc +1)]) AND ($decpar[($kdc +1)][0] ==
'numeric'))) {
276 $predictor = intval($decpar[($kdc +1)][1]);
279 } elseif ($filltrailer) {
280 if (($v[0] ==
'/') AND ($v[1] ==
'Size') AND (isset($sarr[($k +1)]) AND ($sarr[($k +1)][0] ==
'numeric'))) {
281 $xref[
'trailer'][
'size'] = $sarr[($k +1)][1];
282 } elseif (($v[0] ==
'/') AND ($v[1] ==
'Root') AND (isset($sarr[($k +1)]) AND ($sarr[($k +1)][0] ==
'ojbref'))) {
283 $xref[
'trailer'][
'root'] = $sarr[($k +1)][1];
284 } elseif (($v[0] ==
'/') AND ($v[1] ==
'Info') AND (isset($sarr[($k +1)]) AND ($sarr[($k +1)][0] ==
'ojbref'))) {
285 $xref[
'trailer'][
'info'] = $sarr[($k +1)][1];
286 } elseif (($v[0] ==
'/') AND ($v[1] ==
'ID') AND (isset($sarr[($k +1)]))) {
287 $xref[
'trailer'][
'id'] = array();
288 $xref[
'trailer'][
'id'][0] = $sarr[($k +1)][1][0][1];
289 $xref[
'trailer'][
'id'][1] = $sarr[($k +1)][1][1][1];
294 if ($valid_crs AND isset($xrefcrs[1][3][0])) {
298 $sdata = unpack(
'C*', $xrefcrs[1][3][0]);
300 $sdata = array_chunk($sdata, $rowlen);
304 $prev_row = array_fill (0, $rowlen, 0);
306 foreach ($sdata as $k =>
$row) {
308 $ddata[$k] = array();
310 $predictor = (10 +
$row[0]);
315 $row_up = $prev_row[$j];
320 $row_left =
$row[($i - 1)];
321 $row_upleft = $prev_row[($j - 1)];
323 switch ($predictor) {
325 $ddata[$k][$j] =
$row[$i];
329 $ddata[$k][$j] = ((
$row[$i] + $row_left) & 0xff);
333 $ddata[$k][$j] = ((
$row[$i] + $row_up) & 0xff);
337 $ddata[$k][$j] = ((
$row[$i] + (($row_left + $row_up) / 2)) & 0xff);
342 $p = ($row_left + $row_up - $row_upleft);
344 $pa = abs($p - $row_left);
345 $pb = abs($p - $row_up);
346 $pc = abs($p - $row_upleft);
347 $pmin = min($pa, $pb, $pc);
351 $ddata[$k][$j] = ((
$row[$i] + $row_left) & 0xff);
355 $ddata[$k][$j] = ((
$row[$i] + $row_up) & 0xff);
359 $ddata[$k][$j] = ((
$row[$i] + $row_upleft) & 0xff);
366 $this->
Error(
'Unknown PNG predictor');
371 $prev_row = $ddata[$k];
376 foreach ($ddata as $k =>
$row) {
378 $sdata[$k] = array(0, 0, 0);
385 for ($c = 0; $c < 3; ++$c) {
387 for ($b = 0; $b < $wb[$c]; ++$b) {
388 $sdata[$k][$c] += (
$row[$i] << (($wb[$c] - 1 - $b) * 8));
395 if (isset($index_first)) {
396 $obj_num = $index_first;
400 foreach ($sdata as $k =>
$row) {
408 $index = $obj_num.
'_'.
$row[2];
410 if (!isset(
$xref[
'xref'][$index])) {
421 $xref[
'xref'][$index] = -1;
430 if (isset($prevxref)) {
448 $offset += strspn($this->pdfdata,
"\x00\x09\x0a\x0c\x0d\x20", $offset);
450 $char = $this->pdfdata{$offset};
455 $next = strcspn($this->pdfdata,
"\r\n", $offset);
466 if (preg_match(
'/^([^\x00\x09\x0a\x0c\x0d\x20\s\x28\x29\x3c\x3e\x5b\x5d\x7b\x7d\x2f\x25]+)/', substr($this->pdfdata, $offset, 256), $matches) == 1) {
467 $objval = $matches[1];
468 $offset += strlen($objval);
480 while ($open_bracket > 0) {
481 if (!isset($this->pdfdata{$strpos})) {
484 $ch = $this->pdfdata{$strpos};
502 $objval = substr($this->pdfdata, $offset, ($strpos - $offset - 1));
518 $offset = $element[2];
519 $objval[] = $element;
520 }
while ($element[0] !=
']');
528 if (isset($this->pdfdata{($offset + 1)}) AND ($this->pdfdata{($offset + 1)} == $char)) {
530 $objtype = $char.$char;
538 $offset = $element[2];
539 $objval[] = $element;
540 }
while ($element[0] !=
'>>');
548 if (($char ==
'<') AND (preg_match(
'/^([0-9A-Fa-f]+)[>]/iU', substr($this->pdfdata, $offset), $matches) == 1)) {
549 $objval = $matches[1];
550 $offset += strlen($matches[0]);
556 if (substr($this->pdfdata, $offset, 6) ==
'endobj') {
560 } elseif (substr($this->pdfdata, $offset, 4) ==
'null') {
565 } elseif (substr($this->pdfdata, $offset, 4) ==
'true') {
567 $objtype =
'boolean';
570 } elseif (substr($this->pdfdata, $offset, 5) ==
'false') {
572 $objtype =
'boolean';
575 } elseif (substr($this->pdfdata, $offset, 6) ==
'stream') {
579 if (preg_match(
'/^([\r\n]+)/isU', substr($this->pdfdata, $offset), $matches) == 1) {
580 $offset += strlen($matches[0]);
582 if (preg_match(
'/([\r\n]*endstream)/isU', substr($this->pdfdata, $offset), $matches, PREG_OFFSET_CAPTURE) == 1) {
583 $objval = substr($this->pdfdata, $offset, $matches[0][1]);
584 $offset += $matches[0][1];
586 } elseif (substr($this->pdfdata, $offset, 9) ==
'endstream') {
588 $objtype =
'endstream';
590 } elseif (preg_match(
'/^([0-9]+)[\s]+([0-9]+)[\s]+R/iU', substr($this->pdfdata, $offset, 33), $matches) == 1) {
593 $offset += strlen($matches[0]);
594 $objval = intval($matches[1]).
'_'.intval($matches[2]);
595 } elseif (preg_match(
'/^([0-9]+)[\s]+([0-9]+)[\s]+obj/iU', substr($this->pdfdata, $offset, 33), $matches) == 1) {
598 $objval = intval($matches[1]).
'_'.intval($matches[2]);
599 $offset += strlen ($matches[0]);
600 } elseif (($numlen = strspn($this->pdfdata,
'+-.0123456789', $offset)) > 0) {
602 $objtype =
'numeric';
603 $objval = substr($this->pdfdata, $offset, $numlen);
609 return array($objtype, $objval, $offset);
622 $obj = explode(
'_', $obj_ref);
623 if (($obj ===
false) OR (count($obj) != 2)) {
624 $this->
Error(
'Invalid object reference: '.$obj);
627 $objref = $obj[0].
' '.$obj[1].
' obj';
628 if (strpos($this->pdfdata, $objref, $offset) != $offset) {
630 return array(
'null',
'null', $offset);
633 $offset += strlen($objref);
640 $offset = $element[2];
642 if ($decoding AND ($element[0] ==
'stream') AND (isset($objdata[($i - 1)][0])) AND ($objdata[($i - 1)][0] ==
'<<')) {
643 $element[3] = $this->
decodeStream($objdata[($i - 1)][1], substr($element[1], 1));
645 $objdata[$i] = $element;
647 }
while ($element[0] !=
'endobj');
662 if ($obj[0] ==
'objref') {
664 if (isset($this->objects[$obj[1]])) {
666 return $this->objects[$obj[1]];
667 } elseif (isset($this->xref[$obj[1]])) {
669 $this->objects[$obj[1]] = $this->
getIndirectObject($obj[1], $this->xref[$obj[1]],
false);
670 return $this->objects[$obj[1]];
686 $slength = strlen($stream);
688 return array(
'', array());
691 foreach ($sdic as $k => $v) {
693 if (($v[1] ==
'Length') AND (isset($sdic[($k + 1)])) AND ($sdic[($k + 1)][0] ==
'numeric')) {
695 $declength = intval($sdic[($k + 1)][1]);
696 if ($declength < $slength) {
697 $stream = substr($stream, 0, $declength);
698 $slength = $declength;
700 } elseif (($v[1] ==
'Filter') AND (isset($sdic[($k + 1)]))) {
703 if ($objval[0] ==
'/') {
705 $filters[] = $objval[1];
706 } elseif ($objval[0] ==
'[') {
708 foreach ($objval[1] as $flt) {
709 if ($flt[0] ==
'/') {
710 $filters[] = $flt[1];
718 $remaining_filters = array();
719 foreach ($filters as $filter) {
720 if (in_array($filter, $this->FilterDecoders->getAvailableFilters())) {
721 $stream = $this->FilterDecoders->decodeFilter($filter, $stream);
724 $remaining_filters[] = $filter;
727 return array($stream, $remaining_filters);
738 die(
'<strong>TCPDF_PARSER ERROR: </strong>'.$msg);