%PDF- %PDF-
Direktori : /usr/lib/calibre/calibre/ebooks/oeb/polish/check/ |
Current File : //usr/lib/calibre/calibre/ebooks/oeb/polish/check/fonts.py |
#!/usr/bin/env python3 __license__ = 'GPL v3' __copyright__ = '2013, Kovid Goyal <kovid at kovidgoyal.net>' from css_parser.css import CSSRule from calibre import force_unicode from calibre.ebooks.oeb.base import OEB_DOCS, OEB_STYLES from calibre.ebooks.oeb.polish.check.base import BaseError, WARN from calibre.ebooks.oeb.polish.container import OEB_FONTS from calibre.ebooks.oeb.polish.pretty import pretty_script_or_style from calibre.ebooks.oeb.polish.fonts import change_font_in_declaration from calibre.utils.fonts.utils import get_all_font_names, is_font_embeddable, UnsupportedFont from tinycss.fonts3 import parse_font_family from polyglot.builtins import iteritems class InvalidFont(BaseError): HELP = _('This font could not be processed. It most likely will' ' not work in an e-book reader, either') def fix_sheet(sheet, css_name, font_name): changed = False for rule in sheet.cssRules: if rule.type in (CSSRule.FONT_FACE_RULE, CSSRule.STYLE_RULE): changed = change_font_in_declaration(rule.style, css_name, font_name) or changed return changed class NotEmbeddable(BaseError): level = WARN def __init__(self, name, fs_type): BaseError.__init__(self, _('The font {} is not allowed to be embedded').format(name), name) self.HELP = _('The font has a flag in its metadata ({:09b}) set indicating that it is' ' not licensed for embedding. You can ignore this warning, if you are' ' sure you have permission to embed this font.').format(fs_type) class FontAliasing(BaseError): level = WARN def __init__(self, font_name, css_name, name, line): BaseError.__init__(self, _('The CSS font-family name {0} does not match the actual font name {1}').format(css_name, font_name), name, line) self.HELP = _('The font family name specified in the CSS @font-face rule: "{0}" does' ' not match the font name inside the actual font file: "{1}". This can' ' cause problems in some viewers. You should change the CSS font name' ' to match the actual font name.').format(css_name, font_name) self.INDIVIDUAL_FIX = _('Change the font name {0} to {1} everywhere').format(css_name, font_name) self.font_name, self.css_name = font_name, css_name def __call__(self, container): changed = False for name, mt in iteritems(container.mime_map): if mt in OEB_STYLES: sheet = container.parsed(name) if fix_sheet(sheet, self.css_name, self.font_name): container.dirty(name) changed = True elif mt in OEB_DOCS: for style in container.parsed(name).xpath('//*[local-name()="style"]'): if style.get('type', 'text/css') == 'text/css' and style.text: sheet = container.parse_css(style.text) if fix_sheet(sheet, self.css_name, self.font_name): style.text = force_unicode(sheet.cssText, 'utf-8') pretty_script_or_style(container, style) container.dirty(name) changed = True for elem in container.parsed(name).xpath('//*[@style and contains(@style, "font-family")]'): style = container.parse_css(elem.get('style'), is_declaration=True) if change_font_in_declaration(style, self.css_name, self.font_name): elem.set('style', force_unicode(style.cssText, 'utf-8').replace('\n', ' ')) container.dirty(name) changed = True return changed def check_fonts(container): font_map = {} errors = [] for name, mt in iteritems(container.mime_map): if mt in OEB_FONTS: raw = container.raw_data(name) try: name_map = get_all_font_names(raw) except Exception as e: errors.append(InvalidFont(_('Not a valid font: %s') % e, name)) continue font_map[name] = name_map.get('family_name', None) or name_map.get('preferred_family_name', None) or name_map.get('wws_family_name', None) try: embeddable, fs_type = is_font_embeddable(raw) except UnsupportedFont: embeddable = True if not embeddable: errors.append(NotEmbeddable(name, fs_type)) sheets = [] for name, mt in iteritems(container.mime_map): if mt in OEB_STYLES: try: sheets.append((name, container.parsed(name), None)) except Exception: pass # Could not parse, ignore elif mt in OEB_DOCS: for style in container.parsed(name).xpath('//*[local-name()="style"]'): if style.get('type', 'text/css') == 'text/css' and style.text: sheets.append((name, container.parse_css(style.text), style.sourceline)) for name, sheet, line_offset in sheets: for rule in sheet.cssRules.rulesOfType(CSSRule.FONT_FACE_RULE): src = rule.style.getPropertyCSSValue('src') if src is not None and src.length > 0: href = getattr(src.item(0), 'uri', None) if href is not None: fname = container.href_to_name(href, name) font_name = font_map.get(fname, None) if font_name is None: continue families = parse_font_family(rule.style.getPropertyValue('font-family')) if families: if families[0] != font_name: errors.append(FontAliasing(font_name, families[0], name, line_offset)) return errors