From 833a8ca4e2a4df1132115a8ec07b0248a0394801 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Thu, 8 Nov 2012 14:07:14 +0530 Subject: [PATCH] Progress reading CFF tables --- src/calibre/utils/fonts/sfnt/cff.py | 153 -------------- src/calibre/utils/fonts/sfnt/cff/dict_data.py | 124 +++++------ src/calibre/utils/fonts/sfnt/cff/table.py | 193 +++++++++++++++++- 3 files changed, 253 insertions(+), 217 deletions(-) delete mode 100644 src/calibre/utils/fonts/sfnt/cff.py diff --git a/src/calibre/utils/fonts/sfnt/cff.py b/src/calibre/utils/fonts/sfnt/cff.py deleted file mode 100644 index 641fa17d97..0000000000 --- a/src/calibre/utils/fonts/sfnt/cff.py +++ /dev/null @@ -1,153 +0,0 @@ -#!/usr/bin/env python -# vim:fileencoding=UTF-8:ts=4:sw=4:sta:et:sts=4:fdm=marker:ai -from __future__ import (unicode_literals, division, absolute_import, - print_function) - -__license__ = 'GPL v3' -__copyright__ = '2012, Kovid Goyal ' -__docformat__ = 'restructuredtext en' - -from struct import unpack_from, unpack - -from calibre.utils.fonts.sfnt import UnknownTable -from calibre.utils.fonts.sfnt.errors import UnsupportedFont - -# Useful links -# http://www.adobe.com/content/dam/Adobe/en/devnet/font/pdfs/5176.CFF.pdf -# http://www.adobe.com/content/dam/Adobe/en/devnet/font/pdfs/5177.Type2.pdf - -class CFF(object): - - def __init__(self, raw): - (self.major_version, self.minor_version, self.header_size, - self.offset_size) = unpack_from(b'>4B', raw) - if (self.major_version, self.minor_version) != (1, 0): - raise UnsupportedFont('The CFF table has unknown version: ' - '(%d, %d)'%(self.major_version, self.minor_version)) - offset = self.header_size - - # Read Names Index - self.font_names = Index(raw, offset) - offset = self.font_names.pos - if len(self.font_names) > 1: - raise UnsupportedFont('CFF table has more than one font.') - # Read Top Dict - self.top_index = Index(raw, offset) - offset = self.top_index.pos - - # Read strings - self.strings = Strings(raw, offset) - offset = self.strings.pos - print (self.strings[len(cff_standard_strings):]) - -class Index(list): - - def __init__(self, raw, offset): - list.__init__(self) - - count = unpack_from(b'>H', raw, offset)[0] - offset += 2 - self.pos = offset - - if count > 0: - self.offset_size = unpack_from(b'>B', raw, offset)[0] - offset += 1 - if self.offset_size == 3: - offsets = [unpack(b'>L', b'\0' + raw[i:i+3])[0] - for i in xrange(offset, 3*(count+2), 3)] - else: - fmt = {1:'B', 2:'H', 4:'L'}.get(self.offset_size) - fmt = ('>%d%s'%(count+1, fmt)).encode('ascii') - offsets = unpack_from(fmt, raw, offset) - offset += self.offset_size * (count+1) - 1 - - for i in xrange(len(offsets)-1): - off, noff = offsets[i:i+2] - obj = raw[offset+i:offset+noff] - self.append(obj) - - self.pos = offset + offsets[-1] - -class Strings(Index): - - def __init__(self, raw, offset): - super(Strings, self).__init__(raw, offset) - for x in reversed(cff_standard_strings): - self.insert(0, x) - -class CFFTable(UnknownTable): - - def decompile(self): - self.cff = CFF(self.raw) - -# cff_standard_strings {{{ -# The 391 Standard Strings as used in the CFF format. -# from Adobe Technical None #5176, version 1.0, 18 March 1998 - -cff_standard_strings = [ -'.notdef', 'space', 'exclam', 'quotedbl', 'numbersign', 'dollar', 'percent', -'ampersand', 'quoteright', 'parenleft', 'parenright', 'asterisk', 'plus', -'comma', 'hyphen', 'period', 'slash', 'zero', 'one', 'two', 'three', 'four', -'five', 'six', 'seven', 'eight', 'nine', 'colon', 'semicolon', 'less', 'equal', -'greater', 'question', 'at', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', -'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', -'bracketleft', 'backslash', 'bracketright', 'asciicircum', 'underscore', -'quoteleft', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', -'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 'braceleft', -'bar', 'braceright', 'asciitilde', 'exclamdown', 'cent', 'sterling', -'fraction', 'yen', 'florin', 'section', 'currency', 'quotesingle', -'quotedblleft', 'guillemotleft', 'guilsinglleft', 'guilsinglright', 'fi', 'fl', -'endash', 'dagger', 'daggerdbl', 'periodcentered', 'paragraph', 'bullet', -'quotesinglbase', 'quotedblbase', 'quotedblright', 'guillemotright', -'ellipsis', 'perthousand', 'questiondown', 'grave', 'acute', 'circumflex', -'tilde', 'macron', 'breve', 'dotaccent', 'dieresis', 'ring', 'cedilla', -'hungarumlaut', 'ogonek', 'caron', 'emdash', 'AE', 'ordfeminine', 'Lslash', -'Oslash', 'OE', 'ordmasculine', 'ae', 'dotlessi', 'lslash', 'oslash', 'oe', -'germandbls', 'onesuperior', 'logicalnot', 'mu', 'trademark', 'Eth', 'onehalf', -'plusminus', 'Thorn', 'onequarter', 'divide', 'brokenbar', 'degree', 'thorn', -'threequarters', 'twosuperior', 'registered', 'minus', 'eth', 'multiply', -'threesuperior', 'copyright', 'Aacute', 'Acircumflex', 'Adieresis', 'Agrave', -'Aring', 'Atilde', 'Ccedilla', 'Eacute', 'Ecircumflex', 'Edieresis', 'Egrave', -'Iacute', 'Icircumflex', 'Idieresis', 'Igrave', 'Ntilde', 'Oacute', -'Ocircumflex', 'Odieresis', 'Ograve', 'Otilde', 'Scaron', 'Uacute', -'Ucircumflex', 'Udieresis', 'Ugrave', 'Yacute', 'Ydieresis', 'Zcaron', -'aacute', 'acircumflex', 'adieresis', 'agrave', 'aring', 'atilde', 'ccedilla', -'eacute', 'ecircumflex', 'edieresis', 'egrave', 'iacute', 'icircumflex', -'idieresis', 'igrave', 'ntilde', 'oacute', 'ocircumflex', 'odieresis', -'ograve', 'otilde', 'scaron', 'uacute', 'ucircumflex', 'udieresis', 'ugrave', -'yacute', 'ydieresis', 'zcaron', 'exclamsmall', 'Hungarumlautsmall', -'dollaroldstyle', 'dollarsuperior', 'ampersandsmall', 'Acutesmall', -'parenleftsuperior', 'parenrightsuperior', 'twodotenleader', 'onedotenleader', -'zerooldstyle', 'oneoldstyle', 'twooldstyle', 'threeoldstyle', 'fouroldstyle', -'fiveoldstyle', 'sixoldstyle', 'sevenoldstyle', 'eightoldstyle', -'nineoldstyle', 'commasuperior', 'threequartersemdash', 'periodsuperior', -'questionsmall', 'asuperior', 'bsuperior', 'centsuperior', 'dsuperior', -'esuperior', 'isuperior', 'lsuperior', 'msuperior', 'nsuperior', 'osuperior', -'rsuperior', 'ssuperior', 'tsuperior', 'ff', 'ffi', 'ffl', 'parenleftinferior', -'parenrightinferior', 'Circumflexsmall', 'hyphensuperior', 'Gravesmall', -'Asmall', 'Bsmall', 'Csmall', 'Dsmall', 'Esmall', 'Fsmall', 'Gsmall', 'Hsmall', -'Ismall', 'Jsmall', 'Ksmall', 'Lsmall', 'Msmall', 'Nsmall', 'Osmall', 'Psmall', -'Qsmall', 'Rsmall', 'Ssmall', 'Tsmall', 'Usmall', 'Vsmall', 'Wsmall', 'Xsmall', -'Ysmall', 'Zsmall', 'colonmonetary', 'onefitted', 'rupiah', 'Tildesmall', -'exclamdownsmall', 'centoldstyle', 'Lslashsmall', 'Scaronsmall', 'Zcaronsmall', -'Dieresissmall', 'Brevesmall', 'Caronsmall', 'Dotaccentsmall', 'Macronsmall', -'figuredash', 'hypheninferior', 'Ogoneksmall', 'Ringsmall', 'Cedillasmall', -'questiondownsmall', 'oneeighth', 'threeeighths', 'fiveeighths', -'seveneighths', 'onethird', 'twothirds', 'zerosuperior', 'foursuperior', -'fivesuperior', 'sixsuperior', 'sevensuperior', 'eightsuperior', -'ninesuperior', 'zeroinferior', 'oneinferior', 'twoinferior', 'threeinferior', -'fourinferior', 'fiveinferior', 'sixinferior', 'seveninferior', -'eightinferior', 'nineinferior', 'centinferior', 'dollarinferior', -'periodinferior', 'commainferior', 'Agravesmall', 'Aacutesmall', -'Acircumflexsmall', 'Atildesmall', 'Adieresissmall', 'Aringsmall', 'AEsmall', -'Ccedillasmall', 'Egravesmall', 'Eacutesmall', 'Ecircumflexsmall', -'Edieresissmall', 'Igravesmall', 'Iacutesmall', 'Icircumflexsmall', -'Idieresissmall', 'Ethsmall', 'Ntildesmall', 'Ogravesmall', 'Oacutesmall', -'Ocircumflexsmall', 'Otildesmall', 'Odieresissmall', 'OEsmall', 'Oslashsmall', -'Ugravesmall', 'Uacutesmall', 'Ucircumflexsmall', 'Udieresissmall', -'Yacutesmall', 'Thornsmall', 'Ydieresissmall', '001.000', '001.001', '001.002', -'001.003', 'Black', 'Bold', 'Book', 'Light', 'Medium', 'Regular', 'Roman', -'Semibold' -] -# }}} - diff --git a/src/calibre/utils/fonts/sfnt/cff/dict_data.py b/src/calibre/utils/fonts/sfnt/cff/dict_data.py index 2238a514a3..cff049fe3a 100644 --- a/src/calibre/utils/fonts/sfnt/cff/dict_data.py +++ b/src/calibre/utils/fonts/sfnt/cff/dict_data.py @@ -28,17 +28,6 @@ cff_dict_operand_encoding[255] = "reserved" real_nibbles = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '.', 'E', 'E-', None, '-'] -class SimpleConverter(object): - - def read(self, parent, value): - return value - - def write(self, parent, value): - return value - -class TODO(SimpleConverter): - pass - class Reader(dict): def read_byte(self, b0, data, index): @@ -89,20 +78,13 @@ class Dict(Reader): def __init__(self): Reader.__init__(self) - table = self.TABLE[:] - for i in xrange(len(table)): - op, name, arg, default, conv = table[i] - if conv is not None: - continue - if arg in ("delta", "array", 'number', 'SID'): - conv = SimpleConverter() - else: - raise Exception('Should not happen') - table[i] = op, name, arg, default, conv + self.operators = {op:(name, arg) for op, name, arg, default in + self.TABLE} + self.defaults = {name:default for op, name, arg, default in self.TABLE} - self.operators = {op:(name, arg) for op, name, arg, default, conv in - table} + def safe_get(self, name): + return self.get(name, self.defaults[name]) def decompile(self, strings, global_subrs, data): self.strings = strings @@ -162,40 +144,66 @@ class Dict(Reader): class TopDict(Dict): TABLE = [ - #opcode name argument type default converter - ((12, 30), 'ROS', ('SID','SID','number'), None, SimpleConverter()), - ((12, 20), 'SyntheticBase', 'number', None, None), - (0, 'version', 'SID', None, None), - (1, 'Notice', 'SID', None, None), - ((12, 0), 'Copyright', 'SID', None, None), - (2, 'FullName', 'SID', None, None), - ((12, 38), 'FontName', 'SID', None, None), - (3, 'FamilyName', 'SID', None, None), - (4, 'Weight', 'SID', None, None), - ((12, 1), 'isFixedPitch', 'number', 0, None), - ((12, 2), 'ItalicAngle', 'number', 0, None), - ((12, 3), 'UnderlinePosition', 'number', None, None), - ((12, 4), 'UnderlineThickness', 'number', 50, None), - ((12, 5), 'PaintType', 'number', 0, None), - ((12, 6), 'CharstringType', 'number', 2, None), - ((12, 7), 'FontMatrix', 'array', [0.001,0,0,0.001,0,0], None), - (13, 'UniqueID', 'number', None, None), - (5, 'FontBBox', 'array', [0,0,0,0], None), - ((12, 8), 'StrokeWidth', 'number', 0, None), - (14, 'XUID', 'array', None, None), - ((12, 21), 'PostScript', 'SID', None, None), - ((12, 22), 'BaseFontName', 'SID', None, None), - ((12, 23), 'BaseFontBlend', 'delta', None, None), - ((12, 31), 'CIDFontVersion', 'number', 0, None), - ((12, 32), 'CIDFontRevision', 'number', 0, None), - ((12, 33), 'CIDFontType', 'number', 0, None), - ((12, 34), 'CIDCount', 'number', 8720, None), - (15, 'charset', 'number', 0, TODO()), - ((12, 35), 'UIDBase', 'number', None, None), - (16, 'Encoding', 'number', 0, TODO()), - (18, 'Private', ('number','number'), None, TODO()), - ((12, 37), 'FDSelect', 'number', None, TODO()), - ((12, 36), 'FDArray', 'number', None, TODO()), - (17, 'CharStrings', 'number', None, TODO()), + #opcode name argument type default + ((12, 30), 'ROS', ('SID','SID','number'), None, ), + ((12, 20), 'SyntheticBase', 'number', None, ), + (0, 'version', 'SID', None, ), + (1, 'Notice', 'SID', None, ), + ((12, 0), 'Copyright', 'SID', None, ), + (2, 'FullName', 'SID', None, ), + ((12, 38), 'FontName', 'SID', None, ), + (3, 'FamilyName', 'SID', None, ), + (4, 'Weight', 'SID', None, ), + ((12, 1), 'isFixedPitch', 'number', 0, ), + ((12, 2), 'ItalicAngle', 'number', 0, ), + ((12, 3), 'UnderlinePosition', 'number', None, ), + ((12, 4), 'UnderlineThickness', 'number', 50, ), + ((12, 5), 'PaintType', 'number', 0, ), + ((12, 6), 'CharstringType', 'number', 2, ), + ((12, 7), 'FontMatrix', 'array', [0.001,0,0,0.001,0,0], ), + (13, 'UniqueID', 'number', None, ), + (5, 'FontBBox', 'array', [0,0,0,0], ), + ((12, 8), 'StrokeWidth', 'number', 0, ), + (14, 'XUID', 'array', None, ), + ((12, 21), 'PostScript', 'SID', None, ), + ((12, 22), 'BaseFontName', 'SID', None, ), + ((12, 23), 'BaseFontBlend', 'delta', None, ), + ((12, 31), 'CIDFontVersion', 'number', 0, ), + ((12, 32), 'CIDFontRevision', 'number', 0, ), + ((12, 33), 'CIDFontType', 'number', 0, ), + ((12, 34), 'CIDCount', 'number', 8720, ), + (15, 'charset', 'number', 0, ), + ((12, 35), 'UIDBase', 'number', None, ), + (16, 'Encoding', 'number', 0, ), + (18, 'Private', ('number','number'), None, ), + ((12, 37), 'FDSelect', 'number', None, ), + ((12, 36), 'FDArray', 'number', None, ), + (17, 'CharStrings', 'number', None, ), + ] + +class PrivateDict(Dict): + + TABLE = [ +# opcode name argument type default + (6, 'BlueValues', 'delta', None, ), + (7, 'OtherBlues', 'delta', None, ), + (8, 'FamilyBlues', 'delta', None, ), + (9, 'FamilyOtherBlues', 'delta', None, ), + ((12, 9), 'BlueScale', 'number', 0.039625, ), + ((12, 10), 'BlueShift', 'number', 7, ), + ((12, 11), 'BlueFuzz', 'number', 1, ), + (10, 'StdHW', 'number', None, ), + (11, 'StdVW', 'number', None, ), + ((12, 12), 'StemSnapH', 'delta', None, ), + ((12, 13), 'StemSnapV', 'delta', None, ), + ((12, 14), 'ForceBold', 'number', 0, ), + ((12, 15), 'ForceBoldThreshold', 'number', None, ), # deprecated + ((12, 16), 'lenIV', 'number', None, ), # deprecated + ((12, 17), 'LanguageGroup', 'number', 0, ), + ((12, 18), 'ExpansionFactor', 'number', 0.06, ), + ((12, 19), 'initialRandomSeed', 'number', 0, ), + (20, 'defaultWidthX', 'number', 0, ), + (21, 'nominalWidthX', 'number', 0, ), + (19, 'Subrs', 'number', None, ), ] diff --git a/src/calibre/utils/fonts/sfnt/cff/table.py b/src/calibre/utils/fonts/sfnt/cff/table.py index 47dc891346..bf9adfb56d 100644 --- a/src/calibre/utils/fonts/sfnt/cff/table.py +++ b/src/calibre/utils/fonts/sfnt/cff/table.py @@ -7,11 +7,12 @@ __license__ = 'GPL v3' __copyright__ = '2012, Kovid Goyal ' __docformat__ = 'restructuredtext en' -from struct import unpack_from, unpack +from struct import unpack_from, unpack, calcsize +from functools import partial from calibre.utils.fonts.sfnt import UnknownTable from calibre.utils.fonts.sfnt.errors import UnsupportedFont -from calibre.utils.fonts.sfnt.cff.dict_data import TopDict +from calibre.utils.fonts.sfnt.cff.dict_data import TopDict, PrivateDict # Useful links # http://www.adobe.com/content/dam/Adobe/en/devnet/font/pdfs/5176.CFF.pdf @@ -48,8 +49,36 @@ class CFF(object): # Decompile Top Dict self.top_dict.decompile(self.strings, self.global_subrs, self.top_index[0]) + self.is_CID = 'ROS' in self.top_dict + + # Read CharStrings (Glyph definitions) + try: + offset = self.top_dict['CharStrings'] + except KeyError: + raise ValueError('This font has no CharStrings') + cs_type = self.top_dict.safe_get('CharstringType') + if cs_type != 2: + raise UnsupportedFont('This font has unsupported CharstringType: ' + '%s'%cs_type) + self.char_strings = CharStringsIndex(raw, offset) + self.num_glyphs = len(self.char_strings) + + # Read Private Dict + self.private_dict = None + pd = self.top_dict.safe_get('Private') + if pd: + size, offset = pd + self.private_dict = PrivateDict() + self.private_dict.decompile(self.strings, self.global_subrs, + raw[offset:offset+size]) + + # Read charset (Glyph names) + self.charset = Charset(raw, self.top_dict.safe_get('charset'), + self.strings, self.num_glyphs, self.is_CID) + import pprint pprint.pprint(self.top_dict) + pprint.pprint(self.private_dict) class Index(list): @@ -66,9 +95,9 @@ class Index(list): offset += 1 if self.offset_size == 3: offsets = [unpack(b'>L', b'\0' + raw[i:i+3])[0] - for i in xrange(offset, 3*(count+2), 3)] + for i in xrange(offset, offset+3*(count+2), 3)] else: - fmt = {1:'B', 2:'H', 4:'L'}.get(self.offset_size) + fmt = {1:'B', 2:'H', 4:'L'}[self.offset_size] fmt = ('>%d%s'%(count+1, fmt)).encode('ascii') offsets = unpack_from(fmt, raw, offset) offset += self.offset_size * (count+1) - 1 @@ -78,16 +107,168 @@ class Index(list): obj = raw[offset+off:offset+noff] self.append(obj) - self.pos = offset + offsets[-1] + try: + self.pos = offset + offsets[-1] + except IndexError: + self.pos = offset class Strings(Index): def __init__(self, raw, offset): - super(Strings, self).__init__(raw, offset, prepend=cff_standard_strings) + super(Strings, self).__init__(raw, offset, prepend=[x.encode('ascii') + for x in cff_standard_strings]) + +class Charset(list): + + STANDARD_CHARSETS = [ # {{{ + # ISOAdobe + (".notdef", "space", "exclam", "quotedbl", "numbersign", "dollar", + "percent", "ampersand", "quoteright", "parenleft", "parenright", + "asterisk", "plus", "comma", "hyphen", "period", "slash", "zero", + "one", "two", "three", "four", "five", "six", "seven", "eight", "nine", + "colon", "semicolon", "less", "equal", "greater", "question", "at", + "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", + "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", + "bracketleft", "backslash", "bracketright", "asciicircum", + "underscore", "quoteleft", "a", "b", "c", "d", "e", "f", "g", "h", "i", + "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", + "x", "y", "z", "braceleft", "bar", "braceright", "asciitilde", + "exclamdown", "cent", "sterling", "fraction", "yen", "florin", + "section", "currency", "quotesingle", "quotedblleft", "guillemotleft", + "guilsinglleft", "guilsinglright", "fi", "fl", "endash", "dagger", + "daggerdbl", "periodcentered", "paragraph", "bullet", "quotesinglbase", + "quotedblbase", "quotedblright", "guillemotright", "ellipsis", + "perthousand", "questiondown", "grave", "acute", "circumflex", "tilde", + "macron", "breve", "dotaccent", "dieresis", "ring", "cedilla", + "hungarumlaut", "ogonek", "caron", "emdash", "AE", "ordfeminine", + "Lslash", "Oslash", "OE", "ordmasculine", "ae", "dotlessi", "lslash", + "oslash", "oe", "germandbls", "onesuperior", "logicalnot", "mu", + "trademark", "Eth", "onehalf", "plusminus", "Thorn", "onequarter", + "divide", "brokenbar", "degree", "thorn", "threequarters", + "twosuperior", "registered", "minus", "eth", "multiply", + "threesuperior", "copyright", "Aacute", "Acircumflex", "Adieresis", + "Agrave", "Aring", "Atilde", "Ccedilla", "Eacute", "Ecircumflex", + "Edieresis", "Egrave", "Iacute", "Icircumflex", "Idieresis", "Igrave", + "Ntilde", "Oacute", "Ocircumflex", "Odieresis", "Ograve", "Otilde", + "Scaron", "Uacute", "Ucircumflex", "Udieresis", "Ugrave", "Yacute", + "Ydieresis", "Zcaron", "aacute", "acircumflex", "adieresis", "agrave", + "aring", "atilde", "ccedilla", "eacute", "ecircumflex", "edieresis", + "egrave", "iacute", "icircumflex", "idieresis", "igrave", "ntilde", + "oacute", "ocircumflex", "odieresis", "ograve", "otilde", "scaron", + "uacute", "ucircumflex", "udieresis", "ugrave", "yacute", "ydieresis", + "zcaron"), + + # Expert + ("notdef", "space", "exclamsmall", "Hungarumlautsmall", "dollaroldstyle", + "dollarsuperior", "ampersandsmall", "Acutesmall", "parenleftsuperior", + "parenrightsuperior", "twodotenleader", "onedotenleader", "comma", + "hyphen", "period", "fraction", "zerooldstyle", "oneoldstyle", + "twooldstyle", "threeoldstyle", "fouroldstyle", "fiveoldstyle", + "sixoldstyle", "sevenoldstyle", "eightoldstyle", "nineoldstyle", + "colon", "semicolon", "commasuperior", "threequartersemdash", + "periodsuperior", "questionsmall", "asuperior", "bsuperior", + "centsuperior", "dsuperior", "esuperior", "isuperior", "lsuperior", + "msuperior", "nsuperior", "osuperior", "rsuperior", "ssuperior", + "tsuperior", "ff", "fi", "fl", "ffi", "ffl", "parenleftinferior", + "parenrightinferior", "Circumflexsmall", "hyphensuperior", + "Gravesmall", "Asmall", "Bsmall", "Csmall", "Dsmall", "Esmall", + "Fsmall", "Gsmall", "Hsmall", "Ismall", "Jsmall", "Ksmall", "Lsmall", + "Msmall", "Nsmall", "Osmall", "Psmall", "Qsmall", "Rsmall", "Ssmall", + "Tsmall", "Usmall", "Vsmall", "Wsmall", "Xsmall", "Ysmall", "Zsmall", + "colonmonetary", "onefitted", "rupiah", "Tildesmall", + "exclamdownsmall", "centoldstyle", "Lslashsmall", "Scaronsmall", + "Zcaronsmall", "Dieresissmall", "Brevesmall", "Caronsmall", + "Dotaccentsmall", "Macronsmall", "figuredash", "hypheninferior", + "Ogoneksmall", "Ringsmall", "Cedillasmall", "onequarter", "onehalf", + "threequarters", "questiondownsmall", "oneeighth", "threeeighths", + "fiveeighths", "seveneighths", "onethird", "twothirds", "zerosuperior", + "onesuperior", "twosuperior", "threesuperior", "foursuperior", + "fivesuperior", "sixsuperior", "sevensuperior", "eightsuperior", + "ninesuperior", "zeroinferior", "oneinferior", "twoinferior", + "threeinferior", "fourinferior", "fiveinferior", "sixinferior", + "seveninferior", "eightinferior", "nineinferior", "centinferior", + "dollarinferior", "periodinferior", "commainferior", "Agravesmall", + "Aacutesmall", "Acircumflexsmall", "Atildesmall", "Adieresissmall", + "Aringsmall", "AEsmall", "Ccedillasmall", "Egravesmall", "Eacutesmall", + "Ecircumflexsmall", "Edieresissmall", "Igravesmall", "Iacutesmall", + "Icircumflexsmall", "Idieresissmall", "Ethsmall", "Ntildesmall", + "Ogravesmall", "Oacutesmall", "Ocircumflexsmall", "Otildesmall", + "Odieresissmall", "OEsmall", "Oslashsmall", "Ugravesmall", + "Uacutesmall", "Ucircumflexsmall", "Udieresissmall", "Yacutesmall", + "Thornsmall", "Ydieresissmall"), + + # Expert Subset + (".notdef", "space", "dollaroldstyle", "dollarsuperior", + "parenleftsuperior", "parenrightsuperior", "twodotenleader", + "onedotenleader", "comma", "hyphen", "period", "fraction", + "zerooldstyle", "oneoldstyle", "twooldstyle", "threeoldstyle", + "fouroldstyle", "fiveoldstyle", "sixoldstyle", "sevenoldstyle", + "eightoldstyle", "nineoldstyle", "colon", "semicolon", + "commasuperior", "threequartersemdash", "periodsuperior", + "asuperior", "bsuperior", "centsuperior", "dsuperior", "esuperior", + "isuperior", "lsuperior", "msuperior", "nsuperior", "osuperior", + "rsuperior", "ssuperior", "tsuperior", "ff", "fi", "fl", "ffi", + "ffl", "parenleftinferior", "parenrightinferior", "hyphensuperior", + "colonmonetary", "onefitted", "rupiah", "centoldstyle", + "figuredash", "hypheninferior", "onequarter", "onehalf", + "threequarters", "oneeighth", "threeeighths", "fiveeighths", + "seveneighths", "onethird", "twothirds", "zerosuperior", + "onesuperior", "twosuperior", "threesuperior", "foursuperior", + "fivesuperior", "sixsuperior", "sevensuperior", "eightsuperior", + "ninesuperior", "zeroinferior", "oneinferior", "twoinferior", + "threeinferior", "fourinferior", "fiveinferior", "sixinferior", + "seveninferior", "eightinferior", "nineinferior", "centinferior", + "dollarinferior", "periodinferior", "commainferior"), + ] # }}} + + def __init__(self, raw, offset, strings, num_glyphs, is_CID): + super(Charset, self).__init__() + self.standard_charset = offset if offset in {0, 1, 2} else None + if is_CID and self.standard_charset is not None: + raise ValueError("CID font must not use a standard charset") + if self.standard_charset is None: + self.append(b'.notdef') + fmt = unpack_from(b'>B', raw, offset)[0] + offset += 1 + f = {0:self.parse_fmt0, 1:self.parse_fmt1, + 2:partial(self.parse_fmt1, is_two_byte=True)}.get(fmt, None) + if f is None: + raise UnsupportedFont('This font uses unsupported charset ' + 'table format: %d'%fmt) + f(raw, offset, strings, num_glyphs, is_CID) + + def parse_fmt0(self, raw, offset, strings, num_glyphs, is_CID): + fmt = ('>%dH'%(num_glyphs-1)).encode('ascii') + ids = unpack_from(fmt, raw, offset) + if is_CID: + ids = ('cid%05d'%x for x in ids) + else: + ids = (strings[x] for x in ids) + self.extend(ids) + + def parse_fmt1(self, raw, offset, strings, num_glyphs, is_CID, + is_two_byte=False): + fmt = b'>2H' if is_two_byte else b'>HB' + sz = calcsize(fmt) + count = 0 + while count < num_glyphs - 1: + first, nleft = unpack_from(fmt, raw, offset) + offset += sz + count += nleft + 1 + self.extend('cid%05d'%x if is_CID else strings[x] for x in + xrange(first, first + nleft+1)) + + def lookup(self, glyph_id): + if self.standard_charset is None: + return self[glyph_id] + return self.STANDARD_CHARSETS[self.standard_charset][glyph_id].encode('ascii') class GlobalSubrs(Index): pass +class CharStringsIndex(Index): + pass + class CFFTable(UnknownTable): def decompile(self):