PageRenderTime 47ms CodeModel.GetById 24ms RepoModel.GetById 0ms app.codeStats 0ms

/www/system/library/Zend/Pdf/Font.php

https://bitbucket.org/vmihailenco/zf-blog
PHP | 732 lines | 185 code | 157 blank | 390 comment | 13 complexity | c44cb4120ec83ec75553c6bdd272068d 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. * @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: Font.php 20211 2010-01-12 02:14:29Z yoshida@zend.co.jp $
  21. */
  22. /**
  23. * Abstract factory class which vends {@link Zend_Pdf_Resource_Font} objects.
  24. *
  25. * Font objects themselves are normally instantiated through the factory methods
  26. * {@link fontWithName()} or {@link fontWithPath()}.
  27. *
  28. * This class is also the home for font-related constants because the name of
  29. * the true base class ({@link Zend_Pdf_Resource_Font}) is not intuitive for the
  30. * end user.
  31. *
  32. * @package Zend_Pdf
  33. * @subpackage Fonts
  34. * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
  35. * @license http://framework.zend.com/license/new-bsd New BSD License
  36. */
  37. abstract class Zend_Pdf_Font
  38. {
  39. /**** Class Constants ****/
  40. /* Font Types */
  41. /**
  42. * Unknown font type.
  43. */
  44. const TYPE_UNKNOWN = 0;
  45. /**
  46. * One of the standard 14 PDF fonts.
  47. */
  48. const TYPE_STANDARD = 1;
  49. /**
  50. * A PostScript Type 1 font.
  51. */
  52. const TYPE_TYPE_1 = 2;
  53. /**
  54. * A TrueType font or an OpenType font containing TrueType outlines.
  55. */
  56. const TYPE_TRUETYPE = 3;
  57. /**
  58. * Type 0 composite font.
  59. */
  60. const TYPE_TYPE_0 = 4;
  61. /**
  62. * CID font containing a PostScript Type 1 font.
  63. * These fonts are used only to construct Type 0 composite fonts and can't be used directly
  64. */
  65. const TYPE_CIDFONT_TYPE_0 = 5;
  66. /**
  67. * CID font containing a TrueType font or an OpenType font containing TrueType outlines.
  68. * These fonts are used only to construct Type 0 composite fonts and can't be used directly
  69. */
  70. const TYPE_CIDFONT_TYPE_2 = 6;
  71. /* Names of the Standard 14 PDF Fonts */
  72. /**
  73. * Name of the standard PDF font Courier.
  74. */
  75. const FONT_COURIER = 'Courier';
  76. /**
  77. * Name of the bold style of the standard PDF font Courier.
  78. */
  79. const FONT_COURIER_BOLD = 'Courier-Bold';
  80. /**
  81. * Name of the italic style of the standard PDF font Courier.
  82. */
  83. const FONT_COURIER_OBLIQUE = 'Courier-Oblique';
  84. /**
  85. * Convenience constant for a common misspelling of
  86. * {@link FONT_COURIER_OBLIQUE}.
  87. */
  88. const FONT_COURIER_ITALIC = 'Courier-Oblique';
  89. /**
  90. * Name of the bold and italic style of the standard PDF font Courier.
  91. */
  92. const FONT_COURIER_BOLD_OBLIQUE = 'Courier-BoldOblique';
  93. /**
  94. * Convenience constant for a common misspelling of
  95. * {@link FONT_COURIER_BOLD_OBLIQUE}.
  96. */
  97. const FONT_COURIER_BOLD_ITALIC = 'Courier-BoldOblique';
  98. /**
  99. * Name of the standard PDF font Helvetica.
  100. */
  101. const FONT_HELVETICA = 'Helvetica';
  102. /**
  103. * Name of the bold style of the standard PDF font Helvetica.
  104. */
  105. const FONT_HELVETICA_BOLD = 'Helvetica-Bold';
  106. /**
  107. * Name of the italic style of the standard PDF font Helvetica.
  108. */
  109. const FONT_HELVETICA_OBLIQUE = 'Helvetica-Oblique';
  110. /**
  111. * Convenience constant for a common misspelling of
  112. * {@link FONT_HELVETICA_OBLIQUE}.
  113. */
  114. const FONT_HELVETICA_ITALIC = 'Helvetica-Oblique';
  115. /**
  116. * Name of the bold and italic style of the standard PDF font Helvetica.
  117. */
  118. const FONT_HELVETICA_BOLD_OBLIQUE = 'Helvetica-BoldOblique';
  119. /**
  120. * Convenience constant for a common misspelling of
  121. * {@link FONT_HELVETICA_BOLD_OBLIQUE}.
  122. */
  123. const FONT_HELVETICA_BOLD_ITALIC = 'Helvetica-BoldOblique';
  124. /**
  125. * Name of the standard PDF font Symbol.
  126. */
  127. const FONT_SYMBOL = 'Symbol';
  128. /**
  129. * Name of the standard PDF font Times.
  130. */
  131. const FONT_TIMES_ROMAN = 'Times-Roman';
  132. /**
  133. * Convenience constant for a common misspelling of
  134. * {@link FONT_TIMES_ROMAN}.
  135. */
  136. const FONT_TIMES = 'Times-Roman';
  137. /**
  138. * Name of the bold style of the standard PDF font Times.
  139. */
  140. const FONT_TIMES_BOLD = 'Times-Bold';
  141. /**
  142. * Name of the italic style of the standard PDF font Times.
  143. */
  144. const FONT_TIMES_ITALIC = 'Times-Italic';
  145. /**
  146. * Name of the bold and italic style of the standard PDF font Times.
  147. */
  148. const FONT_TIMES_BOLD_ITALIC = 'Times-BoldItalic';
  149. /**
  150. * Name of the standard PDF font Zapf Dingbats.
  151. */
  152. const FONT_ZAPFDINGBATS = 'ZapfDingbats';
  153. /* Font Name String Types */
  154. /**
  155. * Full copyright notice for the font.
  156. */
  157. const NAME_COPYRIGHT = 0;
  158. /**
  159. * Font family name. Used to group similar styles of fonts together.
  160. */
  161. const NAME_FAMILY = 1;
  162. /**
  163. * Font style within the font family. Examples: Regular, Italic, Bold, etc.
  164. */
  165. const NAME_STYLE = 2;
  166. /**
  167. * Unique font identifier.
  168. */
  169. const NAME_ID = 3;
  170. /**
  171. * Full font name. Usually a combination of the {@link NAME_FAMILY} and
  172. * {@link NAME_STYLE} strings.
  173. */
  174. const NAME_FULL = 4;
  175. /**
  176. * Version number of the font.
  177. */
  178. const NAME_VERSION = 5;
  179. /**
  180. * PostScript name for the font. This is the name used to identify fonts
  181. * internally and within the PDF file.
  182. */
  183. const NAME_POSTSCRIPT = 6;
  184. /**
  185. * Font trademark notice. This is distinct from the {@link NAME_COPYRIGHT}.
  186. */
  187. const NAME_TRADEMARK = 7;
  188. /**
  189. * Name of the font manufacturer.
  190. */
  191. const NAME_MANUFACTURER = 8;
  192. /**
  193. * Name of the designer of the font.
  194. */
  195. const NAME_DESIGNER = 9;
  196. /**
  197. * Description of the font. May contain revision information, usage
  198. * recommendations, features, etc.
  199. */
  200. const NAME_DESCRIPTION = 10;
  201. /**
  202. * URL of the font vendor. Some fonts may contain a unique serial number
  203. * embedded in this URL, which is used for licensing.
  204. */
  205. const NAME_VENDOR_URL = 11;
  206. /**
  207. * URL of the font designer ({@link NAME_DESIGNER}).
  208. */
  209. const NAME_DESIGNER_URL = 12;
  210. /**
  211. * Plain language licensing terms for the font.
  212. */
  213. const NAME_LICENSE = 13;
  214. /**
  215. * URL of more detailed licensing information for the font.
  216. */
  217. const NAME_LICENSE_URL = 14;
  218. /**
  219. * Preferred font family. Used by some fonts to work around a Microsoft
  220. * Windows limitation where only four fonts styles can share the same
  221. * {@link NAME_FAMILY} value.
  222. */
  223. const NAME_PREFERRED_FAMILY = 16;
  224. /**
  225. * Preferred font style. A more descriptive string than {@link NAME_STYLE}.
  226. */
  227. const NAME_PREFERRED_STYLE = 17;
  228. /**
  229. * Suggested text to use as a representative sample of the font.
  230. */
  231. const NAME_SAMPLE_TEXT = 19;
  232. /**
  233. * PostScript CID findfont name.
  234. */
  235. const NAME_CID_NAME = 20;
  236. /* Font Weights */
  237. /**
  238. * Thin font weight.
  239. */
  240. const WEIGHT_THIN = 100;
  241. /**
  242. * Extra-light (Ultra-light) font weight.
  243. */
  244. const WEIGHT_EXTRA_LIGHT = 200;
  245. /**
  246. * Light font weight.
  247. */
  248. const WEIGHT_LIGHT = 300;
  249. /**
  250. * Normal (Regular) font weight.
  251. */
  252. const WEIGHT_NORMAL = 400;
  253. /**
  254. * Medium font weight.
  255. */
  256. const WEIGHT_MEDIUM = 500;
  257. /**
  258. * Semi-bold (Demi-bold) font weight.
  259. */
  260. const WEIGHT_SEMI_BOLD = 600;
  261. /**
  262. * Bold font weight.
  263. */
  264. const WEIGHT_BOLD = 700;
  265. /**
  266. * Extra-bold (Ultra-bold) font weight.
  267. */
  268. const WEIGHT_EXTRA_BOLD = 800;
  269. /**
  270. * Black (Heavy) font weight.
  271. */
  272. const WEIGHT_BLACK = 900;
  273. /* Font Widths */
  274. /**
  275. * Ultra-condensed font width. Typically 50% of normal.
  276. */
  277. const WIDTH_ULTRA_CONDENSED = 1;
  278. /**
  279. * Extra-condensed font width. Typically 62.5% of normal.
  280. */
  281. const WIDTH_EXTRA_CONDENSED = 2;
  282. /**
  283. * Condensed font width. Typically 75% of normal.
  284. */
  285. const WIDTH_CONDENSED = 3;
  286. /**
  287. * Semi-condensed font width. Typically 87.5% of normal.
  288. */
  289. const WIDTH_SEMI_CONDENSED = 4;
  290. /**
  291. * Normal (Medium) font width.
  292. */
  293. const WIDTH_NORMAL = 5;
  294. /**
  295. * Semi-expanded font width. Typically 112.5% of normal.
  296. */
  297. const WIDTH_SEMI_EXPANDED = 6;
  298. /**
  299. * Expanded font width. Typically 125% of normal.
  300. */
  301. const WIDTH_EXPANDED = 7;
  302. /**
  303. * Extra-expanded font width. Typically 150% of normal.
  304. */
  305. const WIDTH_EXTRA_EXPANDED = 8;
  306. /**
  307. * Ultra-expanded font width. Typically 200% of normal.
  308. */
  309. const WIDTH_ULTRA_EXPANDED = 9;
  310. /* Font Embedding Options */
  311. /**
  312. * Do not embed the font in the PDF document.
  313. */
  314. const EMBED_DONT_EMBED = 0x01;
  315. /**
  316. * Embed, but do not subset the font in the PDF document.
  317. */
  318. const EMBED_DONT_SUBSET = 0x02;
  319. /**
  320. * Embed, but do not compress the font in the PDF document.
  321. */
  322. const EMBED_DONT_COMPRESS = 0x04;
  323. /**
  324. * Suppress the exception normally thrown if the font cannot be embedded
  325. * due to its copyright bits being set.
  326. */
  327. const EMBED_SUPPRESS_EMBED_EXCEPTION = 0x08;
  328. /**** Class Variables ****/
  329. /**
  330. * Array whose keys are the unique PostScript names of instantiated fonts.
  331. * The values are the font objects themselves.
  332. * @var array
  333. */
  334. private static $_fontNames = array();
  335. /**
  336. * Array whose keys are the md5 hash of the full paths on disk for parsed
  337. * fonts. The values are the font objects themselves.
  338. * @var array
  339. */
  340. private static $_fontFilePaths = array();
  341. /**** Public Interface ****/
  342. /* Factory Methods */
  343. /**
  344. * Returns a {@link Zend_Pdf_Resource_Font} object by full name.
  345. *
  346. * This is the preferred method to obtain one of the standard 14 PDF fonts.
  347. *
  348. * The result of this method is cached, preventing unnecessary duplication
  349. * of font objects. Repetitive calls for a font with the same name will
  350. * return the same object.
  351. *
  352. * The $embeddingOptions parameter allows you to set certain flags related
  353. * to font embedding. You may combine options by OR-ing them together. See
  354. * the EMBED_ constants defined in {@link Zend_Pdf_Font} for the list of
  355. * available options and their descriptions. Note that this value is only
  356. * used when creating a font for the first time. If a font with the same
  357. * name already exists, you will get that object and the options you specify
  358. * here will be ignored. This is because fonts are only embedded within the
  359. * PDF file once.
  360. *
  361. * If the font name supplied does not match the name of a previously
  362. * instantiated object and it is not one of the 14 standard PDF fonts, an
  363. * exception will be thrown.
  364. *
  365. * @param string $name Full PostScript name of font.
  366. * @param integer $embeddingOptions (optional) Options for font embedding.
  367. * @return Zend_Pdf_Resource_Font
  368. * @throws Zend_Pdf_Exception
  369. */
  370. public static function fontWithName($name, $embeddingOptions = 0)
  371. {
  372. /* First check the cache. Don't duplicate font objects.
  373. */
  374. if (isset(Zend_Pdf_Font::$_fontNames[$name])) {
  375. return Zend_Pdf_Font::$_fontNames[$name];
  376. }
  377. /**
  378. * @todo It would be cool to be able to have a mapping of font names to
  379. * file paths in a configuration file for frequently used custom
  380. * fonts. This would allow a user to use custom fonts without having
  381. * to hard-code file paths all over the place. Table this idea until
  382. * {@link Zend_Config} is ready.
  383. */
  384. /* Not an existing font and no mapping in the config file. Check to see
  385. * if this is one of the standard 14 PDF fonts.
  386. */
  387. switch ($name) {
  388. case Zend_Pdf_Font::FONT_COURIER:
  389. $font = new Zend_Pdf_Resource_Font_Simple_Standard_Courier();
  390. break;
  391. case Zend_Pdf_Font::FONT_COURIER_BOLD:
  392. $font = new Zend_Pdf_Resource_Font_Simple_Standard_CourierBold();
  393. break;
  394. case Zend_Pdf_Font::FONT_COURIER_OBLIQUE:
  395. $font = new Zend_Pdf_Resource_Font_Simple_Standard_CourierOblique();
  396. break;
  397. case Zend_Pdf_Font::FONT_COURIER_BOLD_OBLIQUE:
  398. $font = new Zend_Pdf_Resource_Font_Simple_Standard_CourierBoldOblique();
  399. break;
  400. case Zend_Pdf_Font::FONT_HELVETICA:
  401. $font = new Zend_Pdf_Resource_Font_Simple_Standard_Helvetica();
  402. break;
  403. case Zend_Pdf_Font::FONT_HELVETICA_BOLD:
  404. $font = new Zend_Pdf_Resource_Font_Simple_Standard_HelveticaBold();
  405. break;
  406. case Zend_Pdf_Font::FONT_HELVETICA_OBLIQUE:
  407. $font = new Zend_Pdf_Resource_Font_Simple_Standard_HelveticaOblique();
  408. break;
  409. case Zend_Pdf_Font::FONT_HELVETICA_BOLD_OBLIQUE:
  410. $font = new Zend_Pdf_Resource_Font_Simple_Standard_HelveticaBoldOblique();
  411. break;
  412. case Zend_Pdf_Font::FONT_SYMBOL:
  413. $font = new Zend_Pdf_Resource_Font_Simple_Standard_Symbol();
  414. break;
  415. case Zend_Pdf_Font::FONT_TIMES_ROMAN:
  416. $font = new Zend_Pdf_Resource_Font_Simple_Standard_TimesRoman();
  417. break;
  418. case Zend_Pdf_Font::FONT_TIMES_BOLD:
  419. $font = new Zend_Pdf_Resource_Font_Simple_Standard_TimesBold();
  420. break;
  421. case Zend_Pdf_Font::FONT_TIMES_ITALIC:
  422. $font = new Zend_Pdf_Resource_Font_Simple_Standard_TimesItalic();
  423. break;
  424. case Zend_Pdf_Font::FONT_TIMES_BOLD_ITALIC:
  425. $font = new Zend_Pdf_Resource_Font_Simple_Standard_TimesBoldItalic();
  426. break;
  427. case Zend_Pdf_Font::FONT_ZAPFDINGBATS:
  428. $font = new Zend_Pdf_Resource_Font_Simple_Standard_ZapfDingbats();
  429. break;
  430. default:
  431. throw new Zend_Pdf_Exception("Unknown font name: $name",
  432. Zend_Pdf_Exception::BAD_FONT_NAME);
  433. }
  434. /* Add this new font to the cache array and return it for use.
  435. */
  436. Zend_Pdf_Font::$_fontNames[$name] = $font;
  437. return $font;
  438. }
  439. /**
  440. * Returns a {@link Zend_Pdf_Resource_Font} object by file path.
  441. *
  442. * The result of this method is cached, preventing unnecessary duplication
  443. * of font objects. Repetitive calls for the font with the same path will
  444. * return the same object.
  445. *
  446. * The $embeddingOptions parameter allows you to set certain flags related
  447. * to font embedding. You may combine options by OR-ing them together. See
  448. * the EMBED_ constants defined in {@link Zend_Pdf_Font} for the list of
  449. * available options and their descriptions. Note that this value is only
  450. * used when creating a font for the first time. If a font with the same
  451. * name already exists, you will get that object and the options you specify
  452. * here will be ignored. This is because fonts are only embedded within the
  453. * PDF file once.
  454. *
  455. * If the file path supplied does not match the path of a previously
  456. * instantiated object or the font type cannot be determined, an exception
  457. * will be thrown.
  458. *
  459. * @param string $filePath Full path to the font file.
  460. * @param integer $embeddingOptions (optional) Options for font embedding.
  461. * @return Zend_Pdf_Resource_Font
  462. * @throws Zend_Pdf_Exception
  463. */
  464. public static function fontWithPath($filePath, $embeddingOptions = 0)
  465. {
  466. /* First check the cache. Don't duplicate font objects.
  467. */
  468. $filePathKey = md5($filePath);
  469. if (isset(Zend_Pdf_Font::$_fontFilePaths[$filePathKey])) {
  470. return Zend_Pdf_Font::$_fontFilePaths[$filePathKey];
  471. }
  472. /* Create a file parser data source object for this file. File path and
  473. * access permission checks are handled here.
  474. */
  475. $dataSource = new Zend_Pdf_FileParserDataSource_File($filePath);
  476. /* Attempt to determine the type of font. We can't always trust file
  477. * extensions, but try that first since it's fastest.
  478. */
  479. $fileExtension = strtolower(pathinfo($filePath, PATHINFO_EXTENSION));
  480. /* If it turns out that the file is named improperly and we guess the
  481. * wrong type, we'll get null instead of a font object.
  482. */
  483. switch ($fileExtension) {
  484. case 'ttf':
  485. $font = Zend_Pdf_Font::_extractTrueTypeFont($dataSource, $embeddingOptions);
  486. break;
  487. default:
  488. /* Unrecognized extension. Try to determine the type by actually
  489. * parsing it below.
  490. */
  491. $font = null;
  492. break;
  493. }
  494. if ($font === null) {
  495. /* There was no match for the file extension or the extension was
  496. * wrong. Attempt to detect the type of font by actually parsing it.
  497. * We'll do the checks in order of most likely format to try to
  498. * reduce the detection time.
  499. */
  500. // OpenType
  501. // TrueType
  502. if (($font === null) && ($fileExtension != 'ttf')) {
  503. $font = Zend_Pdf_Font::_extractTrueTypeFont($dataSource, $embeddingOptions);
  504. }
  505. // Type 1 PostScript
  506. // Mac OS X dfont
  507. // others?
  508. }
  509. /* Done with the data source object.
  510. */
  511. $dataSource = null;
  512. if ($font !== null) {
  513. /* Parsing was successful. Add this font instance to the cache arrays
  514. * and return it for use.
  515. */
  516. $fontName = $font->getFontName(Zend_Pdf_Font::NAME_POSTSCRIPT, '', '');
  517. Zend_Pdf_Font::$_fontNames[$fontName] = $font;
  518. $filePathKey = md5($filePath);
  519. Zend_Pdf_Font::$_fontFilePaths[$filePathKey] = $font;
  520. return $font;
  521. } else {
  522. /* The type of font could not be determined. Give up.
  523. */
  524. throw new Zend_Pdf_Exception("Cannot determine font type: $filePath",
  525. Zend_Pdf_Exception::CANT_DETERMINE_FONT_TYPE);
  526. }
  527. }
  528. /**** Internal Methods ****/
  529. /* Font Extraction Methods */
  530. /**
  531. * Attempts to extract a TrueType font from the data source.
  532. *
  533. * If the font parser throws an exception that suggests the data source
  534. * simply doesn't contain a TrueType font, catches it and returns null. If
  535. * an exception is thrown that suggests the TrueType font is corrupt or
  536. * otherwise unusable, throws that exception. If successful, returns the
  537. * font object.
  538. *
  539. * @param Zend_Pdf_FileParserDataSource $dataSource
  540. * @param integer $embeddingOptions Options for font embedding.
  541. * @return Zend_Pdf_Resource_Font_OpenType_TrueType May also return null if
  542. * the data source does not appear to contain a TrueType font.
  543. * @throws Zend_Pdf_Exception
  544. */
  545. protected static function _extractTrueTypeFont($dataSource, $embeddingOptions)
  546. {
  547. try {
  548. $fontParser = new Zend_Pdf_FileParser_Font_OpenType_TrueType($dataSource);
  549. $fontParser->parse();
  550. if ($fontParser->isAdobeLatinSubset) {
  551. $font = new Zend_Pdf_Resource_Font_Simple_Parsed_TrueType($fontParser, $embeddingOptions);
  552. } else {
  553. /* Use Composite Type 0 font which supports Unicode character mapping */
  554. $cidFont = new Zend_Pdf_Resource_Font_CidFont_TrueType($fontParser, $embeddingOptions);
  555. $font = new Zend_Pdf_Resource_Font_Type0($cidFont);
  556. }
  557. } catch (Zend_Pdf_Exception $e) {
  558. /* The following exception codes suggest that this isn't really a
  559. * TrueType font. If we caught such an exception, simply return
  560. * null. For all other cases, it probably is a TrueType font but has
  561. * a problem; throw the exception again.
  562. */
  563. $fontParser = null;
  564. switch ($e->getCode()) {
  565. case Zend_Pdf_Exception::WRONG_FONT_TYPE: // break intentionally omitted
  566. case Zend_Pdf_Exception::BAD_TABLE_COUNT: // break intentionally omitted
  567. case Zend_Pdf_Exception::BAD_MAGIC_NUMBER:
  568. return null;
  569. default:
  570. throw new Zend_Pdf_Exception($e->getMessage(), $e->getCode(), $e);
  571. }
  572. }
  573. return $font;
  574. }
  575. }