mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Fixed bug in setting of thumbnails
Added documentation
This commit is contained in:
parent
e6b1f2e829
commit
391ab780b3
@ -73,7 +73,12 @@ class fixed_stringfield(object):
|
|||||||
return "A string of length " + str(self._length) + " starting at byte " + str(self._start)
|
return "A string of length " + str(self._length) + " starting at byte " + str(self._start)
|
||||||
|
|
||||||
class xml_field(object):
|
class xml_field(object):
|
||||||
|
"""
|
||||||
|
Descriptor that gets and sets XML based meta information from an LRF file.
|
||||||
|
Works for simple XML fields of the form <tagname>data</tagname>
|
||||||
|
"""
|
||||||
def __init__(self, tag_name):
|
def __init__(self, tag_name):
|
||||||
|
""" @param tag_name: The XML tag whoose data we operate on """
|
||||||
self.tag_name = tag_name
|
self.tag_name = tag_name
|
||||||
|
|
||||||
def __get__(self, obj, typ=None):
|
def __get__(self, obj, typ=None):
|
||||||
@ -94,17 +99,23 @@ class xml_field(object):
|
|||||||
Print(document, s)
|
Print(document, s)
|
||||||
obj.info = s.getvalue()
|
obj.info = s.getvalue()
|
||||||
s.close()
|
s.close()
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return self.tag_name
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return "XML Field: " + self.tag_name
|
||||||
|
|
||||||
class LRFMetaFile(object):
|
class LRFMetaFile(object):
|
||||||
|
""" Has properties to read and write all Meta information in a LRF file. """
|
||||||
LRF_HEADER = "L\0R\0F\0\0\0"
|
LRF_HEADER = "L\0R\0F\0\0\0" #: The first 8 bytes of all valid LRF files
|
||||||
|
|
||||||
lrf_header = fixed_stringfield(length=8, start=0)
|
lrf_header = fixed_stringfield(length=8, start=0)
|
||||||
version = field(fmt=WORD, start=8)
|
version = field(fmt=WORD, start=8)
|
||||||
xor_key = field(fmt=WORD, start=10)
|
xor_key = field(fmt=WORD, start=10)
|
||||||
root_object_id = field(fmt=DWORD, start=12)
|
root_object_id = field(fmt=DWORD, start=12)
|
||||||
number_of_objets = field(fmt=QWORD, start=16)
|
number_of_objets = field(fmt=QWORD, start=16)
|
||||||
object_table_offset = field(fmt=QWORD, start=24)
|
object_index_offset = field(fmt=QWORD, start=24)
|
||||||
binding = field(fmt=BYTE, start=36)
|
binding = field(fmt=BYTE, start=36)
|
||||||
dpi = field(fmt=WORD, start=38)
|
dpi = field(fmt=WORD, start=38)
|
||||||
width = field(fmt=WORD, start=42)
|
width = field(fmt=WORD, start=42)
|
||||||
@ -131,6 +142,7 @@ class LRFMetaFile(object):
|
|||||||
page = xml_field("Page")
|
page = xml_field("Page")
|
||||||
|
|
||||||
def safe(func):
|
def safe(func):
|
||||||
|
""" Decorator that ensures that function calls leave the pos in the underlying file unchanged """
|
||||||
def restore_pos(*args, **kwargs):
|
def restore_pos(*args, **kwargs):
|
||||||
obj = args[0]
|
obj = args[0]
|
||||||
pos = obj._file.tell()
|
pos = obj._file.tell()
|
||||||
@ -141,6 +153,7 @@ class LRFMetaFile(object):
|
|||||||
return restore_pos
|
return restore_pos
|
||||||
|
|
||||||
def safe_property(func):
|
def safe_property(func):
|
||||||
|
""" Decorator that ensures that read or writing a property leaves the position in the underlying file unchanged """
|
||||||
def decorator(f):
|
def decorator(f):
|
||||||
def restore_pos(*args, **kwargs):
|
def restore_pos(*args, **kwargs):
|
||||||
obj = args[0]
|
obj = args[0]
|
||||||
@ -181,30 +194,44 @@ class LRFMetaFile(object):
|
|||||||
return locals()
|
return locals()
|
||||||
|
|
||||||
@safe_property
|
@safe_property
|
||||||
def thumbail_pos():
|
def thumbnail_pos():
|
||||||
|
doc=""" The position of the thumbnail in the LRF file """
|
||||||
def fget(self):
|
def fget(self):
|
||||||
return self.info_start+ self.compressed_info_size-4
|
return self.info_start+ self.compressed_info_size-4
|
||||||
return locals()
|
return locals()
|
||||||
|
|
||||||
@safe_property
|
@safe_property
|
||||||
def thumbnail():
|
def thumbnail():
|
||||||
|
doc=\
|
||||||
|
""" The thumbnail. Represented as a string. The string you would get from the file read function. """
|
||||||
def fget(self):
|
def fget(self):
|
||||||
if self.thumbnail_size:
|
size = self.thumbnail_size
|
||||||
self._file.seek(self.thumbail_pos)
|
if size:
|
||||||
print hex(self._file.tell())
|
self._file.seek(self.thumbnail_pos)
|
||||||
return self._file.read(self.thumbnail_size)
|
return self._file.read(size)
|
||||||
|
|
||||||
def fset(self, data):
|
def fset(self, data):
|
||||||
if self.version <= 800: raise LRFException("Cannot store thumbnails in LRF files of version <= 800")
|
if self.version <= 800: raise LRFException("Cannot store thumbnails in LRF files of version <= 800")
|
||||||
orig_size = self.thumbnail_size
|
orig_size = self.thumbnail_size
|
||||||
self._file.seek(self.thumbail_pos+orig_size)
|
self._file.seek(self.toc_object_offset)
|
||||||
rest_of_file = self._file.read()
|
toc = self._file.read(self.object_index_offset - self.toc_object_offset)
|
||||||
|
self._file.seek(self.object_index_offset)
|
||||||
|
objects = self._file.read()
|
||||||
self.thumbnail_size = len(data)
|
self.thumbnail_size = len(data)
|
||||||
self._file.seek(self.thumbnail_pos)
|
self._file.seek(self.thumbnail_pos)
|
||||||
self.file.write(data+rest_of_file)
|
self._file.write(data)
|
||||||
delta = len(data) - orig_size
|
orig_offset = self.toc_object_offset
|
||||||
self.object_table_offset = self.object_table_offset + delta
|
self.toc_object_offset = self._file.tell()
|
||||||
self.toc_object_offset = self.toc_object_offset + delta
|
self._file.write(toc)
|
||||||
|
self.object_index_offset = self._file.tell()
|
||||||
|
self._file.write(objects)
|
||||||
|
ttype = 0x14
|
||||||
|
if data[1:4] == "PNG": ttype = 0x12
|
||||||
|
if data[0:2] == "BM": ttype = 0x13
|
||||||
|
if data[0:4] == "JIFF": ttype = 0x11
|
||||||
|
self.thumbnail_type = ttype
|
||||||
self._file.flush()
|
self._file.flush()
|
||||||
|
self.update_object_offsets(self.toc_object_offset - orig_offset) # Needed as new thumbnail may have different size than old thumbnail
|
||||||
return locals()
|
return locals()
|
||||||
|
|
||||||
def __init__(self, file):
|
def __init__(self, file):
|
||||||
@ -212,10 +239,25 @@ class LRFMetaFile(object):
|
|||||||
file.seek(0,2)
|
file.seek(0,2)
|
||||||
self.size = file.tell()
|
self.size = file.tell()
|
||||||
self._file = file
|
self._file = file
|
||||||
if self.lrf_header != LRFFile.LRF_HEADER:
|
if self.lrf_header != LRFMetaFile.LRF_HEADER:
|
||||||
raise LRFException(file.name + " has an invalid LRF header. Are you sure it is an LRF file?")
|
raise LRFException(file.name + " has an invalid LRF header. Are you sure it is an LRF file?")
|
||||||
self.info_start = 0x58 if self.version > 800 else 0x53 #: Byte at which the compressed meta information starts
|
self.info_start = 0x58 if self.version > 800 else 0x53 #: Byte at which the compressed meta information starts
|
||||||
|
|
||||||
|
@safe
|
||||||
|
def update_object_offsets(self, delta):
|
||||||
|
""" Run through the LRF Object index changing the offset by C{delta}. """
|
||||||
|
self._file.seek(self.object_index_offset)
|
||||||
|
while(True):
|
||||||
|
try: self._file.read(4)
|
||||||
|
except EOFError: break
|
||||||
|
pos = self._file.tell()
|
||||||
|
try: offset = self.unpack(fmt=DWORD, start=pos)[0] + delta
|
||||||
|
except struct.error: break
|
||||||
|
self.pack(offset, fmt=DWORD, start=pos)
|
||||||
|
try: self._file.read(12)
|
||||||
|
except EOFError: break
|
||||||
|
self._file.flush()
|
||||||
|
|
||||||
@safe
|
@safe
|
||||||
def unpack(self, fmt=DWORD, start=0):
|
def unpack(self, fmt=DWORD, start=0):
|
||||||
"""
|
"""
|
||||||
@ -250,4 +292,53 @@ class LRFMetaFile(object):
|
|||||||
def __getslice__(self, start, end):
|
def __getslice__(self, start, end):
|
||||||
""" Return a LRFFile rather than a list as the slice """
|
""" Return a LRFFile rather than a list as the slice """
|
||||||
return LRFFile(list.__getslice__(self, start, end))
|
return LRFFile(list.__getslice__(self, start, end))
|
||||||
|
|
||||||
|
def thumbail_extension(self):
|
||||||
|
ext = "gif"
|
||||||
|
ttype = self.thumbnail_type
|
||||||
|
if ttype == 0x11: ext = "jpeg"
|
||||||
|
elif ttype == 0x12: ext = "png"
|
||||||
|
elif ttype == 0x13: ext = "bm"
|
||||||
|
return ext
|
||||||
|
|
||||||
|
def main():
|
||||||
|
import sys, os.path
|
||||||
|
from optparse import OptionParser
|
||||||
|
from libprs500 import __version__ as VERSION
|
||||||
|
parser = OptionParser(usage="usage: %prog [options] mybook.lrf", version=VERSION)
|
||||||
|
parser.add_option("-t", "--title", action="store", type="string", 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("-c", "--category", action="store", type="string", dest="category", help="The category this book belongs to. E.g.: History")
|
||||||
|
parser.add_option("--thumbnail", action="store", type="string", dest="thumbnail", help="Path to a graphic that will be set as this files' thumbnail")
|
||||||
|
parser.add_option("-p", "--page", action="store", type="string", dest="page", help="Set the current page number (I think)")
|
||||||
|
options, args = parser.parse_args()
|
||||||
|
if len(args) != 1:
|
||||||
|
parser.print_help()
|
||||||
|
sys.exit(1)
|
||||||
|
lrf = LRFMetaFile(open(args[0], "r+b"))
|
||||||
|
if options.title: lrf.title = options.title
|
||||||
|
if options.author: lrf.author = options.author
|
||||||
|
if options.category: lrf.category = options.category
|
||||||
|
if options.page: lrf.page = options.page
|
||||||
|
if options.thumbnail:
|
||||||
|
f = open(options.thumbnail, "r")
|
||||||
|
lrf.thumbnail = f.read()
|
||||||
|
f.close()
|
||||||
|
|
||||||
|
t = lrf.thumbnail
|
||||||
|
td = "None"
|
||||||
|
if t and len(t) > 0:
|
||||||
|
td = os.path.basename(args[0])+"_thumbnail_."+lrf.thumbail_extension()
|
||||||
|
f = open(td, "w")
|
||||||
|
f.write(t)
|
||||||
|
f.close()
|
||||||
|
|
||||||
|
fields = LRFMetaFile.__dict__.items()
|
||||||
|
for f in fields:
|
||||||
|
if "XML" in str(f):
|
||||||
|
print str(f[1]) + ":", lrf.__getattribute__(f[0])
|
||||||
|
print "Thumbnail:", td
|
||||||
|
print "object index offset:", hex(lrf.object_index_offset)
|
||||||
|
print "toc object offset", hex(lrf.toc_object_offset)
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user