2 //============================================================+
3 // File name : tcpdf_filters.php
6 // Last Update : 2014-04-25
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
12 // This file is part of TCPDF software library.
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.
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.
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>.
28 // See LICENSE.TXT file for more information.
29 // -------------------------------------------------------------------
31 // Description : This is a PHP class for decoding common PDF filters (PDF 32000-2008 - 7.4 Filters).
33 //============================================================+
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
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.
49 * @author Nicola Asuni - info@tecnick.com
54 * Define a list of available filter decoders.
57 private static $available_filters = array('ASCIIHexDecode', 'ASCII85Decode', 'LZWDecode', 'FlateDecode', 'RunLengthDecode');
59 // -----------------------------------------------------------------------------
62 * Get a list of available decoding filters.
63 * @return array Array of available filter decoders.
64 * @since 1.0.000 (2011-05-23)
67 public static function getAvailableFilters() {
68 return self
::$available_filters;
72 * Decode data using the specified filter type.
73 * @param string $filter Filter name.
74 * @param string $data Data to decode.
75 * @return string Decoded data string.
76 * @since 1.0.000 (2011-05-23)
79 public static function decodeFilter($filter, $data) {
81 case 'ASCIIHexDecode': {
82 return self
::decodeFilterASCIIHexDecode($data);
85 case 'ASCII85Decode': {
86 return self
::decodeFilterASCII85Decode($data);
90 return self
::decodeFilterLZWDecode($data);
94 return self
::decodeFilterFlateDecode($data);
97 case 'RunLengthDecode': {
98 return self
::decodeFilterRunLengthDecode($data);
101 case 'CCITTFaxDecode': {
102 return self
::decodeFilterCCITTFaxDecode($data);
105 case 'JBIG2Decode': {
106 return self
::decodeFilterJBIG2Decode($data);
110 return self
::decodeFilterDCTDecode($data);
114 return self
::decodeFilterJPXDecode($data);
118 return self
::decodeFilterCrypt($data);
122 return self
::decodeFilterStandard($data);
128 // --- FILTERS (PDF 32000-2008 - 7.4 Filters) ------------------------------
132 * Default decoding filter (leaves data unchanged).
133 * @param string $data Data to decode.
134 * @return string Decoded data string.
135 * @since 1.0.000 (2011-05-23)
138 public static function decodeFilterStandard($data) {
144 * Decodes data encoded in an ASCII hexadecimal representation, reproducing the original binary data.
145 * @param string $data Data to decode.
146 * @return string Decoded data string.
147 * @since 1.0.000 (2011-05-23)
150 public static function decodeFilterASCIIHexDecode($data) {
151 // initialize string to return
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);
163 $data_length = strlen($data);
164 if (($data_length %
2) != 0) {
165 // odd number of hexadecimal digits
167 // EOD shall behave as if a 0 (zero) followed the last digit
168 $data = substr($data, 0, -1).'0'.substr($data, -1);
170 self
::Error('decodeFilterASCIIHexDecode: invalid code');
173 // check for invalid characters
174 if (preg_match('/[^a-fA-F\d]/', $data) > 0) {
175 self
::Error('decodeFilterASCIIHexDecode: invalid code');
177 // get one byte of binary data for each pair of ASCII hexadecimal digits
178 $decoded = pack('H*', $data);
184 * Decodes data encoded in an ASCII base-85 representation, reproducing the original binary data.
185 * @param string $data Data to decode.
186 * @return string Decoded data string.
187 * @since 1.0.000 (2011-05-23)
190 public static function decodeFilterASCII85Decode($data) {
191 // initialize string to return
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);
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);
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');
213 $zseq = chr(0).chr(0).chr(0).chr(0);
214 // position inside a group of 4 bytes (0-3)
217 $pow85 = array((85*85*85*85), (85*85*85), (85*85), 85, 1);
218 $last_pos = ($data_length - 1);
220 for ($i = 0; $i < $data_length; ++
$i) {
222 $char = ord($data[$i]);
223 if ($char == 122) { // 'z'
224 if ($group_pos == 0) {
227 self
::Error('decodeFilterASCII85Decode: invalid code');
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);
241 if ($group_pos > 1) {
242 $tuple +
= $pow85[($group_pos - 1)];
244 // last tuple (if any)
245 switch ($group_pos) {
247 $decoded .= chr($tuple >> 24).chr($tuple >> 16).chr($tuple >> 8);
251 $decoded .= chr($tuple >> 24).chr($tuple >> 16);
255 $decoded .= chr($tuple >> 24);
259 self
::Error('decodeFilterASCII85Decode: invalid code');
268 * Decompresses data encoded using the LZW (Lempel-Ziv-Welch) adaptive compression method, reproducing the original text or binary data.
269 * @param string $data Data to decode.
270 * @return string Decoded data string.
271 * @since 1.0.000 (2011-05-23)
274 public static function decodeFilterLZWDecode($data) {
275 // initialize string to return
278 $data_length = strlen($data);
279 // convert string to binary string
281 for ($i = 0; $i < $data_length; ++
$i) {
282 $bitstring .= sprintf('%08b', ord($data[$i]));
284 // get the number of bits
285 $data_length = strlen($bitstring);
286 // initialize code length in bits
288 // initialize dictionary index
290 // initialize the dictionary (with the first 256 entries).
291 $dictionary = array();
292 for ($i = 0; $i < 256; ++
$i) {
293 $dictionary[$i] = chr($i);
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
306 // reset dictionary index
309 // reset the dictionary (with the first 256 entries).
310 $dictionary = array();
311 for ($i = 0; $i < 256; ++
$i) {
312 $dictionary[$i] = chr($i);
314 } elseif ($prev_index == 256) {
316 $decoded .= $dictionary[$index];
317 $prev_index = $index;
319 // check if index exist in the dictionary
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;
327 // index do not exist on dictionary
328 $dic_val = $dictionary[$prev_index].$dictionary[$prev_index][0];
329 $decoded .= $dic_val;
332 $dictionary[$dix] = $dic_val;
334 // change bit length by case
337 } elseif ($dix == 1023) {
339 } elseif ($dix == 511) {
349 * Decompresses data encoded using the zlib/deflate compression method, reproducing the original text or binary data.
350 * @param string $data Data to decode.
351 * @return string Decoded data string.
352 * @since 1.0.000 (2011-05-23)
355 public static function decodeFilterFlateDecode($data) {
356 // initialize string to return
357 $decoded = @gzuncompress
($data);
358 if ($decoded === false) {
359 self
::Error('decodeFilterFlateDecode: invalid code');
366 * Decompresses data encoded using a byte-oriented run-length encoding algorithm.
367 * @param string $data Data to decode.
368 * @since 1.0.000 (2011-05-23)
371 public static function decodeFilterRunLengthDecode($data) {
372 // initialize string to return
375 $data_length = strlen($data);
377 while($i < $data_length) {
378 // get current byte value
379 $byte = ord($data[$i]);
381 // a length value of 128 denote EOD
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
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
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 string $data Data to decode.
404 * @return string Decoded data string.
405 * @since 1.0.000 (2011-05-23)
408 public static function decodeFilterCCITTFaxDecode($data) {
409 self
::Error('~decodeFilterCCITTFaxDecode: this method has not been yet implemented');
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 string $data Data to decode.
417 * @return string Decoded data string.
418 * @since 1.0.000 (2011-05-23)
421 public static function decodeFilterJBIG2Decode($data) {
422 self
::Error('~decodeFilterJBIG2Decode: this method has not been yet implemented');
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 string $data Data to decode.
430 * @return string Decoded data string.
431 * @since 1.0.000 (2011-05-23)
434 public static function decodeFilterDCTDecode($data) {
435 self
::Error('~decodeFilterDCTDecode: this method has not been yet implemented');
440 * JPXDecode (NOT IMPLEMETED - RETURN AN EXCEPTION)
441 * Decompresses data encoded using the wavelet-based JPEG2000 standard, reproducing the original image data.
442 * @param string $data Data to decode.
443 * @return string Decoded data string.
444 * @since 1.0.000 (2011-05-23)
447 public static function decodeFilterJPXDecode($data) {
448 self
::Error('~decodeFilterJPXDecode: this method has not been yet implemented');
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 string $data Data to decode.
456 * @return string Decoded data string.
457 * @since 1.0.000 (2011-05-23)
460 public static function decodeFilterCrypt($data) {
461 self
::Error('~decodeFilterCrypt: this method has not been yet implemented');
465 // --- END FILTERS SECTION -------------------------------------------------
468 * Throw an exception.
469 * @param string $msg The error message
470 * @since 1.0.000 (2011-05-23)
473 public static function Error($msg) {
474 throw new Exception('TCPDF_PARSER ERROR: '.$msg);
477 } // END OF TCPDF_FILTERS CLASS
479 //============================================================+
481 //============================================================+