root / drupal7 / sites / all / libraries / tcpdf-6.2.9 / include / tcpdf_filters.php @ 7295e063
1 | 85ad3d82 | Assos Assos | <?php
|
---|---|---|---|
2 | //============================================================+
|
||
3 | // File name : tcpdf_filters.php
|
||
4 | // Version : 1.0.001
|
||
5 | // Begin : 2011-05-23
|
||
6 | c3ebc5b9 | Assos Assos | // Last Update : 2014-04-25
|
7 | 85ad3d82 | Assos Assos | // 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 | |||
35 | /**
|
||
36 | * @file
|
||
37 | * This is a PHP class for decoding common PDF filters (PDF 32000-2008 - 7.4 Filters).<br>
|
||
38 | * @package com.tecnick.tcpdf
|
||
39 | * @author Nicola Asuni
|
||
40 | * @version 1.0.001
|
||
41 | */
|
||
42 | |||
43 | /**
|
||
44 | * @class TCPDF_FILTERS
|
||
45 | * This is a PHP class for decoding common PDF filters (PDF 32000-2008 - 7.4 Filters).<br>
|
||
46 | * @package com.tecnick.tcpdf
|
||
47 | * @brief This is a PHP class for decoding common PDF filters.
|
||
48 | * @version 1.0.001
|
||
49 | * @author Nicola Asuni - info@tecnick.com
|
||
50 | */
|
||
51 | class TCPDF_FILTERS { |
||
52 | |||
53 | /**
|
||
54 | * Define a list of available filter decoders.
|
||
55 | * @private static
|
||
56 | */
|
||
57 | private static $available_filters = array('ASCIIHexDecode', 'ASCII85Decode', 'LZWDecode', 'FlateDecode', 'RunLengthDecode'); |
||
58 | |||
59 | // -----------------------------------------------------------------------------
|
||
60 | |||
61 | /**
|
||
62 | * Get a list of available decoding filters.
|
||
63 | * @return (array) Array of available filter decoders.
|
||
64 | * @since 1.0.000 (2011-05-23)
|
||
65 | * @public static
|
||
66 | */
|
||
67 | public static function getAvailableFilters() { |
||
68 | return self::$available_filters; |
||
69 | } |
||
70 | |||
71 | /**
|
||
72 | * Decode data using the specified filter type.
|
||
73 | * @param $filter (string) Filter name.
|
||
74 | * @param $data (string) Data to decode.
|
||
75 | * @return Decoded data string.
|
||
76 | * @since 1.0.000 (2011-05-23)
|
||
77 | * @public static
|
||
78 | */
|
||
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 | |||
130 | /**
|
||
131 | * Standard
|
||
132 | * Default decoding filter (leaves data unchanged).
|
||
133 | * @param $data (string) Data to decode.
|
||
134 | * @return Decoded data string.
|
||
135 | * @since 1.0.000 (2011-05-23)
|
||
136 | * @public static
|
||
137 | */
|
||
138 | public static function decodeFilterStandard($data) { |
||
139 | return $data; |
||
140 | } |
||
141 | |||
142 | /**
|
||
143 | * ASCIIHexDecode
|
||
144 | * Decodes data encoded in an ASCII hexadecimal representation, reproducing the original binary data.
|
||
145 | * @param $data (string) Data to decode.
|
||
146 | * @return Decoded data string.
|
||
147 | * @since 1.0.000 (2011-05-23)
|
||
148 | * @public static
|
||
149 | */
|
||
150 | public static function decodeFilterASCIIHexDecode($data) { |
||
151 | c3ebc5b9 | Assos Assos | // initialize string to return
|
152 | 85ad3d82 | Assos Assos | $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 | |||
182 | /**
|
||
183 | * ASCII85Decode
|
||
184 | * Decodes data encoded in an ASCII base-85 representation, reproducing the original binary data.
|
||
185 | * @param $data (string) Data to decode.
|
||
186 | * @return Decoded data string.
|
||
187 | * @since 1.0.000 (2011-05-23)
|
||
188 | * @public static
|
||
189 | */
|
||
190 | public static function decodeFilterASCII85Decode($data) { |
||
191 | c3ebc5b9 | Assos Assos | // initialize string to return
|
192 | 85ad3d82 | Assos Assos | $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 | |||
266 | /**
|
||
267 | * LZWDecode
|
||
268 | * Decompresses data encoded using the LZW (Lempel-Ziv-Welch) adaptive compression method, reproducing the original text or binary data.
|
||
269 | * @param $data (string) Data to decode.
|
||
270 | * @return Decoded data string.
|
||
271 | * @since 1.0.000 (2011-05-23)
|
||
272 | * @public static
|
||
273 | */
|
||
274 | public static function decodeFilterLZWDecode($data) { |
||
275 | c3ebc5b9 | Assos Assos | // initialize string to return
|
276 | 85ad3d82 | Assos Assos | $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 | c3ebc5b9 | Assos Assos | $dic_val = $dictionary[$prev_index].$dictionary[$index][0]; |
324 | 85ad3d82 | Assos Assos | // store current index
|
325 | $prev_index = $index; |
||
326 | } else {
|
||
327 | // index do not exist on dictionary
|
||
328 | c3ebc5b9 | Assos Assos | $dic_val = $dictionary[$prev_index].$dictionary[$prev_index][0]; |
329 | 85ad3d82 | Assos Assos | $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 | |||
347 | /**
|
||
348 | * FlateDecode
|
||
349 | * Decompresses data encoded using the zlib/deflate compression method, reproducing the original text or binary data.
|
||
350 | * @param $data (string) Data to decode.
|
||
351 | * @return Decoded data string.
|
||
352 | * @since 1.0.000 (2011-05-23)
|
||
353 | * @public static
|
||
354 | */
|
||
355 | public static function decodeFilterFlateDecode($data) { |
||
356 | c3ebc5b9 | Assos Assos | // initialize string to return
|
357 | 85ad3d82 | Assos Assos | $decoded = @gzuncompress($data); |
358 | if ($decoded === false) { |
||
359 | self::Error('decodeFilterFlateDecode: invalid code'); |
||
360 | } |
||
361 | return $decoded; |
||
362 | } |
||
363 | |||
364 | /**
|
||
365 | * RunLengthDecode
|
||
366 | * Decompresses data encoded using a byte-oriented run-length encoding algorithm.
|
||
367 | * @param $data (string) Data to decode.
|
||
368 | * @since 1.0.000 (2011-05-23)
|
||
369 | * @public static
|
||
370 | */
|
||
371 | public static function decodeFilterRunLengthDecode($data) { |
||
372 | c3ebc5b9 | Assos Assos | // initialize string to return
|
373 | 85ad3d82 | Assos Assos | $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 | |||
400 | /**
|
||
401 | * CCITTFaxDecode (NOT IMPLEMETED - RETURN AN EXCEPTION)
|
||
402 | * Decompresses data encoded using the CCITT facsimile standard, reproducing the original data (typically monochrome image data at 1 bit per pixel).
|
||
403 | * @param $data (string) Data to decode.
|
||
404 | * @return Decoded data string.
|
||
405 | * @since 1.0.000 (2011-05-23)
|
||
406 | * @public static
|
||
407 | */
|
||
408 | public static function decodeFilterCCITTFaxDecode($data) { |
||
409 | self::Error('~decodeFilterCCITTFaxDecode: this method has not been yet implemented'); |
||
410 | //return $data;
|
||
411 | } |
||
412 | |||
413 | /**
|
||
414 | * JBIG2Decode (NOT IMPLEMETED - RETURN AN EXCEPTION)
|
||
415 | * Decompresses data encoded using the JBIG2 standard, reproducing the original monochrome (1 bit per pixel) image data (or an approximation of that data).
|
||
416 | * @param $data (string) Data to decode.
|
||
417 | * @return Decoded data string.
|
||
418 | * @since 1.0.000 (2011-05-23)
|
||
419 | * @public static
|
||
420 | */
|
||
421 | public static function decodeFilterJBIG2Decode($data) { |
||
422 | self::Error('~decodeFilterJBIG2Decode: this method has not been yet implemented'); |
||
423 | //return $data;
|
||
424 | } |
||
425 | |||
426 | /**
|
||
427 | * DCTDecode (NOT IMPLEMETED - RETURN AN EXCEPTION)
|
||
428 | * Decompresses data encoded using a DCT (discrete cosine transform) technique based on the JPEG standard, reproducing image sample data that approximates the original data.
|
||
429 | * @param $data (string) Data to decode.
|
||
430 | * @return Decoded data string.
|
||
431 | * @since 1.0.000 (2011-05-23)
|
||
432 | * @public static
|
||
433 | */
|
||
434 | public static function decodeFilterDCTDecode($data) { |
||
435 | self::Error('~decodeFilterDCTDecode: this method has not been yet implemented'); |
||
436 | //return $data;
|
||
437 | } |
||
438 | |||
439 | /**
|
||
440 | * JPXDecode (NOT IMPLEMETED - RETURN AN EXCEPTION)
|
||
441 | * Decompresses data encoded using the wavelet-based JPEG2000 standard, reproducing the original image data.
|
||
442 | * @param $data (string) Data to decode.
|
||
443 | * @return Decoded data string.
|
||
444 | * @since 1.0.000 (2011-05-23)
|
||
445 | * @public static
|
||
446 | */
|
||
447 | public static function decodeFilterJPXDecode($data) { |
||
448 | self::Error('~decodeFilterJPXDecode: this method has not been yet implemented'); |
||
449 | //return $data;
|
||
450 | } |
||
451 | |||
452 | /**
|
||
453 | * Crypt (NOT IMPLEMETED - RETURN AN EXCEPTION)
|
||
454 | * Decrypts data encrypted by a security handler, reproducing the data as it was before encryption.
|
||
455 | * @param $data (string) Data to decode.
|
||
456 | * @return Decoded data string.
|
||
457 | * @since 1.0.000 (2011-05-23)
|
||
458 | * @public static
|
||
459 | */
|
||
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 | |||
467 | /**
|
||
468 | * Throw an exception.
|
||
469 | * @param $msg (string) The error message
|
||
470 | * @since 1.0.000 (2011-05-23)
|
||
471 | * @public static
|
||
472 | */
|
||
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 | //============================================================+ |