mirror of
https://github.com/gryf/ebook-converter.git
synced 2026-01-30 10:15:45 +01:00
92 lines
3.3 KiB
Python
92 lines
3.3 KiB
Python
from struct import unpack_from
|
|
from collections import OrderedDict
|
|
|
|
from ebook_converter.utils.fonts.sfnt import UnknownTable
|
|
|
|
|
|
__license__ = 'GPL v3'
|
|
__copyright__ = '2012, Kovid Goyal <kovid at kovidgoyal.net>'
|
|
__docformat__ = 'restructuredtext en'
|
|
|
|
ARG_1_AND_2_ARE_WORDS = 0x0001 # if set args are words otherwise they are bytes
|
|
ARGS_ARE_XY_VALUES = 0x0002 # if set args are xy values, otherwise they are points
|
|
ROUND_XY_TO_GRID = 0x0004 # for the xy values if above is true
|
|
WE_HAVE_A_SCALE = 0x0008 # Sx = Sy, otherwise scale == 1.0
|
|
NON_OVERLAPPING = 0x0010 # set to same value for all components (obsolete!)
|
|
MORE_COMPONENTS = 0x0020 # indicates at least one more glyph after this one
|
|
WE_HAVE_AN_X_AND_Y_SCALE = 0x0040 # Sx, Sy
|
|
WE_HAVE_A_TWO_BY_TWO = 0x0080 # t00, t01, t10, t11
|
|
WE_HAVE_INSTRUCTIONS = 0x0100 # instructions follow
|
|
USE_MY_METRICS = 0x0200 # apply these metrics to parent glyph
|
|
OVERLAP_COMPOUND = 0x0400 # used by Apple in GX fonts
|
|
SCALED_COMPONENT_OFFSET = 0x0800 # composite designed to have the component offset scaled (designed for Apple)
|
|
UNSCALED_COMPONENT_OFFSET = 0x1000 # composite designed not to have the component offset scaled (designed for MS)
|
|
|
|
|
|
class SimpleGlyph(object):
|
|
|
|
def __init__(self, num_of_countours, raw):
|
|
self.num_of_countours = num_of_countours
|
|
self.raw = raw
|
|
# The list of glyph indices referred to by this glyph, will always be
|
|
# empty for a simple glyph and not empty for a composite glyph
|
|
self.glyph_indices = []
|
|
self.is_composite = False
|
|
|
|
def __len__(self):
|
|
return len(self.raw)
|
|
|
|
def __call__(self):
|
|
return self.raw
|
|
|
|
|
|
class CompositeGlyph(SimpleGlyph):
|
|
|
|
def __init__(self, num_of_countours, raw):
|
|
super(CompositeGlyph, self).__init__(num_of_countours, raw)
|
|
self.is_composite = True
|
|
|
|
flags = MORE_COMPONENTS
|
|
offset = 10
|
|
while flags & MORE_COMPONENTS:
|
|
flags, glyph_index = unpack_from(b'>HH', raw, offset)
|
|
self.glyph_indices.append(glyph_index)
|
|
offset += 4
|
|
if flags & ARG_1_AND_2_ARE_WORDS:
|
|
offset += 4
|
|
else:
|
|
offset += 2
|
|
if flags & WE_HAVE_A_SCALE:
|
|
offset += 2
|
|
elif flags & WE_HAVE_AN_X_AND_Y_SCALE:
|
|
offset += 4
|
|
elif flags & WE_HAVE_A_TWO_BY_TWO:
|
|
offset += 8
|
|
|
|
|
|
class GlyfTable(UnknownTable):
|
|
|
|
def glyph_data(self, offset, length, as_raw=False):
|
|
raw = self.raw[offset:offset+length]
|
|
if as_raw:
|
|
return raw
|
|
num_of_countours = unpack_from(b'>h', raw)[0] if raw else 0
|
|
if num_of_countours >= 0:
|
|
return SimpleGlyph(num_of_countours, raw)
|
|
return CompositeGlyph(num_of_countours, raw)
|
|
|
|
def update(self, sorted_glyph_map):
|
|
ans = OrderedDict()
|
|
offset = 0
|
|
block = []
|
|
for glyph_id, glyph in sorted_glyph_map.items():
|
|
raw = glyph()
|
|
pad = 4 - (len(raw) % 4)
|
|
if pad < 4:
|
|
raw += b'\0' * pad
|
|
ans[glyph_id] = offset, len(raw)
|
|
offset += len(raw)
|
|
block.append(raw)
|
|
self.raw = b''.join(block)
|
|
return ans
|