File indexing completed on 2024-05-26 06:03:17

0001 <?php
0002 /**
0003  * Zend Framework
0004  *
0005  * LICENSE
0006  *
0007  * This source file is subject to the new BSD license that is bundled
0008  * with this package in the file LICENSE.txt.
0009  * It is also available through the world-wide-web at this URL:
0010  * http://framework.zend.com/license/new-bsd
0011  * If you did not receive a copy of the license and are unable to
0012  * obtain it through the world-wide-web, please send an email
0013  * to license@zend.com so we can send you a copy immediately.
0014  *
0015  * @category   Zend
0016  * @package    Zend_Pdf
0017  * @copyright  Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
0018  * @license    http://framework.zend.com/license/new-bsd     New BSD License
0019  * @version    $Id$
0020  */
0021 
0022 
0023 /** Zend_Pdf_Filter_Interface */
0024 // require_once 'Zend/Pdf/Filter/Interface.php';
0025 
0026 /**
0027  * ASCII85 stream filter
0028  *
0029  * @package    Zend_Pdf
0030  * @copyright  Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
0031  * @license    http://framework.zend.com/license/new-bsd     New BSD License
0032  */
0033 abstract class Zend_Pdf_Filter_Compression implements Zend_Pdf_Filter_Interface
0034 {
0035     /**
0036      * Paeth prediction function
0037      *
0038      * @param integer $a
0039      * @param integer $b
0040      * @param integer $c
0041      * @return integer
0042      */
0043     private static function _paeth($a, $b, $c)
0044     {
0045         // $a - left, $b - above, $c - upper left
0046         $p  = $a + $b - $c;       // initial estimate
0047         $pa = abs($p - $a);       // distances to a, b, c
0048         $pb = abs($p - $b);
0049         $pc = abs($p - $c);
0050 
0051         // return nearest of a,b,c,
0052         // breaking ties in order a,b,c.
0053         if ($pa <= $pb && $pa <= $pc) {
0054             return $a;
0055         } else if ($pb <= $pc) {
0056             return $b;
0057         } else {
0058             return $c;
0059         }
0060     }
0061 
0062 
0063     /**
0064      * Get Predictor decode param value
0065      *
0066      * @param array $params
0067      * @return integer
0068      * @throws Zend_Pdf_Exception
0069      */
0070     private static function _getPredictorValue(&$params)
0071     {
0072         if (isset($params['Predictor'])) {
0073             $predictor = $params['Predictor'];
0074 
0075             if ($predictor != 1   &&  $predictor != 2   &&
0076                 $predictor != 10  &&  $predictor != 11  &&   $predictor != 12  &&
0077                 $predictor != 13  &&  $predictor != 14  &&   $predictor != 15) {
0078                 // require_once 'Zend/Pdf/Exception.php';
0079                 throw new Zend_Pdf_Exception('Invalid value of \'Predictor\' decode param - ' . $predictor . '.' );
0080             }
0081             return $predictor;
0082         } else {
0083             return 1;
0084         }
0085     }
0086 
0087     /**
0088      * Get Colors decode param value
0089      *
0090      * @param array $params
0091      * @return integer
0092      * @throws Zend_Pdf_Exception
0093      */
0094     private static function _getColorsValue(&$params)
0095     {
0096         if (isset($params['Colors'])) {
0097             $colors = $params['Colors'];
0098 
0099             if ($colors != 1  &&  $colors != 2  &&  $colors != 3  &&  $colors != 4) {
0100                 // require_once 'Zend/Pdf/Exception.php';
0101                 throw new Zend_Pdf_Exception('Invalid value of \'Color\' decode param - ' . $colors . '.' );
0102             }
0103             return $colors;
0104         } else {
0105             return 1;
0106         }
0107     }
0108 
0109     /**
0110      * Get BitsPerComponent decode param value
0111      *
0112      * @param array $params
0113      * @return integer
0114      * @throws Zend_Pdf_Exception
0115      */
0116     private static function _getBitsPerComponentValue(&$params)
0117     {
0118         if (isset($params['BitsPerComponent'])) {
0119             $bitsPerComponent = $params['BitsPerComponent'];
0120 
0121             if ($bitsPerComponent != 1  &&  $bitsPerComponent != 2  &&
0122                 $bitsPerComponent != 4  &&  $bitsPerComponent != 8  &&
0123                 $bitsPerComponent != 16 ) {
0124                 // require_once 'Zend/Pdf/Exception.php';
0125                 throw new Zend_Pdf_Exception('Invalid value of \'BitsPerComponent\' decode param - ' . $bitsPerComponent . '.' );
0126             }
0127             return $bitsPerComponent;
0128         } else {
0129             return 8;
0130         }
0131     }
0132 
0133     /**
0134      * Get Columns decode param value
0135      *
0136      * @param array $params
0137      * @return integer
0138      */
0139     private static function _getColumnsValue(&$params)
0140     {
0141         if (isset($params['Columns'])) {
0142             return $params['Columns'];
0143         } else {
0144             return 1;
0145         }
0146     }
0147 
0148 
0149     /**
0150      * Convert stream data according to the filter params set before encoding.
0151      *
0152      * @param string $data
0153      * @param array $params
0154      * @return string
0155      * @throws Zend_Pdf_Exception
0156      */
0157     protected static function _applyEncodeParams($data, $params) {
0158         $predictor        = self::_getPredictorValue($params);
0159         $colors           = self::_getColorsValue($params);
0160         $bitsPerComponent = self::_getBitsPerComponentValue($params);
0161         $columns          = self::_getColumnsValue($params);
0162 
0163         /** None of prediction */
0164         if ($predictor == 1) {
0165             return $data;
0166         }
0167 
0168         /** TIFF Predictor 2 */
0169         if ($predictor == 2) {
0170             // require_once 'Zend/Pdf/Exception.php';
0171             throw new Zend_Pdf_Exception('Not implemented yet' );
0172         }
0173 
0174         /** Optimal PNG prediction */
0175         if ($predictor == 15) {
0176             /** Use Paeth prediction as optimal */
0177             $predictor = 14;
0178         }
0179 
0180         /** PNG prediction */
0181         if ($predictor == 10 ||  /** None of prediction */
0182             $predictor == 11 ||  /** Sub prediction     */
0183             $predictor == 12 ||  /** Up prediction      */
0184             $predictor == 13 ||  /** Average prediction */
0185             $predictor == 14     /** Paeth prediction   */
0186             ) {
0187             $predictor -= 10;
0188 
0189             if($bitsPerComponent == 16) {
0190                 // require_once 'Zend/Pdf/Exception.php';
0191                 throw new Zend_Pdf_Exception("PNG Prediction with bit depth greater than 8 not yet supported.");
0192             }
0193 
0194             $bitsPerSample  = $bitsPerComponent*$colors;
0195             $bytesPerSample = (int)(($bitsPerSample + 7)/8);           // (int)ceil(...) emulation
0196             $bytesPerRow    = (int)(($bitsPerSample*$columns + 7)/8);  // (int)ceil(...) emulation
0197             $rows           = strlen($data)/$bytesPerRow;
0198             $output         = '';
0199             $offset         = 0;
0200 
0201             if (!is_integer($rows)) {
0202                 // require_once 'Zend/Pdf/Exception.php';
0203                 throw new Zend_Pdf_Exception('Wrong data length.');
0204             }
0205 
0206             switch ($predictor) {
0207                 case 0: // None of prediction
0208                     for ($count = 0; $count < $rows; $count++) {
0209                         $output .= chr($predictor);
0210                         $output .= substr($data, $offset, $bytesPerRow);
0211                         $offset += $bytesPerRow;
0212                     }
0213                     break;
0214 
0215                 case 1: // Sub prediction
0216                     for ($count = 0; $count < $rows; $count++) {
0217                         $output .= chr($predictor);
0218 
0219                         $lastSample = array_fill(0, $bytesPerSample, 0);
0220                         for ($count2 = 0; $count2 < $bytesPerRow; $count2++) {
0221                             $newByte = ord($data[$offset++]);
0222                             // Note. chr() automatically cuts input to 8 bit
0223                             $output .= chr($newByte - $lastSample[$count2 % $bytesPerSample]);
0224                             $lastSample[$count2 % $bytesPerSample] = $newByte;
0225                         }
0226                     }
0227                     break;
0228 
0229                 case 2: // Up prediction
0230                     $lastRow = array_fill(0, $bytesPerRow, 0);
0231                     for ($count = 0; $count < $rows; $count++) {
0232                         $output .= chr($predictor);
0233 
0234                         for ($count2 = 0; $count2 < $bytesPerRow; $count2++) {
0235                             $newByte = ord($data[$offset++]);
0236                             // Note. chr() automatically cuts input to 8 bit
0237                             $output .= chr($newByte - $lastRow[$count2]);
0238                             $lastRow[$count2] = $newByte;
0239                         }
0240                     }
0241                     break;
0242 
0243                 case 3: // Average prediction
0244                     $lastRow = array_fill(0, $bytesPerRow, 0);
0245                     for ($count = 0; $count < $rows; $count++) {
0246                         $output .= chr($predictor);
0247 
0248                         $lastSample = array_fill(0, $bytesPerSample, 0);
0249                         for ($count2 = 0; $count2 < $bytesPerRow; $count2++) {
0250                             $newByte = ord($data[$offset++]);
0251                             // Note. chr() automatically cuts input to 8 bit
0252                             $output .= chr($newByte - floor(( $lastSample[$count2 % $bytesPerSample] + $lastRow[$count2])/2));
0253                             $lastSample[$count2 % $bytesPerSample] = $lastRow[$count2] = $newByte;
0254                         }
0255                     }
0256                     break;
0257 
0258                 case 4: // Paeth prediction
0259                     $lastRow    = array_fill(0, $bytesPerRow, 0);
0260                     $currentRow = array();
0261                     for ($count = 0; $count < $rows; $count++) {
0262                         $output .= chr($predictor);
0263 
0264                         $lastSample = array_fill(0, $bytesPerSample, 0);
0265                         for ($count2 = 0; $count2 < $bytesPerRow; $count2++) {
0266                             $newByte = ord($data[$offset++]);
0267                             // Note. chr() automatically cuts input to 8 bit
0268                             $output .= chr($newByte - self::_paeth( $lastSample[$count2 % $bytesPerSample],
0269                                                                     $lastRow[$count2],
0270                                                                     ($count2 - $bytesPerSample  <  0)?
0271                                                                          0 : $lastRow[$count2 - $bytesPerSample] ));
0272                             $lastSample[$count2 % $bytesPerSample] = $currentRow[$count2] = $newByte;
0273                         }
0274                         $lastRow = $currentRow;
0275                     }
0276                     break;
0277             }
0278             return $output;
0279         }
0280 
0281         // require_once 'Zend/Pdf/Exception.php';
0282         throw new Zend_Pdf_Exception('Unknown prediction algorithm - ' . $predictor . '.' );
0283     }
0284 
0285     /**
0286      * Convert stream data according to the filter params set after decoding.
0287      *
0288      * @param string $data
0289      * @param array $params
0290      * @return string
0291      */
0292     protected static function _applyDecodeParams($data, $params) {
0293         $predictor        = self::_getPredictorValue($params);
0294         $colors           = self::_getColorsValue($params);
0295         $bitsPerComponent = self::_getBitsPerComponentValue($params);
0296         $columns          = self::_getColumnsValue($params);
0297 
0298         /** None of prediction */
0299         if ($predictor == 1) {
0300             return $data;
0301         }
0302 
0303         /** TIFF Predictor 2 */
0304         if ($predictor == 2) {
0305             // require_once 'Zend/Pdf/Exception.php';
0306             throw new Zend_Pdf_Exception('Not implemented yet' );
0307         }
0308 
0309         /**
0310          * PNG prediction
0311          * Prediction code is duplicated on each row.
0312          * Thus all cases can be brought to one
0313          */
0314         if ($predictor == 10 ||  /** None of prediction */
0315             $predictor == 11 ||  /** Sub prediction     */
0316             $predictor == 12 ||  /** Up prediction      */
0317             $predictor == 13 ||  /** Average prediction */
0318             $predictor == 14 ||  /** Paeth prediction   */
0319             $predictor == 15     /** Optimal prediction */) {
0320 
0321             $bitsPerSample  = $bitsPerComponent*$colors;
0322             $bytesPerSample = ceil($bitsPerSample/8);
0323             $bytesPerRow    = ceil($bitsPerSample*$columns/8);
0324             $rows           = ceil(strlen($data)/($bytesPerRow + 1));
0325             $output         = '';
0326             $offset         = 0;
0327 
0328             $lastRow = array_fill(0, $bytesPerRow, 0);
0329             for ($count = 0; $count < $rows; $count++) {
0330                 $lastSample = array_fill(0, $bytesPerSample, 0);
0331                 switch (ord($data[$offset++])) {
0332                     case 0: // None of prediction
0333                         $output .= substr($data, $offset, $bytesPerRow);
0334                         for ($count2 = 0; $count2 < $bytesPerRow  &&  $offset < strlen($data); $count2++) {
0335                             $lastSample[$count2 % $bytesPerSample] = $lastRow[$count2] = ord($data[$offset++]);
0336                         }
0337                         break;
0338 
0339                     case 1: // Sub prediction
0340                         for ($count2 = 0; $count2 < $bytesPerRow  &&  $offset < strlen($data); $count2++) {
0341                             $decodedByte = (ord($data[$offset++]) + $lastSample[$count2 % $bytesPerSample]) & 0xFF;
0342                             $lastSample[$count2 % $bytesPerSample] = $lastRow[$count2] = $decodedByte;
0343                             $output .= chr($decodedByte);
0344                         }
0345                         break;
0346 
0347                     case 2: // Up prediction
0348                         for ($count2 = 0; $count2 < $bytesPerRow  &&  $offset < strlen($data); $count2++) {
0349                             $decodedByte = (ord($data[$offset++]) + $lastRow[$count2]) & 0xFF;
0350                             $lastSample[$count2 % $bytesPerSample] = $lastRow[$count2] = $decodedByte;
0351                             $output .= chr($decodedByte);
0352                         }
0353                         break;
0354 
0355                     case 3: // Average prediction
0356                         for ($count2 = 0; $count2 < $bytesPerRow  &&  $offset < strlen($data); $count2++) {
0357                             $decodedByte = (ord($data[$offset++]) +
0358                                             floor(( $lastSample[$count2 % $bytesPerSample] + $lastRow[$count2])/2)
0359                                            ) & 0xFF;
0360                             $lastSample[$count2 % $bytesPerSample] = $lastRow[$count2] = $decodedByte;
0361                             $output .= chr($decodedByte);
0362                         }
0363                         break;
0364 
0365                     case 4: // Paeth prediction
0366                         $currentRow = array();
0367                         for ($count2 = 0; $count2 < $bytesPerRow  &&  $offset < strlen($data); $count2++) {
0368                             $decodedByte = (ord($data[$offset++]) +
0369                                             self::_paeth($lastSample[$count2 % $bytesPerSample],
0370                                                          $lastRow[$count2],
0371                                                          ($count2 - $bytesPerSample  <  0)?
0372                                                               0 : $lastRow[$count2 - $bytesPerSample])
0373                                            ) & 0xFF;
0374                             $lastSample[$count2 % $bytesPerSample] = $currentRow[$count2] = $decodedByte;
0375                             $output .= chr($decodedByte);
0376                         }
0377                         $lastRow = $currentRow;
0378                         break;
0379 
0380                     default:
0381                         // require_once 'Zend/Pdf/Exception.php';
0382                         throw new Zend_Pdf_Exception('Unknown prediction tag.');
0383                 }
0384             }
0385             return $output;
0386         }
0387 
0388         // require_once 'Zend/Pdf/Exception.php';
0389         throw new Zend_Pdf_Exception('Unknown prediction algorithm - ' . $predictor . '.' );
0390     }
0391 }