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:
Marshall T. Vandegrift 2009-01-11 15:41:34 -05:00
parent ed6f3b6702
commit 2397ee84bf
4 changed files with 139 additions and 3 deletions

View File

@ -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'

View File

@ -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)

View File

@ -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)

View 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')