diff --git a/setup.py b/setup.py
index 5302fa9bc3..de0f292d8d 100644
--- a/setup.py
+++ b/setup.py
@@ -20,23 +20,23 @@ from libprs500 import __appname__ as APPNAME
entry_points = {
'console_scripts': [ \
- 'prs500 = libprs500.devices.prs500.cli.main:main', \
- 'lrf-meta = libprs500.ebooks.lrf.meta:main', \
- 'rtf-meta = libprs500.ebooks.metadata.rtf:main', \
- 'pdf-meta = libprs500.ebooks.metadata.pdf:main', \
- 'txt2lrf = libprs500.ebooks.lrf.txt.convert_from:main', \
- 'html2lrf = libprs500.ebooks.lrf.html.convert_from:main',\
- 'markdown = libprs500.ebooks.markdown.markdown:main',\
- 'lit2lrf = libprs500.ebooks.lrf.lit.convert_from:main',\
- 'rtf2lrf = libprs500.ebooks.lrf.rtf.convert_from:main',\
- 'web2disk = libprs500.web.fetch.simple:main',\
- 'web2lrf = libprs500.ebooks.lrf.web.convert_from:main',\
- 'pdf2lrf = libprs500.ebooks.lrf.pdf.convert_from:main',\
- 'any2lrf = libprs500.ebooks.lrf.any.convert_from:main',\
- 'lrf2lrs = libprs500.ebooks.lrf.parser:main',\
- 'libprs500-beta = libprs500.gui2.main:main',\
+ 'prs500 = libprs500.devices.prs500.cli.main:main',
+ 'lrf-meta = libprs500.ebooks.lrf.meta:main',
+ 'rtf-meta = libprs500.ebooks.metadata.rtf:main',
+ 'pdf-meta = libprs500.ebooks.metadata.pdf:main',
+ 'txt2lrf = libprs500.ebooks.lrf.txt.convert_from:main',
+ 'html2lrf = libprs500.ebooks.lrf.html.convert_from:main',
+ 'markdown = libprs500.ebooks.markdown.markdown:main',
+ 'lit2lrf = libprs500.ebooks.lrf.lit.convert_from:main',
+ 'rtf2lrf = libprs500.ebooks.lrf.rtf.convert_from:main',
+ 'web2disk = libprs500.web.fetch.simple:main',
+ 'web2lrf = libprs500.ebooks.lrf.web.convert_from:main',
+ 'pdf2lrf = libprs500.ebooks.lrf.pdf.convert_from:main',
+ 'any2lrf = libprs500.ebooks.lrf.any.convert_from:main',
+ 'lrf2lrs = libprs500.ebooks.lrf.parser:main',
+ 'lrfviewer = libprs500.gui2.lrf_renderer.main:main',
],
- 'gui_scripts' : [ APPNAME+' = libprs500.gui.main:main']
+ 'gui_scripts' : [ APPNAME+' = libprs500.gui2.main:main']
}
def _ep_to_script(ep, base='src'):
diff --git a/src/libprs500/ebooks/lrf/objects.py b/src/libprs500/ebooks/lrf/objects.py
index daf1a7244a..9c931fef59 100644
--- a/src/libprs500/ebooks/lrf/objects.py
+++ b/src/libprs500/ebooks/lrf/objects.py
@@ -17,21 +17,21 @@ import struct, array, zlib, cStringIO
from libprs500.ebooks.lrf import LRFParseError
from libprs500.ebooks.lrf.tags import Tag
-class LRFObject(object):
-
- tag_map = {
- 0xF500: ['', ''],
- 0xF502: ['infoLink', 'D'],
- 0xF501: ['', ''],
-
- # Ruby tags
+ruby_tags = {
0xF575: ['rubyAlignAndAdjust', 'W'],
0xF576: ['rubyoverhang', 'W', {0: 'none', 1:'auto'}],
0xF577: ['empdotsposition', 'W', {1: 'before', 2:'after'}],
0xF578: ['','parse_empdots'],
0xF579: ['emplineposition', 'W', {1: 'before', 2:'after'}],
0xF57A: ['emplinetype', 'W', {0: 'none', 0x10: 'solid', 0x20: 'dashed', 0x30: 'double', 0x40: 'dotted'}]
+}
+class LRFObject(object):
+
+ tag_map = {
+ 0xF500: ['', ''],
+ 0xF502: ['infoLink', 'D'],
+ 0xF501: ['', ''],
}
@classmethod
@@ -99,7 +99,7 @@ class LRFObject(object):
return unicode(self.__class__.__name__)
def __str__(self):
- return unicode(self)
+ return unicode(self).encode('utf-8')
class LRFContentObject(LRFObject):
@@ -199,14 +199,27 @@ class PageTree(LRFObject):
class StyleObject(object):
- def __unicode__(self):
- s = '<%s objid="%s" stylelabel="%s" '%(self.__class__.__name__.replace('Attr', 'Style'), self.id, self.id)
+ def _tags_to_xml(self):
+ s = u''
for h in self.tag_map.values():
attr = h[0]
if hasattr(self, attr):
- s += '%s="%s" '%(attr, getattr(self, attr))
- s += '/>\n'
+ s += u'%s="%s" '%(attr, getattr(self, attr))
return s
+
+ def __unicode__(self):
+ s = u'<%s objid="%s" stylelabel="%s" '%(self.__class__.__name__.replace('Attr', 'Style'), self.id, self.id)
+ s += self._tags_to_xml()
+ s += u'/>\n'
+ return s
+
+ def as_dict(self):
+ d = {}
+ for h in self.tag_map.values():
+ attr = h[0]
+ if hasattr(self, attr):
+ d[attr] = getattr(self, attr)
+ return d
class PageAttr(StyleObject, LRFObject):
tag_map = {
@@ -234,13 +247,20 @@ class PageAttr(StyleObject, LRFObject):
class Color(object):
def __init__(self, val):
- self.b, self.g, self.r, self.a = val & 0xFF, (val>>8)&0xFF, (val>>16)&0xFF, (val>>24)&0xFF
+ self.a, self.r, self.g, self.b = val & 0xFF, (val>>8)&0xFF, (val>>16)&0xFF, (val>>24)&0xFF
def __unicode__(self):
return u'0x%02x%02x%02x%02x'%(self.a, self.r, self.g, self.b)
def __str__(self):
return unicode(self)
+
+ def __len__(self):
+ return 4
+
+ def __getitem__(self, i): # Qt compatible ordering and values
+ return (self.r, self.g, self.b, 0xff-self.a)[i] # In Qt 0xff is opaque while in LRS 0x00 is opaque
+
class EmptyPageElement(object):
def __iter__(self):
@@ -310,6 +330,11 @@ class Page(LRFStream):
}
tag_map.update(PageAttr.tag_map)
tag_map.update(LRFStream.tag_map)
+ style = property(fget=lambda self : self._document.objects[self.style_id])
+ evenheader = property(fget=lambda self : self._document.objects[self.style.evenheaderid])
+ evenfooter = property(fget=lambda self : self._document.objects[self.style.evenfooterid])
+ oddheader = property(fget=lambda self : self._document.objects[self.style.oddheaderid])
+ oddfooter = property(fget=lambda self : self._document.objects[self.style.oddfooterid])
class Content(LRFContentObject):
tag_map = {
@@ -372,11 +397,13 @@ class Page(LRFStream):
if hasattr(self, 'xspace'): delattr(self, 'xspace')
if hasattr(self, 'yspace'): delattr(self, 'yspace')
- @apply
- def style():
- def fget(self):
- return self._document.objects[self.style_id]
- return property(fget=fget)
+ def header(self, odd):
+ id = self._document.objects[self.style_id].oddheaderid if odd else self._document.objects[self.style_id].evenheaderid
+ return self._document.objects[id]
+
+ def footer(self, odd):
+ id = self._document.objects[self.style_id].oddfooterid if odd else self._document.objects[self.style_id].evenfooterid
+ return self._document.objects[id]
def initialize(self):
self.content = Page.Content(self.stream, self._document.objects)
@@ -437,6 +464,7 @@ class TextAttr(StyleObject, LRFObject):
0xF5F1: ['textlinewidth', 'W'],
0xF5F2: ['linecolor', 'D', Color],
}
+ tag_map.update(ruby_tags)
tag_map.update(LRFObject.tag_map)
@@ -450,17 +478,8 @@ class Block(LRFStream):
extra_attrs = [i[0] for i in BlockAttr.tag_map.values()]
extra_attrs.extend([i[0] for i in TextAttr.tag_map.values()])
- @apply
- def style():
- def fget(self):
- return self._document.objects[self.style_id]
- return property(fget=fget)
-
- @apply
- def textstyle():
- def fget(self):
- return self._document.objects[self.textstyle_id]
- return property(fget=fget)
+ style = property(fget=lambda self : self._document.objects[self.style_id])
+ textstyle = property(fget=lambda self : self._document.objects[self.textstyle_id])
def initialize(self):
self.attrs = {}
@@ -527,11 +546,7 @@ class Text(LRFStream):
tag_map.update(TextAttr.tag_map)
tag_map.update(LRFStream.tag_map)
- @apply
- def style():
- def fget(self):
- return self._document.objects[self.style_id]
- return property(fget=fget)
+ style = property(fget=lambda self : self._document.objects[self.style_id])
class Content(LRFContentObject):
tag_map = {
@@ -561,7 +576,7 @@ class Text(LRFStream):
0xF5BC: 'end_container',
0xF5BD: ['simple_container', 'EmpDots'],
0xF5BE: 'end_container',
- 0xF5C1: ['simple_container', 'EmpLine'],
+ 0xF5C1: 'empline',
0xF5C2: 'end_container',
0xF5C3: 'draw_char',
0xF5C4: 'end_container',
@@ -576,6 +591,7 @@ class Text(LRFStream):
text_map = { 0x22: u'"', 0x26: u'&', 0x27: u''', 0x3c: u'<', 0x3e: u'>' }
linetype_map = {0: 'none', 0x10: 'solid', 0x20: 'dashed', 0x30: 'double', 0x40: 'dotted'}
adjustment_map = {1: 'top', 2: 'center', 3: 'baseline', 4: 'bottom'}
+ lineposition_map = {1:'before', 2:'after'}
def __init__(self, bytes, objects, parent=None, name=None, attrs={}):
self.parent = parent
@@ -663,6 +679,37 @@ class Text(LRFStream):
self._contents.append(Text.Content(self.stream, self.objects, parent=self,
name='CharButton', attrs={'refobj':tag.dword}))
+ def empline(self, tag):
+
+ def invalid(op):
+ self.stream.seek(op)
+ self.simple_container('EmpLine')
+
+ oldpos = self.stream.tell()
+ try:
+ t = Tag(self.stream)
+ if t.id not in [0xF579, 0xF57A]:
+ raise LRFParseError
+ except LRFParseError:
+ invalid(oldpos)
+ return
+ h = TextAttr.tag_map[t.id]
+ attrs = {}
+ attrs[h[0]] = TextAttr.tag_to_val(h, None, t, None)
+ oldpos = self.stream.tell()
+ try:
+ t = Tag(self.stream)
+ if t.id not in [0xF579, 0xF57A]:
+ raise LRFParseError
+ h = TextAttr.tag_map[t.id]
+ attrs[h[0]] = TextAttr.tag_to_val(h, None, t, None)
+ except LRFParseError:
+ self.stream.seek(oldpos)
+
+ cont = Text.Content(self.stream, self.objects, parent=self,
+ name='EmpLine', attrs=attrs)
+ self._contents.append(cont)
+
def space(self, tag):
self._contents.append(Text.Content('', self.objects, parent=self,
name='Space', attrs={'xsize':tag.sword}))
@@ -737,17 +784,9 @@ class Image(LRFObject):
def parse_image_size(self, tag, f):
self.xsize, self.ysize = struct.unpack("\n'%\
@@ -755,8 +794,9 @@ class Image(LRFObject):
class PutObj(EmptyPageElement):
- def __init__(self, x, y, refobj):
+ def __init__(self, objects, x, y, refobj):
self.x, self.y, self.refobj = x, y, refobj
+ self.object = objects[refobj]
def __unicode__(self):
return u''%(self.x, self.y, self.refobj)
@@ -791,7 +831,7 @@ class Canvas(LRFStream):
stream = cStringIO.StringIO(self.stream)
while stream.tell() < len(self.stream):
tag = Tag(stream)
- self._contents.append(PutObj(*struct.unpack("\n'
return s
- @apply
- def refpage():
- def fget(self):
- return self.jump_action(2)[0]
- return property(fget=fget)
+ refpage = property(fget=lambda self : self.jump_action(2)[0])
+ refobject = property(fget=lambda self : self.jump_action(2)[1])
- @apply
- def refobject():
- def fget(self):
- return self.jump_action(2)[1]
- return property(fget=fget)
-
class Window(LRFObject):
pass
@@ -957,6 +984,7 @@ class Font(LRFStream):
0xF55D: ['fontfacename', 'P'],
}
tag_map.update(LRFStream.tag_map)
+ data = property(fget=lambda self: self.stream)
def end_stream(self, *args):
LRFStream.end_stream(self, *args)
@@ -978,6 +1006,7 @@ class BookAttr(StyleObject, LRFObject):
0xF5D8: ['', 'add_font'],
0xF5DA: ['setwaitprop', 'W', {1: 'replay', 2: 'noreplay'}],
}
+ tag_map.update(ruby_tags)
tag_map.update(LRFObject.tag_map)
binding_map = {1: 'Lr', 16 : 'Rl'}
@@ -990,6 +1019,7 @@ class BookAttr(StyleObject, LRFObject):
def __unicode__(self):
s = u'\n'%(self.id, self.id)
+ s += u'\n'%(self._tags_to_xml(),)
doc = self._document
s += u'\n'%\
(self.binding_map[doc.binding], doc.dpi, doc.width, doc.height, doc.color_depth)
diff --git a/src/libprs500/ebooks/lrf/parser.py b/src/libprs500/ebooks/lrf/parser.py
index 752bdd47d0..0e2274939c 100644
--- a/src/libprs500/ebooks/lrf/parser.py
+++ b/src/libprs500/ebooks/lrf/parser.py
@@ -19,11 +19,13 @@ import sys, array, os, re, codecs, logging
from libprs500 import __author__, __appname__, __version__, setup_cli_handlers
from libprs500.ebooks.lrf.meta import LRFMetaFile
from libprs500.ebooks.lrf.objects import get_object, PageTree, StyleObject, \
- Font, Text, TOCObject
+ Font, Text, TOCObject, BookAttr, ruby_tags
class LRFDocument(LRFMetaFile):
+ class temp(object): pass
+
def __init__(self, stream):
LRFMetaFile.__init__(self, stream)
self.scramble_key = self.xor_key
@@ -32,6 +34,17 @@ class LRFDocument(LRFMetaFile):
self.image_map = {}
self._parse_objects()
self.toc = None
+ self.metadata = LRFDocument.temp()
+ for a in ('title', 'title_reading', 'author', 'author_reading', 'book_id',
+ 'classification', 'free_text', 'publisher', 'label', 'category'):
+ setattr(self.metadata, a, getattr(self, a))
+ self.doc_info = LRFDocument.temp()
+ for a in ('thumbnail', 'language', 'creator', 'producer', 'page'):
+ setattr(self.doc_info, a, getattr(self, a))
+ self.doc_info.thumbnail_extension = self.thumbail_extension()
+ self.device_info = LRFDocument.temp()
+ for a in ('dpi', 'width', 'height'):
+ setattr(self.device_info, a, getattr(self, a))
def _parse_objects(self):
self.objects = {}
@@ -53,6 +66,12 @@ class LRFDocument(LRFMetaFile):
self.page_trees.append(obj)
elif isinstance(obj, TOCObject):
self.toc = obj
+ elif isinstance(obj, BookAttr):
+ self.ruby_tags = {}
+ for h in ruby_tags.values():
+ attr = h[0]
+ if hasattr(obj, attr):
+ self.ruby_tags[attr] = getattr(obj, attr)
def __iter__(self):
for pt in self.page_trees:
@@ -64,22 +83,22 @@ class LRFDocument(LRFMetaFile):
def to_xml(self):
bookinfo = u'\n\n\n'
- bookinfo += u'%s\n'%(self.title_reading, self.title)
- bookinfo += u'%s\n'%(self.author_reading, self.author)
- bookinfo += u'%s\n'%(self.book_id,)
- bookinfo += u'%s\n'%(self.publisher,)
- bookinfo += u'\n'%(self.label,)
- bookinfo += u'%s\n'%(self.category,)
- bookinfo += u'%s\n'%(self.classification,)
- bookinfo += u'%s\n\n\n'%(self.free_text,)
- th = self.thumbnail
+ bookinfo += u'%s\n'%(self.metadata.title_reading, self.metadata.title)
+ bookinfo += u'%s\n'%(self.metadata.author_reading, self.metadata.author)
+ bookinfo += u'%s\n'%(self.metadata.book_id,)
+ bookinfo += u'%s\n'%(self.metadata.publisher,)
+ bookinfo += u'\n'%(self.metadata.label,)
+ bookinfo += u'%s\n'%(self.metadata.category,)
+ bookinfo += u'%s\n'%(self.metadata.classification,)
+ bookinfo += u'%s\n\n\n'%(self.metadata.free_text,)
+ th = self.doc_info.thumbnail
if th:
- bookinfo += u'\n'%(self.title+'_thumbnail.'+self.thumbail_extension(),)
- open(self.title+'_thumbnail.'+self.thumbail_extension(), 'wb').write(th)
- bookinfo += u'%s\n'%(self.language,)
- bookinfo += u'%s\n'%(self.creator,)
- bookinfo += u'%s\n'%(self.producer,)
- bookinfo += u'%s\n\n\n\n'%(self.page,)
+ bookinfo += u'\n'%(self.metadata.title+'_thumbnail.'+self.doc_info.thumbail_extension(),)
+ open(self.metadata.title+'_thumbnail.'+self.doc_info.thumbail_extension(), 'wb').write(th)
+ bookinfo += u'%s\n'%(self.doc_info.language,)
+ bookinfo += u'%s\n'%(self.doc_info.creator,)
+ bookinfo += u'%s\n'%(self.doc_info.producer,)
+ bookinfo += u'%s\n\n\n\n'%(self.doc_info.page,)
pages = u''
done_main = False
pt_id = -1
@@ -112,13 +131,16 @@ class LRFDocument(LRFMetaFile):
self.write_files()
return '\n' + bookinfo + pages + styles + objects + ''
-
-def main(args=sys.argv, logger=None):
+def option_parser():
from optparse import OptionParser
parser = OptionParser(usage='%prog book.lrf', epilog='Created by '+__author__,
version=__appname__ + ' ' + __version__)
parser.add_option('--output', '-o', default=None, help='Output LRS file', dest='out')
parser.add_option('--verbose', default=False, action='store_true', dest='verbose')
+ return parser
+
+def main(args=sys.argv, logger=None):
+ parser = option_parser()
opts, args = parser.parse_args(args)
if logger is None:
level = logging.DEBUG if opts.verbose else logging.INFO