Просмотр исходного кода

Zend_Pdf: RunLength filter support. ZF-8396.

git-svn-id: http://framework.zend.com/svn/framework/standard/trunk@19743 44c647ce-9c0f-0410-b52a-842ac1e357ba
alexander 16 лет назад
Родитель
Сommit
a17162d2b6

+ 11 - 1
library/Zend/Pdf/Element/Object/Stream.php

@@ -211,6 +211,11 @@ class Zend_Pdf_Element_Object_Stream extends Zend_Pdf_Element_Object
                                                                         $this->_originalDictionary['DecodeParms'][$id]);
                     break;
 
+                case 'RunLengthDecode':
+                    require_once 'Zend/Pdf/Filter/RunLength.php';
+                    $valueRef = Zend_Pdf_Filter_RunLength::decode($valueRef);
+                    break;
+
                 default:
                     require_once 'Zend/Pdf/Exception.php';
                     throw new Zend_Pdf_Exception('Unknown stream filter: \'' . $filterName . '\'.');
@@ -265,7 +270,12 @@ class Zend_Pdf_Element_Object_Stream extends Zend_Pdf_Element_Object
                                                                         $this->_originalDictionary['DecodeParms'][$id]);
                     break;
 
-                default:
+                 case 'RunLengthDecode':
+                    require_once 'Zend/Pdf/Filter/RunLength.php';
+                    $valueRef = Zend_Pdf_Filter_RunLength::encode($valueRef);
+                    break;
+
+               default:
                     require_once 'Zend/Pdf/Exception.php';
                     throw new Zend_Pdf_Exception('Unknown stream filter: \'' . $filterName . '\'.');
             }

+ 124 - 0
library/Zend/Pdf/Filter/RunLength.php

@@ -0,0 +1,124 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Pdf
+ * @copyright  Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+
+
+/** Zend_Pdf_Filter_Interface */
+require_once 'Zend/Pdf/Filter/Interface.php';
+
+/**
+ * RunLength stream filter
+ *
+ * @package    Zend_Pdf
+ * @copyright  Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+class Zend_Pdf_Filter_RunLength implements Zend_Pdf_Filter_Interface
+{
+    /**
+     * Encode data
+     *
+     * @param string $data
+     * @param array $params
+     * @return string
+     * @throws Zend_Pdf_Exception
+     */
+    public static function encode($data, $params = null)
+    {
+        $output = '';
+
+        $chainStartOffset = 0;
+        $offset = 0;
+
+        while ($offset < strlen($data)) {
+            // Do not encode 2 char chains since they produce 2 char run sequence,
+            // but it takes more time to decode such output (because of processing additional run)
+            if (($repeatedCharChainLength = strspn($data, $data[$offset], $offset + 1, 127) + 1)  >  2) {
+                if ($chainStartOffset != $offset) {
+                    // Drop down previouse (non-repeatable chars) run
+                    $output .= chr($offset - $chainStartOffset - 1)
+                             . substr($data, $chainStartOffset, $offset - $chainStartOffset);
+                }
+
+                $output .= chr(257 - $repeatedCharChainLength) . $data[$offset];
+
+                $offset += $repeatedCharChainLength;
+                $chainStartOffset = $offset;
+            } else {
+                $offset++;
+
+                if ($offset - $chainStartOffset == 128) {
+                    // Maximum run length is reached
+                    // Drop down non-repeatable chars run
+                    $output .= "\x7F" . substr($data, $chainStartOffset, 128);
+
+                    $chainStartOffset = $offset;
+                }
+            }
+        }
+
+        if ($chainStartOffset != $offset) {
+            // Drop down non-repeatable chars run
+            $output .= chr($offset - $chainStartOffset - 1) . substr($data, $chainStartOffset, $offset - $chainStartOffset);
+        }
+
+        $output .= "\x80";
+
+        return $output;
+    }
+
+    /**
+     * Decode data
+     *
+     * @param string $data
+     * @param array $params
+     * @return string
+     * @throws Zend_Pdf_Exception
+     */
+    public static function decode($data, $params = null)
+    {
+        $dataLength = strlen($data);
+        $output = '';
+        $offset = 0;
+
+        while($offset < $dataLength) {
+            $length = ord($data[$offset]);
+
+            $offset++;
+
+            if ($length == 128) {
+                // EOD byte
+                break;
+            } else if ($length < 128) {
+                $length++;
+
+                $output .= substr($data, $offset, $length);
+
+                $offset += $length;
+            } else if ($length > 128) {
+                $output .= str_repeat($data[$offset], 257 - $length);
+
+                $offset++;
+            }
+        }
+
+        return $output;
+    }
+}
+

+ 2 - 0
tests/Zend/Pdf/AllTests.php

@@ -34,6 +34,7 @@ require_once 'Zend/Pdf/NamedDestinationsTest.php';
 require_once 'Zend/Pdf/ProcessingTest.php';
 
 require_once 'Zend/Pdf/Element/AllTests.php';
+require_once 'Zend/Pdf/Filter/AllTests.php';
 
 /**
  * @category   Zend
@@ -62,6 +63,7 @@ class Zend_Pdf_AllTests
         $suite->addTestSuite('Zend_Pdf_ProcessingTest');
 
         $suite->addTest(Zend_Pdf_Element_AllTests::suite());
+        $suite->addTest(Zend_Pdf_Filter_AllTests::suite());
 
         return $suite;
     }

+ 59 - 0
tests/Zend/Pdf/Filter/AllTests.php

@@ -0,0 +1,59 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Pdf
+ * @subpackage UnitTests
+ * @copyright  Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+
+if (!defined('PHPUnit_MAIN_METHOD')) {
+    define('PHPUnit_MAIN_METHOD', 'Zend_Pdf_Filter_AllTests::main');
+}
+
+require_once 'PHPUnit/Framework/TestSuite.php';
+require_once 'PHPUnit/TextUI/TestRunner.php';
+
+require_once 'Zend/Pdf/Filter/RunLengthTest.php';
+
+/**
+ * @category   Zend
+ * @package    Zend_Pdf
+ * @subpackage UnitTests
+ * @copyright  Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @group      Zend_Pdf
+ */
+class Zend_Pdf_Filter_AllTests
+{
+    public static function main()
+    {
+        PHPUnit_TextUI_TestRunner::run(self::suite());
+    }
+
+    public static function suite()
+    {
+        $suite = new PHPUnit_Framework_TestSuite('Zend Framework - Zend_Pdf_Filter');
+
+        $suite->addTestSuite('Zend_Pdf_Filter_RunLengthTest');
+
+        return $suite;
+    }
+}
+
+if (PHPUnit_MAIN_METHOD == 'Zend_Pdf_Filter_AllTests::main') {
+    Zend_Pdf_Filter_AllTests::main();
+}
+

+ 87 - 0
tests/Zend/Pdf/Filter/RunLengthTest.php

@@ -0,0 +1,87 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Pdf
+ * @subpackage UnitTests
+ * @copyright  Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+
+/**
+ * Zend_Pdf_Filter_RunLength
+ */
+require_once 'Zend/Pdf/Filter/RunLength.php';
+
+/**
+ * PHPUnit Test Case
+ */
+require_once 'PHPUnit/Framework/TestCase.php';
+
+/**
+ * @category   Zend
+ * @package    Zend_Pdf
+ * @subpackage UnitTests
+ * @copyright  Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @group      Zend_Pdf
+ */
+class Zend_Pdf_Filter_RunLengthTest extends PHPUnit_Framework_TestCase
+{
+    public function testSimpleStringEncode()
+    {
+        $decodedContents  = 'WWWWWWWWWWWWBWWWWWWWWWWWWBBBWWWW'
+                          . 'WWWWWWWWWWWWWWWWWWWWBWWWWWWWWWWWWWW';
+        $encodedContents = Zend_Pdf_Filter_RunLength::encode($decodedContents);
+        $testString  = "\xF5W\x00B\xF5W\xFEB\xE9W\x00B\xF3W\x80";
+        $this->assertEquals($encodedContents, $testString);
+    }
+
+    public function testSimpleStringDecode()
+    {
+        $encodedContents  = "\xF5W\x00B\xF5W\xFEB\xE9W\x00B\xF3W\x80";
+        $decodedContents = Zend_Pdf_Filter_RunLength::decode($encodedContents);
+        $testString  = 'WWWWWWWWWWWWBWWWWWWWWWWWWBBBWWWW'
+                     . 'WWWWWWWWWWWWWWWWWWWWBWWWWWWWWWWWWWW';
+        $this->assertEquals($decodedContents, $testString);
+    }
+
+    public function testRepeatBytesLongerThan128BytesEncode()
+    {
+        $decodedContents  = 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA'
+                          . 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA'
+                          . 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA'
+                          . 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA'
+                          . 'AAAAAAAAAAAAAAAAAAAAAABBBCDEFFFF';
+        $encodedContents = Zend_Pdf_Filter_RunLength::encode($decodedContents);
+        $testString  = "\x81A\xEBA\xFEB\x02CDE\xFDF\x80";
+        $this->assertEquals($encodedContents, $testString);
+    }
+
+    public function testRepeatBytesLongerThan128BytesDecode()
+    {
+        $testString  = 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA'
+                     . 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA'
+                     . 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA'
+                     . 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA'
+                     . 'AAAAAAAAAAAAAAAAAAAAAABBBCDEFFFF';
+
+        $encodedContents = "\x81A\xEBA\xFEB\x00C\x00D\x00E\xFDF\x80";
+        $this->assertEquals(Zend_Pdf_Filter_RunLength::decode($encodedContents), $testString);
+
+        $encodedContents = "\x81A\xEBA\xFEB\x02CDE\xFDF\x80";
+        $this->assertEquals(Zend_Pdf_Filter_RunLength::decode($encodedContents), $testString);
+    }
+}
+