Cmap.php 11 KB

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