123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481 |
- <?php
- //============================================================+
- // File name : tcpdf_filters.php
- // Version : 1.0.001
- // Begin : 2011-05-23
- // Last Update : 2014-04-25
- // Author : Nicola Asuni - Tecnick.com LTD - www.tecnick.com - info@tecnick.com
- // License : GNU-LGPL v3 (http://www.gnu.org/copyleft/lesser.html)
- // -------------------------------------------------------------------
- // Copyright (C) 2011-2013 Nicola Asuni - Tecnick.com LTD
- //
- // This file is part of TCPDF software library.
- //
- // TCPDF is free software: you can redistribute it and/or modify it
- // under the terms of the GNU Lesser General Public License as
- // published by the Free Software Foundation, either version 3 of the
- // License, or (at your option) any later version.
- //
- // TCPDF is distributed in the hope that it will be useful, but
- // WITHOUT ANY WARRANTY; without even the implied warranty of
- // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- // See the GNU Lesser General Public License for more details.
- //
- // You should have received a copy of the License
- // along with TCPDF. If not, see
- // <http://www.tecnick.com/pagefiles/tcpdf/LICENSE.TXT>.
- //
- // See LICENSE.TXT file for more information.
- // -------------------------------------------------------------------
- //
- // Description : This is a PHP class for decoding common PDF filters (PDF 32000-2008 - 7.4 Filters).
- //
- //============================================================+
- /**
- * @file
- * This is a PHP class for decoding common PDF filters (PDF 32000-2008 - 7.4 Filters).<br>
- * @package com.tecnick.tcpdf
- * @author Nicola Asuni
- * @version 1.0.001
- */
- /**
- * @class TCPDF_FILTERS
- * This is a PHP class for decoding common PDF filters (PDF 32000-2008 - 7.4 Filters).<br>
- * @package com.tecnick.tcpdf
- * @brief This is a PHP class for decoding common PDF filters.
- * @version 1.0.001
- * @author Nicola Asuni - info@tecnick.com
- */
- class TCPDF_FILTERS {
- /**
- * Define a list of available filter decoders.
- * @private static
- */
- private static $available_filters = array('ASCIIHexDecode', 'ASCII85Decode', 'LZWDecode', 'FlateDecode', 'RunLengthDecode');
- // -----------------------------------------------------------------------------
- /**
- * Get a list of available decoding filters.
- * @return array Array of available filter decoders.
- * @since 1.0.000 (2011-05-23)
- * @public static
- */
- public static function getAvailableFilters() {
- return self::$available_filters;
- }
- /**
- * Decode data using the specified filter type.
- * @param string $filter Filter name.
- * @param string $data Data to decode.
- * @return string Decoded data string.
- * @since 1.0.000 (2011-05-23)
- * @public static
- */
- public static function decodeFilter($filter, $data) {
- switch ($filter) {
- case 'ASCIIHexDecode': {
- return self::decodeFilterASCIIHexDecode($data);
- break;
- }
- case 'ASCII85Decode': {
- return self::decodeFilterASCII85Decode($data);
- break;
- }
- case 'LZWDecode': {
- return self::decodeFilterLZWDecode($data);
- break;
- }
- case 'FlateDecode': {
- return self::decodeFilterFlateDecode($data);
- break;
- }
- case 'RunLengthDecode': {
- return self::decodeFilterRunLengthDecode($data);
- break;
- }
- case 'CCITTFaxDecode': {
- return self::decodeFilterCCITTFaxDecode($data);
- break;
- }
- case 'JBIG2Decode': {
- return self::decodeFilterJBIG2Decode($data);
- break;
- }
- case 'DCTDecode': {
- return self::decodeFilterDCTDecode($data);
- break;
- }
- case 'JPXDecode': {
- return self::decodeFilterJPXDecode($data);
- break;
- }
- case 'Crypt': {
- return self::decodeFilterCrypt($data);
- break;
- }
- default: {
- return self::decodeFilterStandard($data);
- break;
- }
- }
- }
- // --- FILTERS (PDF 32000-2008 - 7.4 Filters) ------------------------------
- /**
- * Standard
- * Default decoding filter (leaves data unchanged).
- * @param string $data Data to decode.
- * @return string Decoded data string.
- * @since 1.0.000 (2011-05-23)
- * @public static
- */
- public static function decodeFilterStandard($data) {
- return $data;
- }
- /**
- * ASCIIHexDecode
- * Decodes data encoded in an ASCII hexadecimal representation, reproducing the original binary data.
- * @param string $data Data to decode.
- * @return string Decoded data string.
- * @since 1.0.000 (2011-05-23)
- * @public static
- */
- public static function decodeFilterASCIIHexDecode($data) {
- // initialize string to return
- $decoded = '';
- // all white-space characters shall be ignored
- $data = preg_replace('/[\s]/', '', $data);
- // check for EOD character: GREATER-THAN SIGN (3Eh)
- $eod = strpos($data, '>');
- if ($eod !== false) {
- // remove EOD and extra data (if any)
- $data = substr($data, 0, $eod);
- $eod = true;
- }
- // get data length
- $data_length = strlen($data);
- if (($data_length % 2) != 0) {
- // odd number of hexadecimal digits
- if ($eod) {
- // EOD shall behave as if a 0 (zero) followed the last digit
- $data = substr($data, 0, -1).'0'.substr($data, -1);
- } else {
- self::Error('decodeFilterASCIIHexDecode: invalid code');
- }
- }
- // check for invalid characters
- if (preg_match('/[^a-fA-F\d]/', $data) > 0) {
- self::Error('decodeFilterASCIIHexDecode: invalid code');
- }
- // get one byte of binary data for each pair of ASCII hexadecimal digits
- $decoded = pack('H*', $data);
- return $decoded;
- }
- /**
- * ASCII85Decode
- * Decodes data encoded in an ASCII base-85 representation, reproducing the original binary data.
- * @param string $data Data to decode.
- * @return string Decoded data string.
- * @since 1.0.000 (2011-05-23)
- * @public static
- */
- public static function decodeFilterASCII85Decode($data) {
- // initialize string to return
- $decoded = '';
- // all white-space characters shall be ignored
- $data = preg_replace('/[\s]/', '', $data);
- // remove start sequence 2-character sequence <~ (3Ch)(7Eh)
- if (strpos($data, '<~') !== false) {
- // remove EOD and extra data (if any)
- $data = substr($data, 2);
- }
- // check for EOD: 2-character sequence ~> (7Eh)(3Eh)
- $eod = strpos($data, '~>');
- if ($eod !== false) {
- // remove EOD and extra data (if any)
- $data = substr($data, 0, $eod);
- }
- // data length
- $data_length = strlen($data);
- // check for invalid characters
- if (preg_match('/[^\x21-\x75,\x74]/', $data) > 0) {
- self::Error('decodeFilterASCII85Decode: invalid code');
- }
- // z sequence
- $zseq = chr(0).chr(0).chr(0).chr(0);
- // position inside a group of 4 bytes (0-3)
- $group_pos = 0;
- $tuple = 0;
- $pow85 = array((85*85*85*85), (85*85*85), (85*85), 85, 1);
- $last_pos = ($data_length - 1);
- // for each byte
- for ($i = 0; $i < $data_length; ++$i) {
- // get char value
- $char = ord($data[$i]);
- if ($char == 122) { // 'z'
- if ($group_pos == 0) {
- $decoded .= $zseq;
- } else {
- self::Error('decodeFilterASCII85Decode: invalid code');
- }
- } else {
- // the value represented by a group of 5 characters should never be greater than 2^32 - 1
- $tuple += (($char - 33) * $pow85[$group_pos]);
- if ($group_pos == 4) {
- $decoded .= chr($tuple >> 24).chr($tuple >> 16).chr($tuple >> 8).chr($tuple);
- $tuple = 0;
- $group_pos = 0;
- } else {
- ++$group_pos;
- }
- }
- }
- if ($group_pos > 1) {
- $tuple += $pow85[($group_pos - 1)];
- }
- // last tuple (if any)
- switch ($group_pos) {
- case 4: {
- $decoded .= chr($tuple >> 24).chr($tuple >> 16).chr($tuple >> 8);
- break;
- }
- case 3: {
- $decoded .= chr($tuple >> 24).chr($tuple >> 16);
- break;
- }
- case 2: {
- $decoded .= chr($tuple >> 24);
- break;
- }
- case 1: {
- self::Error('decodeFilterASCII85Decode: invalid code');
- break;
- }
- }
- return $decoded;
- }
- /**
- * LZWDecode
- * Decompresses data encoded using the LZW (Lempel-Ziv-Welch) adaptive compression method, reproducing the original text or binary data.
- * @param string $data Data to decode.
- * @return string Decoded data string.
- * @since 1.0.000 (2011-05-23)
- * @public static
- */
- public static function decodeFilterLZWDecode($data) {
- // initialize string to return
- $decoded = '';
- // data length
- $data_length = strlen($data);
- // convert string to binary string
- $bitstring = '';
- for ($i = 0; $i < $data_length; ++$i) {
- $bitstring .= sprintf('%08b', ord($data[$i]));
- }
- // get the number of bits
- $data_length = strlen($bitstring);
- // initialize code length in bits
- $bitlen = 9;
- // initialize dictionary index
- $dix = 258;
- // initialize the dictionary (with the first 256 entries).
- $dictionary = array();
- for ($i = 0; $i < 256; ++$i) {
- $dictionary[$i] = chr($i);
- }
- // previous val
- $prev_index = 0;
- // while we encounter EOD marker (257), read code_length bits
- while (($data_length > 0) AND (($index = bindec(substr($bitstring, 0, $bitlen))) != 257)) {
- // remove read bits from string
- $bitstring = substr($bitstring, $bitlen);
- // update number of bits
- $data_length -= $bitlen;
- if ($index == 256) { // clear-table marker
- // reset code length in bits
- $bitlen = 9;
- // reset dictionary index
- $dix = 258;
- $prev_index = 256;
- // reset the dictionary (with the first 256 entries).
- $dictionary = array();
- for ($i = 0; $i < 256; ++$i) {
- $dictionary[$i] = chr($i);
- }
- } elseif ($prev_index == 256) {
- // first entry
- $decoded .= $dictionary[$index];
- $prev_index = $index;
- } else {
- // check if index exist in the dictionary
- if ($index < $dix) {
- // index exist on dictionary
- $decoded .= $dictionary[$index];
- $dic_val = $dictionary[$prev_index].$dictionary[$index][0];
- // store current index
- $prev_index = $index;
- } else {
- // index do not exist on dictionary
- $dic_val = $dictionary[$prev_index].$dictionary[$prev_index][0];
- $decoded .= $dic_val;
- }
- // update dictionary
- $dictionary[$dix] = $dic_val;
- ++$dix;
- // change bit length by case
- if ($dix == 2047) {
- $bitlen = 12;
- } elseif ($dix == 1023) {
- $bitlen = 11;
- } elseif ($dix == 511) {
- $bitlen = 10;
- }
- }
- }
- return $decoded;
- }
- /**
- * FlateDecode
- * Decompresses data encoded using the zlib/deflate compression method, reproducing the original text or binary data.
- * @param string $data Data to decode.
- * @return string Decoded data string.
- * @since 1.0.000 (2011-05-23)
- * @public static
- */
- public static function decodeFilterFlateDecode($data) {
- // initialize string to return
- $decoded = @gzuncompress($data);
- if ($decoded === false) {
- self::Error('decodeFilterFlateDecode: invalid code');
- }
- return $decoded;
- }
- /**
- * RunLengthDecode
- * Decompresses data encoded using a byte-oriented run-length encoding algorithm.
- * @param string $data Data to decode.
- * @since 1.0.000 (2011-05-23)
- * @public static
- */
- public static function decodeFilterRunLengthDecode($data) {
- // initialize string to return
- $decoded = '';
- // data length
- $data_length = strlen($data);
- $i = 0;
- while($i < $data_length) {
- // get current byte value
- $byte = ord($data[$i]);
- if ($byte == 128) {
- // a length value of 128 denote EOD
- break;
- } elseif ($byte < 128) {
- // if the length byte is in the range 0 to 127
- // the following length + 1 (1 to 128) bytes shall be copied literally during decompression
- $decoded .= substr($data, ($i + 1), ($byte + 1));
- // move to next block
- $i += ($byte + 2);
- } else {
- // if length is in the range 129 to 255,
- // the following single byte shall be copied 257 - length (2 to 128) times during decompression
- $decoded .= str_repeat($data[($i + 1)], (257 - $byte));
- // move to next block
- $i += 2;
- }
- }
- return $decoded;
- }
- /**
- * CCITTFaxDecode (NOT IMPLEMETED - RETURN AN EXCEPTION)
- * Decompresses data encoded using the CCITT facsimile standard, reproducing the original data (typically monochrome image data at 1 bit per pixel).
- * @param string $data Data to decode.
- * @return string Decoded data string.
- * @since 1.0.000 (2011-05-23)
- * @public static
- */
- public static function decodeFilterCCITTFaxDecode($data) {
- self::Error('~decodeFilterCCITTFaxDecode: this method has not been yet implemented');
- //return $data;
- }
- /**
- * JBIG2Decode (NOT IMPLEMETED - RETURN AN EXCEPTION)
- * Decompresses data encoded using the JBIG2 standard, reproducing the original monochrome (1 bit per pixel) image data (or an approximation of that data).
- * @param string $data Data to decode.
- * @return string Decoded data string.
- * @since 1.0.000 (2011-05-23)
- * @public static
- */
- public static function decodeFilterJBIG2Decode($data) {
- self::Error('~decodeFilterJBIG2Decode: this method has not been yet implemented');
- //return $data;
- }
- /**
- * DCTDecode (NOT IMPLEMETED - RETURN AN EXCEPTION)
- * Decompresses data encoded using a DCT (discrete cosine transform) technique based on the JPEG standard, reproducing image sample data that approximates the original data.
- * @param string $data Data to decode.
- * @return string Decoded data string.
- * @since 1.0.000 (2011-05-23)
- * @public static
- */
- public static function decodeFilterDCTDecode($data) {
- self::Error('~decodeFilterDCTDecode: this method has not been yet implemented');
- //return $data;
- }
- /**
- * JPXDecode (NOT IMPLEMETED - RETURN AN EXCEPTION)
- * Decompresses data encoded using the wavelet-based JPEG2000 standard, reproducing the original image data.
- * @param string $data Data to decode.
- * @return string Decoded data string.
- * @since 1.0.000 (2011-05-23)
- * @public static
- */
- public static function decodeFilterJPXDecode($data) {
- self::Error('~decodeFilterJPXDecode: this method has not been yet implemented');
- //return $data;
- }
- /**
- * Crypt (NOT IMPLEMETED - RETURN AN EXCEPTION)
- * Decrypts data encrypted by a security handler, reproducing the data as it was before encryption.
- * @param string $data Data to decode.
- * @return string Decoded data string.
- * @since 1.0.000 (2011-05-23)
- * @public static
- */
- public static function decodeFilterCrypt($data) {
- self::Error('~decodeFilterCrypt: this method has not been yet implemented');
- //return $data;
- }
- // --- END FILTERS SECTION -------------------------------------------------
- /**
- * Throw an exception.
- * @param string $msg The error message
- * @since 1.0.000 (2011-05-23)
- * @public static
- */
- public static function Error($msg) {
- throw new Exception('TCPDF_PARSER ERROR: '.$msg);
- }
- } // END OF TCPDF_FILTERS CLASS
- //============================================================+
- // END OF FILE
- //============================================================+
|