Exemplo n.º 1
0
 def create_sfnt(self, text_item):
     get_table = partial(self.qt_hack.get_sfnt_table, text_item)
     try:
         ans = Font(Sfnt(get_table))
     except UnsupportedFont as e:
         raise UnsupportedFont('The font %s is not a valid sfnt. Error: %s'%(
             text_item.font().family(), e))
     glyph_map = self.qt_hack.get_glyph_map(text_item)
     gm = {}
     for uc, glyph_id in enumerate(glyph_map):
         if glyph_id not in gm:
             gm[glyph_id] = unichr(uc)
     ans.full_glyph_map = gm
     return ans
Exemplo n.º 2
0
 def mergeable(fonts):
     has_type0 = False
     for font in fonts:
         if font['Subtype'] == 'Type0':
             has_type0 = True
             if not font['Encoding'] or not font['Encoding'].startswith('Identity-'):
                 return False
         else:
             if not font['Data']:
                 return False
             try:
                 sfnt = Sfnt(font['Data'])
             except UnsupportedFont:
                 return False
             font['sfnt'] = sfnt
             if b'glyf' not in sfnt:
                 return False
     return has_type0
Exemplo n.º 3
0
 def create_sfnt(self, text_item):
     get_table = partial(self.qt_hack.get_sfnt_table, text_item)
     try:
         ans = Font(Sfnt(get_table))
     except UnsupportedFont as e:
         raise UnsupportedFont(
             'The font %s is not a valid sfnt. Error: %s' %
             (text_item.font().family(), e))
     glyph_map = self.qt_hack.get_glyph_map(text_item)
     gm = {}
     ans.ignore_glyphs = set()
     for uc, glyph_id in enumerate(glyph_map):
         if glyph_id not in gm:
             gm[glyph_id] = codepoint_to_chr(uc)
             if uc in (0xad, 0x200b):
                 ans.ignore_glyphs.add(glyph_id)
     ans.full_glyph_map = gm
     return ans
Exemplo n.º 4
0
def subset_fonts(pdf_doc, log):
    all_fonts = pdf_doc.list_fonts(True)
    for font in all_fonts:
        if font['Subtype'] != 'Type0' and font['Data']:
            try:
                sfnt = Sfnt(font['Data'])
            except UnsupportedFont:
                continue
            if b'glyf' not in sfnt:
                continue
            num, gen = font['Reference']
            glyphs = all_glyph_ids_in_w_arrays(
                (font['W'] or (), font['W2'] or ()), as_set=True)
            pdf_subset(sfnt, glyphs)
            data = sfnt()[0]
            log('Subset embedded font from: {} to {}'.format(
                human_readable(len(font['Data'])), human_readable(len(data))))
            pdf_doc.replace_font_data(data, num, gen)
Exemplo n.º 5
0
def subset(raw, individual_chars, ranges=(), warnings=None):
    warn = partial(do_warn, warnings)

    chars = set(map(ord, individual_chars))
    for r in ranges:
        chars |= set(xrange(ord(r[0]), ord(r[1]) + 1))

    # Always add the space character for ease of use from the command line
    if ord(' ') not in chars:
        chars.add(ord(' '))

    sfnt = Sfnt(raw)
    old_sizes = sfnt.sizes()

    # Remove the Digital Signature table since it is useless in a subset
    # font anyway
    sfnt.pop(b'DSIG', None)

    # Remove non core tables as they aren't likely to be used by renderers
    # anyway
    core_tables = {
        b'cmap', b'hhea', b'head', b'hmtx', b'maxp', b'name', b'OS/2', b'post',
        b'cvt ', b'fpgm', b'glyf', b'loca', b'prep', b'CFF ', b'VORG', b'EBDT',
        b'EBLC', b'EBSC', b'BASE', b'GSUB', b'GPOS', b'GDEF', b'JSTF', b'gasp',
        b'hdmx', b'kern', b'LTSH', b'PCLT', b'VDMX', b'vhea', b'vmtx', b'MATH'
    }
    for tag in list(sfnt):
        if tag not in core_tables:
            del sfnt[tag]

    try:
        cmap = sfnt[b'cmap']
    except KeyError:
        raise UnsupportedFont('This font has no cmap table')

    # Get mapping of chars to glyph ids for all specified chars
    character_map = cmap.get_character_map(chars)

    extra_glyphs = set()

    if b'GSUB' in sfnt:
        # Parse all substitution rules to ensure that glyphs that can be
        # substituted for the specified set of glyphs are not removed
        gsub = sfnt[b'GSUB']
        try:
            gsub.decompile()
            extra_glyphs = gsub.all_substitutions(character_map.itervalues())
        except UnsupportedFont as e:
            warn('Usupported GSUB table: %s' % e)
        except Exception as e:
            warn('Failed to decompile GSUB table:', traceback.format_exc())

    if b'loca' in sfnt and b'glyf' in sfnt:
        # TrueType Outlines
        subset_truetype(sfnt, character_map, extra_glyphs)
    elif b'CFF ' in sfnt:
        # PostScript Outlines
        subset_postscript(sfnt, character_map, extra_glyphs)
    else:
        raise UnsupportedFont('This font does not contain TrueType '
                              'or PostScript outlines')

    # Restrict the cmap table to only contain entries for the resolved glyphs
    cmap.set_character_map(character_map)

    if b'kern' in sfnt:
        try:
            sfnt[b'kern'].restrict_to_glyphs(
                frozenset(character_map.itervalues()))
        except UnsupportedFont as e:
            warn('kern table unsupported, ignoring: %s' % e)
        except Exception as e:
            warn('Subsetting of kern table failed, ignoring:',
                 traceback.format_exc())

    raw, new_sizes = sfnt()
    return raw, old_sizes, new_sizes
Exemplo n.º 6
0
        cmap = self.cmap.get_character_map(chars)
        glyph_ids = (cmap[c] for c in chars)
        pixel_size_x = stretch * pixel_size
        xscale = pixel_size_x / self.units_per_em
        return tuple(i * xscale for i in self.glyph_widths(glyph_ids))

    def glyph_widths(self, glyph_ids):
        last = len(self._advance_widths)
        return tuple(self._advance_widths[i if i < last else -1]
                     for i in glyph_ids)

    def width(self, string, pixel_size=12.0, stretch=1.0):
        'The width of the string at the specified pixel size and stretch, in pixels'
        return sum(self.advance_widths(string, pixel_size, stretch))


if __name__ == '__main__':
    import sys
    from calibre.utils.fonts.sfnt.container import Sfnt
    with open(sys.argv[-1], 'rb') as f:
        raw = f.read()
    sfnt = Sfnt(raw)
    m = FontMetrics(sfnt)
    print('Ascent:', m.pdf_ascent)
    print('Descent:', m.pdf_descent)
    print('PDF BBox:', m.pdf_bbox)
    print('CapHeight:', m.pdf_capheight)
    print('AvgWidth:', m.pdf_avg_width)
    print('ItalicAngle', m.post.italic_angle)
    print('StemV', m.pdf_stemv)
Exemplo n.º 7
0
def load_font(stream_or_path):
    raw = stream_or_path
    if hasattr(raw, 'read'):
        raw = raw.read()
    from calibre.utils.fonts.sfnt.container import Sfnt
    return Sfnt(raw)
Exemplo n.º 8
0
def subset(raw, individual_chars, ranges=(), warnings=None):
    warn = partial(do_warn, warnings)

    chars = set(map(ord, individual_chars))
    for r in ranges:
        chars |= set(xrange(ord(r[0]), ord(r[1])+1))

    # Always add the space character for ease of use from the command line
    if ord(' ') not in chars:
        chars.add(ord(' '))

    sfnt = Sfnt(raw)
    old_sizes = sfnt.sizes()

    # Remove the Digital Signature table since it is useless in a subset
    # font anyway
    sfnt.pop(b'DSIG', None)

    # Remove non core tables as they aren't likely to be used by renderers
    # anyway
    core_tables = {b'cmap', b'hhea', b'head', b'hmtx', b'maxp', b'name',
            b'OS/2', b'post', b'cvt ', b'fpgm', b'glyf', b'loca', b'prep',
            b'CFF ', b'VORG', b'EBDT', b'EBLC', b'EBSC', b'BASE', b'GSUB',
            b'GPOS', b'GDEF', b'JSTF', b'gasp', b'hdmx', b'kern', b'LTSH',
            b'PCLT', b'VDMX', b'vhea', b'vmtx', b'MATH'}
    for tag in list(sfnt):
        if tag not in core_tables:
            del sfnt[tag]

    try:
        cmap = sfnt[b'cmap']
    except KeyError:
        raise UnsupportedFont('This font has no cmap table')

    # Get mapping of chars to glyph ids for all specified chars
    character_map = cmap.get_character_map(chars)

    extra_glyphs = set()

    if b'GSUB' in sfnt:
        # Parse all substitution rules to ensure that glyphs that can be
        # substituted for the specified set of glyphs are not removed
        gsub = sfnt[b'GSUB']
        try:
            gsub.decompile()
            extra_glyphs = gsub.all_substitutions(character_map.itervalues())
        except UnsupportedFont as e:
            warn('Usupported GSUB table: %s'%e)
        except Exception as e:
            warn('Failed to decompile GSUB table:', traceback.format_exc())

    if b'loca' in sfnt and b'glyf' in sfnt:
        # TrueType Outlines
        subset_truetype(sfnt, character_map, extra_glyphs)
    elif b'CFF ' in sfnt:
        # PostScript Outlines
        subset_postscript(sfnt, character_map, extra_glyphs)
    else:
        raise UnsupportedFont('This font does not contain TrueType '
                'or PostScript outlines')

    # Restrict the cmap table to only contain entries for the resolved glyphs
    cmap.set_character_map(character_map)

    if b'kern' in sfnt:
        try:
            sfnt[b'kern'].restrict_to_glyphs(frozenset(character_map.itervalues()))
        except UnsupportedFont as e:
            warn('kern table unsupported, ignoring: %s'%e)
        except Exception as e:
            warn('Subsetting of kern table failed, ignoring:',
                    traceback.format_exc())

    raw, new_sizes = sfnt()
    return raw, old_sizes, new_sizes