Minor bug fixes in lrf.meta as well as an initial import of code to create LRF files. Will work more on this only if BBeBook-0.3 proves insufficient.

This commit is contained in:
Kovid Goyal 2007-01-06 19:43:50 +00:00
parent fa758e1b2c
commit eb07f9c91f
4 changed files with 183 additions and 13 deletions

View File

@ -0,0 +1,68 @@
## Copyright (C) 2006 Kovid Goyal kovid@kovidgoyal.net
## This program is free software; you can redistribute it and/or modify
## it under the terms of the GNU General Public License as published by
## the Free Software Foundation; either version 2 of the License, or
## (at your option) any later version.
##
## This program is distributed in the hope that it will be useful,
## but WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
## GNU General Public License for more details.
##
## You should have received a copy of the GNU General Public License along
## with this program; if not, write to the Free Software Foundation, Inc.,
## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
from cStringIO import StringIO
from zlib import compress
from xml.dom import minidom as dom
from libprs500.lrf.meta import LRFMetaFile, LRFException
GIF_PIXEL = 'GIF89a\x01\x00\x01\x00\xf0\x00\x00Mhh\x00\x00\x00!\xf9\x04\x00\x00'\
'\x00\x00\x00,\x00\x00\x00\x00\x01\x00\x01\x00\x00\x02\x02D\x01\x00;'
def create_lrf_file():
buff = StringIO()
buff.write(LRFMetaFile.LRF_HEADER)
buff.write("".join(['\0' for i in range(0x56 - 6)]))
lrf = LRFMetaFile(buff)
lrf.version = 999 # No reason
lrf.xor_key = 0x30 # No reason
lrf.root_object_id = 0x32 # No reason
lrf.binding = 0x01 # front to back 0x10 for back to front
lrf.dpi = 1600 # TODO: Play with this
lrf.width = 600 # TODO: Play with this
lrf.height = 800 # TODO: Play with this
lrf.color_depth = 24 # Seems like a good idea
lrf.toc_object_id = 0x42 # No reason
lrf.thumbnail_type = 0x14 # GIF
lrf.thumbnail_size = len(GIF_PIXEL)
doc = dom.getDOMImplementation().createDocument(None, None, None)
info = doc.createElement('Info')
info.setAttribute('version', '1.0')
book_info = doc.createElement('BookInfo')
doc_info = doc.createElement('DocInfo')
info.appendChild(book_info)
info.appendChild(doc_info)
info = doc.toxml(encoding='utf-16')
stream = compress(info)
lrf.compressed_info_size = 4 + len(stream)
lrf.uncompressed_info_size = len(info)
buff.write(stream + GIF_PIXEL)
pos = buff.tell()
if pos%16 != 0:
buff.write("".join(['\0' for i in range(16 - pos%16)]))
buff.seek(0)
return lrf
class LRFCreator(object):
pass
if __name__ == "__main__":
open('test.lrf', 'wb').write(create_lrf_file()._file.read())

View File

@ -0,0 +1,93 @@
## Copyright (C) 2006 Kovid Goyal kovid@kovidgoyal.net
## This program is free software; you can redistribute it and/or modify
## it under the terms of the GNU General Public License as published by
## the Free Software Foundation; either version 2 of the License, or
## (at your option) any later version.
##
## This program is distributed in the hope that it will be useful,
## but WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
## GNU General Public License for more details.
##
## You should have received a copy of the GNU General Public License along
## with this program; if not, write to the Free Software Foundation, Inc.,
## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
import struct
from libprs500.prstypes import field
from libprs500.lrf.meta import WORD, DWORD
class LRFTag(list):
"""
Base class for all LRF tags.
An LRFTag is simply a sequence of bytes. The first two bytes are the tag id.
Tag ids are always of the form (encoded little endian) # f5 where # is a byte.
Thus there can be atmost 256 distinct tags.
"""
id = field(fmt=WORD, start=0)
def __init__(self, _id, size):
"""
@param _id: The tag id should be an integer
@param _size: The initial size of this tag
"""
list.__init__(self, ['\0' for i in range(size+4)])
self.id = _id
def pack(self, val, fmt=DWORD, start=0):
"""
Encode C{val} and write it to buffer.
@param fmt: See U{struct<http://docs.python.org/lib/module-struct.html>}
@param start: Position in buffer at which to write encoded data
"""
self[start:start+struct.calcsize(fmt)] = struct.pack(fmt, val)
def unpack(self, fmt=DWORD, start=0):
"""
Return decoded data from buffer.
@param fmt: See U{struct<http://docs.python.org/lib/module-struct.html>}
@param start: Position in buffer from which to decode
"""
end = start + struct.calcsize(fmt)
return struct.unpack(fmt, "".join(list.__getslice__(self, start, end)))
class ObjectStart(LRFTag):
""" Tag that marks the start of an LRFObject """
ID = 0xf500
# Stored in 4 bytes. Thus there can be only 1024*1024*1024 objects in an LRF file
object_id = field(fmt=DWORD, start=0)
# Stored in 2 bytes. Thus there can be at most 256**2 distinct object types.
object_type = field(fmt=WORD, start=4)
def __init__(self, _id, _type):
LRFTag.__init__(self, ObjectStart.ID, 6)
self.object_id = _id
self.object_type = _type
class ObjectEnd(LRFTag):
""" Tag that marks the end of an LRFObject """
ID = 0xf501
def __init__(self):
LRFTag.__init__(self, ObjectEnd.ID, 0)
class LRFObject(list):
"""
Base class for all LRF objects. An LRF object is simply a sequence of
L{LRFTag}s. It must start with an L{ObjectStart} tag and end with
an L{ObjectEnd} tag.
"""
def __str__(self):
return "".join(self)
class BookAttr(LRFObject):
"""
Global properties for an LRF ebook. Root element of the LRF element
structure.
"""

View File

@ -77,7 +77,7 @@ def makelrf(author=None, title=None, \
if not os.access(src, os.R_OK):
raise LRFException("Unable to read from file: " + src)
if thumbnail:
thumb = os.path.abspath(options.thumbnail)
thumb = os.path.abspath(thumbnail)
if not os.access(thumb, os.R_OK):
raise LRFException("Unable to read from " + thumb)
else:
@ -88,7 +88,7 @@ def makelrf(author=None, title=None, \
if not title:
title = os.path.basename(src)
label = os.path.basename(src)
id = hashlib.md5(os.path.basename(label)).hexdigest()
id = 'FB' + hashlib.md5(os.path.basename(label)).hexdigest()[:14]
name, ext = os.path.splitext(label)
cwd = os.path.dirname(src)
dirpath = None
@ -163,7 +163,7 @@ def main(cargs=None):
dest="title", help="Set the book title")
parser.add_option("-a", "--author", action="store", type="string", \
dest="author", help="Set the author")
parser.add_option('-r', '--rasterize', action='store_true', \
parser.add_option('-r', '--rasterize', action='store_false', \
dest="rasterize",
help="Convert pdfs into image files.")
parser.add_option('-c', '--cover', action='store', dest='cover',\

View File

@ -213,13 +213,14 @@ class LRFMetaFile(object):
title = xml_field("Title", parent="BookInfo")
author = xml_field("Author", parent="BookInfo")
# 16 characters. First two chars should be FB for personal use ebooks.
book_id = xml_field("BookID", parent="BookInfo")
publisher = xml_field("Publisher", parent="BookInfo")
label = xml_field("Label", parent="BookInfo")
category = xml_field("Category", parent="BookInfo")
classification = xml_field("Classification", parent="BookInfo")
free_text = xml_field("FreeText", parent="BookInfo")
# Should use ISO 639 language codes
language = xml_field("Language", parent="DocInfo")
creator = xml_field("Creator", parent="DocInfo")
# Format is %Y-%m-%d
@ -296,7 +297,7 @@ class LRFMetaFile(object):
else:
candidate = candidate.encode('utf-16')
return candidate.strip()
except zlib.error, e:
except zlib.error:
raise LRFException("Unable to decompress document meta information")
def fset(self, info):
@ -453,6 +454,22 @@ class LRFMetaFile(object):
slice = self.thumbnail[0:16]
self.thumbnail_type = self._detect_thumbnail_type(slice)
def seek(self, *args):
""" See L{file.seek} """
return self._file.seek(*args)
def tell(self):
""" See L{file.tell} """
return self._file.tell()
def read(self):
""" See L{file.read} """
return self._file.read()
def write(self, val):
""" See L{file.write} """
self._file.write(val)
def main():
import sys, os.path
@ -520,11 +537,3 @@ def main():
print str(f[1]) + ":", lrf.__getattribute__(f[0])
if options.get_thumbnail:
print "Thumbnail:", td
def zeroes(num):
temp = [ '\0' for i in range(num) ]
return "".join(temp)
def create_lrf_header():
buffer = StringIO()
buffer.write()