Exemplo n.º 1
0
class HeadTable(UnknownTable):

    created = DateTimeProperty('_created')
    modified = DateTimeProperty('_modified')
    version_number = FixedProperty('_version_number')
    font_revision = FixedProperty('_font_revision')

    def __init__(self, *args, **kwargs):
        super(HeadTable, self).__init__(*args, **kwargs)

        field_types = ('_version_number', 'l', '_font_revision', 'l',
                       'checksum_adjustment', 'L', 'magic_number', 'L',
                       'flags', 'H', 'units_per_em', 'H', '_created', 'q',
                       '_modified', 'q', 'x_min', 'h', 'y_min', 'h', 'x_max',
                       'h', 'y_max', 'h', 'mac_style', 'H', 'lowest_rec_ppem',
                       'H', 'font_direction_hint', 'h', 'index_to_loc_format',
                       'h', 'glyph_data_format', 'h')

        self._fmt = ('>%s' % (''.join(field_types[1::2]))).encode('ascii')
        self._fields = field_types[0::2]

        for f, val in zip(self._fields, unpack_from(self._fmt, self.raw)):
            setattr(self, f, val)

    def update(self):
        vals = [getattr(self, f) for f in self._fields]
        self.raw = pack(self._fmt, *vals)
Exemplo n.º 2
0
class PostTable(UnknownTable):

    version_number = FixedProperty('_version')
    italic_angle = FixedProperty('_italic_angle')

    def read_data(self):
        if hasattr(self, 'underline_position'): return
        (self._version, self._italic_angle, self.underline_position,
         self.underline_thickness) = unpack_from(b'>llhh', self.raw)
Exemplo n.º 3
0
class VerticalHeader(UnknownTable):

    version_number = FixedProperty('_version_number')

    def read_data(self, vmtx):
        if hasattr(self, 'ascender'):
            return
        field_types = (
            '_version_number',
            'l',
            'ascender',
            'h',
            'descender',
            'h',
            'line_gap',
            'h',
            'advance_height_max',
            'H',
            'min_top_side_bearing',
            'h',
            'min_bottom_side_bearing',
            'h',
            'y_max_extent',
            'h',
            'caret_slope_rise',
            'h',
            'caret_slop_run',
            'h',
            'caret_offset',
            'h',
            'r1',
            'h',
            'r2',
            'h',
            'r3',
            'h',
            'r4',
            'h',
            'metric_data_format',
            'h',
            'number_of_v_metrics',
            'H',
        )

        self._fmt = ('>%s' % (''.join(field_types[1::2]))).encode('ascii')
        self._fields = field_types[0::2]

        for f, val in zip(self._fields, unpack_from(self._fmt, self.raw)):
            setattr(self, f, val)

        raw = vmtx.raw
        num = self.number_of_h_metrics
        if len(raw) < 4 * num:
            raise UnsupportedFont('The vmtx table has insufficient data')
        long_hor_metric = raw[:4 * num]
        long_hor_metric = raw[:4 * num]
        a = read_array(long_hor_metric)
        self.advance_heights = a[0::2]
        a = read_array(long_hor_metric, 'h')
        self.top_side_bearings = a[1::2]
Exemplo n.º 4
0
class MaxpTable(UnknownTable):

    version = FixedProperty('_version')

    def __init__(self, *args, **kwargs):
        super(MaxpTable, self).__init__(*args, **kwargs)

        self._fmt = b'>lH'
        self._version, self.num_glyphs = unpack_from(self._fmt, self.raw)
        self.fields = ('_version', 'num_glyphs')

        if self.version > 1.0:
            raise UnsupportedFont(
                'This font has a maxp table with version: %s' % self.version)
        if self.version == 1.0:
            self.fields = ('_version', 'num_glyphs', 'max_points',
                           'max_contours', 'max_composite_points',
                           'max_composite_contours', 'max_zones',
                           'max_twilight_points', 'max_storage',
                           'max_function_defs', 'max_instruction_defs',
                           'max_stack_elements', 'max_size_of_instructions',
                           'max_component_elements', 'max_component_depth')
            self._fmt = b'>lH' + b'H' * (len(self.fields) - 2)

            vals = unpack_from(self._fmt, self.raw)
            for f, val in zip(self.fields, vals):
                setattr(self, f, val)

    def update(self):
        vals = [getattr(self, f) for f in self._fields]
        self.raw = pack(self._fmt, *vals)
Exemplo n.º 5
0
class GSUBTable(UnknownTable):

    version = FixedProperty('_version')

    def decompile(self):
        (self._version, self.scriptlist_offset, self.featurelist_offset,
                self.lookuplist_offset) = unpack_from(b'>L3H', self.raw)
        if self._version != 0x10000:
            raise UnsupportedFont('The GSUB table has unknown version: 0x%x'%
                    self._version)

        self.script_list_table = ScriptListTable(self.raw,
                self.scriptlist_offset)
        # self.script_list_table.dump()

        self.feature_list_table = FeatureListTable(self.raw,
                self.featurelist_offset)
        # self.feature_list_table.dump()

        self.lookup_list_table = LookupListTable(self.raw,
                self.lookuplist_offset)

    def all_substitutions(self, glyph_ids):
        ans = set()
        glyph_ids = frozenset(glyph_ids)
        for lookup_table in self.lookup_list_table:
            for subtable in lookup_table:
                gids = subtable.all_substitutions(glyph_ids)
                ans |= gids
        return ans
Exemplo n.º 6
0
class HorizontalHeader(UnknownTable):

    version_number = FixedProperty('_version_number')

    def read_data(self, hmtx):
        if hasattr(self, 'ascender'): return
        field_types = (
            '_version_number',
            'l',
            'ascender',
            'h',
            'descender',
            'h',
            'line_gap',
            'h',
            'advance_width_max',
            'H',
            'min_left_size_bearing',
            'h',
            'min_right_side_bearing',
            'h',
            'x_max_extent',
            'h',
            'caret_slope_rise',
            'h',
            'caret_slop_run',
            'h',
            'caret_offset',
            'h',
            'r1',
            'h',
            'r2',
            'h',
            'r3',
            'h',
            'r4',
            'h',
            'metric_data_format',
            'h',
            'number_of_h_metrics',
            'H',
        )

        self._fmt = ('>%s' % (''.join(field_types[1::2]))).encode('ascii')
        self._fields = field_types[0::2]

        for f, val in izip(self._fields, unpack_from(self._fmt, self.raw)):
            setattr(self, f, val)

        raw = hmtx.raw
        num = self.number_of_h_metrics
        if len(raw) < 4 * num:
            raise UnsupportedFont('The hmtx table has insufficient data')
        long_hor_metric = raw[:4 * num]
        fmt = '>%dH' % (2 * num)
        entries = unpack_from(fmt.encode('ascii'), long_hor_metric)
        self.advance_widths = entries[0::2]
        fmt = '>%dh' % (2 * num)
        entries = unpack_from(fmt.encode('ascii'), long_hor_metric)
        self.left_side_bearings = entries[1::2]
Exemplo n.º 7
0
class HorizontalHeader(UnknownTable):

    version_number = FixedProperty('_version_number')
    field_types = (
        '_version_number' , 'l',
        'ascender', 'h',
        'descender', 'h',
        'line_gap', 'h',
        'advance_width_max', 'H',
        'min_left_side_bearing', 'h',
        'min_right_side_bearing', 'h',
        'x_max_extent', 'h',
        'caret_slope_rise', 'h',
        'caret_slop_run', 'h',
        'caret_offset', 'h',
        'r1', 'h',
        'r2', 'h',
        'r3', 'h',
        'r4', 'h',
        'metric_data_format', 'h',
        'number_of_h_metrics', 'H',
    )

    def read_data(self, hmtx, num_glyphs):
        self._fmt = ('>%s'%(''.join(self.field_types[1::2]))).encode('ascii')
        self._fields = self.field_types[0::2]

        for f, val in zip(self._fields, unpack_from(self._fmt, self.raw)):
            setattr(self, f, val)

        self.advance_widths, self.left_side_bearings = read_metrics(hmtx.raw, self.number_of_h_metrics, num_glyphs, 'hmtx')

    def metrics_for(self, glyph_id):
        lsb = self.left_side_bearings[glyph_id]
        if glyph_id >= len(self.advance_widths):
            glyph_id = -1
        return self.advance_widths[glyph_id], lsb

    def update(self, metrics_map, mtx_table):
        aw, b = update_metrics_table(metrics_map, mtx_table)
        self.advance_widths = aw
        self.left_side_bearings = b
        self.number_of_h_metrics = len(metrics_map)
        self.advance_width_max = max(aw or (0,))
        self.min_left_side_bearing = min(b or (0,))
        data = (getattr(self, x) for x in self._fields)
        self.raw = pack('>' + ''.join(self.field_types[1::2]), *data)
Exemplo n.º 8
0
class KernTable(UnknownTable):

    version = FixedProperty('_version')

    def __init__(self, *args, **kwargs):
        super(KernTable, self).__init__(*args, **kwargs)
        self._version, self.num_tables = unpack_from(b'>HH', self.raw)
        if self._version == 1 and len(self.raw) >= 8:
            self._version, self.num_tables = unpack_from(b'>LL', self.raw)
        self.headerfmt = b'>HH' if self._version == 0 else b'>LL'

    def restrict_to_glyphs(self, glyph_ids):
        if self._version not in {0, 0x10000}:
            raise UnsupportedFont('kern table has version: %x' % self._version)
        offset = 4 if (self._version == 0) else 8
        tables = []
        for i in range(self.num_tables):
            if self._version == 0:
                version, length, coverage = unpack_from(
                    b'>3H', self.raw, offset)
                table_format = version
            else:
                length, coverage = unpack_from(b'>LH', self.raw, offset)
                table_format = coverage & 0xff
            raw = self.raw[offset:offset + length]
            if table_format == 0:
                raw = self.restrict_format_0(raw, glyph_ids)
                if not raw:
                    continue
            tables.append(raw)
            offset += length
        self.raw = pack(self.headerfmt, self._version,
                        len(tables)) + b''.join(tables)

    def restrict_format_0(self, raw, glyph_ids):
        if self._version == 0:
            version, length, coverage, npairs = unpack_from(b'>4H', raw)
            headerfmt = b'>3H'
        else:
            length, coverage, tuple_index, npairs = unpack_from(b'>L3H', raw)
            headerfmt = b'>L2H'

        offset = calcsize(headerfmt + b'4H')
        entries = []
        entrysz = calcsize(b'>2Hh')
        for i in range(npairs):
            try:
                left, right, value = unpack_from(b'>2Hh', raw, offset)
            except struct_error:
                offset = len(raw)
                break  # Buggy kern table
            if left in glyph_ids and right in glyph_ids:
                entries.append(pack(b'>2Hh', left, right, value))
            offset += entrysz

        if offset != len(raw):
            raise UnsupportedFont('This font has extra data at the end of'
                                  ' a Format 0 kern subtable')

        npairs = len(entries)
        if npairs == 0:
            return b''

        entry_selector = max_power_of_two(npairs)
        search_range = (2**entry_selector) * 6
        range_shift = (npairs - (2**entry_selector)) * 6

        entries = b''.join(entries)
        length = calcsize(headerfmt + b'4H') + len(entries)
        if self._version == 0:
            header = pack(headerfmt, version, length, coverage)
        else:
            header = pack(headerfmt, length, coverage, tuple_index)
        return header + pack(b'>4H', npairs, search_range, entry_selector,
                             range_shift) + entries