mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
PDF Output: Fix font kerning issues with some TrueType fonts. Fixes #1929240 [Kerning problems with generated pdf](https://bugs.launchpad.net/calibre/+bug/1929240)
Preserve glyph ids when merging font copies in the PDF. Also merge the glyph metrics tables, not just the shape tables.
This commit is contained in:
parent
d696927d7e
commit
dfb86551f8
@ -12,25 +12,51 @@ class GlyphSizeMismatch(ValueError):
|
|||||||
|
|
||||||
|
|
||||||
def merge_truetype_fonts_for_pdf(fonts, log=None):
|
def merge_truetype_fonts_for_pdf(fonts, log=None):
|
||||||
# only merges the glyf and loca tables, ignoring all other tables
|
|
||||||
all_glyphs = {}
|
all_glyphs = {}
|
||||||
ans = fonts[0]
|
ans = fonts[0]
|
||||||
|
hmetrics_map = {}
|
||||||
|
vmetrics_map = {}
|
||||||
|
|
||||||
for font in fonts:
|
for font in fonts:
|
||||||
loca = font[b'loca']
|
loca = font[b'loca']
|
||||||
glyf = font[b'glyf']
|
glyf = font[b'glyf']
|
||||||
|
num_glyphs = font[b'maxp'].num_glyphs
|
||||||
loca.load_offsets(font[b'head'], font[b'maxp'])
|
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):
|
for glyph_id in range(len(loca.offset_map) - 1):
|
||||||
offset, sz = loca.glyph_location(glyph_id)
|
offset, sz = loca.glyph_location(glyph_id)
|
||||||
if sz > 0:
|
|
||||||
prev_glyph_data = all_glyphs.get(glyph_id)
|
prev_glyph_data = all_glyphs.get(glyph_id)
|
||||||
if prev_glyph_data is None:
|
if not prev_glyph_data:
|
||||||
all_glyphs[glyph_id] = glyf.glyph_data(offset, sz, as_raw=True)
|
all_glyphs[glyph_id] = glyf.glyph_data(offset, sz, as_raw=True)
|
||||||
else:
|
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:
|
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))
|
# raise Exception('Size mismatch for glyph id: {} prev_sz: {} sz: {}'.format(glyph_id, len(prev_glyph_data), sz))
|
||||||
if log is not None:
|
if log is not None:
|
||||||
log('Size mismatch for glyph id: {} prev_sz: {} sz: {}'.format(glyph_id, len(prev_glyph_data), sz))
|
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']
|
glyf = ans[b'glyf']
|
||||||
head = ans[b'head']
|
head = ans[b'head']
|
||||||
@ -46,4 +72,11 @@ def merge_truetype_fonts_for_pdf(fonts, log=None):
|
|||||||
head.update()
|
head.update()
|
||||||
maxp.num_glyphs = len(loca.offset_map) - 1
|
maxp.num_glyphs = len(loca.offset_map) - 1
|
||||||
maxp.update()
|
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
|
return ans
|
||||||
|
Loading…
x
Reference in New Issue
Block a user