def data(self, index, role=Qt.DisplayRole): if role == Qt.DisplayRole: row, col = index.row(), index.column() try: name = self.items[row] embedded = '✓ ' if self.font_data[name] else '' except (IndexError, KeyError): return return name if col == 1 else embedded if role == Qt.TextAlignmentRole: col = index.column() if col == 0: return Qt.AlignHCenter | Qt.AlignVCenter if role in (Qt.UserRole, Qt.UserRole + 1): row = index.row() try: name = self.items[row] except (IndexError, KeyError): return if role == Qt.UserRole: try: return font_scanner.fonts_for_family(name) except NoFonts: return [] else: return name
def embed_font(container, font, all_font_rules, report, warned): rule = matching_rule(font, all_font_rules) ff = font['font-family'] if not isinstance(ff, string_or_bytes): ff = ff[0] if rule is None: from calibre.utils.fonts.scanner import font_scanner, NoFonts if ff in warned: return try: fonts = font_scanner.fonts_for_family(ff) except NoFonts: report(_('Failed to find fonts for family: %s, not embedding') % ff) warned.add(ff) return wt = weight_as_number(font.get('font-weight')) for f in fonts: if f['weight'] == wt and f['font-style'] == font.get('font-style', 'normal') and f['font-stretch'] == font.get('font-stretch', 'normal'): return do_embed(container, f, report) f = find_matching_font(fonts, font.get('font-weight', '400'), font.get('font-style', 'normal'), font.get('font-stretch', 'normal')) wkey = ('fallback-font', ff, wt, font.get('font-style'), font.get('font-stretch')) if wkey not in warned: warned.add(wkey) format_fallback_match_report(f, ff, font, report) return do_embed(container, f, report) else: name = rule['src'] href = container.name_to_href(name) rule = {k:ff if k == 'font-family' else rule.get(k, v) for k, v in iteritems(props)} rule['src'] = 'url(%s)' % href rule['name'] = name return rule
def data(self, index, role=Qt.ItemDataRole.DisplayRole): if role == Qt.ItemDataRole.DisplayRole: row, col = index.row(), index.column() try: name = self.items[row] embedded = '✓ ' if self.font_data[name] else '' except (IndexError, KeyError): return return name if col == 1 else embedded if role == Qt.ItemDataRole.TextAlignmentRole: col = index.column() if col == 0: return Qt.AlignmentFlag.AlignHCenter | Qt.AlignmentFlag.AlignVCenter if role in (Qt.ItemDataRole.UserRole, Qt.ItemDataRole.UserRole + 1): row = index.row() try: name = self.items[row] except (IndexError, KeyError): return if role == Qt.ItemDataRole.UserRole: try: return font_scanner.fonts_for_family(name) except NoFonts: return [] else: return name
def embed_font(container, font, all_font_rules, report, warned): rule = matching_rule(font, all_font_rules) ff = font['font-family'] if not isinstance(ff, basestring): ff = ff[0] if rule is None: from calibre.utils.fonts.scanner import font_scanner, NoFonts if ff in warned: return try: fonts = font_scanner.fonts_for_family(ff) except NoFonts: report( _('Failed to find fonts for family: %s, not embedding') % ff) warned.add(ff) return wt = int(font.get('font-weight', '400')) for f in fonts: if f['weight'] == wt and f['font-style'] == font.get( 'font-style', 'normal') and f['font-stretch'] == font.get( 'font-stretch', 'normal'): report('Embedding font %s from %s' % (f['full_name'], f['path'])) data = font_scanner.get_font_data(f) fname = f['full_name'] ext = 'otf' if f['is_otf'] else 'ttf' fname = ascii_filename(fname).replace(' ', '-').replace( '(', '').replace(')', '') item = container.generate_item('fonts/%s.%s' % (fname, ext), id_prefix='font') name = container.href_to_name(item.get('href'), container.opf_name) with container.open(name, 'wb') as out: out.write(data) href = container.name_to_href(name) rule = {k: f.get(k, v) for k, v in props.iteritems()} rule['src'] = 'url(%s)' % href rule['name'] = name return rule msg = _( 'Failed to find font matching: family: %(family)s; weight: %(weight)s; style: %(style)s; stretch: %(stretch)s' ) % dict(family=ff, weight=font['font-weight'], style=font['font-style'], stretch=font['font-stretch']) if msg not in warned: warned.add(msg) report(msg) else: name = rule['src'] href = container.name_to_href(name) rule = { k: ff if k == 'font-family' else rule.get(k, v) for k, v in props.iteritems() } rule['src'] = 'url(%s)' % href rule['name'] = name return rule
def normalized_family(self): ans = self.family try: ans = font_scanner.fonts_for_family(ans)[0]['font-family'] except (NoFonts, IndexError, KeyError): pass if icu_lower(ans) == 'sansserif': ans = 'sans-serif' return ans
def embed_font(self, style): ff = [ unicode(f) for f in style.get('font-family', []) if unicode(f).lower() not in { 'serif', 'sansserif', 'sans-serif', 'fantasy', 'cursive', 'monospace' } ] if not ff: return ff = ff[0] if ff in self.warned or ff == 'inherit': return try: fonts = font_scanner.fonts_for_family(ff) except NoFonts: self.log.warn('Failed to find fonts for family:', ff, 'not embedding') self.warned.add(ff) return try: weight = int(style.get('font-weight', '400')) except (ValueError, TypeError, AttributeError): 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) name = f['full_name'] ext = 'otf' if f['is_otf'] else 'ttf' name = ascii_filename(name).replace(' ', '-').replace( '(', '').replace(')', '') fid, href = self.oeb.manifest.generate(id=u'font', href=u'fonts/%s.%s' % (name, ext)) item = self.oeb.manifest.add(fid, href, guess_type('dummy.' + ext)[0], data=data) item.unload_data_from_memory() page_sheet = self.get_page_sheet() href = page_sheet.relhref(item.href) css = '''@font-face { font-family: "%s"; font-weight: %s; font-style: %s; font-stretch: %s; src: url(%s) }''' % ( f['font-family'], f['font-weight'], f['font-style'], f['font-stretch'], href) sheet = self.parser.parseString(css, validate=False) page_sheet.data.insertRule(sheet.cssRules[0], len(page_sheet.data.cssRules)) return find_font_face_rules(sheet, self.oeb)[0]
def all(): from calibre.utils.fonts.scanner import font_scanner failed = [] unsupported = [] warnings = {} total = 0 averages = [] for family in font_scanner.find_font_families(): for font in font_scanner.fonts_for_family(family): raw = font_scanner.get_font_data(font) print('Subsetting', font['full_name'], end='\t') total += 1 try: w = [] sf, old_stats, new_stats = subset(raw, set(('a', 'b', 'c')), (), w) if w: warnings[font['full_name'] + ' (%s)' % font['path']] = w except NoGlyphs: print('No glyphs!') continue except UnsupportedFont as e: unsupported.append( (font['full_name'], font['path'], unicode_type(e))) print('Unsupported!') continue except Exception as e: print('Failed!') failed.append( (font['full_name'], font['path'], unicode_type(e))) else: averages.append( sum(itervalues(new_stats)) / sum(itervalues(old_stats)) * 100) print('Reduced to:', '%.1f' % averages[-1], '%') if unsupported: print('\n\nUnsupported:') for name, path, err in unsupported: print(name, path, err) print() if warnings: print('\n\nWarnings:') for name, w in iteritems(warnings): if w: print(name) print('', '\n\t'.join(w), sep='\t') if failed: print('\n\nFailures:') for name, path, err in failed: print(name, path, err) print() print('Average reduction to: %.1f%%' % (sum(averages) / len(averages))) print('Total:', total, 'Unsupported:', len(unsupported), 'Failed:', len(failed), 'Warnings:', len(warnings))
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 all(): from calibre.utils.fonts.scanner import font_scanner failed = [] unsupported = [] warnings = {} total = 0 averages = [] for family in font_scanner.find_font_families(): for font in font_scanner.fonts_for_family(family): raw = font_scanner.get_font_data(font) print ('Subsetting', font['full_name'], end='\t') total += 1 try: w = [] sf, old_stats, new_stats = subset(raw, set(('a', 'b', 'c')), (), w) if w: warnings[font['full_name'] + ' (%s)'%font['path']] = w except NoGlyphs: print('No glyphs!') continue except UnsupportedFont as e: unsupported.append((font['full_name'], font['path'], unicode(e))) print ('Unsupported!') continue except Exception as e: print ('Failed!') failed.append((font['full_name'], font['path'], unicode(e))) else: averages.append(sum(new_stats.itervalues())/sum(old_stats.itervalues()) * 100) print ('Reduced to:', '%.1f'%averages[-1] , '%') if unsupported: print ('\n\nUnsupported:') for name, path, err in unsupported: print (name, path, err) print() if warnings: print ('\n\nWarnings:') for name, w in warnings.iteritems(): if w: print (name) print('', '\n\t'.join(w), sep='\t') if failed: print ('\n\nFailures:') for name, path, err in failed: print (name, path, err) print() print ('Average reduction to: %.1f%%'%( sum(averages)/len(averages))) print('Total:', total, 'Unsupported:', len(unsupported), 'Failed:', len(failed), 'Warnings:', len(warnings))
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 generate_masthead(title, output_path=None, width=600, height=60): from calibre.ebooks.conversion.config import load_defaults from calibre.utils.config import tweaks fp = tweaks["generate_cover_title_font"] if not fp: fp = P("fonts/liberation/LiberationSerif-Bold.ttf") font_path = default_font = fp recs = load_defaults("mobi_output") masthead_font_family = recs.get("masthead_font", "Default") if masthead_font_family != "Default": from calibre.utils.fonts.scanner import font_scanner, NoFonts try: faces = font_scanner.fonts_for_family(masthead_font_family) except NoFonts: faces = [] if faces: font_path = faces[0]["path"] if not font_path or not os.access(font_path, os.R_OK): font_path = default_font try: from PIL import Image, ImageDraw, ImageFont Image, ImageDraw, ImageFont except ImportError: import Image, ImageDraw, ImageFont img = Image.new("RGB", (width, height), "white") draw = ImageDraw.Draw(img) try: font = ImageFont.truetype(font_path, 48, encoding="unic") except: font = ImageFont.truetype(default_font, 48, encoding="unic") text = force_unicode(title) width, height = draw.textsize(text, font=font) left = max(int((width - width) / 2.0), 0) top = max(int((height - height) / 2.0), 0) draw.text((left, top), text, fill=(0, 0, 0), font=font) if output_path is None: f = StringIO() img.save(f, "JPEG") return f.getvalue() else: with open(output_path, "wb") as f: img.save(f, "JPEG")
def generate_masthead(title, output_path=None, width=600, height=60): from calibre.ebooks.conversion.config import load_defaults from calibre.utils.config import tweaks fp = tweaks['generate_cover_title_font'] if not fp: fp = P('fonts/liberation/LiberationSerif-Bold.ttf') font_path = default_font = fp recs = load_defaults('mobi_output') masthead_font_family = recs.get('masthead_font', 'Default') if masthead_font_family != 'Default': from calibre.utils.fonts.scanner import font_scanner, NoFonts try: faces = font_scanner.fonts_for_family(masthead_font_family) except NoFonts: faces = [] if faces: font_path = faces[0]['path'] if not font_path or not os.access(font_path, os.R_OK): font_path = default_font try: from PIL import Image, ImageDraw, ImageFont Image, ImageDraw, ImageFont except ImportError: import Image, ImageDraw, ImageFont img = Image.new('RGB', (width, height), 'white') draw = ImageDraw.Draw(img) try: font = ImageFont.truetype(font_path, 48, encoding='unic') except: font = ImageFont.truetype(default_font, 48, encoding='unic') text = force_unicode(title) width, height = draw.textsize(text, font=font) left = max(int((width - width)/2.), 0) top = max(int((height - height)/2.), 0) draw.text((left, top), text, fill=(0,0,0), font=font) if output_path is None: f = StringIO() img.save(f, 'JPEG') return f.getvalue() else: with open(output_path, 'wb') as f: img.save(f, 'JPEG')
def embed_font(self, style): from calibre.ebooks.oeb.polish.embed import find_matching_font, weight_as_number ff = font_families_from_style(style) if not ff: return ff = ff[0] if ff in self.warned or ff == 'inherit': return try: fonts = font_scanner.fonts_for_family(ff) except NoFonts: self.log.warn('Failed to find fonts for family:', ff, 'not embedding') self.warned.add(ff) return weight = weight_as_number(style.get('font-weight', '400')) def do_embed(f): data = font_scanner.get_font_data(f) name = f['full_name'] ext = 'otf' if f['is_otf'] else 'ttf' name = ascii_filename(name).replace(' ', '-').replace('(', '').replace(')', '') fid, href = self.oeb.manifest.generate(id=u'font', href=u'fonts/%s.%s'%(name, ext)) item = self.oeb.manifest.add(fid, href, guess_type('dummy.'+ext)[0], data=data) item.unload_data_from_memory() page_sheet = self.get_page_sheet() href = page_sheet.relhref(item.href) css = '''@font-face { font-family: "%s"; font-weight: %s; font-style: %s; font-stretch: %s; src: url(%s) }''' % ( f['font-family'], f['font-weight'], f['font-style'], f['font-stretch'], href) sheet = self.parser.parseString(css, validate=False) page_sheet.data.insertRule(sheet.cssRules[0], len(page_sheet.data.cssRules)) return find_font_face_rules(sheet, self.oeb)[0] 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: f = find_matching_font(fonts, style.get('font-weight', 'normal'), style.get('font-style', 'normal'), style.get('font-stretch', 'normal')) except Exception: if ff not in self.warned2: self.log.exception('Failed to find a matching font for family', ff, 'not embedding') self.warned2.add(ff) return self.log('Embedding font %s from %s' % (f['full_name'], f['path'])) return do_embed(f)
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 embed_font(container, font, all_font_rules, report, warned): rule = matching_rule(font, all_font_rules) ff = font['font-family'] if not isinstance(ff, basestring): ff = ff[0] if rule is None: from calibre.utils.fonts.scanner import font_scanner, NoFonts if ff in warned: return try: fonts = font_scanner.fonts_for_family(ff) except NoFonts: report(_('Failed to find fonts for family: %s, not embedding') % ff) warned.add(ff) return wt = int(font.get('font-weight', '400')) for f in fonts: if f['weight'] == wt and f['font-style'] == font.get('font-style', 'normal') and f['font-stretch'] == font.get('font-stretch', 'normal'): report('Embedding font %s from %s' % (f['full_name'], f['path'])) data = font_scanner.get_font_data(f) fname = f['full_name'] ext = 'otf' if f['is_otf'] else 'ttf' fname = ascii_filename(fname).replace(' ', '-').replace('(', '').replace(')', '') item = container.generate_item('fonts/%s.%s'%(fname, ext), id_prefix='font') name = container.href_to_name(item.get('href'), container.opf_name) with container.open(name, 'wb') as out: out.write(data) href = container.name_to_href(name) rule = {k:f.get(k, v) for k, v in props.iteritems()} rule['src'] = 'url(%s)' % href rule['name'] = name return rule msg = _('Failed to find font matching: family: %(family)s; weight: %(weight)s; style: %(style)s; stretch: %(stretch)s') % dict( family=ff, weight=font['font-weight'], style=font['font-style'], stretch=font['font-stretch']) if msg not in warned: warned.add(msg) report(msg) else: name = rule['src'] href = container.name_to_href(name) rule = {k:ff if k == 'font-family' else rule.get(k, v) for k, v in props.iteritems()} rule['src'] = 'url(%s)' % href rule['name'] = name return rule
def embed_font(self, style): ff = [unicode(f) for f in style.get('font-family', []) if unicode(f).lower() not in { 'serif', 'sansserif', 'sans-serif', 'fantasy', 'cursive', 'monospace'}] if not ff: return ff = ff[0] if ff in self.warned or ff == 'inherit': return try: fonts = font_scanner.fonts_for_family(ff) except NoFonts: self.log.warn('Failed to find fonts for family:', ff, 'not embedding') self.warned.add(ff) return try: weight = int(style.get('font-weight', '400')) except (ValueError, TypeError, AttributeError): 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) name = f['full_name'] ext = 'otf' if f['is_otf'] else 'ttf' name = ascii_filename(name).replace(' ', '-').replace('(', '').replace(')', '') fid, href = self.oeb.manifest.generate(id=u'font', href=u'fonts/%s.%s'%(name, ext)) item = self.oeb.manifest.add(fid, href, guess_type('dummy.'+ext)[0], data=data) item.unload_data_from_memory() page_sheet = self.get_page_sheet() href = page_sheet.relhref(item.href) css = '''@font-face { font-family: "%s"; font-weight: %s; font-style: %s; font-stretch: %s; src: url(%s) }''' % ( f['font-family'], f['font-weight'], f['font-style'], f['font-stretch'], href) sheet = self.parser.parseString(css, validate=False) page_sheet.data.insertRule(sheet.cssRules[0], len(page_sheet.data.cssRules)) return find_font_face_rules(sheet, self.oeb)[0]
def has_system_fonts(name): try: return bool(font_scanner.fonts_for_family(name)) except NoFonts: return False