def get_embed_font_info(self, family, failure_critical=True): efi = [] body_font_family = None if not family: return body_font_family, efi from calibre.utils.fonts.scanner import font_scanner, NoFonts from calibre.utils.fonts.utils import panose_to_css_generic_family try: faces = font_scanner.fonts_for_family(family) except NoFonts: msg = (u'No embeddable fonts found for family: %r' % family) if failure_critical: raise ValueError(msg) self.oeb.log.warn(msg) return body_font_family, efi if not faces: msg = (u'No embeddable fonts found for family: %r' % family) if failure_critical: raise ValueError(msg) self.oeb.log.warn(msg) return body_font_family, efi for i, font in enumerate(faces): ext = 'otf' if font['is_otf'] else 'ttf' fid, href = self.oeb.manifest.generate( id=u'font', href=u'fonts/%s.%s' % (ascii_filename(font['full_name']).replace(u' ', u'-'), ext)) item = self.oeb.manifest.add(fid, href, guess_type('dummy.' + ext)[0], data=font_scanner.get_font_data(font)) item.unload_data_from_memory() cfont = { u'font-family': u'"%s"' % font['font-family'], u'panose-1': u' '.join(map(unicode_type, font['panose'])), u'src': u'url(%s)' % item.href, } if i == 0: generic_family = panose_to_css_generic_family(font['panose']) body_font_family = u"'%s',%s" % (font['font-family'], generic_family) self.oeb.log(u'Embedding font: %s' % font['font-family']) for k in (u'font-weight', u'font-style', u'font-stretch'): if font[k] != u'normal': cfont[k] = font[k] rule = '@font-face { %s }' % ('; '.join( u'%s:%s' % (k, v) for k, v in iteritems(cfont))) rule = css_parser.parseString(rule) efi.append(rule) return body_font_family, efi
def get_embed_font_info(self, family, failure_critical=True): efi = [] body_font_family = None if not family: return body_font_family, efi from calibre.utils.fonts.scanner import font_scanner, NoFonts from calibre.utils.fonts.utils import panose_to_css_generic_family try: faces = font_scanner.fonts_for_family(family) except NoFonts: msg = (u'No embeddable fonts found for family: %r'%family) if failure_critical: raise ValueError(msg) self.oeb.log.warn(msg) return body_font_family, efi if not faces: msg = (u'No embeddable fonts found for family: %r'%family) if failure_critical: raise ValueError(msg) self.oeb.log.warn(msg) return body_font_family, efi for i, font in enumerate(faces): ext = 'otf' if font['is_otf'] else 'ttf' fid, href = self.oeb.manifest.generate(id=u'font', href=u'fonts/%s.%s'%(ascii_filename(font['full_name']).replace(u' ', u'-'), ext)) item = self.oeb.manifest.add(fid, href, guess_type('dummy.'+ext)[0], data=font_scanner.get_font_data(font)) item.unload_data_from_memory() cfont = { u'font-family':u'"%s"'%font['font-family'], u'panose-1': u' '.join(map(unicode_type, font['panose'])), u'src': u'url(%s)'%item.href, } if i == 0: generic_family = panose_to_css_generic_family(font['panose']) body_font_family = u"'%s',%s"%(font['font-family'], generic_family) self.oeb.log(u'Embedding font: %s'%font['font-family']) for k in (u'font-weight', u'font-style', u'font-stretch'): if font[k] != u'normal': cfont[k] = font[k] rule = '@font-face { %s }'%('; '.join(u'%s:%s'%(k, v) for k, v in iteritems(cfont))) rule = css_parser.parseString(rule) efi.append(rule) return body_font_family, efi
def __init__(self, elem, embed_relationships, XPath, get): self.name = self.family_name = get(elem, 'w:name') self.alt_names = tuple( get(x, 'w:val') for x in XPath('./w:altName')(elem)) if self.alt_names and not has_system_fonts(self.name): for x in self.alt_names: if has_system_fonts(x): self.family_name = x break self.embedded = {} for x in ('Regular', 'Bold', 'Italic', 'BoldItalic'): for y in XPath('./w:embed%s[@r:id]' % x)(elem): rid = get(y, 'r:id') key = get(y, 'w:fontKey') subsetted = get(y, 'w:subsetted') in {'1', 'true', 'on'} if rid in embed_relationships: self.embedded[x] = Embed(embed_relationships[rid], key, subsetted) self.generic_family = 'auto' for x in XPath('./w:family[@w:val]')(elem): self.generic_family = get(x, 'w:val', 'auto') ntt = binary_property(elem, 'notTrueType', XPath, get) self.is_ttf = ntt is inherit or not ntt self.panose1 = None self.panose_name = None for x in XPath('./w:panose1[@w:val]')(elem): try: v = get(x, 'w:val') v = tuple(int(v[i:i + 2], 16) for i in range(0, len(v), 2)) except (TypeError, ValueError, IndexError): pass else: self.panose1 = v self.panose_name = panose_to_css_generic_family(v) self.css_generic_family = { 'roman': 'serif', 'swiss': 'sans-serif', 'modern': 'monospace', 'decorative': 'fantasy', 'script': 'cursive' }.get(self.generic_family, None) self.css_generic_family = self.css_generic_family or self.panose_name or 'serif'
def find_font_for_text(self, text, allowed_families={'serif', 'sans-serif'}, preferred_families=('serif', 'sans-serif', 'monospace', 'cursive', 'fantasy')): ''' Find a font on the system capable of rendering the given text. Returns a font family (as given by fonts_for_family()) that has a "normal" font and that can render the supplied text. If no such font exists, returns None. :return: (family name, faces) or None, None ''' from calibre.utils.fonts.utils import (supports_text, panose_to_css_generic_family, get_printable_characters) if not isinstance(text, unicode_type): raise TypeError(u'%r is not unicode' % text) text = get_printable_characters(text) found = {} def filter_faces(font): try: raw = self.get_font_data(font) return supports_text(raw, text) except: pass return False for family in self.find_font_families(): faces = list(filter(filter_faces, self.fonts_for_family(family))) if not faces: continue generic_family = panose_to_css_generic_family(faces[0]['panose']) if generic_family in allowed_families or generic_family == preferred_families[ 0]: return (family, faces) elif generic_family not in found: found[generic_family] = (family, faces) for f in preferred_families: if f in found: return found[f] return None, None
def get_embed_font_info(self, family, failure_critical=True): efi = [] body_font_family = None if not family: return body_font_family, efi from calibre.utils.fonts.scanner import font_scanner from calibre.utils.fonts.utils import panose_to_css_generic_family faces = font_scanner.fonts_for_family(family) if not faces: msg = u"No embeddable fonts found for family: %r" % self.opts.embed_font_family if failure_critical: raise ValueError(msg) self.oeb.log.warn(msg) return body_font_family, efi for i, font in enumerate(faces): ext = "otf" if font["is_otf"] else "ttf" fid, href = self.oeb.manifest.generate( id=u"font", href=u"fonts/%s.%s" % (ascii_filename(font["full_name"]).replace(u" ", u"-"), ext) ) item = self.oeb.manifest.add( fid, href, guess_type("dummy." + ext)[0], data=font_scanner.get_font_data(font) ) item.unload_data_from_memory() cfont = { u"font-family": u'"%s"' % font["font-family"], u"panose-1": u" ".join(map(unicode, font["panose"])), u"src": u"url(%s)" % item.href, } if i == 0: generic_family = panose_to_css_generic_family(font["panose"]) body_font_family = u"'%s',%s" % (font["font-family"], generic_family) self.oeb.log(u"Embedding font: %s" % font["font-family"]) for k in (u"font-weight", u"font-style", u"font-stretch"): if font[k] != u"normal": cfont[k] = font[k] rule = "@font-face { %s }" % ("; ".join(u"%s:%s" % (k, v) for k, v in cfont.iteritems())) rule = cssutils.parseString(rule) efi.append(rule) return body_font_family, efi
def find_font_for_text( self, text, allowed_families={"serif", "sans-serif"}, preferred_families=("serif", "sans-serif", "monospace", "cursive", "fantasy"), ): """ Find a font on the system capable of rendering the given text. Returns a font family (as given by fonts_for_family()) that has a "normal" font and that can render the supplied text. If no such font exists, returns None. :return: (family name, faces) or None, None """ from calibre.utils.fonts.utils import supports_text, panose_to_css_generic_family, get_printable_characters if not isinstance(text, unicode): raise TypeError("%r is not unicode" % text) text = get_printable_characters(text) found = {} def filter_faces(font): try: raw = self.get_font_data(font) return supports_text(raw, text) except: pass return False for family in self.find_font_families(): faces = filter(filter_faces, self.fonts_for_family(family)) if not faces: continue generic_family = panose_to_css_generic_family(faces[0]["panose"]) if generic_family in allowed_families or generic_family == preferred_families[0]: return (family, faces) elif generic_family not in found: found[generic_family] = (family, faces) for f in preferred_families: if f in found: return found[f] return None, None
def __init__(self, elem, embed_relationships, XPath, get): self.name = self.family_name = get(elem, 'w:name') self.alt_names = tuple(get(x, 'w:val') for x in XPath('./w:altName')(elem)) if self.alt_names and not has_system_fonts(self.name): for x in self.alt_names: if has_system_fonts(x): self.family_name = x break self.embedded = {} for x in ('Regular', 'Bold', 'Italic', 'BoldItalic'): for y in XPath('./w:embed%s[@r:id]' % x)(elem): rid = get(y, 'r:id') key = get(y, 'w:fontKey') subsetted = get(y, 'w:subsetted') in {'1', 'true', 'on'} if rid in embed_relationships: self.embedded[x] = Embed(embed_relationships[rid], key, subsetted) self.generic_family = 'auto' for x in XPath('./w:family[@w:val]')(elem): self.generic_family = get(x, 'w:val', 'auto') ntt = binary_property(elem, 'notTrueType', XPath, get) self.is_ttf = ntt is inherit or not ntt self.panose1 = None self.panose_name = None for x in XPath('./w:panose1[@w:val]')(elem): try: v = get(x, 'w:val') v = tuple(int(v[i:i+2], 16) for i in xrange(0, len(v), 2)) except (TypeError, ValueError, IndexError): pass else: self.panose1 = v self.panose_name = panose_to_css_generic_family(v) self.css_generic_family = {'roman':'serif', 'swiss':'sans-serif', 'modern':'monospace', 'decorative':'fantasy', 'script':'cursive'}.get(self.generic_family, None) self.css_generic_family = self.css_generic_family or self.panose_name or 'serif'