Example #1
0
    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)
Example #2
0
    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)
Example #3
0
 def get_font_family_name(self, name):
     try:
         with current_container().open(name) as f:
             f.seek(0, os.SEEK_END)
             sz = f.tell()
     except Exception:
         sz = 0
     key = name, sz
     if key not in self.font_name_cache:
         raw = current_container().raw_data(name, decode=False)
         f = QRawFont(raw, 12)
         if f.isValid():
             ans = f.familyName() + ' ' + f.styleName()
         else:
             ans = None
         self.font_name_cache[key] = ans
     return self.font_name_cache[key]
Example #4
0
    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 PyQt5.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'
Example #5
0
    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 PyQt5.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'