mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
EPUB Output: Consolidate inline CSS generated by calibre into external stylesheets for ease of editing the EPUB
This commit is contained in:
parent
6a88470186
commit
3b1921fca4
@ -312,13 +312,9 @@ class EPUBOutput(OutputFormatPlugin):
|
||||
Perform various markup transforms to get the output to render correctly
|
||||
in the quirky ADE.
|
||||
'''
|
||||
from calibre.ebooks.oeb.base import XPath, XHTML, OEB_STYLES, barename, urlunquote
|
||||
from calibre.ebooks.oeb.base import XPath, XHTML, barename, urlunquote
|
||||
|
||||
stylesheet = None
|
||||
for item in self.oeb.manifest:
|
||||
if item.media_type.lower() in OEB_STYLES:
|
||||
stylesheet = item
|
||||
break
|
||||
stylesheet = self.oeb.manifest.main_stylesheet
|
||||
|
||||
# ADE cries big wet tears when it encounters an invalid fragment
|
||||
# identifier in the NCX toc.
|
||||
|
@ -99,12 +99,8 @@ class PDFOutput(OutputFormatPlugin):
|
||||
|
||||
# Remove page-break-before on <body> element as it causes
|
||||
# blank pages in PDF Output
|
||||
from calibre.ebooks.oeb.base import OEB_STYLES, XPath
|
||||
stylesheet = None
|
||||
for item in self.oeb.manifest:
|
||||
if item.media_type.lower() in OEB_STYLES:
|
||||
stylesheet = item
|
||||
break
|
||||
from calibre.ebooks.oeb.base import XPath
|
||||
stylesheet = self.oeb.manifest.main_stylesheet
|
||||
if stylesheet is not None:
|
||||
from cssutils.css import CSSRule
|
||||
classes = set(['.calibre'])
|
||||
|
@ -1142,6 +1142,19 @@ class Manifest(object):
|
||||
element(elem, OPF('item'), attrib=attrib)
|
||||
return elem
|
||||
|
||||
@dynamic_property
|
||||
def main_stylesheet(self):
|
||||
def fget(self):
|
||||
ans = getattr(self, '_main_stylesheet', None)
|
||||
if ans is None:
|
||||
for item in self:
|
||||
if item.media_type.lower() in OEB_STYLES:
|
||||
ans = item
|
||||
break
|
||||
return ans
|
||||
def fset(self, item):
|
||||
self._main_stylesheet = item
|
||||
return property(fget=fget, fset=fset)
|
||||
|
||||
class Spine(object):
|
||||
"""Collection of manifest items composing an OEB data model book's main
|
||||
|
@ -378,7 +378,7 @@ class CSSFlattener(object):
|
||||
for child in node:
|
||||
self.flatten_node(child, stylizer, names, styles, psize, item_id, left)
|
||||
|
||||
def flatten_head(self, item, stylizer, href):
|
||||
def flatten_head(self, item, href, global_href):
|
||||
html = item.data
|
||||
head = html.find(XHTML('head'))
|
||||
for node in head:
|
||||
@ -390,33 +390,55 @@ class CSSFlattener(object):
|
||||
and node.get('type', CSS_MIME) in OEB_STYLES:
|
||||
head.remove(node)
|
||||
href = item.relhref(href)
|
||||
etree.SubElement(head, XHTML('link'),
|
||||
l = etree.SubElement(head, XHTML('link'),
|
||||
rel='stylesheet', type=CSS_MIME, href=href)
|
||||
l.tail='\n'
|
||||
href = item.relhref(global_href)
|
||||
l = etree.SubElement(head, XHTML('link'),
|
||||
rel='stylesheet', type=CSS_MIME, href=href)
|
||||
l.tail = '\n'
|
||||
|
||||
def replace_css(self, css):
|
||||
manifest = self.oeb.manifest
|
||||
for item in manifest.values():
|
||||
if item.media_type in OEB_STYLES:
|
||||
manifest.remove(item)
|
||||
id, href = manifest.generate('css', 'stylesheet.css')
|
||||
item = manifest.add(id, href, CSS_MIME, data=cssutils.parseString(css,
|
||||
validate=False))
|
||||
self.oeb.manifest.main_stylesheet = item
|
||||
return href
|
||||
|
||||
def collect_global_css(self):
|
||||
global_css = defaultdict(list)
|
||||
for item in self.oeb.spine:
|
||||
stylizer = self.stylizers[item]
|
||||
stylizer.page_rule['margin-top'] = '%gpt'%\
|
||||
float(self.context.margin_top)
|
||||
stylizer.page_rule['margin-bottom'] = '%gpt'%\
|
||||
float(self.context.margin_bottom)
|
||||
|
||||
items = stylizer.page_rule.items()
|
||||
items.sort()
|
||||
css = '; '.join("%s: %s" % (key, val) for key, val in items)
|
||||
style = etree.SubElement(head, XHTML('style'), type=CSS_MIME)
|
||||
style.text = "\n\t\t@page { %s; }" % css
|
||||
css = ';\n'.join("%s: %s" % (key, val) for key, val in items)
|
||||
css = '@page {\n%s\n}\n'%css
|
||||
rules = [r.cssText for r in stylizer.font_face_rules]
|
||||
raw = '\n\n'.join(rules)
|
||||
# Make URLs referring to fonts relative to this item
|
||||
sheet = cssutils.parseString(raw, validate=False)
|
||||
cssutils.replaceUrls(sheet, item.relhref, ignoreImportRules=True)
|
||||
style.text += '\n' + sheet.cssText
|
||||
css += '\n\n' + raw
|
||||
global_css[css].append(item)
|
||||
|
||||
def replace_css(self, css):
|
||||
gc_map = {}
|
||||
manifest = self.oeb.manifest
|
||||
id, href = manifest.generate('css', 'stylesheet.css')
|
||||
for item in manifest.values():
|
||||
if item.media_type in OEB_STYLES:
|
||||
manifest.remove(item)
|
||||
item = manifest.add(id, href, CSS_MIME, data=css)
|
||||
return href
|
||||
for css in global_css:
|
||||
id_, href = manifest.generate('page_css', 'page_styles.css')
|
||||
manifest.add(id_, href, CSS_MIME, data=cssutils.parseString(css,
|
||||
validate=False))
|
||||
gc_map[css] = href
|
||||
|
||||
ans = {}
|
||||
for css, items in global_css.iteritems():
|
||||
for item in items:
|
||||
ans[item] = gc_map[css]
|
||||
return ans
|
||||
|
||||
def flatten_spine(self):
|
||||
names = defaultdict(int)
|
||||
@ -433,7 +455,8 @@ class CSSFlattener(object):
|
||||
items.sort()
|
||||
css = ''.join(".%s {\n%s;\n}\n\n" % (key, val) for key, val in items)
|
||||
href = self.replace_css(css)
|
||||
global_css = self.collect_global_css()
|
||||
for item in self.oeb.spine:
|
||||
stylizer = self.stylizers[item]
|
||||
self.flatten_head(item, stylizer, href)
|
||||
self.flatten_head(item, href, global_css[item])
|
||||
|
||||
|
@ -9,7 +9,7 @@ __docformat__ = 'restructuredtext en'
|
||||
|
||||
from collections import Counter
|
||||
|
||||
from calibre.ebooks.oeb.base import OEB_STYLES, barename, XPath
|
||||
from calibre.ebooks.oeb.base import barename, XPath
|
||||
|
||||
class RemoveAdobeMargins(object):
|
||||
'''
|
||||
@ -51,10 +51,7 @@ class RemoveFakeMargins(object):
|
||||
self.stats = {}
|
||||
self.selector_map = {}
|
||||
|
||||
for item in self.oeb.manifest:
|
||||
if item.media_type.lower() in OEB_STYLES:
|
||||
stylesheet = item
|
||||
break
|
||||
stylesheet = self.oeb.manifest.main_stylesheet
|
||||
if stylesheet is None:
|
||||
return
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user