1
# -*- coding: utf-8 -*-
4
__copyright__ = '2009, John Schember <john@nachtimwald.com>'
5
__docformat__ = 'restructuredtext en'
19
from calibre.ebooks.rb.rbml import RBMLizer
20
from calibre.ebooks.rb import HEADER
21
from calibre.ebooks.rb import unique_name
22
from calibre.ebooks.oeb.base import OEB_IMAGES
23
from calibre.constants import __appname__, __version__
25
TEXT_RECORD_SIZE = 4096
27
class TocItem(object):
29
def __init__(self, name, size, flags):
35
class RBWriter(object):
37
def __init__(self, opts, log):
42
def write_content(self, oeb_book, out_stream, metadata=None):
43
info = [('info.info', self._info_section(metadata))]
44
images = self._images(oeb_book.manifest)
45
text_size, chuncks = self._text(oeb_book)
46
chunck_sizes = [len(x) for x in chuncks]
47
text = [('index.html', chuncks)]
48
hidx = [('index.hidx', ' ')]
52
for name, data in info+text+hidx+images:
55
if (name, data) in text:
58
for c in chunck_sizes:
60
size += 8 + (len(chunck_sizes) * 4)
61
elif (name, data) in info:
65
toc_items.append(TocItem(name.ljust(32, '\x00')[:32], size, flags))
67
self.log.debug('Writing file header...')
68
out_stream.write(HEADER)
69
out_stream.write(struct.pack('<I', 0))
70
out_stream.write(struct.pack('<IH', 0, 0))
71
out_stream.write(struct.pack('<I', 0x128))
72
out_stream.write(struct.pack('<I', 0))
73
for i in range(0x20, 0x128, 4):
74
out_stream.write(struct.pack('<I', 0))
75
out_stream.write(struct.pack('<I', page_count))
76
offset = out_stream.tell() + (len(toc_items) * 44)
77
for item in toc_items:
78
out_stream.write(item.name)
79
out_stream.write(struct.pack('<I', item.size))
80
out_stream.write(struct.pack('<I', offset))
81
out_stream.write(struct.pack('<I', item.flags))
84
out_stream.write(info[0][1])
86
self.log.debug('Writing compressed RB HTHML...')
87
# Compressed text with proper heading
88
out_stream.write(struct.pack('<I', len(text[0][1])))
89
out_stream.write(struct.pack('<I', text_size))
90
for size in chunck_sizes:
91
out_stream.write(struct.pack('<I', size))
92
for chunck in text[0][1]:
93
out_stream.write(chunck)
95
self.log.debug('Writing images...')
96
for item in hidx+images:
97
out_stream.write(item[1])
99
total_size = out_stream.tell()
100
out_stream.seek(0x1c)
101
out_stream.write(struct.pack('<I', total_size))
103
def _text(self, oeb_book):
104
rbmlizer = RBMLizer(self.log, name_map=self.name_map)
105
text = rbmlizer.extract_content(oeb_book, self.opts).encode('cp1252', 'xmlcharrefreplace')
109
for i in range(0, (len(text) / TEXT_RECORD_SIZE) + 1):
110
pages.append(zlib.compress(text[i * TEXT_RECORD_SIZE : (i * TEXT_RECORD_SIZE) + TEXT_RECORD_SIZE], 9))
114
def _images(self, manifest):
118
for item in manifest:
119
if item.media_type in OEB_IMAGES:
122
im = Image.open(cStringIO.StringIO(item.data)).convert('L')
123
data = cStringIO.StringIO()
125
data = data.getvalue()
127
name = '%s.png' % os.path.splitext(os.path.basename(item.href))[0]
128
name = unique_name(name, used_names)
129
used_names.append(name)
130
self.name_map[os.path.basename(item.href)] = name
132
images.append((name, data))
136
def _info_section(self, metadata):
139
if len(metadata.title) >= 1:
140
text += 'TITLE=%s\n' % metadata.title[0].value
141
if len(metadata.creator) >= 1:
142
from calibre.ebooks.metadata import authors_to_string
143
text += 'AUTHOR=%s\n' % authors_to_string([x.value for x in metadata.creator])
144
text += 'GENERATOR=%s - %s\n' % (__appname__, __version__)
147
text += 'BODY=index.html\n'