mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Mobipocket support:
- Add 'vertical-align: text-top' as a <sup/>-generating case - Add titles to title-less known <guide/> <reference/>s and cleanly ignoren any others - Add transform to generate results of CSS 'text-transform' and 'font-variant'
This commit is contained in:
parent
ed6f3b6702
commit
2397ee84bf
@ -303,7 +303,7 @@ class MobiMLizer(object):
|
||||
else:
|
||||
istate.family = 'serif'
|
||||
valign = style['vertical-align']
|
||||
if valign in ('super', 'sup') or asfloat(valign) > 0:
|
||||
if valign in ('super', 'text-top') or asfloat(valign) > 0:
|
||||
istate.valign = 'super'
|
||||
elif valign == 'sub' or asfloat(valign) < 0:
|
||||
istate.valign = 'sub'
|
||||
|
@ -28,6 +28,7 @@ from calibre.ebooks.oeb.transforms.flatcss import CSSFlattener
|
||||
from calibre.ebooks.oeb.transforms.rasterize import SVGRasterizer
|
||||
from calibre.ebooks.oeb.transforms.trimmanifest import ManifestTrimmer
|
||||
from calibre.ebooks.oeb.transforms.htmltoc import HTMLTOCAdder
|
||||
from calibre.ebooks.oeb.transforms.manglecase import CaseMangler
|
||||
from calibre.ebooks.mobi.palmdoc import compress_doc
|
||||
from calibre.ebooks.mobi.langcodes import iana2mobi
|
||||
from calibre.ebooks.mobi.mobiml import MBP_NS, MBP, MobiMLizer
|
||||
@ -114,7 +115,8 @@ class Serializer(object):
|
||||
buffer.write('<guide>')
|
||||
for ref in self.oeb.guide.values():
|
||||
path, frag = urldefrag(ref.href)
|
||||
if hrefs[path].media_type not in OEB_DOCS:
|
||||
if hrefs[path].media_type not in OEB_DOCS or
|
||||
not ref.title:
|
||||
continue
|
||||
buffer.write('<reference title="%s" type="%s" '
|
||||
% (ref.title, ref.type))
|
||||
@ -485,12 +487,14 @@ def main(argv=sys.argv):
|
||||
fbase = context.dest.fbase
|
||||
fkey = context.dest.fnums.values()
|
||||
tocadder = HTMLTOCAdder()
|
||||
mangler = CaseMangler()
|
||||
flattener = CSSFlattener(
|
||||
fbase=fbase, fkey=fkey, unfloat=True, untable=True)
|
||||
rasterizer = SVGRasterizer()
|
||||
trimmer = ManifestTrimmer()
|
||||
mobimlizer = MobiMLizer()
|
||||
tocadder.transform(oeb, context)
|
||||
mangler.transform(oeb, context)
|
||||
flattener.transform(oeb, context)
|
||||
rasterizer.transform(oeb, context)
|
||||
mobimlizer.transform(oeb, context)
|
||||
|
@ -66,6 +66,25 @@ OEB_RASTER_IMAGES = set([GIF_MIME, JPEG_MIME, PNG_MIME])
|
||||
OEB_IMAGES = set([GIF_MIME, JPEG_MIME, PNG_MIME, SVG_MIME])
|
||||
|
||||
MS_COVER_TYPE = 'other.ms-coverimage-standard'
|
||||
GUIDE_TITLES = {
|
||||
'cover': 'Cover',
|
||||
'title-page': 'Title Page',
|
||||
'toc': 'Table of Contents',
|
||||
'index': 'Index',
|
||||
'glossary': 'Glossary',
|
||||
'acknowledgements': 'Acknowledgements',
|
||||
'bibliography': 'Bibliography',
|
||||
'colophon': 'Colophon',
|
||||
'copyright-page': 'Copyright',
|
||||
'dedication': 'Dedication',
|
||||
'epigraph': 'Epigraph',
|
||||
'foreword': 'Foreword',
|
||||
'loi': 'List of Illustrations',
|
||||
'lot': 'List of Tables',
|
||||
'notes': 'Notes',
|
||||
'preface': 'Preface',
|
||||
'text': 'Begin Reading'
|
||||
}
|
||||
|
||||
recode = lambda s: s.decode('iso-8859-1').encode('ascii', 'xmlcharrefreplace')
|
||||
ENTITYDEFS = dict((k, recode(v)) for k, v in htmlentitydefs.entitydefs.items())
|
||||
@ -537,10 +556,12 @@ class Spine(object):
|
||||
class Guide(object):
|
||||
class Reference(object):
|
||||
def __init__(self, type, title, href):
|
||||
if not title and type in GUIDE_TITLES:
|
||||
title = GUIDE_TITLES[type]
|
||||
self.type = type
|
||||
self.title = title
|
||||
self.href = urlnormalize(href)
|
||||
|
||||
|
||||
def __repr__(self):
|
||||
return 'Reference(type=%r, title=%r, href=%r)' \
|
||||
% (self.type, self.title, self.href)
|
||||
|
111
src/calibre/ebooks/oeb/transforms/manglecase.py
Normal file
111
src/calibre/ebooks/oeb/transforms/manglecase.py
Normal file
@ -0,0 +1,111 @@
|
||||
'''
|
||||
CSS case-mangling transform.
|
||||
'''
|
||||
from __future__ import with_statement
|
||||
|
||||
__license__ = 'GPL v3'
|
||||
__copyright__ = '2008, Marshall T. Vandegrift <llasram@gmail.com>'
|
||||
|
||||
import sys
|
||||
import os
|
||||
import re
|
||||
import operator
|
||||
import math
|
||||
from itertools import chain
|
||||
from collections import defaultdict
|
||||
from lxml import etree
|
||||
from calibre.ebooks.oeb.base import XHTML, XHTML_NS
|
||||
from calibre.ebooks.oeb.base import CSS_MIME
|
||||
from calibre.ebooks.oeb.base import namespace
|
||||
from calibre.ebooks.oeb.stylizer import Stylizer
|
||||
|
||||
CASE_MANGLER_CSS = """
|
||||
.calibre_lowercase {
|
||||
font-variant: normal;
|
||||
font-size: 0.65em;
|
||||
}
|
||||
"""
|
||||
|
||||
TEXT_TRANSFORMS = set(['capitalize', 'uppercase', 'lowercase'])
|
||||
|
||||
class CaseMangler(object):
|
||||
def transform(self, oeb, context):
|
||||
oeb.logger.info('Applying case-transforming CSS...')
|
||||
self.oeb = oeb
|
||||
self.profile = context.source
|
||||
self.mangle_spine()
|
||||
|
||||
def mangle_spine(self):
|
||||
id, href = self.oeb.manifest.generate('manglecase', 'manglecase.css')
|
||||
self.oeb.manifest.add(id, href, CSS_MIME, data=CASE_MANGLER_CSS)
|
||||
for item in self.oeb.spine:
|
||||
html = item.data
|
||||
etree.SubElement(html.find(XHTML('head')), XHTML('link'),
|
||||
rel='stylesheet', href=href, type=CSS_MIME)
|
||||
stylizer = Stylizer(html, item.href, self.oeb, self.profile)
|
||||
self.mangle_elem(html.find(XHTML('body')), stylizer)
|
||||
|
||||
def text_transform(self, transform, text):
|
||||
if transform == 'capitalize':
|
||||
return text.title()
|
||||
elif transform == 'uppercase':
|
||||
return text.upper()
|
||||
elif transform == 'lowercase':
|
||||
return text.lower()
|
||||
return text
|
||||
|
||||
def split_text(self, text):
|
||||
results = ['']
|
||||
isupper = text[0].isupper()
|
||||
for char in text:
|
||||
if char.isupper() == isupper:
|
||||
results[-1] += char
|
||||
else:
|
||||
isupper = not isupper
|
||||
results.append(char)
|
||||
return results
|
||||
|
||||
def smallcaps_elem(self, elem, attr):
|
||||
texts = self.split_text(getattr(elem, attr))
|
||||
setattr(elem, attr, None)
|
||||
last = elem if attr == 'tail' else None
|
||||
attrib = {'class': 'calibre_lowercase'}
|
||||
for text in texts:
|
||||
if text.isupper():
|
||||
if last is None:
|
||||
elem.text = text
|
||||
else:
|
||||
last.tail = text
|
||||
else:
|
||||
child = etree.Element(XHTML('span'), attrib=attrib)
|
||||
child.text = text.upper()
|
||||
if last is None:
|
||||
elem.insert(0, child)
|
||||
else:
|
||||
# addnext() moves the tail for some reason
|
||||
tail = last.tail
|
||||
last.addnext(child)
|
||||
last.tail = tail
|
||||
child.tail = None
|
||||
last = child
|
||||
|
||||
def mangle_elem(self, elem, stylizer):
|
||||
if not isinstance(elem.tag, basestring) or \
|
||||
namespace(elem.tag) != XHTML_NS:
|
||||
return
|
||||
children = list(elem)
|
||||
style = stylizer.style(elem)
|
||||
transform = style['text-transform']
|
||||
variant = style['font-variant']
|
||||
if elem.text:
|
||||
if transform in TEXT_TRANSFORMS:
|
||||
elem.text = self.text_transform(transform, elem.text)
|
||||
if variant == 'small-caps':
|
||||
self.smallcaps_elem(elem, 'text')
|
||||
for child in children:
|
||||
self.mangle_elem(child, stylizer)
|
||||
if child.tail:
|
||||
if transform in TEXT_TRANSFORMS:
|
||||
child.tail = self.text_transform(transform, child.tail)
|
||||
if variant == 'small-caps':
|
||||
self.smallcaps_elem(child, 'tail')
|
Loading…
x
Reference in New Issue
Block a user