def handle_embedded_fonts(self): ''' Make sure all fonts are embeddable. ''' from calibre.ebooks.oeb.base import urlnormalize from calibre.utils.fonts.utils import remove_embed_restriction processed = set() for item in list(self.oeb.manifest): if not hasattr(item.data, 'cssRules'): continue for i, rule in enumerate(item.data.cssRules): if rule.type == rule.FONT_FACE_RULE: try: s = rule.style src = s.getProperty('src').propertyValue[0].uri except: continue path = item.abshref(src) ff = self.oeb.manifest.hrefs.get(urlnormalize(path), None) if ff is None: continue raw = nraw = ff.data if path not in processed: processed.add(path) try: nraw = remove_embed_restriction(raw) except: continue if nraw != raw: ff.data = nraw self.oeb.container.write(path, nraw)
def handle_embedded_fonts(self): """ On windows, Qt uses GDI which does not support OpenType (CFF) fonts, so we need to nuke references to OpenType fonts. Qt's directwrite text backend is not mature. Also make sure all fonts are embeddable. """ from calibre.ebooks.oeb.base import urlnormalize from calibre.utils.fonts.utils import remove_embed_restriction from PyQt5.Qt import QByteArray, QRawFont font_warnings = set() processed = set() is_cff = {} for item in list(self.oeb.manifest): if not hasattr(item.data, "cssRules"): continue remove = set() for i, rule in enumerate(item.data.cssRules): if rule.type == rule.FONT_FACE_RULE: try: s = rule.style src = s.getProperty("src").propertyValue[0].uri except: continue path = item.abshref(src) ff = self.oeb.manifest.hrefs.get(urlnormalize(path), None) if ff is None: continue raw = nraw = ff.data if path not in processed: processed.add(path) try: nraw = remove_embed_restriction(raw) except: continue if nraw != raw: ff.data = nraw self.oeb.container.write(path, nraw) if iswindows: if path not in is_cff: f = QRawFont(QByteArray(nraw), 12) is_cff[path] = f.isValid() and len(f.fontTable("head")) == 0 if is_cff[path]: if path not in font_warnings: font_warnings.add(path) self.log.warn("CFF OpenType fonts are not supported on windows, ignoring: %s" % path) remove.add(i) for i in sorted(remove, reverse=True): item.data.cssRules.pop(i)
def process_fonts(self): ''' Make sure all fonts are embeddable. Also remove some fonts that cause problems. ''' from calibre.ebooks.oeb.base import urlnormalize from calibre.utils.fonts.utils import remove_embed_restriction processed = set() for item in list(self.oeb.manifest): if not hasattr(item.data, 'cssRules'): continue for i, rule in enumerate(item.data.cssRules): if rule.type == rule.FONT_FACE_RULE: try: s = rule.style src = s.getProperty('src').propertyValue[0].uri except: continue path = item.abshref(src) ff = self.oeb.manifest.hrefs.get(urlnormalize(path), None) if ff is None: continue raw = nraw = ff.data if path not in processed: processed.add(path) try: nraw = remove_embed_restriction(raw) except: continue if nraw != raw: ff.data = nraw self.oeb.container.write(path, nraw) elif iswindows and rule.type == rule.STYLE_RULE: from tinycss.fonts3 import parse_font_family, serialize_font_family s = rule.style f = s.getProperty(u'font-family') if f is not None: font_families = parse_font_family( f.propertyValue.cssText) ff = [ x for x in font_families if x.lower() != u'courier' ] if len(ff) != len(font_families): if 'courier' not in self.filtered_font_warnings: # See https://bugs.launchpad.net/bugs/1665835 self.filtered_font_warnings.add(u'courier') self.log.warn( u'Removing courier font family as it does not render on windows' ) f.propertyValue.cssText = serialize_font_family( ff or [u'monospace'])
def process_fonts(self): ''' Make sure all fonts are embeddable. Also remove some fonts that causes problems. ''' from calibre.ebooks.oeb.base import urlnormalize from calibre.utils.fonts.utils import remove_embed_restriction processed = set() for item in list(self.oeb.manifest): if not hasattr(item.data, 'cssRules'): continue for i, rule in enumerate(item.data.cssRules): if rule.type == rule.FONT_FACE_RULE: try: s = rule.style src = s.getProperty('src').propertyValue[0].uri except: continue path = item.abshref(src) ff = self.oeb.manifest.hrefs.get(urlnormalize(path), None) if ff is None: continue raw = nraw = ff.data if path not in processed: processed.add(path) try: nraw = remove_embed_restriction(raw) except: continue if nraw != raw: ff.data = nraw self.oeb.container.write(path, nraw) elif iswindows and rule.type == rule.STYLE_RULE: from tinycss.fonts3 import parse_font_family, serialize_font_family s = rule.style f = s.getProperty(u'font-family') if f is not None: font_families = parse_font_family(f.propertyValue.cssText) ff = [x for x in font_families if x.lower() != u'courier'] if len(ff) != len(font_families): if 'courier' not in self.filtered_font_warnings: # See https://bugs.launchpad.net/bugs/1665835 self.filtered_font_warnings.add(u'courier') self.log.warn(u'Removing courier font family as it does not render on windows') f.propertyValue.cssText = serialize_font_family(ff or [u'monospace'])
def handle_embedded_fonts(self): ''' Because of QtWebKit's inability to handle embedded fonts correctly, we remove the embedded fonts and make them available system wide instead. If you ever move to Qt WebKit 2.3+ then this will be unnecessary. ''' from calibre.ebooks.oeb.base import urlnormalize from calibre.utils.fonts.utils import remove_embed_restriction from PyQt4.Qt import QFontDatabase, QByteArray, QRawFont, QFont # First find all @font-face rules and remove them, adding the embedded # fonts to Qt family_map = {} for item in list(self.oeb.manifest): if not hasattr(item.data, 'cssRules'): continue remove = set() for i, rule in enumerate(item.data.cssRules): if rule.type == rule.FONT_FACE_RULE: remove.add(i) try: s = rule.style src = s.getProperty('src').propertyValue[0].uri font_family = s.getProperty( 'font-family').propertyValue[0].value except: continue path = item.abshref(src) ff = self.oeb.manifest.hrefs.get(urlnormalize(path), None) if ff is None: continue raw = ff.data self.oeb.manifest.remove(ff) try: raw = remove_embed_restriction(raw) except: continue fid = QFontDatabase.addApplicationFontFromData( QByteArray(raw)) family_name = None if fid > -1: try: family_name = unicode( QFontDatabase.applicationFontFamilies(fid)[0]) except (IndexError, KeyError): pass if family_name: family_map[icu_lower(font_family)] = family_name for i in sorted(remove, reverse=True): item.data.cssRules.pop(i) # Now map the font family name specified in the css to the actual # family name of the embedded font (they may be different in general). font_warnings = set() for item in self.oeb.manifest: if not hasattr(item.data, 'cssRules'): continue for i, rule in enumerate(item.data.cssRules): if rule.type != rule.STYLE_RULE: continue ff = rule.style.getProperty('font-family') if ff is None: continue val = ff.propertyValue for i in xrange(val.length): try: k = icu_lower(val[i].value) except (AttributeError, TypeError): val[i].value = k = 'times' if k in family_map: val[i].value = family_map[k] if iswindows: # On windows, Qt uses GDI which does not support OpenType # (CFF) fonts, so we need to nuke references to OpenType # fonts. Note that you could compile QT with configure # -directwrite, but that requires atleast Vista SP2 for i in xrange(val.length): family = val[i].value if family: f = QRawFont.fromFont(QFont(family)) if len(f.fontTable('head')) == 0: if family not in font_warnings: self.log.warn( 'Ignoring unsupported font: %s' % family) font_warnings.add(family) # Either a bitmap or (more likely) a CFF font val[i].value = 'times'
def handle_embedded_fonts(self): ''' Because of QtWebKit's inability to handle embedded fonts correctly, we remove the embedded fonts and make them available system wide instead. If you ever move to Qt WebKit 2.3+ then this will be unnecessary. ''' from calibre.ebooks.oeb.base import urlnormalize from calibre.utils.fonts.utils import remove_embed_restriction from PyQt4.Qt import QFontDatabase, QByteArray, QRawFont, QFont # First find all @font-face rules and remove them, adding the embedded # fonts to Qt family_map = {} for item in list(self.oeb.manifest): if not hasattr(item.data, 'cssRules'): continue remove = set() for i, rule in enumerate(item.data.cssRules): if rule.type == rule.FONT_FACE_RULE: remove.add(i) try: s = rule.style src = s.getProperty('src').propertyValue[0].uri font_family = s.getProperty('font-family').propertyValue[0].value except: continue path = item.abshref(src) ff = self.oeb.manifest.hrefs.get(urlnormalize(path), None) if ff is None: continue raw = ff.data self.oeb.manifest.remove(ff) try: raw = remove_embed_restriction(raw) except: continue fid = QFontDatabase.addApplicationFontFromData(QByteArray(raw)) family_name = None if fid > -1: try: family_name = unicode(QFontDatabase.applicationFontFamilies(fid)[0]) except (IndexError, KeyError): pass if family_name: family_map[icu_lower(font_family)] = family_name for i in sorted(remove, reverse=True): item.data.cssRules.pop(i) # Now map the font family name specified in the css to the actual # family name of the embedded font (they may be different in general). font_warnings = set() for item in self.oeb.manifest: if not hasattr(item.data, 'cssRules'): continue for i, rule in enumerate(item.data.cssRules): if rule.type != rule.STYLE_RULE: continue ff = rule.style.getProperty('font-family') if ff is None: continue val = ff.propertyValue for i in xrange(val.length): try: k = icu_lower(val[i].value) except (AttributeError, TypeError): val[i].value = k = 'times' if k in family_map: val[i].value = family_map[k] if iswindows: # On windows, Qt uses GDI which does not support OpenType # (CFF) fonts, so we need to nuke references to OpenType # fonts. Note that you could compile QT with configure # -directwrite, but that requires atleast Vista SP2 for i in xrange(val.length): family = val[i].value if family: f = QRawFont.fromFont(QFont(family)) if len(f.fontTable('head')) == 0: if family not in font_warnings: self.log.warn('Ignoring unsupported font: %s' %family) font_warnings.add(family) # Either a bitmap or (more likely) a CFF font val[i].value = 'times'
def handle_embedded_fonts(self): ''' Because of QtWebKit's inability to handle embedded fonts correctly, we remove the embedded fonts and make them available system wide instead. If you ever move to Qt WebKit 2.3+ then this will be unnecessary. ''' from calibre.ebooks.oeb.base import urlnormalize from calibre.gui2 import must_use_qt from calibre.utils.fonts.utils import get_font_names, remove_embed_restriction from PyQt4.Qt import QFontDatabase, QByteArray # First find all @font-face rules and remove them, adding the embedded # fonts to Qt family_map = {} for item in list(self.oeb.manifest): if not hasattr(item.data, 'cssRules'): continue remove = set() for i, rule in enumerate(item.data.cssRules): if rule.type == rule.FONT_FACE_RULE: remove.add(i) try: s = rule.style src = s.getProperty('src').propertyValue[0].uri font_family = s.getProperty('font-family').propertyValue[0].value except: continue path = item.abshref(src) ff = self.oeb.manifest.hrefs.get(urlnormalize(path), None) if ff is None: continue raw = ff.data self.oeb.manifest.remove(ff) try: raw = remove_embed_restriction(raw) except: continue must_use_qt() QFontDatabase.addApplicationFontFromData(QByteArray(raw)) try: family_name = get_font_names(raw)[0] except: family_name = None if family_name: family_map[icu_lower(font_family)] = family_name for i in sorted(remove, reverse=True): item.data.cssRules.pop(i) # Now map the font family name specified in the css to the actual # family name of the embedded font (they may be different in general). for item in self.oeb.manifest: if not hasattr(item.data, 'cssRules'): continue for i, rule in enumerate(item.data.cssRules): if rule.type != rule.STYLE_RULE: continue ff = rule.style.getProperty('font-family') if ff is None: continue val = ff.propertyValue for i in xrange(val.length): k = icu_lower(val[i].value) if k in family_map: val[i].value = family_map[k]