📄 opentype.php
字号:
<?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. * * @package Zend_Pdf * @subpackage FileParser * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com) * @license http://framework.zend.com/license/new-bsd New BSD License *//** Zend_Pdf_FileParser_Font */require_once 'Zend/Pdf/FileParser/Font.php';/** Zend_Pdf_Cmap */require_once 'Zend/Pdf/Cmap.php';/** * Abstract base class for OpenType font file parsers. * * TrueType was originally developed by Apple and was adopted as the default * font format for the Microsoft Windows platform. OpenType is an extension of * TrueType, developed jointly by Microsoft and Adobe, which adds support for * PostScript font data. * * This abstract parser class forms the foundation for concrete subclasses which * extract either TrueType or PostScript font data from the file. * * All OpenType files use big-endian byte ordering. * * The full TrueType and OpenType specifications can be found at: * <ul> * <li>{@link http://developer.apple.com/textfonts/TTRefMan/} * <li>{@link http://www.microsoft.com/typography/OTSPEC/} * <li>{@link http://partners.adobe.com/public/developer/opentype/index_spec.html} * </ul> * * @package Zend_Pdf * @subpackage FileParser * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com) * @license http://framework.zend.com/license/new-bsd New BSD License */abstract class Zend_Pdf_FileParser_Font_OpenType extends Zend_Pdf_FileParser_Font{ /**** Instance Variables ****/ /** * Stores the scaler type (font type) for the font file. See * {@link _readScalerType()}. * @var integer */ protected $_scalerType = 0; /** * Stores the byte offsets to the various information tables. * @var array */ protected $_tableDirectory = array(); /**** Public Interface ****/ /* Semi-Concrete Class Implementation */ /** * Verifies that the font file is in the expected format. * * NOTE: This method should be overridden in subclasses to check the * specific format and set $this->_isScreened! * * @throws Zend_Pdf_Exception */ public function screen() { if ($this->_isScreened) { return; } $this->_readScalerType(); } /** * Reads and parses the font data from the file on disk. * * NOTE: This method should be overridden in subclasses to add type- * specific parsing and set $this->isParsed. * * @throws Zend_Pdf_Exception */ public function parse() { if ($this->_isParsed) { return; } /* Screen the font file first, if it hasn't been done yet. */ $this->screen(); /* Start by reading the table directory. */ $this->_parseTableDirectory(); /* Then parse all of the required tables. */ $this->_parseHeadTable(); $this->_parseNameTable(); $this->_parsePostTable(); $this->_parseHheaTable(); $this->_parseMaxpTable();
$this->_parseOs2Table(); $this->_parseHmtxTable(); $this->_parseCmapTable(); /* If present, parse the optional tables. */ /** * @todo Add parser for kerning pairs. * @todo Add parser for ligatures. * @todo Add parser for other useful hinting tables. */ } /**** Internal Methods ****/ /* Parser Methods */ /** * Parses the OpenType table directory. * * The table directory contains the identifier, checksum, byte offset, and * length of each of the information tables housed in the font file. * * @throws Zend_Pdf_Exception */ protected function _parseTableDirectory() { $this->moveToOffset(4); $tableCount = $this->readUInt(2); $this->_debugLog('%d tables', $tableCount); /* Sanity check, in case we're not actually reading a OpenType file and * the first four bytes coincidentally matched an OpenType signature in * screen() above. * * There are at minimum 7 required tables: cmap, head, hhea, hmtx, maxp, * name, and post. In the current OpenType standard, only 32 table types * are defined, so use 50 as a practical limit. */ if (($tableCount < 7) || ($tableCount > 50)) { throw new Zend_Pdf_Exception('Table count not within expected range', Zend_Pdf_Exception::BAD_TABLE_COUNT); } /* Skip the next 6 bytes, which contain values to aid a binary search. */ $this->skipBytes(6); /* The directory contains four values: the name of the table, checksum, * offset to the table from the beginning of the font, and actual data * length of the table. */ for ($tableIndex = 0; $tableIndex < $tableCount; $tableIndex++) { $tableName = $this->readBytes(4); /* We ignore the checksum here for two reasons: First, the PDF viewer * will do this later anyway; Second, calculating the checksum would * require unsigned integers, which PHP does not currently provide. * We may revisit this in the future. */ $this->skipBytes(4); $tableOffset = $this->readUInt(4); $tableLength = $this->readUInt(4); $this->_debugLog('%s offset: 0x%x; length: %d', $tableName, $tableOffset, $tableLength); /* Sanity checks for offset and length values. */ $fileSize = $this->_dataSource->getSize(); if (($tableOffset < 0) || ($tableOffset > $fileSize)) { throw new Zend_Pdf_Exception("Table offset ($tableOffset) not within expected range", Zend_Pdf_Exception::INDEX_OUT_OF_RANGE); } if (($tableLength < 0) || (($tableOffset + $tableLength) > $fileSize)) { throw new Zend_Pdf_Exception("Table length ($tableLength) not within expected range", Zend_Pdf_Exception::INDEX_OUT_OF_RANGE); } $this->_tableDirectory[$tableName]['offset'] = $tableOffset; $this->_tableDirectory[$tableName]['length'] = $tableLength; } } /** * Parses the OpenType head (Font Header) table. * * The head table contains global information about the font such as the * revision number and global metrics. * * @throws Zend_Pdf_Exception */ protected function _parseHeadTable() { $this->_jumpToTable('head'); /* We can read any version 1 table. */ $tableVersion = $this->_readTableVersion(1, 1); /* Skip the font revision number and checksum adjustment. */ $this->skipBytes(8); $magicNumber = $this->readUInt(4); if ($magicNumber != 0x5f0f3cf5) { throw new Zend_Pdf_Exception('Wrong magic number. Expected: 0x5f0f3cf5; actual: ' . sprintf('%x', $magicNumber), Zend_Pdf_Exception::BAD_MAGIC_NUMBER); } /* Most of the flags we ignore, but there are a few values that are * useful for our layout routines. */ $flags = $this->readUInt(2); $this->baselineAtZero = $this->isBitSet(0, $flags); $this->useIntegerScaling = $this->isBitSet(3, $flags); $this->unitsPerEm = $this->readUInt(2); $this->_debugLog('Units per em: %d', $this->unitsPerEm); /* Skip creation and modification date/time. */ $this->skipBytes(16); $this->xMin = $this->readInt(2); $this->yMin = $this->readInt(2); $this->xMax = $this->readInt(2); $this->yMax = $this->readInt(2); $this->_debugLog('Font bounding box: %d %d %d %d', $this->xMin, $this->yMin, $this->xMax, $this->yMax); /* The style bits here must match the fsSelection bits in the OS/2 * table, if present. */ $macStyleBits = $this->readUInt(2); $this->isBold = $this->isBitSet(0, $macStyleBits); $this->isItalic = $this->isBitSet(1, $macStyleBits); /* We don't need the remainder of data in this table: smallest readable * size, font direction hint, indexToLocFormat, and glyphDataFormat. */ } /** * Parses the OpenType name (Naming) table. * * The name table contains all of the identifying strings associated with * the font such as its name, copyright, trademark, license, etc. * * @throws Zend_Pdf_Exception */ protected function _parseNameTable() { $this->_jumpToTable('name'); $baseOffset = $this->_tableDirectory['name']['offset']; /* The name table begins with a short header, followed by each of the * fixed-length name records, followed by the variable-length strings. */ /* We only understand version 0 tables. */ $tableFormat = $this->readUInt(2); if ($tableFormat != 0) { throw new Zend_Pdf_Exception("Unable to read format $tableFormat table", Zend_Pdf_Exception::DONT_UNDERSTAND_TABLE_VERSION); } $this->_debugLog('Format %d table', $tableFormat); $nameCount = $this->readUInt(2); $this->_debugLog('%d name strings', $nameCount); $storageOffset = $this->readUInt(2) + $baseOffset; $this->_debugLog('Storage offset: 0x%x', $storageOffset); /* Scan the name records for those we're interested in. We'll skip over * encodings and languages we don't understand or support. Prefer the * Microsoft Unicode encoding for a given name/language combination, but * use Mac Roman if nothing else is available. We will extract the * actual strings later. */ $nameRecords = array(); for ($nameIndex = 0; $nameIndex < $nameCount; $nameIndex++) { $platformID = $this->readUInt(2); $encodingID = $this->readUInt(2); if (! ( (($platformID == 3) && ($encodingID == 1)) || // Microsoft Unicode (($platformID == 1) && ($encodingID == 0)) // Mac Roman ) ) { $this->skipBytes(8); // Not a supported encoding. Move on. continue; } $languageID = $this->readUInt(2); $nameID = $this->readUInt(2); $nameLength = $this->readUInt(2); $nameOffset = $this->readUInt(2); $languageCode = $this->_languageCodeForPlatform($platformID, $languageID); if (is_null($languageCode)) { $this->_debugLog('Skipping languageID: 0x%x; platformID %d', $languageID, $platformID); continue; // Not a supported language. Move on. } $this->_debugLog('Adding nameID: %d; languageID: 0x%x; platformID: %d; offset: 0x%x (0x%x); length: %d', $nameID, $languageID, $platformID, $baseOffset + $nameOffset, $nameOffset, $nameLength); /* Entries in the name table are sorted by platform ID. If an entry * exists for both Mac Roman and Microsoft Unicode, the Unicode entry * will prevail since it is processed last. */ $nameRecords[$nameID][$languageCode] = array('platform' => $platformID, 'offset' => $nameOffset, 'length' => $nameLength ); } /* Now go back and extract the interesting strings. */ $fontNames = array(); foreach ($nameRecords as $name => $languages) { foreach ($languages as $language => $attributes) { $stringOffset = $storageOffset + $attributes['offset']; $this->moveToOffset($stringOffset); if ($attributes['platform'] == 3) { $string = $this->readStringUTF16($attributes['length']); } else { $string = $this->readStringMacRoman($attributes['length']); } $fontNames[$name][$language] = $string; } } $this->names = $fontNames; } /** * Parses the OpenType post (PostScript Information) table. * * The post table contains additional information required for using the font * on PostScript printers. It also contains the preferred location and
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -