mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-08-11 09:13:57 -04:00
Handle <pre> tags and <table> tags (kind of).
This commit is contained in:
parent
6e3d8aee52
commit
d11347331c
@ -20,7 +20,8 @@ MBP_NS = 'http://mobipocket.com/ns/mbp'
|
|||||||
def MBP(name): return '{%s}%s' % (MBP_NS, name)
|
def MBP(name): return '{%s}%s' % (MBP_NS, name)
|
||||||
|
|
||||||
HEADER_TAGS = set(['h1', 'h2', 'h3', 'h4', 'h5', 'h6'])
|
HEADER_TAGS = set(['h1', 'h2', 'h3', 'h4', 'h5', 'h6'])
|
||||||
NESTABLE_TAGS = set(['ol', 'ul', 'li', 'table', 'tr', 'td'])
|
NESTABLE_TAGS = set(['ol', 'ul', 'li', 'table', 'tr', 'td', 'th'])
|
||||||
|
TABLE_TAGS = set(['table', 'tr', 'td', 'th'])
|
||||||
SPECIAL_TAGS = set(['hr', 'br'])
|
SPECIAL_TAGS = set(['hr', 'br'])
|
||||||
CONTENT_TAGS = set(['img', 'hr', 'br'])
|
CONTENT_TAGS = set(['img', 'hr', 'br'])
|
||||||
|
|
||||||
@ -51,6 +52,7 @@ class FormatState(object):
|
|||||||
self.bold = False
|
self.bold = False
|
||||||
self.preserve = True
|
self.preserve = True
|
||||||
self.href = None
|
self.href = None
|
||||||
|
self.list_num = 0
|
||||||
self.attrib = {}
|
self.attrib = {}
|
||||||
|
|
||||||
def __eq__(self, other):
|
def __eq__(self, other):
|
||||||
@ -98,6 +100,18 @@ class MobiMLizer(object):
|
|||||||
return "%dpt" % int(round(ptsize * 2))
|
return "%dpt" % int(round(ptsize * 2))
|
||||||
return "%dem" % int(round(ptsize / fbase))
|
return "%dem" % int(round(ptsize / fbase))
|
||||||
|
|
||||||
|
def preize_text(self, text):
|
||||||
|
text = unicode(text).replace(u' ', u'\xa0')
|
||||||
|
text = text.replace('\r\n', '\n')
|
||||||
|
text = text.replace('\r', '\n')
|
||||||
|
lines = text.split('\n')
|
||||||
|
result = lines[:1]
|
||||||
|
for line in lines[1:]:
|
||||||
|
result.append(etree.Element('br'))
|
||||||
|
if line:
|
||||||
|
result.append(line)
|
||||||
|
return result
|
||||||
|
|
||||||
def mobimlize_content(self, tag, text, bstate, istates):
|
def mobimlize_content(self, tag, text, bstate, istates):
|
||||||
istate = istates[-1]
|
istate = istates[-1]
|
||||||
if istate.ids:
|
if istate.ids:
|
||||||
@ -111,29 +125,34 @@ class MobiMLizer(object):
|
|||||||
para = para if para is not None else bstate.body
|
para = para if para is not None else bstate.body
|
||||||
elif para is None:
|
elif para is None:
|
||||||
bstate.istate = None
|
bstate.istate = None
|
||||||
|
parent = bstate.nested[-1] if bstate.nested else bstate.body
|
||||||
if bstate.pbreak:
|
if bstate.pbreak:
|
||||||
etree.SubElement(bstate.body, MBP('pagebreak'))
|
etree.SubElement(parent, MBP('pagebreak'))
|
||||||
bstate.pbreak = False
|
bstate.pbreak = False
|
||||||
if tag in NESTABLE_TAGS:
|
if tag in NESTABLE_TAGS:
|
||||||
parent = bstate.nested[-1] if bstate.nested else bstate.body
|
|
||||||
para = wrapper = etree.SubElement(parent, tag)
|
para = wrapper = etree.SubElement(parent, tag)
|
||||||
bstate.nested.append(para)
|
bstate.nested.append(para)
|
||||||
|
# Should instead support full CSS lists?
|
||||||
|
if tag == 'li' and len(istates) > 1:
|
||||||
|
istates[-2].list_num += 1
|
||||||
|
para.attrib['value'] = str(istates[-2].list_num)
|
||||||
elif bstate.left > 0 and istate.indent >= 0:
|
elif bstate.left > 0 and istate.indent >= 0:
|
||||||
para = wrapper = etree.SubElement(bstate.body, 'blockquote')
|
para = wrapper = etree.SubElement(parent, 'blockquote')
|
||||||
left = int(round(bstate.left / self.profile.fbase)) - 1
|
left = int(round(bstate.left / self.profile.fbase)) - 1
|
||||||
while left > 0:
|
while left > 0:
|
||||||
para = etree.SubElement(para, 'blockquote')
|
para = etree.SubElement(para, 'blockquote')
|
||||||
left -= 1
|
left -= 1
|
||||||
else:
|
else:
|
||||||
ptag = tag if tag in HEADER_TAGS else 'p'
|
ptag = tag if tag in HEADER_TAGS else 'p'
|
||||||
para = wrapper = etree.SubElement(bstate.body, ptag)
|
para = wrapper = etree.SubElement(parent, ptag)
|
||||||
bstate.inline = bstate.para = para
|
bstate.inline = bstate.para = para
|
||||||
vspace = bstate.vpadding + bstate.vmargin
|
vspace = bstate.vpadding + bstate.vmargin
|
||||||
bstate.vpadding = bstate.vmargin = 0
|
bstate.vpadding = bstate.vmargin = 0
|
||||||
wrapper.attrib['height'] = self.mobimlize_measure(vspace)
|
if tag not in TABLE_TAGS:
|
||||||
para.attrib['width'] = self.mobimlize_measure(istate.indent)
|
wrapper.attrib['height'] = self.mobimlize_measure(vspace)
|
||||||
|
para.attrib['width'] = self.mobimlize_measure(istate.indent)
|
||||||
if istate.halign != 'auto':
|
if istate.halign != 'auto':
|
||||||
wrapper.attrib['align'] = istate.halign
|
para.attrib['align'] = istate.halign
|
||||||
pstate = bstate.istate
|
pstate = bstate.istate
|
||||||
if tag in CONTENT_TAGS:
|
if tag in CONTENT_TAGS:
|
||||||
bstate.inline = para
|
bstate.inline = para
|
||||||
@ -150,6 +169,8 @@ class MobiMLizer(object):
|
|||||||
inline = etree.SubElement(inline, 'sup')
|
inline = etree.SubElement(inline, 'sup')
|
||||||
elif valign == 'sub':
|
elif valign == 'sub':
|
||||||
inline = etree.SubElement(inline, 'sub')
|
inline = etree.SubElement(inline, 'sub')
|
||||||
|
if istate.preserve:
|
||||||
|
inline = etree.SubElement(inline, 'tt')
|
||||||
if fsize != 3:
|
if fsize != 3:
|
||||||
inline = etree.SubElement(inline, 'font', size=str(fsize))
|
inline = etree.SubElement(inline, 'font', size=str(fsize))
|
||||||
if istate.italic:
|
if istate.italic:
|
||||||
@ -161,20 +182,23 @@ class MobiMLizer(object):
|
|||||||
bstate.inline = inline
|
bstate.inline = inline
|
||||||
bstate.istate = istate
|
bstate.istate = istate
|
||||||
inline = bstate.inline
|
inline = bstate.inline
|
||||||
if inline == para:
|
items = self.preize_text(text) if istate.preserve else [text]
|
||||||
if len(para) == 0:
|
for item in items:
|
||||||
para.text = (para.text or '') + text
|
if isinstance(item, basestring):
|
||||||
|
if len(inline) == 0:
|
||||||
|
inline.text = (inline.text or '') + item
|
||||||
|
else:
|
||||||
|
last = inline[-1]
|
||||||
|
last.tail = (last.tail or '') + item
|
||||||
else:
|
else:
|
||||||
last = para[-1]
|
inline.append(item)
|
||||||
last.tail = (last.tail or '') + text
|
|
||||||
else:
|
|
||||||
inline.text = (inline.text or '') + text
|
|
||||||
|
|
||||||
def mobimlize_elem(self, elem, stylizer, bstate, istates):
|
def mobimlize_elem(self, elem, stylizer, bstate, istates):
|
||||||
if not isinstance(elem.tag, basestring) \
|
if not isinstance(elem.tag, basestring) \
|
||||||
or namespace(elem.tag) != XHTML_NS:
|
or namespace(elem.tag) != XHTML_NS:
|
||||||
return
|
return
|
||||||
istate = copy.copy(istates[-1])
|
istate = copy.copy(istates[-1])
|
||||||
|
istate.list_num = 0
|
||||||
istates.append(istate)
|
istates.append(istate)
|
||||||
tag = barename(elem.tag)
|
tag = barename(elem.tag)
|
||||||
style = stylizer.style(elem)
|
style = stylizer.style(elem)
|
||||||
@ -227,8 +251,10 @@ class MobiMLizer(object):
|
|||||||
if tag == 'img' and 'src' in elem.attrib:
|
if tag == 'img' and 'src' in elem.attrib:
|
||||||
istate.attrib['src'] = elem.attrib['src']
|
istate.attrib['src'] = elem.attrib['src']
|
||||||
istate.attrib['align'] = 'baseline'
|
istate.attrib['align'] = 'baseline'
|
||||||
if tag == 'hr' and 'width' in style.cssdict():
|
elif tag == 'hr' and 'width' in style.cssdict():
|
||||||
istate.attrib['width'] = mobimlize_measure(style['width'])
|
istate.attrib['width'] = mobimlize_measure(style['width'])
|
||||||
|
elif tag in TABLE_TAGS:
|
||||||
|
istate.attrib.update(dict(elem.attrib))
|
||||||
text = None
|
text = None
|
||||||
if elem.text:
|
if elem.text:
|
||||||
if istate.preserve:
|
if istate.preserve:
|
||||||
@ -237,7 +263,7 @@ class MobiMLizer(object):
|
|||||||
text = None
|
text = None
|
||||||
else:
|
else:
|
||||||
text = COLLAPSE.sub(' ', elem.text)
|
text = COLLAPSE.sub(' ', elem.text)
|
||||||
if text or tag in CONTENT_TAGS:
|
if text or tag in CONTENT_TAGS or tag in NESTABLE_TAGS:
|
||||||
self.mobimlize_content(tag, text, bstate, istates)
|
self.mobimlize_content(tag, text, bstate, istates)
|
||||||
for child in elem:
|
for child in elem:
|
||||||
self.mobimlize_elem(child, stylizer, bstate, istates)
|
self.mobimlize_elem(child, stylizer, bstate, istates)
|
||||||
|
@ -45,7 +45,7 @@ PROFILES = {
|
|||||||
fsizes=[9, 10, 11, 12, 14, 17, 20, 24]),
|
fsizes=[9, 10, 11, 12, 14, 17, 20, 24]),
|
||||||
|
|
||||||
# No clue on usable screen size and DPI
|
# No clue on usable screen size and DPI
|
||||||
'Cybook3':
|
'CybookG3':
|
||||||
Profile(width=584, height=754, dpi=168.451, fbase=12,
|
Profile(width=584, height=754, dpi=168.451, fbase=12,
|
||||||
fsizes=[9, 10, 11, 12, 14, 17, 20, 24]),
|
fsizes=[9, 10, 11, 12, 14, 17, 20, 24]),
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user