~ubuntu-branches/ubuntu/karmic/calibre/karmic

« back to all changes in this revision

Viewing changes to src/calibre/ebooks/rb/rbml.py

  • Committer: Bazaar Package Importer
  • Author(s): Martin Pitt
  • Date: 2009-07-30 12:49:41 UTC
  • mfrom: (1.3.2 upstream)
  • Revision ID: james.westby@ubuntu.com-20090730124941-qjdsmri25zt8zocn
Tags: 0.6.3+dfsg-0ubuntu1
* New upstream release. Please see http://calibre.kovidgoyal.net/new_in_6/
  for the list of new features and changes.
* remove_postinstall.patch: Update for new version.
* build_debug.patch: Does not apply any more, disable for now. Might not be
  necessary any more.
* debian/copyright: Fix reference to versionless GPL.
* debian/rules: Drop obsolete dh_desktop call.
* debian/rules: Add workaround for weird Python 2.6 setuptools behaviour of
  putting compiled .so files into src/calibre/plugins/calibre/plugins
  instead of src/calibre/plugins.
* debian/rules: Drop hal fdi moving, new upstream version does not use hal
  any more. Drop hal dependency, too.
* debian/rules: Install udev rules into /lib/udev/rules.d.
* Add debian/calibre.preinst: Remove unmodified
  /etc/udev/rules.d/95-calibre.rules on upgrade.
* debian/control: Bump Python dependencies to 2.6, since upstream needs
  it now.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# -*- coding: utf-8 -*-
 
2
 
 
3
__license__ = 'GPL 3'
 
4
__copyright__ = '2009, John Schember <john@nachtimwald.com>'
 
5
__docformat__ = 'restructuredtext en'
 
6
 
 
7
'''
 
8
Transform OEB content into RB compatible markup.
 
9
'''
 
10
 
 
11
import os
 
12
import re
 
13
 
 
14
from calibre.ebooks.oeb.base import XHTML, XHTML_NS, barename, namespace
 
15
from calibre.ebooks.oeb.stylizer import Stylizer
 
16
 
 
17
TAGS = [
 
18
    'b',
 
19
    'big',
 
20
    'blockquote',
 
21
    'br',
 
22
    'center',
 
23
    'code',
 
24
    'div',
 
25
    'h1',
 
26
    'h2',
 
27
    'h3',
 
28
    'h4',
 
29
    'h5',
 
30
    'h6',
 
31
    'hr',
 
32
    'i',
 
33
    'li',
 
34
    'ol',
 
35
    'p',
 
36
    'pre',
 
37
    'small',
 
38
    'sub',
 
39
    'sup',
 
40
    'ul',
 
41
]
 
42
 
 
43
LINK_TAGS = [
 
44
    'a',
 
45
]
 
46
 
 
47
STYLES = [
 
48
    ('font-weight', {'bold'   : 'b', 'bolder' : 'b'}),
 
49
    ('font-style', {'italic' : 'i'}),
 
50
    ('text-align', {'center' : 'center'}),
 
51
]
 
52
 
 
53
class RBMLizer(object):
 
54
 
 
55
    def __init__(self, log, name_map={}):
 
56
        self.log = log
 
57
        self.name_map = name_map
 
58
 
 
59
    def extract_content(self, oeb_book, opts):
 
60
        self.log.info('Converting XHTML to RB markup...')
 
61
        self.oeb_book = oeb_book
 
62
        self.opts = opts
 
63
        return self.mlize_spine()
 
64
 
 
65
 
 
66
    def mlize_spine(self):
 
67
        output = u'<HTML><HEAD><TITLE></TITLE></HEAD><BODY>'
 
68
        if 'titlepage' in self.oeb_book.guide:
 
69
            self.log.debug('Generating cover page...')
 
70
            href = self.oeb_book.guide['titlepage'].href
 
71
            item = self.oeb_book.manifest.hrefs[href]
 
72
            if item.spine_position is None:
 
73
                stylizer = Stylizer(item.data, item.href, self.oeb_book, self.opts.output_profile)
 
74
                output += self.dump_text(item.data.find(XHTML('body')), stylizer)
 
75
        for item in self.oeb_book.spine:
 
76
            self.log.debug('Converting %s to RocketBook HTML...' % item.href)
 
77
            stylizer = Stylizer(item.data, item.href, self.oeb_book, self.opts.output_profile)
 
78
            output += self.add_page_anchor(item.href)
 
79
            output += self.dump_text(item.data.find(XHTML('body')), stylizer)
 
80
        output += u'</BODY></HTML>'
 
81
        output = self.clean_text(output)
 
82
        return output
 
83
 
 
84
    def add_page_anchor(self, href):
 
85
        href = os.path.splitext(os.path.basename(href))[0]
 
86
        return u'<A NAME="%s"></A>' % href
 
87
 
 
88
    def clean_text(self, text):        
 
89
        # Remove anchors that do not have links
 
90
        anchors = set(re.findall(r'(?<=<A NAME=").+?(?="></A>)', text))
 
91
        links = set(re.findall(r'(?<=<A HREF="#).+?(?=">)', text))
 
92
        for unused in anchors.difference(links):
 
93
            text = text.replace('<A NAME="%s"></A>' % unused, '')
 
94
 
 
95
        return text
 
96
 
 
97
    def dump_text(self, elem, stylizer, tag_stack=[]):
 
98
        if not isinstance(elem.tag, basestring) \
 
99
           or namespace(elem.tag) != XHTML_NS:
 
100
            return u''
 
101
 
 
102
        text = u''
 
103
        style = stylizer.style(elem)
 
104
 
 
105
        if style['display'] in ('none', 'oeb-page-head', 'oeb-page-foot') \
 
106
           or style['visibility'] == 'hidden':
 
107
            return u''
 
108
 
 
109
        tag = barename(elem.tag)
 
110
        tag_count = 0
 
111
        
 
112
        # Process tags that need special processing and that do not have inner
 
113
        # text. Usually these require an argument
 
114
        if tag == 'img':
 
115
            src = os.path.basename(elem.get('src'))
 
116
            name = self.name_map.get(src, src)
 
117
            text += '<IMG SRC="%s">' % name
 
118
 
 
119
        rb_tag = tag.upper() if tag in TAGS else None
 
120
        if rb_tag:
 
121
            tag_count += 1
 
122
            text += '<%s>' % rb_tag
 
123
            tag_stack.append(rb_tag)
 
124
 
 
125
        if tag in LINK_TAGS:
 
126
            href = elem.get('href')
 
127
            if href:
 
128
                if '://' not in href:
 
129
                    if '#' in href:
 
130
                        href = href.partition('#')[2]
 
131
                    href = os.path.splitext(os.path.basename(href))[0]
 
132
                tag_count += 1
 
133
                text += '<A HREF="#%s">' % href
 
134
                tag_stack.append('A')
 
135
 
 
136
        # Anchor ids
 
137
        id_name = elem.get('id')
 
138
        if id_name:
 
139
            text += '<A NAME="%s"></A>' % os.path.splitext(id_name)[0]
 
140
 
 
141
        # Processes style information
 
142
        for s in STYLES:
 
143
            style_tag = s[1].get(style[s[0]], None)
 
144
            if style_tag:
 
145
                style_tag = style_tag.upper()
 
146
                tag_count += 1
 
147
                text += '<%s>' % style_tag
 
148
                tag_stack.append(style_tag)
 
149
 
 
150
        # Proccess tags that contain text.
 
151
        if hasattr(elem, 'text') and elem.text != None and elem.text.strip() != '':
 
152
            text += elem.text
 
153
 
 
154
        for item in elem:
 
155
            text += self.dump_text(item, stylizer, tag_stack)
 
156
 
 
157
        close_tag_list = []
 
158
        for i in range(0, tag_count):
 
159
            close_tag_list.insert(0, tag_stack.pop())
 
160
 
 
161
        text += self.close_tags(close_tag_list)
 
162
 
 
163
        if hasattr(elem, 'tail') and elem.tail != None and elem.tail.strip() != '':
 
164
                text += elem.tail
 
165
 
 
166
        return text
 
167
 
 
168
    def close_tags(self, tags):
 
169
        text = u''
 
170
        for i in range(0, len(tags)):
 
171
            tag = tags.pop()
 
172
            text += '</%s>' % tag
 
173
 
 
174
        return text