Beispiel #1
0
def merge_font_files(fonts, log):
    # As of Qt 5.15.1 Chromium has switched to harfbuzz and dropped sfntly. It
    # now produces font descriptors whose W arrays dont match the glyph width
    # information from the hhea table, in contravention of the PDF spec. So
    # we can no longer merge font descriptors, all we can do is merge the
    # actual sfnt data streams into a single stream and subset it to contain
    # only the glyphs from all W arrays.
    # choose the largest font as the base font

    fonts.sort(key=lambda f: len(f['Data'] or b''), reverse=True)
    descendant_fonts = [f for f in fonts if f['Subtype'] != 'Type0']
    total_size = sum(len(f['Data']) for f in descendant_fonts)
    merged_sfnt = merge_truetype_fonts_for_pdf(
        tuple(f['sfnt'] for f in descendant_fonts), log)
    w_arrays = tuple(filter(None, (f['W'] for f in descendant_fonts)))
    glyph_ids = all_glyph_ids_in_w_arrays(w_arrays, as_set=True)
    h_arrays = tuple(filter(None, (f['W2'] for f in descendant_fonts)))
    glyph_ids |= all_glyph_ids_in_w_arrays(h_arrays, as_set=True)
    try:
        pdf_subset(merged_sfnt, glyph_ids)
    except NoGlyphs:
        log.warn(
            f'Subsetting of {fonts[0]["BaseFont"]} failed with no glyphs found, ignoring'
        )
    font_data = merged_sfnt()[0]
    log(f'Merged {len(fonts)} instances of {fonts[0]["BaseFont"]} reducing size from {human_readable(total_size)} to {human_readable(len(font_data))}'
        )
    return font_data, tuple(f['Reference'] for f in descendant_fonts)
Beispiel #2
0
 def embed(self, objects):
     self.font_descriptor['FontFile'+('3' if self.is_otf else '2')
                          ] = objects.add(self.font_stream)
     self.write_widths(objects)
     self.write_to_unicode(objects)
     pdf_subset(self.metrics.sfnt, self.used_glyphs)
     if self.is_otf:
         self.font_stream.write(self.metrics.sfnt['CFF '].raw)
     else:
         self.metrics.os2.zero_fstype()
         self.metrics.sfnt(self.font_stream)
Beispiel #3
0
 def embed(self, objects, debug):
     self.font_descriptor['FontFile'+('3' if self.is_otf else '2')
                          ] = objects.add(self.font_stream)
     self.write_widths(objects)
     self.write_to_unicode(objects)
     try:
         pdf_subset(self.metrics.sfnt, self.used_glyphs)
     except UnsupportedFont as e:
         debug('Subsetting of %s not supported, embedding full font. Error: %s'%(
             self.metrics.names.get('full_name', 'Unknown'), as_unicode(e)))
     if self.is_otf:
         self.font_stream.write(self.metrics.sfnt['CFF '].raw)
     else:
         self.metrics.os2.zero_fstype()
         self.metrics.sfnt(self.font_stream)
Beispiel #4
0
 def embed(self, objects, debug):
     self.font_descriptor['FontFile' +
                          ('3' if self.is_otf else '2')] = objects.add(
                              self.font_stream)
     self.write_widths(objects)
     self.write_to_unicode(objects)
     try:
         pdf_subset(self.metrics.sfnt, self.used_glyphs)
     except UnsupportedFont as e:
         debug(
             'Subsetting of %s not supported, embedding full font. Error: %s'
             % (self.metrics.names.get('full_name',
                                       'Unknown'), as_unicode(e)))
     if self.is_otf:
         self.font_stream.write(self.metrics.sfnt['CFF '].raw)
     else:
         self.metrics.os2.zero_fstype()
         self.metrics.sfnt(self.font_stream)
Beispiel #5
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)
Beispiel #6
0
 def embed(self, objects, debug):
     self.font_descriptor['FontFile'+('3' if self.is_otf else '2')
                          ] = objects.add(self.font_stream)
     self.write_widths(objects)
     self.write_to_unicode(objects)
     try:
         pdf_subset(self.metrics.sfnt, self.used_glyphs)
     except UnsupportedFont as e:
         debug('Subsetting of %s not supported, embedding full font. Error: %s'%(
             self.metrics.names.get('full_name', 'Unknown'), as_unicode(e)))
     except NoGlyphs:
         if self.used_glyphs:
             debug(
                 'Subsetting of %s failed, font appears to have no glyphs for the %d characters it is used with, some text may not be rendered in the PDF' %
                 (self.metrics.names.get('full_name', 'Unknown'), len(self.used_glyphs)))
     if self.is_otf:
         self.font_stream.write(self.metrics.sfnt['CFF '].raw)
     else:
         self.metrics.os2.zero_fstype()
         self.metrics.sfnt(self.font_stream)
Beispiel #7
0
 def embed(self, objects, debug):
     self.font_descriptor['FontFile'+('3' if self.is_otf else '2')
                          ] = objects.add(self.font_stream)
     self.write_widths(objects)
     self.write_to_unicode(objects)
     try:
         pdf_subset(self.metrics.sfnt, self.used_glyphs)
     except UnsupportedFont as e:
         debug('Subsetting of %s not supported, embedding full font. Error: %s'%(
             self.metrics.names.get('full_name', 'Unknown'), as_unicode(e)))
     except NoGlyphs:
         if self.used_glyphs:
             debug(
                 'Subsetting of %s failed, font appears to have no glyphs for the %d characters it is used with, some text may not be rendered in the PDF' %
                 (self.metrics.names.get('full_name', 'Unknown'), len(self.used_glyphs)))
     if self.is_otf:
         self.font_stream.write(self.metrics.sfnt['CFF '].raw)
     else:
         self.metrics.os2.zero_fstype()
         self.metrics.sfnt(self.font_stream)