You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

336 lines
11 KiB

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