PageRenderTime 206ms CodeModel.GetById 100ms app.highlight 20ms RepoModel.GetById 81ms app.codeStats 0ms

/Pdf/Filter/Compression.php

https://bitbucket.org/gkawka/zend-framework
PHP | 391 lines | 252 code | 43 blank | 96 comment | 100 complexity | 89348f00806a065828d639a867d04037 MD5 | raw file
  1<?php
  2/**
  3 * Zend Framework
  4 *
  5 * LICENSE
  6 *
  7 * This source file is subject to the new BSD license that is bundled
  8 * with this package in the file LICENSE.txt.
  9 * It is also available through the world-wide-web at this URL:
 10 * http://framework.zend.com/license/new-bsd
 11 * If you did not receive a copy of the license and are unable to
 12 * obtain it through the world-wide-web, please send an email
 13 * to license@zend.com so we can send you a copy immediately.
 14 *
 15 * @category   Zend
 16 * @package    Zend_Pdf
 17 * @copyright  Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
 18 * @license    http://framework.zend.com/license/new-bsd     New BSD License
 19 * @version    $Id: Compression.php 24593 2012-01-05 20:35:02Z matthew $
 20 */
 21
 22
 23/** Zend_Pdf_Filter_Interface */
 24require_once 'Zend/Pdf/Filter/Interface.php';
 25
 26/**
 27 * ASCII85 stream filter
 28 *
 29 * @package    Zend_Pdf
 30 * @copyright  Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
 31 * @license    http://framework.zend.com/license/new-bsd     New BSD License
 32 */
 33abstract class Zend_Pdf_Filter_Compression implements Zend_Pdf_Filter_Interface
 34{
 35    /**
 36     * Paeth prediction function
 37     *
 38     * @param integer $a
 39     * @param integer $b
 40     * @param integer $c
 41     * @return integer
 42     */
 43    private static function _paeth($a, $b, $c)
 44    {
 45        // $a - left, $b - above, $c - upper left
 46        $p  = $a + $b - $c;       // initial estimate
 47        $pa = abs($p - $a);       // distances to a, b, c
 48        $pb = abs($p - $b);
 49        $pc = abs($p - $c);
 50
 51        // return nearest of a,b,c,
 52        // breaking ties in order a,b,c.
 53        if ($pa <= $pb && $pa <= $pc) {
 54            return $a;
 55        } else if ($pb <= $pc) {
 56            return $b;
 57        } else {
 58            return $c;
 59        }
 60    }
 61
 62
 63    /**
 64     * Get Predictor decode param value
 65     *
 66     * @param array $params
 67     * @return integer
 68     * @throws Zend_Pdf_Exception
 69     */
 70    private static function _getPredictorValue(&$params)
 71    {
 72        if (isset($params['Predictor'])) {
 73            $predictor = $params['Predictor'];
 74
 75            if ($predictor != 1   &&  $predictor != 2   &&
 76                $predictor != 10  &&  $predictor != 11  &&   $predictor != 12  &&
 77                $predictor != 13  &&  $predictor != 14  &&   $predictor != 15) {
 78                require_once 'Zend/Pdf/Exception.php';
 79                throw new Zend_Pdf_Exception('Invalid value of \'Predictor\' decode param - ' . $predictor . '.' );
 80            }
 81            return $predictor;
 82        } else {
 83            return 1;
 84        }
 85    }
 86
 87    /**
 88     * Get Colors decode param value
 89     *
 90     * @param array $params
 91     * @return integer
 92     * @throws Zend_Pdf_Exception
 93     */
 94    private static function _getColorsValue(&$params)
 95    {
 96        if (isset($params['Colors'])) {
 97            $colors = $params['Colors'];
 98
 99            if ($colors != 1  &&  $colors != 2  &&  $colors != 3  &&  $colors != 4) {
100                require_once 'Zend/Pdf/Exception.php';
101                throw new Zend_Pdf_Exception('Invalid value of \'Color\' decode param - ' . $colors . '.' );
102            }
103            return $colors;
104        } else {
105            return 1;
106        }
107    }
108
109    /**
110     * Get BitsPerComponent decode param value
111     *
112     * @param array $params
113     * @return integer
114     * @throws Zend_Pdf_Exception
115     */
116    private static function _getBitsPerComponentValue(&$params)
117    {
118        if (isset($params['BitsPerComponent'])) {
119            $bitsPerComponent = $params['BitsPerComponent'];
120
121            if ($bitsPerComponent != 1  &&  $bitsPerComponent != 2  &&
122                $bitsPerComponent != 4  &&  $bitsPerComponent != 8  &&
123                $bitsPerComponent != 16 ) {
124                require_once 'Zend/Pdf/Exception.php';
125                throw new Zend_Pdf_Exception('Invalid value of \'BitsPerComponent\' decode param - ' . $bitsPerComponent . '.' );
126            }
127            return $bitsPerComponent;
128        } else {
129            return 8;
130        }
131    }
132
133    /**
134     * Get Columns decode param value
135     *
136     * @param array $params
137     * @return integer
138     */
139    private static function _getColumnsValue(&$params)
140    {
141        if (isset($params['Columns'])) {
142            return $params['Columns'];
143        } else {
144            return 1;
145        }
146    }
147
148
149    /**
150     * Convert stream data according to the filter params set before encoding.
151     *
152     * @param string $data
153     * @param array $params
154     * @return string
155     * @throws Zend_Pdf_Exception
156     */
157    protected static function _applyEncodeParams($data, $params) {
158        $predictor        = self::_getPredictorValue($params);
159        $colors           = self::_getColorsValue($params);
160        $bitsPerComponent = self::_getBitsPerComponentValue($params);
161        $columns          = self::_getColumnsValue($params);
162
163        /** None of prediction */
164        if ($predictor == 1) {
165            return $data;
166        }
167
168        /** TIFF Predictor 2 */
169        if ($predictor == 2) {
170            require_once 'Zend/Pdf/Exception.php';
171            throw new Zend_Pdf_Exception('Not implemented yet' );
172        }
173
174        /** Optimal PNG prediction */
175        if ($predictor == 15) {
176            /** Use Paeth prediction as optimal */
177            $predictor = 14;
178        }
179
180        /** PNG prediction */
181        if ($predictor == 10 ||  /** None of prediction */
182            $predictor == 11 ||  /** Sub prediction     */
183            $predictor == 12 ||  /** Up prediction      */
184            $predictor == 13 ||  /** Average prediction */
185            $predictor == 14     /** Paeth prediction   */
186            ) {
187            $predictor -= 10;
188
189            if($bitsPerComponent == 16) {
190                require_once 'Zend/Pdf/Exception.php';
191                throw new Zend_Pdf_Exception("PNG Prediction with bit depth greater than 8 not yet supported.");
192            }
193
194            $bitsPerSample  = $bitsPerComponent*$colors;
195            $bytesPerSample = (int)(($bitsPerSample + 7)/8);           // (int)ceil(...) emulation
196            $bytesPerRow    = (int)(($bitsPerSample*$columns + 7)/8);  // (int)ceil(...) emulation
197            $rows           = strlen($data)/$bytesPerRow;
198            $output         = '';
199            $offset         = 0;
200
201            if (!is_integer($rows)) {
202                require_once 'Zend/Pdf/Exception.php';
203                throw new Zend_Pdf_Exception('Wrong data length.');
204            }
205
206            switch ($predictor) {
207                case 0: // None of prediction
208                    for ($count = 0; $count < $rows; $count++) {
209                        $output .= chr($predictor);
210                        $output .= substr($data, $offset, $bytesPerRow);
211                        $offset += $bytesPerRow;
212                    }
213                    break;
214
215                case 1: // Sub prediction
216                    for ($count = 0; $count < $rows; $count++) {
217                        $output .= chr($predictor);
218
219                        $lastSample = array_fill(0, $bytesPerSample, 0);
220                        for ($count2 = 0; $count2 < $bytesPerRow; $count2++) {
221                            $newByte = ord($data[$offset++]);
222                            // Note. chr() automatically cuts input to 8 bit
223                            $output .= chr($newByte - $lastSample[$count2 % $bytesPerSample]);
224                            $lastSample[$count2 % $bytesPerSample] = $newByte;
225                        }
226                    }
227                    break;
228
229                case 2: // Up prediction
230                    $lastRow = array_fill(0, $bytesPerRow, 0);
231                    for ($count = 0; $count < $rows; $count++) {
232                        $output .= chr($predictor);
233
234                        for ($count2 = 0; $count2 < $bytesPerRow; $count2++) {
235                            $newByte = ord($data[$offset++]);
236                            // Note. chr() automatically cuts input to 8 bit
237                            $output .= chr($newByte - $lastRow[$count2]);
238                            $lastRow[$count2] = $newByte;
239                        }
240                    }
241                    break;
242
243                case 3: // Average prediction
244                    $lastRow = array_fill(0, $bytesPerRow, 0);
245                    for ($count = 0; $count < $rows; $count++) {
246                        $output .= chr($predictor);
247
248                        $lastSample = array_fill(0, $bytesPerSample, 0);
249                        for ($count2 = 0; $count2 < $bytesPerRow; $count2++) {
250                            $newByte = ord($data[$offset++]);
251                            // Note. chr() automatically cuts input to 8 bit
252                            $output .= chr($newByte - floor(( $lastSample[$count2 % $bytesPerSample] + $lastRow[$count2])/2));
253                            $lastSample[$count2 % $bytesPerSample] = $lastRow[$count2] = $newByte;
254                        }
255                    }
256                    break;
257
258                case 4: // Paeth prediction
259                    $lastRow    = array_fill(0, $bytesPerRow, 0);
260                    $currentRow = array();
261                    for ($count = 0; $count < $rows; $count++) {
262                        $output .= chr($predictor);
263
264                        $lastSample = array_fill(0, $bytesPerSample, 0);
265                        for ($count2 = 0; $count2 < $bytesPerRow; $count2++) {
266                            $newByte = ord($data[$offset++]);
267                            // Note. chr() automatically cuts input to 8 bit
268                            $output .= chr($newByte - self::_paeth( $lastSample[$count2 % $bytesPerSample],
269                                                                    $lastRow[$count2],
270                                                                    ($count2 - $bytesPerSample  <  0)?
271                                                                         0 : $lastRow[$count2 - $bytesPerSample] ));
272                            $lastSample[$count2 % $bytesPerSample] = $currentRow[$count2] = $newByte;
273                        }
274                        $lastRow = $currentRow;
275                    }
276                    break;
277            }
278            return $output;
279        }
280
281        require_once 'Zend/Pdf/Exception.php';
282        throw new Zend_Pdf_Exception('Unknown prediction algorithm - ' . $predictor . '.' );
283    }
284
285    /**
286     * Convert stream data according to the filter params set after decoding.
287     *
288     * @param string $data
289     * @param array $params
290     * @return string
291     */
292    protected static function _applyDecodeParams($data, $params) {
293        $predictor        = self::_getPredictorValue($params);
294        $colors           = self::_getColorsValue($params);
295        $bitsPerComponent = self::_getBitsPerComponentValue($params);
296        $columns          = self::_getColumnsValue($params);
297
298        /** None of prediction */
299        if ($predictor == 1) {
300            return $data;
301        }
302
303        /** TIFF Predictor 2 */
304        if ($predictor == 2) {
305            require_once 'Zend/Pdf/Exception.php';
306            throw new Zend_Pdf_Exception('Not implemented yet' );
307        }
308
309        /**
310         * PNG prediction
311         * Prediction code is duplicated on each row.
312         * Thus all cases can be brought to one
313         */
314        if ($predictor == 10 ||  /** None of prediction */
315            $predictor == 11 ||  /** Sub prediction     */
316            $predictor == 12 ||  /** Up prediction      */
317            $predictor == 13 ||  /** Average prediction */
318            $predictor == 14 ||  /** Paeth prediction   */
319            $predictor == 15     /** Optimal prediction */) {
320
321            $bitsPerSample  = $bitsPerComponent*$colors;
322            $bytesPerSample = ceil($bitsPerSample/8);
323            $bytesPerRow    = ceil($bitsPerSample*$columns/8);
324            $rows           = ceil(strlen($data)/($bytesPerRow + 1));
325            $output         = '';
326            $offset         = 0;
327
328            $lastRow = array_fill(0, $bytesPerRow, 0);
329            for ($count = 0; $count < $rows; $count++) {
330                $lastSample = array_fill(0, $bytesPerSample, 0);
331                switch (ord($data[$offset++])) {
332                    case 0: // None of prediction
333                        $output .= substr($data, $offset, $bytesPerRow);
334                        for ($count2 = 0; $count2 < $bytesPerRow  &&  $offset < strlen($data); $count2++) {
335                            $lastSample[$count2 % $bytesPerSample] = $lastRow[$count2] = ord($data[$offset++]);
336                        }
337                        break;
338
339                    case 1: // Sub prediction
340                        for ($count2 = 0; $count2 < $bytesPerRow  &&  $offset < strlen($data); $count2++) {
341                            $decodedByte = (ord($data[$offset++]) + $lastSample[$count2 % $bytesPerSample]) & 0xFF;
342                            $lastSample[$count2 % $bytesPerSample] = $lastRow[$count2] = $decodedByte;
343                            $output .= chr($decodedByte);
344                        }
345                        break;
346
347                    case 2: // Up prediction
348                        for ($count2 = 0; $count2 < $bytesPerRow  &&  $offset < strlen($data); $count2++) {
349                            $decodedByte = (ord($data[$offset++]) + $lastRow[$count2]) & 0xFF;
350                            $lastSample[$count2 % $bytesPerSample] = $lastRow[$count2] = $decodedByte;
351                            $output .= chr($decodedByte);
352                        }
353                        break;
354
355                    case 3: // Average prediction
356                        for ($count2 = 0; $count2 < $bytesPerRow  &&  $offset < strlen($data); $count2++) {
357                            $decodedByte = (ord($data[$offset++]) +
358                                            floor(( $lastSample[$count2 % $bytesPerSample] + $lastRow[$count2])/2)
359                                           ) & 0xFF;
360                            $lastSample[$count2 % $bytesPerSample] = $lastRow[$count2] = $decodedByte;
361                            $output .= chr($decodedByte);
362                        }
363                        break;
364
365                    case 4: // Paeth prediction
366                        $currentRow = array();
367                        for ($count2 = 0; $count2 < $bytesPerRow  &&  $offset < strlen($data); $count2++) {
368                            $decodedByte = (ord($data[$offset++]) +
369                                            self::_paeth($lastSample[$count2 % $bytesPerSample],
370                                                         $lastRow[$count2],
371                                                         ($count2 - $bytesPerSample  <  0)?
372                                                              0 : $lastRow[$count2 - $bytesPerSample])
373                                           ) & 0xFF;
374                            $lastSample[$count2 % $bytesPerSample] = $currentRow[$count2] = $decodedByte;
375                            $output .= chr($decodedByte);
376                        }
377                        $lastRow = $currentRow;
378                        break;
379
380                    default:
381                        require_once 'Zend/Pdf/Exception.php';
382                        throw new Zend_Pdf_Exception('Unknown prediction tag.');
383                }
384            }
385            return $output;
386        }
387
388        require_once 'Zend/Pdf/Exception.php';
389        throw new Zend_Pdf_Exception('Unknown prediction algorithm - ' . $predictor . '.' );
390    }
391}