PDF Output: Do not error out when subsetting fails

PDF Output: Do not error out when the input document uses a font that
cannot be subset, such as the Symbol font. Instead print a warning and
embed the full font. Fixes #1203449 [EPUB to PDF conversion fails](https://bugs.launchpad.net/calibre/+bug/1203449)
This commit is contained in:
Kovid Goyal 2013-07-25 10:50:39 +05:30
parent ce5821eec8
commit 2b8dc4505d

View File

@ -16,7 +16,7 @@ from future_builtins import map
from calibre import as_unicode from calibre import as_unicode
from calibre.ebooks.pdf.render.common import (Array, String, Stream, from calibre.ebooks.pdf.render.common import (Array, String, Stream,
Dictionary, Name) Dictionary, Name)
from calibre.utils.fonts.sfnt.subset import pdf_subset, UnsupportedFont from calibre.utils.fonts.sfnt.subset import pdf_subset, UnsupportedFont, NoGlyphs
STANDARD_FONTS = { STANDARD_FONTS = {
'Times-Roman', 'Helvetica', 'Courier', 'Symbol', 'Times-Bold', 'Times-Roman', 'Helvetica', 'Courier', 'Symbol', 'Times-Bold',
@ -84,7 +84,6 @@ class CMap(Stream):
end end
''') ''')
def __init__(self, name, glyph_map, compress=False): def __init__(self, name, glyph_map, compress=False):
Stream.__init__(self, compress) Stream.__init__(self, compress)
current_map = OrderedDict() current_map = OrderedDict()
@ -118,7 +117,7 @@ class Font(object):
self.font_descriptor = Dictionary({ self.font_descriptor = Dictionary({
'Type': Name('FontDescriptor'), 'Type': Name('FontDescriptor'),
'FontName': Name('%s+%s'%(self.subset_tag, metrics.postscript_name)), 'FontName': Name('%s+%s'%(self.subset_tag, metrics.postscript_name)),
'Flags': 0b100, # Symbolic font 'Flags': 0b100, # Symbolic font
'FontBBox': Array(metrics.pdf_bbox), 'FontBBox': Array(metrics.pdf_bbox),
'ItalicAngle': metrics.post.italic_angle, 'ItalicAngle': metrics.post.italic_angle,
'Ascent': metrics.pdf_ascent, 'Ascent': metrics.pdf_ascent,
@ -161,6 +160,11 @@ class Font(object):
except UnsupportedFont as e: except UnsupportedFont as e:
debug('Subsetting of %s not supported, embedding full font. Error: %s'%( debug('Subsetting of %s not supported, embedding full font. Error: %s'%(
self.metrics.names.get('full_name', 'Unknown'), as_unicode(e))) 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: if self.is_otf:
self.font_stream.write(self.metrics.sfnt['CFF '].raw) self.font_stream.write(self.metrics.sfnt['CFF '].raw)
else: else:
@ -184,7 +188,7 @@ class Font(object):
widths = {g:w for g, w in widths.iteritems() if w != most_common} widths = {g:w for g, w in widths.iteritems() if w != most_common}
groups = Array() groups = Array()
for k, g in groupby(enumerate(widths.iterkeys()), lambda (i,x):i-x): for k, g in groupby(enumerate(widths.iterkeys()), lambda i_x:i_x[0]-i_x[1]):
group = list(map(itemgetter(1), g)) group = list(map(itemgetter(1), g))
gwidths = [widths[g] for g in group] gwidths = [widths[g] for g in group]
if len(set(gwidths)) == 1 and len(group) > 1: if len(set(gwidths)) == 1 and len(group) > 1:
@ -230,3 +234,4 @@ class FontManager(object):
for font in self.fonts: for font in self.fonts:
font.embed(self.objects, debug) font.embed(self.objects, debug)