include/tcpdf_filters.php Quellcode

tcpdf_filters.php
gehe zur Dokumentation dieser Datei
1 <?php
2 //============================================================+
3 // File name : tcpdf_filters.php
4 // Version : 1.0.001
5 // Begin : 2011-05-23
6 // Last Update : 2013-09-15
7 // Author : Nicola Asuni - Tecnick.com LTD - www.tecnick.com - info@tecnick.com
8 // License : GNU-LGPL v3 (http://www.gnu.org/copyleft/lesser.html)
9 // -------------------------------------------------------------------
10 // Copyright (C) 2011-2013 Nicola Asuni - Tecnick.com LTD
11 //
12 // This file is part of TCPDF software library.
13 //
14 // TCPDF is free software: you can redistribute it and/or modify it
15 // under the terms of the GNU Lesser General Public License as
16 // published by the Free Software Foundation, either version 3 of the
17 // License, or (at your option) any later version.
18 //
19 // TCPDF is distributed in the hope that it will be useful, but
20 // WITHOUT ANY WARRANTY; without even the implied warranty of
21 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
22 // See the GNU Lesser General Public License for more details.
23 //
24 // You should have received a copy of the License
25 // along with TCPDF. If not, see
26 // <http://www.tecnick.com/pagefiles/tcpdf/LICENSE.TXT>.
27 //
28 // See LICENSE.TXT file for more information.
29 // -------------------------------------------------------------------
30 //
31 // Description : This is a PHP class for decoding common PDF filters (PDF 32000-2008 - 7.4 Filters).
32 //
33 //============================================================+
34 
52 
57  private static $available_filters = array('ASCIIHexDecode', 'ASCII85Decode', 'LZWDecode', 'FlateDecode', 'RunLengthDecode');
58 
59 // -----------------------------------------------------------------------------
60 
67  public static function getAvailableFilters() {
68  return self::$available_filters;
69  }
70 
79  public static function decodeFilter($filter, $data) {
80  switch ($filter) {
81  case 'ASCIIHexDecode': {
82  return self::decodeFilterASCIIHexDecode($data);
83  break;
84  }
85  case 'ASCII85Decode': {
86  return self::decodeFilterASCII85Decode($data);
87  break;
88  }
89  case 'LZWDecode': {
90  return self::decodeFilterLZWDecode($data);
91  break;
92  }
93  case 'FlateDecode': {
94  return self::decodeFilterFlateDecode($data);
95  break;
96  }
97  case 'RunLengthDecode': {
98  return self::decodeFilterRunLengthDecode($data);
99  break;
100  }
101  case 'CCITTFaxDecode': {
102  return self::decodeFilterCCITTFaxDecode($data);
103  break;
104  }
105  case 'JBIG2Decode': {
106  return self::decodeFilterJBIG2Decode($data);
107  break;
108  }
109  case 'DCTDecode': {
110  return self::decodeFilterDCTDecode($data);
111  break;
112  }
113  case 'JPXDecode': {
114  return self::decodeFilterJPXDecode($data);
115  break;
116  }
117  case 'Crypt': {
118  return self::decodeFilterCrypt($data);
119  break;
120  }
121  default: {
122  return self::decodeFilterStandard($data);
123  break;
124  }
125  }
126  }
127 
128  // --- FILTERS (PDF 32000-2008 - 7.4 Filters) ------------------------------
129 
138  public static function decodeFilterStandard($data) {
139  return $data;
140  }
141 
150  public static function decodeFilterASCIIHexDecode($data) {
151  // intialize string to return
152  $decoded = '';
153  // all white-space characters shall be ignored
154  $data = preg_replace('/[\s]/', '', $data);
155  // check for EOD character: GREATER-THAN SIGN (3Eh)
156  $eod = strpos($data, '>');
157  if ($eod !== false) {
158  // remove EOD and extra data (if any)
159  $data = substr($data, 0, $eod);
160  $eod = true;
161  }
162  // get data length
163  $data_length = strlen($data);
164  if (($data_length % 2) != 0) {
165  // odd number of hexadecimal digits
166  if ($eod) {
167  // EOD shall behave as if a 0 (zero) followed the last digit
168  $data = substr($data, 0, -1).'0'.substr($data, -1);
169  } else {
170  self::Error('decodeFilterASCIIHexDecode: invalid code');
171  }
172  }
173  // check for invalid characters
174  if (preg_match('/[^a-fA-F\d]/', $data) > 0) {
175  self::Error('decodeFilterASCIIHexDecode: invalid code');
176  }
177  // get one byte of binary data for each pair of ASCII hexadecimal digits
178  $decoded = pack('H*', $data);
179  return $decoded;
180  }
181 
190  public static function decodeFilterASCII85Decode($data) {
191  // intialize string to return
192  $decoded = '';
193  // all white-space characters shall be ignored
194  $data = preg_replace('/[\s]/', '', $data);
195  // remove start sequence 2-character sequence <~ (3Ch)(7Eh)
196  if (strpos($data, '<~') !== false) {
197  // remove EOD and extra data (if any)
198  $data = substr($data, 2);
199  }
200  // check for EOD: 2-character sequence ~> (7Eh)(3Eh)
201  $eod = strpos($data, '~>');
202  if ($eod !== false) {
203  // remove EOD and extra data (if any)
204  $data = substr($data, 0, $eod);
205  }
206  // data length
207  $data_length = strlen($data);
208  // check for invalid characters
209  if (preg_match('/[^\x21-\x75,\x74]/', $data) > 0) {
210  self::Error('decodeFilterASCII85Decode: invalid code');
211  }
212  // z sequence
213  $zseq = chr(0).chr(0).chr(0).chr(0);
214  // position inside a group of 4 bytes (0-3)
215  $group_pos = 0;
216  $tuple = 0;
217  $pow85 = array((85*85*85*85), (85*85*85), (85*85), 85, 1);
218  $last_pos = ($data_length - 1);
219  // for each byte
220  for ($i = 0; $i < $data_length; ++$i) {
221  // get char value
222  $char = ord($data[$i]);
223  if ($char == 122) { // 'z'
224  if ($group_pos == 0) {
225  $decoded .= $zseq;
226  } else {
227  self::Error('decodeFilterASCII85Decode: invalid code');
228  }
229  } else {
230  // the value represented by a group of 5 characters should never be greater than 2^32 - 1
231  $tuple += (($char - 33) * $pow85[$group_pos]);
232  if ($group_pos == 4) {
233  $decoded .= chr($tuple >> 24).chr($tuple >> 16).chr($tuple >> 8).chr($tuple);
234  $tuple = 0;
235  $group_pos = 0;
236  } else {
237  ++$group_pos;
238  }
239  }
240  }
241  if ($group_pos > 1) {
242  $tuple += $pow85[($group_pos - 1)];
243  }
244  // last tuple (if any)
245  switch ($group_pos) {
246  case 4: {
247  $decoded .= chr($tuple >> 24).chr($tuple >> 16).chr($tuple >> 8);
248  break;
249  }
250  case 3: {
251  $decoded .= chr($tuple >> 24).chr($tuple >> 16);
252  break;
253  }
254  case 2: {
255  $decoded .= chr($tuple >> 24);
256  break;
257  }
258  case 1: {
259  self::Error('decodeFilterASCII85Decode: invalid code');
260  break;
261  }
262  }
263  return $decoded;
264  }
265 
274  public static function decodeFilterLZWDecode($data) {
275  // intialize string to return
276  $decoded = '';
277  // data length
278  $data_length = strlen($data);
279  // convert string to binary string
280  $bitstring = '';
281  for ($i = 0; $i < $data_length; ++$i) {
282  $bitstring .= sprintf('%08b', ord($data{$i}));
283  }
284  // get the number of bits
285  $data_length = strlen($bitstring);
286  // initialize code length in bits
287  $bitlen = 9;
288  // initialize dictionary index
289  $dix = 258;
290  // initialize the dictionary (with the first 256 entries).
291  $dictionary = array();
292  for ($i = 0; $i < 256; ++$i) {
293  $dictionary[$i] = chr($i);
294  }
295  // previous val
296  $prev_index = 0;
297  // while we encounter EOD marker (257), read code_length bits
298  while (($data_length > 0) AND (($index = bindec(substr($bitstring, 0, $bitlen))) != 257)) {
299  // remove read bits from string
300  $bitstring = substr($bitstring, $bitlen);
301  // update number of bits
302  $data_length -= $bitlen;
303  if ($index == 256) { // clear-table marker
304  // reset code length in bits
305  $bitlen = 9;
306  // reset dictionary index
307  $dix = 258;
308  $prev_index = 256;
309  // reset the dictionary (with the first 256 entries).
310  $dictionary = array();
311  for ($i = 0; $i < 256; ++$i) {
312  $dictionary[$i] = chr($i);
313  }
314  } elseif ($prev_index == 256) {
315  // first entry
316  $decoded .= $dictionary[$index];
317  $prev_index = $index;
318  } else {
319  // check if index exist in the dictionary
320  if ($index < $dix) {
321  // index exist on dictionary
322  $decoded .= $dictionary[$index];
323  $dic_val = $dictionary[$prev_index].$dictionary[$index]{0};
324  // store current index
325  $prev_index = $index;
326  } else {
327  // index do not exist on dictionary
328  $dic_val = $dictionary[$prev_index].$dictionary[$prev_index]{0};
329  $decoded .= $dic_val;
330  }
331  // update dictionary
332  $dictionary[$dix] = $dic_val;
333  ++$dix;
334  // change bit length by case
335  if ($dix == 2047) {
336  $bitlen = 12;
337  } elseif ($dix == 1023) {
338  $bitlen = 11;
339  } elseif ($dix == 511) {
340  $bitlen = 10;
341  }
342  }
343  }
344  return $decoded;
345  }
346 
355  public static function decodeFilterFlateDecode($data) {
356  // intialize string to return
357  $decoded = @gzuncompress($data);
358  if ($decoded === false) {
359  self::Error('decodeFilterFlateDecode: invalid code');
360  }
361  return $decoded;
362  }
363 
371  public static function decodeFilterRunLengthDecode($data) {
372  // intialize string to return
373  $decoded = '';
374  // data length
375  $data_length = strlen($data);
376  $i = 0;
377  while($i < $data_length) {
378  // get current byte value
379  $byte = ord($data{$i});
380  if ($byte == 128) {
381  // a length value of 128 denote EOD
382  break;
383  } elseif ($byte < 128) {
384  // if the length byte is in the range 0 to 127
385  // the following length + 1 (1 to 128) bytes shall be copied literally during decompression
386  $decoded .= substr($data, ($i + 1), ($byte + 1));
387  // move to next block
388  $i += ($byte + 2);
389  } else {
390  // if length is in the range 129 to 255,
391  // the following single byte shall be copied 257 - length (2 to 128) times during decompression
392  $decoded .= str_repeat($data{($i + 1)}, (257 - $byte));
393  // move to next block
394  $i += 2;
395  }
396  }
397  return $decoded;
398  }
399 
408  public static function decodeFilterCCITTFaxDecode($data) {
409  self::Error('~decodeFilterCCITTFaxDecode: this method has not been yet implemented');
410  //return $data;
411  }
412 
421  public static function decodeFilterJBIG2Decode($data) {
422  self::Error('~decodeFilterJBIG2Decode: this method has not been yet implemented');
423  //return $data;
424  }
425 
434  public static function decodeFilterDCTDecode($data) {
435  self::Error('~decodeFilterDCTDecode: this method has not been yet implemented');
436  //return $data;
437  }
438 
447  public static function decodeFilterJPXDecode($data) {
448  self::Error('~decodeFilterJPXDecode: this method has not been yet implemented');
449  //return $data;
450  }
451 
460  public static function decodeFilterCrypt($data) {
461  self::Error('~decodeFilterCrypt: this method has not been yet implemented');
462  //return $data;
463  }
464 
465  // --- END FILTERS SECTION -------------------------------------------------
466 
473  public static function Error($msg) {
474  throw new Exception('TCPDF_PARSER ERROR: '.$msg);
475  }
476 
477 } // END OF TCPDF_FILTERS CLASS
478 
479 //============================================================+
480 // END OF FILE
481 //============================================================+




Korrekturen, Hinweise und Ergänzungen

Bitte scheuen Sie sich nicht und melden Sie, was auf dieser Seite sachlich falsch oder irreführend ist, was ergänzt werden sollte, was fehlt usw. Dazu bitte oben aus dem Menü Seite den Eintrag Support Forum wählen. Es ist eine kostenlose Anmeldung erforderlich, um Anmerkungen zu posten. Unpassende Postings, Spam usw. werden kommentarlos entfernt.