%PDF- %PDF-
Direktori : /usr/lib/calibre/calibre/utils/fonts/sfnt/cff/ |
Current File : //usr/lib/calibre/calibre/utils/fonts/sfnt/cff/dict_data.py |
#!/usr/bin/env python3 # vim:fileencoding=UTF-8:ts=4:sw=4:sta:et:sts=4:fdm=marker:ai __license__ = 'GPL v3' __copyright__ = '2012, Kovid Goyal <kovid at kovidgoyal.net>' __docformat__ = 'restructuredtext en' from struct import pack, unpack_from t1_operand_encoding = [None] * 256 t1_operand_encoding[0:32] = (32) * ["do_operator"] t1_operand_encoding[32:247] = (247 - 32) * ["read_byte"] t1_operand_encoding[247:251] = (251 - 247) * ["read_small_int1"] t1_operand_encoding[251:255] = (255 - 251) * ["read_small_int2"] t1_operand_encoding[255] = "read_long_int" t2_operand_encoding = t1_operand_encoding[:] t2_operand_encoding[28] = "read_short_int" t2_operand_encoding[255] = "read_fixed_1616" cff_dict_operand_encoding = t2_operand_encoding[:] cff_dict_operand_encoding[29] = "read_long_int" cff_dict_operand_encoding[30] = "read_real_number" cff_dict_operand_encoding[255] = "reserved" real_nibbles = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '.', 'E', 'E-', None, '-'] real_nibbles_map = {x:i for i, x in enumerate(real_nibbles)} class ByteCode(dict): def read_byte(self, b0, data, index): return b0 - 139, index def read_small_int1(self, b0, data, index): b1 = ord(data[index:index+1]) return (b0-247)*256 + b1 + 108, index+1 def read_small_int2(self, b0, data, index): b1 = ord(data[index:index+1]) return -(b0-251)*256 - b1 - 108, index+1 def read_short_int(self, b0, data, index): value, = unpack_from(b">h", data, index) return value, index+2 def read_long_int(self, b0, data, index): value, = unpack_from(b">l", data, index) return value, index+4 def read_fixed_1616(self, b0, data, index): value, = unpack_from(b">l", data, index) return value / 65536.0, index+4 def read_real_number(self, b0, data, index): number = '' while True: b = ord(data[index:index+1]) index = index + 1 nibble0 = (b & 0xf0) >> 4 nibble1 = b & 0x0f if nibble0 == 0xf: break number = number + real_nibbles[nibble0] if nibble1 == 0xf: break number = number + real_nibbles[nibble1] return float(number), index def write_float(self, f, encoding='ignored'): s = str(f).upper() if s[:2] == "0.": s = s[1:] elif s[:3] == "-0.": s = "-" + s[2:] nibbles = [] while s: c = s[0] s = s[1:] if c == "E" and s[:1] == "-": s = s[1:] c = "E-" nibbles.append(real_nibbles_map[c]) nibbles.append(0xf) if len(nibbles) % 2: nibbles.append(0xf) d = bytearray([30]) for i in range(0, len(nibbles), 2): d.append(nibbles[i] << 4 | nibbles[i+1]) return bytes(d) def write_int(self, value, encoding="cff"): four_byte_op = {'cff':29, 't1':255}.get(encoding, None) if -107 <= value <= 107: code = bytes(bytearray([value + 139])) elif 108 <= value <= 1131: value = value - 108 code = bytes(bytearray([(value >> 8) + 247, (value & 0xFF)])) elif -1131 <= value <= -108: value = -value - 108 code = bytes(bytearray([(value >> 8) + 251, (value & 0xFF)])) elif four_byte_op is None: # T2 only supports 2 byte ints code = bytes(bytearray([28])) + pack(b">h", value) else: code = bytes(bytearray([four_byte_op])) + pack(b">l", value) return code def write_offset(self, value): return bytes(bytearray([29])) + pack(b">l", value) def write_number(self, value, encoding="cff"): f = self.write_float if isinstance(value, float) else self.write_int return f(value, encoding) class Dict(ByteCode): operand_encoding = cff_dict_operand_encoding TABLE = () FILTERED = frozenset() OFFSETS = frozenset() def __init__(self): ByteCode.__init__(self) 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} def safe_get(self, name): return self.get(name, self.defaults[name]) def decompile(self, strings, global_subrs, data): self.strings = strings self.global_subrs = global_subrs self.stack = [] index = 0 while index < len(data): b0 = ord(data[index:index+1]) index += 1 handler = getattr(self, self.operand_encoding[b0]) value, index = handler(b0, data, index) if value is not None: self.stack.append(value) def do_operator(self, b0, data, index): if b0 == 12: op = (b0, ord(data[index:index+1])) index += 1 else: op = b0 operator, arg_type = self.operators[op] self.handle_operator(operator, arg_type) return None, index def handle_operator(self, operator, arg_type): if isinstance(arg_type, tuple): value = () for i in range(len(arg_type)-1, -1, -1): arg = arg_type[i] arghandler = getattr(self, 'arg_' + arg) value = (arghandler(operator),) + value else: arghandler = getattr(self, 'arg_' + arg_type) value = arghandler(operator) self[operator] = value def arg_number(self, name): return self.stack.pop() def arg_SID(self, name): return self.strings[self.stack.pop()] def arg_array(self, name): ans = self.stack[:] del self.stack[:] return ans def arg_delta(self, name): out = [] current = 0 for v in self.stack: current = current + v out.append(current) del self.stack[:] return out def compile(self, strings): data = [] for op, name, arg, default in self.TABLE: if name in self.FILTERED: continue val = self.safe_get(name) opcode = bytes(bytearray(op if isinstance(op, tuple) else [op])) if val != self.defaults[name]: self.encoding_offset = name in self.OFFSETS if isinstance(arg, tuple): if len(val) != len(arg): raise ValueError('Invalid argument %s for operator: %s' %(val, op)) for typ, v in zip(arg, val): if typ == 'SID': val = strings(val) data.append(getattr(self, 'encode_'+typ)(v)) else: if arg == 'SID': val = strings(val) data.append(getattr(self, 'encode_'+arg)(val)) data.append(opcode) self.raw = b''.join(data) return self.raw def encode_number(self, val): if self.encoding_offset: return self.write_offset(val) return self.write_number(val) def encode_SID(self, val): return self.write_int(val) def encode_array(self, val): return b''.join(map(self.encode_number, val)) def encode_delta(self, value): out = [] last = 0 for v in value: out.append(v - last) last = v return self.encode_array(out) class TopDict(Dict): TABLE = ( # 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,), ) # We will not write these operators out FILTERED = {'ROS', 'SyntheticBase', 'UniqueID', 'XUID', 'CIDFontVersion', 'CIDFontRevision', 'CIDFontType', 'CIDCount', 'UIDBase', 'Encoding', 'FDSelect', 'FDArray'} OFFSETS = {'charset', 'Encoding', 'CharStrings', 'Private'} 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,), ) OFFSETS = {'Subrs'}