diff --git a/src/calibre/utils/fonts/sfnt/merge.py b/src/calibre/utils/fonts/sfnt/merge.py index 01ed837938..49526d86d3 100644 --- a/src/calibre/utils/fonts/sfnt/merge.py +++ b/src/calibre/utils/fonts/sfnt/merge.py @@ -12,25 +12,51 @@ class GlyphSizeMismatch(ValueError): def merge_truetype_fonts_for_pdf(fonts, log=None): - # only merges the glyf and loca tables, ignoring all other tables all_glyphs = {} ans = fonts[0] + hmetrics_map = {} + vmetrics_map = {} for font in fonts: loca = font[b'loca'] glyf = font[b'glyf'] + num_glyphs = font[b'maxp'].num_glyphs loca.load_offsets(font[b'head'], font[b'maxp']) + try: + hhea = font[b'hhea'] + except KeyError: + hhea = None + else: + hhea.read_data(font[b'hmtx'], num_glyphs) + try: + vhea = font[b'vhea'] + except KeyError: + vhea = None + else: + vhea.read_data(font[b'vmtx'], num_glyphs) + for glyph_id in range(len(loca.offset_map) - 1): offset, sz = loca.glyph_location(glyph_id) - if sz > 0: - prev_glyph_data = all_glyphs.get(glyph_id) - if prev_glyph_data is None: - all_glyphs[glyph_id] = glyf.glyph_data(offset, sz, as_raw=True) - else: - if abs(sz - len(prev_glyph_data)) > 8: - # raise Exception('Size mismatch for glyph id: {} prev_sz: {} sz: {}'.format(glyph_id, len(prev_glyph_data), sz)) - if log is not None: - log('Size mismatch for glyph id: {} prev_sz: {} sz: {}'.format(glyph_id, len(prev_glyph_data), sz)) + prev_glyph_data = all_glyphs.get(glyph_id) + if not prev_glyph_data: + all_glyphs[glyph_id] = glyf.glyph_data(offset, sz, as_raw=True) + if hhea is not None: + hmetrics_map[glyph_id] = hhea.metrics_for(glyph_id) + if vhea is not None: + vmetrics_map[glyph_id] = vhea.metrics_for(glyph_id) + elif sz > 0: + if abs(sz - len(prev_glyph_data)) > 8: + # raise Exception('Size mismatch for glyph id: {} prev_sz: {} sz: {}'.format(glyph_id, len(prev_glyph_data), sz)) + if log is not None: + log('Size mismatch for glyph id: {} prev_sz: {} sz: {}'.format(glyph_id, len(prev_glyph_data), sz)) + if hhea is not None: + m = hhea.metrics_for(glyph_id) + if m != hmetrics_map[glyph_id]: + log(f'Metrics mismatch for glyph id: {glyph_id} prev: {hmetrics_map[glyph_id]} cur: {m}') + if vhea is not None: + m = vhea.metrics_for(glyph_id) + if m != vmetrics_map[glyph_id]: + log(f'Metrics mismatch for glyph id: {glyph_id} prev: {vmetrics_map[glyph_id]} cur: {m}') glyf = ans[b'glyf'] head = ans[b'head'] @@ -46,4 +72,11 @@ def merge_truetype_fonts_for_pdf(fonts, log=None): head.update() maxp.num_glyphs = len(loca.offset_map) - 1 maxp.update() + if hmetrics_map: + ans[b'hhea'].update(hmetrics_map, ans[b'hmtx']) + if vmetrics_map: + ans[b'vhea'].update(vmetrics_map, ans[b'vmtx']) + + for name in 'hdmx GPOS GSUB'.split(): + ans.pop(name.encode('ascii'), None) return ans