mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
E-book viewer: Add workaround for Qt embedded font bug (at least for ebooks that put all their css in .css files, such as ebooks generated by calibre)
This commit is contained in:
parent
dd97a1b705
commit
3a5a616226
@ -22,7 +22,6 @@ from calibre.utils.logging import default_log
|
|||||||
from calibre import (guess_type, prepare_string_for_xml,
|
from calibre import (guess_type, prepare_string_for_xml,
|
||||||
xml_replace_entities)
|
xml_replace_entities)
|
||||||
from calibre.ebooks.oeb.transforms.cover import CoverManager
|
from calibre.ebooks.oeb.transforms.cover import CoverManager
|
||||||
|
|
||||||
from calibre.ebooks.oeb.iterator.spine import (SpineItem, create_indexing_data)
|
from calibre.ebooks.oeb.iterator.spine import (SpineItem, create_indexing_data)
|
||||||
from calibre.ebooks.oeb.iterator.bookmarks import BookmarksMixin
|
from calibre.ebooks.oeb.iterator.bookmarks import BookmarksMixin
|
||||||
|
|
||||||
@ -76,7 +75,8 @@ class EbookIterator(BookmarksMixin):
|
|||||||
return i
|
return i
|
||||||
|
|
||||||
def __enter__(self, processed=False, only_input_plugin=False,
|
def __enter__(self, processed=False, only_input_plugin=False,
|
||||||
run_char_count=True, read_anchor_map=True):
|
run_char_count=True, read_anchor_map=True,
|
||||||
|
extract_embedded_fonts_for_qt=False):
|
||||||
''' Convert an ebook file into an exploded OEB book suitable for
|
''' Convert an ebook file into an exploded OEB book suitable for
|
||||||
display in viewers/preprocessing etc. '''
|
display in viewers/preprocessing etc. '''
|
||||||
|
|
||||||
@ -174,6 +174,16 @@ class EbookIterator(BookmarksMixin):
|
|||||||
|
|
||||||
self.read_bookmarks()
|
self.read_bookmarks()
|
||||||
|
|
||||||
|
if extract_embedded_fonts_for_qt:
|
||||||
|
from calibre.ebooks.oeb.iterator.extract_fonts import extract_fonts
|
||||||
|
try:
|
||||||
|
extract_fonts(self.opf, self.log)
|
||||||
|
except:
|
||||||
|
ol = self.log.filter_level
|
||||||
|
self.log.filter_level = self.log.DEBUG
|
||||||
|
self.log.exception('Failed to extract fonts')
|
||||||
|
self.log.filter_level = ol
|
||||||
|
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def __exit__(self, *args):
|
def __exit__(self, *args):
|
||||||
|
100
src/calibre/ebooks/oeb/iterator/extract_fonts.py
Normal file
100
src/calibre/ebooks/oeb/iterator/extract_fonts.py
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
# vim:fileencoding=UTF-8:ts=4:sw=4:sta:et:sts=4:fdm=marker:ai
|
||||||
|
from __future__ import (unicode_literals, division, absolute_import,
|
||||||
|
print_function)
|
||||||
|
|
||||||
|
__license__ = 'GPL v3'
|
||||||
|
__copyright__ = '2012, Kovid Goyal <kovid at kovidgoyal.net>'
|
||||||
|
__docformat__ = 'restructuredtext en'
|
||||||
|
|
||||||
|
import re, os, logging
|
||||||
|
from functools import partial
|
||||||
|
from future_builtins import map
|
||||||
|
|
||||||
|
class FamilyMap(dict):
|
||||||
|
|
||||||
|
def __init__(self, log):
|
||||||
|
dict.__init__(self)
|
||||||
|
self.replace_map = {}
|
||||||
|
self.added_fonts = set()
|
||||||
|
self.log = log
|
||||||
|
|
||||||
|
def __call__(self, basedir, match):
|
||||||
|
self.read_font_fule(basedir, match.group())
|
||||||
|
return b''
|
||||||
|
|
||||||
|
def finalize(self):
|
||||||
|
if self.replace_map:
|
||||||
|
self.pat = re.compile(br'(font-family.*?)(' +
|
||||||
|
b'|'.join(self.replace_map.iterkeys())+b')', re.I)
|
||||||
|
|
||||||
|
def replace_font_families(self, raw):
|
||||||
|
if self.replace_map:
|
||||||
|
def sub(m):
|
||||||
|
k = m.group(2).lower()
|
||||||
|
for q, val in self.replace_map.iteritems():
|
||||||
|
if q.lower() == k.lower():
|
||||||
|
return m.group().replace(m.group(2), val)
|
||||||
|
return m.group()
|
||||||
|
|
||||||
|
return self.pat.sub(sub, raw)
|
||||||
|
|
||||||
|
def read_font_fule(self, basedir, css):
|
||||||
|
from PyQt4.Qt import QFontDatabase
|
||||||
|
import cssutils
|
||||||
|
cssutils.log.setLevel(logging.ERROR)
|
||||||
|
try:
|
||||||
|
sheet = cssutils.parseString(css)
|
||||||
|
except:
|
||||||
|
return
|
||||||
|
for rule in sheet.cssRules:
|
||||||
|
try:
|
||||||
|
s = rule.style
|
||||||
|
src = s.getProperty('src').propertyValue[0].uri
|
||||||
|
font_family = s.getProperty('font-family').propertyValue[0].value
|
||||||
|
except:
|
||||||
|
continue
|
||||||
|
if not src or not font_family:
|
||||||
|
continue
|
||||||
|
font_file = os.path.normcase(os.path.abspath(os.path.join(basedir,
|
||||||
|
src)))
|
||||||
|
if font_file not in self.added_fonts:
|
||||||
|
self.added_fonts.add(font_file)
|
||||||
|
if os.path.exists(font_file):
|
||||||
|
with open(font_file, 'rb') as f:
|
||||||
|
idx = QFontDatabase.addApplicationFontFromData(f.read())
|
||||||
|
if idx > -1:
|
||||||
|
family = map(unicode,
|
||||||
|
QFontDatabase.applicationFontFamilies(idx)).next()
|
||||||
|
self.log('Extracted embedded font:', family, 'from',
|
||||||
|
os.path.basename(font_file))
|
||||||
|
if (family and family != font_family and
|
||||||
|
family not in self.replace_map):
|
||||||
|
self.log('Replacing font family value:',
|
||||||
|
font_family, 'with', family)
|
||||||
|
self.replace_map[font_family.encode('utf-8')] = \
|
||||||
|
family.encode('utf-8')
|
||||||
|
|
||||||
|
def extract_fonts(opf, log):
|
||||||
|
css_files = {}
|
||||||
|
font_family_map = FamilyMap(log)
|
||||||
|
pat = re.compile(br'^\s*@font-face\s*{[^}]+}', re.M)
|
||||||
|
|
||||||
|
for item in opf.manifest:
|
||||||
|
if item.mime_type and item.mime_type.lower() in {
|
||||||
|
'text/css', 'text/x-oeb1-css', 'text/x-oeb-css'}:
|
||||||
|
try:
|
||||||
|
with open(item.path, 'rb') as f:
|
||||||
|
raw = f.read()
|
||||||
|
except EnvironmentError:
|
||||||
|
continue
|
||||||
|
css_files[item.path] = pat.sub(partial(font_family_map,
|
||||||
|
os.path.dirname(item.path)), raw)
|
||||||
|
|
||||||
|
font_family_map.finalize()
|
||||||
|
|
||||||
|
for path, raw in css_files.iteritems():
|
||||||
|
with open(path, 'wb') as f:
|
||||||
|
nraw = font_family_map.replace_font_families(raw)
|
||||||
|
f.write(nraw)
|
||||||
|
|
@ -963,7 +963,8 @@ class EbookViewer(MainWindow, Ui_EbookViewer):
|
|||||||
self.iterator.__exit__()
|
self.iterator.__exit__()
|
||||||
self.iterator = EbookIterator(pathtoebook)
|
self.iterator = EbookIterator(pathtoebook)
|
||||||
self.open_progress_indicator(_('Loading ebook...'))
|
self.open_progress_indicator(_('Loading ebook...'))
|
||||||
worker = Worker(target=self.iterator.__enter__)
|
worker = Worker(target=partial(self.iterator.__enter__,
|
||||||
|
extract_embedded_fonts_for_qt=True))
|
||||||
worker.start()
|
worker.start()
|
||||||
while worker.isAlive():
|
while worker.isAlive():
|
||||||
worker.join(0.1)
|
worker.join(0.1)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user