web/lib/Zend/Pdf/Cmap.php
changeset 64 162c1de6545a
parent 19 1c2f13fd785c
child 68 ecaf28ffe26e
equal deleted inserted replaced
63:5b37998e522e 64:162c1de6545a
       
     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  * @subpackage Fonts
       
    18  * @copyright  Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
       
    19  * @license    http://framework.zend.com/license/new-bsd     New BSD License
       
    20  * @version    $Id: Cmap.php 20096 2010-01-06 02:05:09Z bkarwin $
       
    21  */
       
    22 
       
    23 
       
    24 /**
       
    25  * Abstract helper class for {@link Zend_Pdf_Resource_Font} which manages font
       
    26  * character maps.
       
    27  *
       
    28  * Defines the public interface for concrete subclasses which are responsible
       
    29  * for mapping Unicode characters to the font's glyph numbers. Also provides
       
    30  * shared utility methods.
       
    31  *
       
    32  * Cmap objects should ordinarily be obtained through the factory method
       
    33  * {@link cmapWithTypeData()}.
       
    34  *
       
    35  * The supported character map types are those found in the OpenType spec. For
       
    36  * additional detail on the internal binary format of these tables, see:
       
    37  * <ul>
       
    38  *  <li>{@link http://developer.apple.com/textfonts/TTRefMan/RM06/Chap6cmap.html}
       
    39  *  <li>{@link http://www.microsoft.com/OpenType/OTSpec/cmap.htm}
       
    40  *  <li>{@link http://partners.adobe.com/public/developer/opentype/index_cmap.html}
       
    41  * </ul>
       
    42  *
       
    43  * @todo Write code for Zend_Pdf_FontCmap_HighByteMapping class.
       
    44  * @todo Write code for Zend_Pdf_FontCmap_MixedCoverage class.
       
    45  * @todo Write code for Zend_Pdf_FontCmap_TrimmedArray class.
       
    46  * @todo Write code for Zend_Pdf_FontCmap_SegmentedCoverage class.
       
    47  *
       
    48  * @package    Zend_Pdf
       
    49  * @subpackage Fonts
       
    50  * @copyright  Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
       
    51  * @license    http://framework.zend.com/license/new-bsd     New BSD License
       
    52  */
       
    53 abstract class Zend_Pdf_Cmap
       
    54 {
       
    55   /**** Class Constants ****/
       
    56 
       
    57 
       
    58   /* Cmap Table Types */
       
    59 
       
    60     /**
       
    61      * Byte Encoding character map table type.
       
    62      */
       
    63     const TYPE_BYTE_ENCODING = 0x00;
       
    64 
       
    65     /**
       
    66      * High Byte Mapping character map table type.
       
    67      */
       
    68     const TYPE_HIGH_BYTE_MAPPING = 0x02;
       
    69 
       
    70     /**
       
    71      * Segment Value to Delta Mapping character map table type.
       
    72      */
       
    73     const TYPE_SEGMENT_TO_DELTA = 0x04;
       
    74 
       
    75     /**
       
    76      * Trimmed Table character map table type.
       
    77      */
       
    78     const TYPE_TRIMMED_TABLE = 0x06;
       
    79 
       
    80     /**
       
    81      * Mixed Coverage character map table type.
       
    82      */
       
    83     const TYPE_MIXED_COVERAGE = 0x08;
       
    84 
       
    85     /**
       
    86      * Trimmed Array character map table type.
       
    87      */
       
    88     const TYPE_TRIMMED_ARRAY = 0x0a;
       
    89 
       
    90     /**
       
    91      * Segmented Coverage character map table type.
       
    92      */
       
    93     const TYPE_SEGMENTED_COVERAGE = 0x0c;
       
    94 
       
    95     /**
       
    96      * Static Byte Encoding character map table type. Variant of
       
    97      * {@link TYPE_BYTEENCODING}.
       
    98      */
       
    99     const TYPE_BYTE_ENCODING_STATIC = 0xf1;
       
   100 
       
   101     /**
       
   102      * Unknown character map table type.
       
   103      */
       
   104     const TYPE_UNKNOWN = 0xff;
       
   105 
       
   106 
       
   107   /* Special Glyph Names */
       
   108 
       
   109     /**
       
   110      * Glyph representing missing characters.
       
   111      */
       
   112     const MISSING_CHARACTER_GLYPH = 0x00;
       
   113 
       
   114 
       
   115 
       
   116   /**** Public Interface ****/
       
   117 
       
   118 
       
   119   /* Factory Methods */
       
   120 
       
   121     /**
       
   122      * Instantiates the appropriate concrete subclass based on the type of cmap
       
   123      * table and returns the instance.
       
   124      *
       
   125      * The cmap type must be one of the following values:
       
   126      * <ul>
       
   127      *  <li>{@link Zend_Pdf_Cmap::TYPE_BYTE_ENCODING}
       
   128      *  <li>{@link Zend_Pdf_Cmap::TYPE_BYTE_ENCODING_STATIC}
       
   129      *  <li>{@link Zend_Pdf_Cmap::TYPE_HIGH_BYTE_MAPPING}
       
   130      *  <li>{@link Zend_Pdf_Cmap::TYPE_SEGMENT_TO_DELTA}
       
   131      *  <li>{@link Zend_Pdf_Cmap::TYPE_TRIMMED_TABLE}
       
   132      *  <li>{@link Zend_Pdf_Cmap::TYPE_MIXED_COVERAGE}
       
   133      *  <li>{@link Zend_Pdf_Cmap::TYPE_TRIMMED_ARRAY}
       
   134      *  <li>{@link Zend_Pdf_Cmap::TYPE_SEGMENTED_COVERAGE}
       
   135      * </ul>
       
   136      *
       
   137      * Throws an exception if the table type is invalid or the cmap table data
       
   138      * cannot be validated.
       
   139      *
       
   140      * @param integer $cmapType Type of cmap.
       
   141      * @param mixed $cmapData Cmap table data. Usually a string or array.
       
   142      * @return Zend_Pdf_Cmap
       
   143      * @throws Zend_Pdf_Exception
       
   144      */
       
   145     public static function cmapWithTypeData($cmapType, $cmapData)
       
   146     {
       
   147         switch ($cmapType) {
       
   148             case Zend_Pdf_Cmap::TYPE_BYTE_ENCODING:
       
   149                 require_once 'Zend/Pdf/Cmap/ByteEncoding.php';
       
   150                 return new Zend_Pdf_Cmap_ByteEncoding($cmapData);
       
   151 
       
   152             case Zend_Pdf_Cmap::TYPE_BYTE_ENCODING_STATIC:
       
   153                 require_once 'Zend/Pdf/Cmap/ByteEncoding/Static.php';
       
   154                 return new Zend_Pdf_Cmap_ByteEncoding_Static($cmapData);
       
   155 
       
   156             case Zend_Pdf_Cmap::TYPE_HIGH_BYTE_MAPPING:
       
   157                 require_once 'Zend/Pdf/Exception.php';
       
   158                 throw new Zend_Pdf_Exception('High byte mapping cmap currently unsupported',
       
   159                                              Zend_Pdf_Exception::CMAP_TYPE_UNSUPPORTED);
       
   160 
       
   161             case Zend_Pdf_Cmap::TYPE_SEGMENT_TO_DELTA:
       
   162                 require_once 'Zend/Pdf/Cmap/SegmentToDelta.php';
       
   163                 return new Zend_Pdf_Cmap_SegmentToDelta($cmapData);
       
   164 
       
   165             case Zend_Pdf_Cmap::TYPE_TRIMMED_TABLE:
       
   166                 require_once 'Zend/Pdf/Cmap/TrimmedTable.php';
       
   167                 return new Zend_Pdf_Cmap_TrimmedTable($cmapData);
       
   168 
       
   169             case Zend_Pdf_Cmap::TYPE_MIXED_COVERAGE:
       
   170                 require_once 'Zend/Pdf/Exception.php';
       
   171                 throw new Zend_Pdf_Exception('Mixed coverage cmap currently unsupported',
       
   172                                              Zend_Pdf_Exception::CMAP_TYPE_UNSUPPORTED);
       
   173 
       
   174             case Zend_Pdf_Cmap::TYPE_TRIMMED_ARRAY:
       
   175                 require_once 'Zend/Pdf/Exception.php';
       
   176                 throw new Zend_Pdf_Exception('Trimmed array cmap currently unsupported',
       
   177                                              Zend_Pdf_Exception::CMAP_TYPE_UNSUPPORTED);
       
   178 
       
   179             case Zend_Pdf_Cmap::TYPE_SEGMENTED_COVERAGE:
       
   180                 require_once 'Zend/Pdf/Exception.php';
       
   181                 throw new Zend_Pdf_Exception('Segmented coverage cmap currently unsupported',
       
   182                                              Zend_Pdf_Exception::CMAP_TYPE_UNSUPPORTED);
       
   183 
       
   184             default:
       
   185                 require_once 'Zend/Pdf/Exception.php';
       
   186                 throw new Zend_Pdf_Exception("Unknown cmap type: $cmapType",
       
   187                                              Zend_Pdf_Exception::CMAP_UNKNOWN_TYPE);
       
   188         }
       
   189     }
       
   190 
       
   191 
       
   192   /* Abstract Methods */
       
   193 
       
   194     /**
       
   195      * Object constructor
       
   196      *
       
   197      * Parses the raw binary table data. Throws an exception if the table is
       
   198      * malformed.
       
   199      *
       
   200      * @param string $cmapData Raw binary cmap table data.
       
   201      * @throws Zend_Pdf_Exception
       
   202      */
       
   203     abstract public function __construct($cmapData);
       
   204 
       
   205     /**
       
   206      * Returns an array of glyph numbers corresponding to the Unicode characters.
       
   207      *
       
   208      * If a particular character doesn't exist in this font, the special 'missing
       
   209      * character glyph' will be substituted.
       
   210      *
       
   211      * See also {@link glyphNumberForCharacter()}.
       
   212      *
       
   213      * @param array $characterCodes Array of Unicode character codes (code points).
       
   214      * @return array Array of glyph numbers.
       
   215      */
       
   216     abstract public function glyphNumbersForCharacters($characterCodes);
       
   217 
       
   218     /**
       
   219      * Returns the glyph number corresponding to the Unicode character.
       
   220      *
       
   221      * If a particular character doesn't exist in this font, the special 'missing
       
   222      * character glyph' will be substituted.
       
   223      *
       
   224      * See also {@link glyphNumbersForCharacters()} which is optimized for bulk
       
   225      * operations.
       
   226      *
       
   227      * @param integer $characterCode Unicode character code (code point).
       
   228      * @return integer Glyph number.
       
   229      */
       
   230     abstract public function glyphNumberForCharacter($characterCode);
       
   231 
       
   232     /**
       
   233      * Returns an array containing the Unicode characters that have entries in
       
   234      * this character map.
       
   235      *
       
   236      * @return array Unicode character codes.
       
   237      */
       
   238     abstract public function getCoveredCharacters();
       
   239 
       
   240     /**
       
   241      * Returns an array containing the glyphs numbers that have entries in this character map.
       
   242      * Keys are Unicode character codes (integers)
       
   243      *
       
   244      * This functionality is partially covered by glyphNumbersForCharacters(getCoveredCharacters())
       
   245      * call, but this method do it in more effective way (prepare complete list instead of searching
       
   246      * glyph for each character code).
       
   247      *
       
   248      * @internal
       
   249      * @return array Array representing <Unicode character code> => <glyph number> pairs.
       
   250      */
       
   251     abstract public function getCoveredCharactersGlyphs();
       
   252 
       
   253 
       
   254   /**** Internal Methods ****/
       
   255 
       
   256 
       
   257   /* Internal Utility Methods */
       
   258 
       
   259     /**
       
   260      * Extracts a signed 2-byte integer from a string.
       
   261      *
       
   262      * Integers are always big-endian. Throws an exception if the index is out
       
   263      * of range.
       
   264      *
       
   265      * @param string &$data
       
   266      * @param integer $index Position in string of integer.
       
   267      * @return integer
       
   268      * @throws Zend_Pdf_Exception
       
   269      */
       
   270     protected function _extractInt2(&$data, $index)
       
   271     {
       
   272         if (($index < 0) | (($index + 1) > strlen($data))) {
       
   273             require_once 'Zend/Pdf/Exception.php';
       
   274             throw new Zend_Pdf_Exception("Index out of range: $index",
       
   275                                          Zend_Pdf_Exception::INDEX_OUT_OF_RANGE);
       
   276         }
       
   277         $number = ord($data[$index]);
       
   278         if (($number & 0x80) == 0x80) {    // negative
       
   279             $number = ~((((~ $number) & 0xff) << 8) | ((~ ord($data[++$index])) & 0xff));
       
   280         } else {
       
   281             $number = ($number << 8) | ord($data[++$index]);
       
   282         }
       
   283         return $number;
       
   284     }
       
   285 
       
   286     /**
       
   287      * Extracts an unsigned 2-byte integer from a string.
       
   288      *
       
   289      * Integers are always big-endian. Throws an exception if the index is out
       
   290      * of range.
       
   291      *
       
   292      * @param string &$data
       
   293      * @param integer $index Position in string of integer.
       
   294      * @return integer
       
   295      * @throws Zend_Pdf_Exception
       
   296      */
       
   297     protected function _extractUInt2(&$data, $index)
       
   298     {
       
   299         if (($index < 0) | (($index + 1) > strlen($data))) {
       
   300             require_once 'Zend/Pdf/Exception.php';
       
   301             throw new Zend_Pdf_Exception("Index out of range: $index",
       
   302                                          Zend_Pdf_Exception::INDEX_OUT_OF_RANGE);
       
   303         }
       
   304         $number = (ord($data[$index]) << 8) | ord($data[++$index]);
       
   305         return $number;
       
   306     }
       
   307 
       
   308     /**
       
   309      * Extracts an unsigned 4-byte integer from a string.
       
   310      *
       
   311      * Integers are always big-endian. Throws an exception if the index is out
       
   312      * of range.
       
   313      *
       
   314      * NOTE: If you ask for a 4-byte unsigned integer on a 32-bit machine, the
       
   315      * resulting value WILL BE SIGNED because PHP uses signed integers internally
       
   316      * for everything. To guarantee portability, be sure to use bitwise or
       
   317      * similar operators on large integers!
       
   318      *
       
   319      * @param string &$data
       
   320      * @param integer $index Position in string of integer.
       
   321      * @return integer
       
   322      * @throws Zend_Pdf_Exception
       
   323      */
       
   324     protected function _extractUInt4(&$data, $index)
       
   325     {
       
   326         if (($index < 0) | (($index + 3) > strlen($data))) {
       
   327             require_once 'Zend/Pdf/Exception.php';
       
   328             throw new Zend_Pdf_Exception("Index out of range: $index",
       
   329                                          Zend_Pdf_Exception::INDEX_OUT_OF_RANGE);
       
   330         }
       
   331         $number = (ord($data[$index]) << 24) | (ord($data[++$index]) << 16) |
       
   332                   (ord($data[++$index]) << 8) | ord($data[++$index]);
       
   333         return $number;
       
   334     }
       
   335 
       
   336 }