Also use the new font fallback code for embedding fonts in the conversion pipeline

This commit is contained in:
Kovid Goyal 2016-11-15 12:29:10 +05:30
parent 57476aa5cb
commit 8f6f6fe4a0

View File

@ -19,9 +19,18 @@ from calibre.utils.filenames import ascii_filename
from calibre.utils.fonts.scanner import font_scanner, NoFonts from calibre.utils.fonts.scanner import font_scanner, NoFonts
def used_font(style, embedded_fonts): def font_families_from_style(style):
ff = [unicode(f) for f in style.get('font-family', []) if unicode(f).lower() not in { return [unicode(f) for f in style.get('font-family', []) if unicode(f).lower() not in {
'serif', 'sansserif', 'sans-serif', 'fantasy', 'cursive', 'monospace'}] 'serif', 'sansserif', 'sans-serif', 'fantasy', 'cursive', 'monospace'}]
def font_already_embedded(style, newly_embedded_fonts):
ff = font_families_from_style(style)
return not ff or ff[0] in newly_embedded_fonts
def used_font(style, embedded_fonts):
ff = font_families_from_style(style)
if not ff: if not ff:
return False, None return False, None
lnames = {unicode(x).lower() for x in ff} lnames = {unicode(x).lower() for x in ff}
@ -85,7 +94,7 @@ class EmbedFonts(object):
self.parser = cssutils.CSSParser(loglevel=logging.CRITICAL, log=logging.getLogger('calibre.css')) self.parser = cssutils.CSSParser(loglevel=logging.CRITICAL, log=logging.getLogger('calibre.css'))
self.warned = set() self.warned = set()
self.warned2 = set() self.warned2 = set()
self.warned3 = set() self.newly_embedded_fonts = set()
for item in oeb.spine: for item in oeb.spine:
if not hasattr(item.data, 'xpath'): if not hasattr(item.data, 'xpath'):
@ -171,7 +180,7 @@ class EmbedFonts(object):
for child in elem: for child in elem:
self.find_usage_in(child, style, ff_rules) self.find_usage_in(child, style, ff_rules)
has_font, existing = used_font(style, ff_rules) has_font, existing = used_font(style, ff_rules)
if not has_font: if not has_font or font_already_embedded(style, self.newly_embedded_fonts):
return return
if existing is None: if existing is None:
in_book = used_font(style, self.embedded_fonts)[1] in_book = used_font(style, self.embedded_fonts)[1]
@ -194,8 +203,8 @@ class EmbedFonts(object):
page_sheet.data.insertRule(rule, len(page_sheet.data.cssRules)) page_sheet.data.insertRule(rule, len(page_sheet.data.cssRules))
def embed_font(self, style): def embed_font(self, style):
ff = [unicode(f) for f in style.get('font-family', []) if unicode(f).lower() not in { from calibre.ebooks.oeb.polish.embed import find_matching_font, weight_as_number
'serif', 'sansserif', 'sans-serif', 'fantasy', 'cursive', 'monospace'}] ff = font_families_from_style(style)
if not ff: if not ff:
return return
ff = ff[0] ff = ff[0]
@ -203,21 +212,16 @@ class EmbedFonts(object):
return return
try: try:
fonts = font_scanner.fonts_for_family(ff) fonts = font_scanner.fonts_for_family(ff)
except NoFonts:
try:
fonts = font_scanner.alt_fonts_for_family(ff)
except NoFonts: except NoFonts:
self.log.warn('Failed to find fonts for family:', ff, 'not embedding') self.log.warn('Failed to find fonts for family:', ff, 'not embedding')
self.warned.add(ff) self.warned.add(ff)
return return
try: weight = weight_as_number(style.get('font-weight', '400'))
weight = int(style.get('font-weight', '400'))
except (ValueError, TypeError, AttributeError): def do_embed(f):
w = style['font-weight']
if w not in self.warned2:
self.log.warn('Invalid weight in font style: %r' % w)
self.warned2.add(w)
return
for f in fonts:
if f['weight'] == weight and f['font-style'] == style.get('font-style', 'normal') and f['font-stretch'] == style.get('font-stretch', 'normal'):
self.log('Embedding font %s from %s' % (f['full_name'], f['path']))
data = font_scanner.get_font_data(f) data = font_scanner.get_font_data(f)
name = f['full_name'] name = f['full_name']
ext = 'otf' if f['is_otf'] else 'ttf' ext = 'otf' if f['is_otf'] else 'ttf'
@ -231,12 +235,19 @@ class EmbedFonts(object):
f['font-family'], f['font-weight'], f['font-style'], f['font-stretch'], href) f['font-family'], f['font-weight'], f['font-style'], f['font-stretch'], href)
sheet = self.parser.parseString(css, validate=False) sheet = self.parser.parseString(css, validate=False)
page_sheet.data.insertRule(sheet.cssRules[0], len(page_sheet.data.cssRules)) page_sheet.data.insertRule(sheet.cssRules[0], len(page_sheet.data.cssRules))
self.newly_embedded_fonts.add(ff)
return find_font_face_rules(sheet, self.oeb)[0] return find_font_face_rules(sheet, self.oeb)[0]
else:
for f in fonts:
if f['weight'] == weight and f['font-style'] == style.get('font-style', 'normal') and f['font-stretch'] == style.get('font-stretch', 'normal'):
self.log('Embedding font %s from %s' % (f['full_name'], f['path']))
return do_embed(f)
try: try:
w = int(f['weight']) f = find_matching_font(fonts, style.get('font-weight', 'normal'), style.get('font-style', 'normal'), style.get('font-stretch', 'normal'))
except Exception: except Exception:
w = 200 if ff not in self.warned2:
if w % 100 and ((ff, w) not in self.warned3): self.log.exception('Failed to find a matching font for family', ff, 'not embedding')
self.warned3.add((ff, w)) self.warned2.add(ff)
self.log.warn('The font %s has a non-standard weight: %s, it will not be embedded' % (ff, w)) return
self.log('Embedding font %s from %s' % (f['full_name'], f['path']))
return do_embed(f)