E-book viewer: Add partial support for CSS font aliasing

This commit is contained in:
Kovid Goyal 2009-10-31 14:17:18 -06:00
parent 19d9edb2f7
commit f0a7a8ecd8

View File

@ -19,7 +19,7 @@ from calibre.utils.zipfile import safe_replace, ZipFile
from calibre.utils.config import DynamicConfig from calibre.utils.config import DynamicConfig
from calibre.utils.logging import Log from calibre.utils.logging import Log
from calibre.ebooks.epub.output import EPUBOutput from calibre.ebooks.epub.output import EPUBOutput
from calibre import guess_type from calibre import guess_type, prints
TITLEPAGE = EPUBOutput.TITLEPAGE_COVER.decode('utf-8') TITLEPAGE = EPUBOutput.TITLEPAGE_COVER.decode('utf-8')
@ -99,29 +99,63 @@ class EbookIterator(object):
if text in open(path, 'rb').read().decode(path.encoding).lower(): if text in open(path, 'rb').read().decode(path.encoding).lower():
return i return i
def find_missing_css_files(self):
for x in os.walk(os.path.dirname(self.pathtoopf)):
for f in x[-1]:
if f.endswith('.css'):
yield os.path.join(x[0], f)
def find_declared_css_files(self):
for item in self.opf.manifest:
if item.mime_type and 'css' in item.mime_type.lower():
yield item.path
def find_embedded_fonts(self): def find_embedded_fonts(self):
''' '''
This will become unnecessary once Qt WebKit supports the @font-face rule. This will become unnecessary once Qt WebKit supports the @font-face rule.
''' '''
for item in self.opf.manifest: css_files = set(self.find_declared_css_files())
if item.mime_type and 'css' in item.mime_type.lower(): if not css_files:
css = open(item.path, 'rb').read().decode('utf-8', 'replace') css_files = set(self.find_missing_css_files())
for match in re.compile(r'@font-face\s*{([^}]+)}').finditer(css): bad_map = {}
block = match.group(1) font_family_pat = re.compile(r'font-family\s*:\s*([^;]+)')
family = re.compile(r'font-family\s*:\s*([^;]+)').search(block) for csspath in css_files:
url = re.compile(r'url\s*\([\'"]*(.+?)[\'"]*\)', re.DOTALL).search(block) css = open(csspath, 'rb').read().decode('utf-8', 'replace')
if url: for match in re.compile(r'@font-face\s*{([^}]+)}').finditer(css):
path = url.group(1).split('/') block = match.group(1)
path = os.path.join(os.path.dirname(item.path), *path) family = font_family_pat.search(block)
id = QFontDatabase.addApplicationFont(path) url = re.compile(r'url\s*\([\'"]*(.+?)[\'"]*\)', re.DOTALL).search(block)
if id != -1: if url:
families = [unicode(f) for f in QFontDatabase.applicationFontFamilies(id)] path = url.group(1).split('/')
if family: path = os.path.join(os.path.dirname(csspath), *path)
family = family.group(1).strip().replace('"', '') if not os.access(path, os.R_OK):
if family not in families: continue
print 'WARNING: Family aliasing not supported:', block id = QFontDatabase.addApplicationFont(path)
else: if id != -1:
print 'Loaded embedded font:', repr(family) families = [unicode(f) for f in QFontDatabase.applicationFontFamilies(id)]
if family:
family = family.group(1).strip().replace('"', '')
bad_map[family] = families[0]
if family not in families:
prints('WARNING: Family aliasing not fully supported.')
prints('\tDeclared family: %s not in actual families: %s'
% (family, families))
else:
prints('Loaded embedded font:', repr(family))
if bad_map:
def prepend_embedded_font(match):
for bad, good in bad_map.items():
if bad in match.group(1):
prints('Substituting font family: %s -> %s'%(bad, good))
return 'font-family: %s;'%good
for csspath in css_files:
with open(csspath, 'r+b') as f:
css = f.read()
css = font_family_pat.sub(prepend_embedded_font, css)
f.seek(0)
f.truncate()
f.write(css)
def __enter__(self, processed=False): def __enter__(self, processed=False):
self.delete_on_exit = [] self.delete_on_exit = []