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

« back to all changes in this revision

Viewing changes to src/calibre/ebooks/pdb/ereader/writer.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
'''
 
4
Write content to ereader pdb file.
 
5
'''
 
6
 
 
7
__license__   = 'GPL v3'
 
8
__copyright__ = '2009, John Schember <john@nachtimwald.com>'
 
9
__docformat__ = 'restructuredtext en'
 
10
 
 
11
import struct
 
12
import zlib
 
13
 
 
14
try:
 
15
    from PIL import Image
 
16
    Image
 
17
except ImportError:
 
18
    import Image
 
19
 
 
20
import cStringIO
 
21
 
 
22
from calibre.ebooks.pdb.formatwriter import FormatWriter
 
23
from calibre.ebooks.oeb.base import OEB_IMAGES
 
24
from calibre.ebooks.pdb.header import PdbHeaderBuilder
 
25
from calibre.ebooks.pdb.ereader import image_name
 
26
from calibre.ebooks.pml.pmlml import PMLMLizer
 
27
 
 
28
IDENTITY = 'PNRdPPrs'
 
29
 
 
30
# This is an arbitrary number that is small enough to work. The actual maximum
 
31
# record size is unknown.
 
32
MAX_RECORD_SIZE = 3560
 
33
 
 
34
class Writer(FormatWriter):
 
35
 
 
36
    def __init__(self, opts, log):
 
37
        self.opts = opts
 
38
        self.log = log
 
39
 
 
40
    def write_content(self, oeb_book, out_stream, metadata=None):
 
41
        text = self._text(oeb_book)
 
42
        images = self._images(oeb_book.manifest)
 
43
        metadata = [self._metadata(metadata)]
 
44
 
 
45
        hr = [self._header_record(len(text), len(images))]
 
46
 
 
47
        sections = hr+text+images+metadata+['MeTaInFo\x00']
 
48
 
 
49
        lengths = [len(i) if i not in images else len(i[0]) + len(i[1]) for i in sections]
 
50
 
 
51
        pdbHeaderBuilder = PdbHeaderBuilder(IDENTITY, metadata[0].partition('\x00')[0])
 
52
        pdbHeaderBuilder.build_header(lengths, out_stream)
 
53
 
 
54
        for item in sections:
 
55
            if item in images:
 
56
                out_stream.write(item[0])
 
57
                out_stream.write(item[1])
 
58
            else:
 
59
                out_stream.write(item)
 
60
 
 
61
    def _text(self, oeb_book):
 
62
        pmlmlizer = PMLMLizer(self.log)
 
63
        pml = unicode(pmlmlizer.extract_content(oeb_book, self.opts)).encode('cp1252', 'replace')
 
64
 
 
65
        pml_pages = []
 
66
        for i in range(0, (len(pml) / MAX_RECORD_SIZE) + 1):
 
67
            pml_pages.append(zlib.compress(pml[i * MAX_RECORD_SIZE : (i * MAX_RECORD_SIZE) + MAX_RECORD_SIZE]))
 
68
 
 
69
        return pml_pages
 
70
 
 
71
    def _images(self, manifest):
 
72
        images = []
 
73
 
 
74
        for item in manifest:
 
75
            if item.media_type in OEB_IMAGES:
 
76
                header = 'PNG '
 
77
 
 
78
                header += image_name(item.href)
 
79
                header = header.ljust(62, '\x00')
 
80
 
 
81
                im = Image.open(cStringIO.StringIO(item.data)).convert('P')
 
82
                im.thumbnail((300,300), Image.ANTIALIAS)
 
83
 
 
84
                data = cStringIO.StringIO()
 
85
                im.save(data, 'PNG')
 
86
                data = data.getvalue()
 
87
 
 
88
                if len(data) + len(header) < 65505:
 
89
                    images.append((header, data))
 
90
 
 
91
        return images
 
92
 
 
93
    def _metadata(self, metadata):
 
94
        '''
 
95
        Metadata takes the form:
 
96
        title\x00
 
97
        author\x00
 
98
        copyright\x00
 
99
        publisher\x00
 
100
        isbn\x00
 
101
        '''
 
102
 
 
103
        title = _('Unknown')
 
104
        author = _('Unknown')
 
105
        copyright = ''
 
106
        publisher = ''
 
107
        isbn = ''
 
108
 
 
109
        if metadata:
 
110
            if len(metadata.title) >= 1:
 
111
                title = metadata.title[0].value
 
112
            if len(metadata.creator) >= 1:
 
113
                from calibre.ebooks.metadata import authors_to_string
 
114
                author = authors_to_string([x.value for x in metadata.creator])
 
115
            if len(metadata.rights) >= 1:
 
116
                copyright = metadata.rights[0].value
 
117
            if len(metadata.publisher) >= 1:
 
118
                publisher = metadata.publisher[0].value
 
119
 
 
120
        return '%s\x00%s\x00%s\x00%s\x00%s\x00' % (title, author, copyright, publisher, isbn)
 
121
 
 
122
    def _header_record(self, text_items, image_items):
 
123
        '''
 
124
        text_items = the number of text pages
 
125
        image_items = the number of images
 
126
        '''
 
127
        version = 10 # Zlib compression
 
128
        non_text_offset = text_items + 1
 
129
 
 
130
        if image_items > 0:
 
131
            image_data_offset = text_items + 1
 
132
            meta_data_offset = image_data_offset + image_items
 
133
            last_data_offset = meta_data_offset + 1
 
134
        else:
 
135
            meta_data_offset = text_items + 1
 
136
            last_data_offset = meta_data_offset + 1
 
137
            image_data_offset = last_data_offset
 
138
 
 
139
        record = ''
 
140
 
 
141
        record += struct.pack('>H', version)                # [0:2]    # Version. Specifies compression and drm. 2 = palmdoc, 10 = zlib. 260 and 272 = DRM
 
142
        record += struct.pack('>H', 0)                      # [2:4]
 
143
        record += struct.pack('>H', 0)                      # [4:6]
 
144
        record += struct.pack('>H', 25152)                  # [6:8]    # 25152 is MAGIC. Somehow represents the cp1252 encoding of the text
 
145
        record += struct.pack('>H', 0)                      # [8:10]
 
146
        record += struct.pack('>H', 0)                      # [10:12]
 
147
        record += struct.pack('>H', non_text_offset)        # [12:14]  # non_text_offset
 
148
        record += struct.pack('>H', 0)                      # [14:16]
 
149
        record += struct.pack('>H', 0)                      # [16:18]
 
150
        record += struct.pack('>H', 0)                      # [18:20]
 
151
        record += struct.pack('>H', image_items)            # [20:22]  # Number of images
 
152
        record += struct.pack('>H', 0)                      # [22:24]
 
153
        record += struct.pack('>H', 1)                      # [24:26]  # 1 if has metadata, 0 if not
 
154
        record += struct.pack('>H', 0)                      # [26:28]
 
155
        record += struct.pack('>H', 0)                      # [28:30]  # footnote_rec
 
156
        record += struct.pack('>H', 0)                      # [30:32]  # sidebar_rec
 
157
        record += struct.pack('>H', last_data_offset)       # [32:34]  # bookmark_offset
 
158
        record += struct.pack('>H', 2560)                   # [34:36]  # 2560 is MAGIC
 
159
        record += struct.pack('>H', 0)                      # [36:38]
 
160
        record += struct.pack('>H', 0)                      # [38:40]
 
161
        record += struct.pack('>H', image_data_offset)      # [40:42]  # image_data_offset. This will be the last data offset if there are no images
 
162
        record += struct.pack('>H', 0)                      # [42:44]
 
163
        record += struct.pack('>H', meta_data_offset)       # [44:46]  # meta_data_offset. This will be the last data offset if there are no images
 
164
        record += struct.pack('>H', 0)                      # [46:48]
 
165
        record += struct.pack('>H', last_data_offset)       # [48:50]  # footnote_offset. This will be the last data offset if there are no images
 
166
        record += struct.pack('>H', last_data_offset)       # [50:52]  # sidebar_offset. This will be the last data offset if there are no images
 
167
        record += struct.pack('>H', last_data_offset)       # [52:54]  # last_data_offset
 
168
 
 
169
        for i in range(54, 132, 2):
 
170
            record += struct.pack('>H', 0)                  # [54:132]
 
171
 
 
172
        return record
 
173