mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-07 10:14:46 -04:00
Fix thumbnail type detection in lrf.meta and initial integration of BBeBook into libprs500
This commit is contained in:
parent
ee2c0ca1b0
commit
268405d35c
@ -87,7 +87,7 @@
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text" >
|
||||
<string>For help visit <a href="http://libprs500.kovidgoyal.net">http://libprs500.kovidgoyal.net</a><br><br><b>libprs500</b> was created by <b>Kovid Goyal</b> &copy; 2006<br>%1 %2 %3</string>
|
||||
<string>For help visit <a href="https://libprs500.kovidgoyal.net/wiki/GuiUsage">http://libprs500.kovidgoyal.net</a><br><br><b>libprs500</b> was created by <b>Kovid Goyal</b> &copy; 2006<br>%1 %2 %3</string>
|
||||
</property>
|
||||
<property name="textFormat" >
|
||||
<enum>Qt::RichText</enum>
|
||||
|
BIN
libprs500/lrf/BBeBook-0.2.jar
Normal file
BIN
libprs500/lrf/BBeBook-0.2.jar
Normal file
Binary file not shown.
191
libprs500/lrf/makelrf.py
Executable file
191
libprs500/lrf/makelrf.py
Executable file
@ -0,0 +1,191 @@
|
||||
## 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 os
|
||||
import shutil
|
||||
import sys
|
||||
import hashlib
|
||||
import re
|
||||
import time
|
||||
import pkg_resources
|
||||
import subprocess
|
||||
from tempfile import mkdtemp
|
||||
from optparse import OptionParser
|
||||
import xml.dom.minidom as dom
|
||||
|
||||
from libprs500.lrf.meta import LRFException, LRFMetaFile
|
||||
from libprs500.ptempfile import PersistentTemporaryFile
|
||||
|
||||
_bbebook = 'BBeBook-0.2.jar'
|
||||
|
||||
def generate_thumbnail(path):
|
||||
""" Generate a JPEG thumbnail of size ~ 128x128 (aspect ratio preserved)"""
|
||||
try:
|
||||
import Image
|
||||
except ImportError:
|
||||
raise LRFException("Unable to initialize Python Imaging Library." \
|
||||
"Thumbnail generation is disabled")
|
||||
im = Image.open(path)
|
||||
im.thumbnail((128, 128), Image.ANTIALIAS)
|
||||
thumb = PersistentTemporaryFile(prefix="makelrf_", suffix=".jpeg")
|
||||
thumb.close()
|
||||
im = im.convert()
|
||||
im.save(thumb.name)
|
||||
return thumb
|
||||
|
||||
def create_xml(cfg):
|
||||
doc = dom.getDOMImplementation().createDocument(None, None, None)
|
||||
def add_field(parent, tag, value):
|
||||
elem = doc.createElement(tag)
|
||||
elem.appendChild(doc.createTextNode(value))
|
||||
parent.appendChild(elem)
|
||||
|
||||
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)
|
||||
add_field(book_info, 'File', cfg['File'])
|
||||
add_field(doc_info, 'Output', cfg['Output'])
|
||||
for field in ['Title', 'Author', 'BookID', 'Publisher', 'Label', \
|
||||
'Category', 'Classification', 'Icon', 'Cover', 'FreeText']:
|
||||
if cfg.has_key(field):
|
||||
add_field(book_info, field, cfg[field])
|
||||
add_field(doc_info, 'Language', 'en')
|
||||
add_field(doc_info, 'Creator', _bbebook)
|
||||
add_field(doc_info, 'CreationDate', time.strftime('%Y-%m-%d', time.gmtime()))
|
||||
doc.appendChild(info)
|
||||
return doc.toxml()
|
||||
|
||||
def makelrf(author=None, title=None, \
|
||||
thumbnail=None, src=None, odir=".",\
|
||||
rasterize=True, cover=None):
|
||||
src = os.path.normpath(os.path.abspath(src))
|
||||
bbebook = pkg_resources.resource_filename(__name__, _bbebook)
|
||||
if not os.access(src, os.R_OK):
|
||||
raise LRFException("Unable to read from file: " + src)
|
||||
if thumbnail:
|
||||
thumb = os.path.abspath(options.thumbnail)
|
||||
if not os.access(thumb, os.R_OK):
|
||||
raise LRFException("Unable to read from " + thumb)
|
||||
else:
|
||||
thumb = pkg_resources.resource_filename(__name__, 'cover.jpg')
|
||||
|
||||
if not author:
|
||||
author = "Unknown"
|
||||
if not title:
|
||||
title = os.path.basename(src)
|
||||
label = os.path.basename(src)
|
||||
id = hashlib.md5(os.path.basename(label)).hexdigest()
|
||||
name, ext = os.path.splitext(label)
|
||||
cwd = os.path.dirname(src)
|
||||
dirpath = None
|
||||
try:
|
||||
if ext == ".rar":
|
||||
dirpath = mkdtemp('','makelrf')
|
||||
cwd = dirpath
|
||||
cmd = " ".join(["unrar", "e", '"'+src+'"'])
|
||||
proc = subprocess.Popen(cmd, cwd=cwd, shell=True, stderr=subprocess.PIPE)
|
||||
if proc.wait():
|
||||
raise LRFException("unrar failed with error:\n\n" + \
|
||||
proc.stderr.read())
|
||||
path, msize = None, 0
|
||||
for root, dirs, files in os.walk(dirpath):
|
||||
for name in files:
|
||||
if os.path.splitext(name)[1] == ".html":
|
||||
size = os.stat(os.path.join(root, name)).st_size
|
||||
if size > msize:
|
||||
msize, path = size, os.path.join(root, name)
|
||||
if not path:
|
||||
raise LRFException("Could not find .html file in rar archive")
|
||||
src = path
|
||||
|
||||
name = re.sub("\s", "_", name)
|
||||
name = os.path.abspath(os.path.join(odir, name)) + ".lrf"
|
||||
cfg = { 'File' : src, 'Output' : name, 'Label' : label, 'BookID' : id, \
|
||||
'Author' : author, 'Title' : title, 'Publisher' : 'Unknown' \
|
||||
}
|
||||
|
||||
|
||||
if cover:
|
||||
cover = os.path.normpath(os.path.abspath(cover))
|
||||
try:
|
||||
thumbf = generate_thumbnail(cover)
|
||||
thumb = thumbf.name
|
||||
except Exception, e:
|
||||
print >> sys.stderr, "WARNING: Unable to generate thumbnail:\n", \
|
||||
str(e)
|
||||
thumb = cover
|
||||
cfg['Cover'] = cover
|
||||
cfg['Icon'] = thumb
|
||||
config = PersistentTemporaryFile(prefix='makelrf_', suffix='.xml')
|
||||
config.write(create_xml(cfg))
|
||||
config.close()
|
||||
jar = '-jar "' + bbebook + '"'
|
||||
cmd = " ".join(["java", jar, "-r" if rasterize else "", '"'+config.name+'"'])
|
||||
proc = subprocess.Popen(cmd, \
|
||||
cwd=cwd, shell=True, stderr=subprocess.PIPE)
|
||||
if proc.wait():
|
||||
raise LRFException("BBeBook failed with error:\n\n" + \
|
||||
proc.stderr.read())
|
||||
# Needed as BBeBook-0.2 doesn't handle non GIF thumbnails correctly.
|
||||
lrf = open(name, "r+b")
|
||||
LRFMetaFile(lrf).fix_thumbnail_type()
|
||||
lrf.close()
|
||||
return name
|
||||
finally:
|
||||
if dirpath:
|
||||
shutil.rmtree(dirpath, True)
|
||||
|
||||
def main(cargs=None):
|
||||
parser = OptionParser(usage=\
|
||||
"""usage: %prog [options] mybook.[html|pdf|rar]
|
||||
|
||||
%prog converts mybook to mybook.lrf
|
||||
If you specify a rar file you must have the unrar command line client
|
||||
installed. makelrf assumes the rar file is an archive containing the
|
||||
html file you want converted."""\
|
||||
)
|
||||
|
||||
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('-r', '--rasterize', action='store_true', \
|
||||
dest="rasterize",
|
||||
help="Convert pdfs into image files.")
|
||||
parser.add_option('-c', '--cover', action='store', dest='cover',\
|
||||
help="Path to a graphic that will be set as the cover. "\
|
||||
"If it is specified the thumbnail is automatically "\
|
||||
"generated from it")
|
||||
parser.add_option("--thumbnail", action="store", type="string", \
|
||||
dest="thumbnail", \
|
||||
help="Path to a graphic that will be set as the thumbnail")
|
||||
if not cargs:
|
||||
cargs = sys.argv
|
||||
options, args = parser.parse_args()
|
||||
if len(args) != 1:
|
||||
parser.print_help()
|
||||
sys.exit(1)
|
||||
src = args[0]
|
||||
root, ext = os.path.splitext(src)
|
||||
if ext not in ['.html', '.pdf', '.rar']:
|
||||
print >> sys.stderr, "Can only convert files ending in .html|.pdf|.rar"
|
||||
parser.print_help()
|
||||
sys.exit(1)
|
||||
name = makelrf(author=options.author, title=options.title, \
|
||||
thumbnail=options.thumbnail, src=src, cover=options.cover, \
|
||||
rasterize=options.rasterize)
|
||||
print "LRF generated:", name
|
@ -155,7 +155,7 @@ class xml_field(object):
|
||||
class LRFMetaFile(object):
|
||||
""" Has properties to read and write all Meta information in a LRF file. """
|
||||
# The first 8 bytes of all valid LRF files
|
||||
LRF_HEADER = u'LRF'.encode('utf-16')[2:]+'\0\0'
|
||||
LRF_HEADER = 'LRF'.encode('utf-16le')+'\0\0'
|
||||
|
||||
lrf_header = fixed_stringfield(length=8, start=0)
|
||||
version = field(fmt=WORD, start=8)
|
||||
@ -281,6 +281,19 @@ class LRFMetaFile(object):
|
||||
return self.info_start+ self.compressed_info_size-4
|
||||
return { "fget":fget, "doc":doc }
|
||||
|
||||
@classmethod
|
||||
def _detect_thumbnail_type(cls, slice):
|
||||
""" @param slice: The first 16 bytes of the thumbnail """
|
||||
ttype = 0x14 # GIF
|
||||
if "PNG" in slice:
|
||||
ttype = 0x12
|
||||
if "BM" in slice:
|
||||
ttype = 0x13
|
||||
if "JFIF" in slice:
|
||||
ttype = 0x11
|
||||
return ttype
|
||||
|
||||
|
||||
@safe_property
|
||||
def thumbnail():
|
||||
doc = \
|
||||
@ -299,6 +312,7 @@ class LRFMetaFile(object):
|
||||
if self.version <= 800:
|
||||
raise LRFException("Cannot store thumbnails in LRF files \
|
||||
of version <= 800")
|
||||
slice = data[0:16]
|
||||
orig_size = self.thumbnail_size
|
||||
self._file.seek(self.toc_object_offset)
|
||||
toc = self._file.read(self.object_index_offset - self.toc_object_offset)
|
||||
@ -314,14 +328,7 @@ class LRFMetaFile(object):
|
||||
self._file.write(objects)
|
||||
self._file.flush()
|
||||
self._file.truncate() # Incase old thumbnail was bigger than new
|
||||
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.thumbnail_type = self._detect_thumbnail_type(slice)
|
||||
# Needed as new thumbnail may have different size than old thumbnail
|
||||
self.update_object_offsets(self.toc_object_offset - orig_offset)
|
||||
return { "fget":fget, "fset":fset, "doc":doc }
|
||||
@ -392,6 +399,11 @@ class LRFMetaFile(object):
|
||||
self._file.flush()
|
||||
|
||||
def thumbail_extension(self):
|
||||
"""
|
||||
Return the extension for the thumbnail image type as specified
|
||||
by L{self.thumbnail_type}. If the LRF file was created by buggy
|
||||
software, the extension maye be incorrect. See L{self.fix_thumbnail_type}.
|
||||
"""
|
||||
ext = "gif"
|
||||
ttype = self.thumbnail_type
|
||||
if ttype == 0x11:
|
||||
@ -402,6 +414,15 @@ class LRFMetaFile(object):
|
||||
ext = "bm"
|
||||
return ext
|
||||
|
||||
def fix_thumbnail_type(self):
|
||||
"""
|
||||
Attempt to guess the thumbnail image format and set
|
||||
L{self.thumbnail_type} accordingly.
|
||||
"""
|
||||
slice = self.thumbnail[0:16]
|
||||
self.thumbnail_type = self._detect_thumbnail_type(slice)
|
||||
|
||||
|
||||
def main():
|
||||
import sys, os.path
|
||||
from optparse import OptionParser
|
||||
|
17
prs-500.e4p
17
prs-500.e4p
@ -1,8 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE Project SYSTEM "Project-4.0.dtd">
|
||||
<!-- eric4 project file for project prs-500 -->
|
||||
<!-- Saved: 2006-12-08, 23:24:29 -->
|
||||
<!-- Copyright (C) 2006 Kovid Goyal, kovid@kovidgoyal.net -->
|
||||
<!-- Saved: 2007-01-03, 23:14:45 -->
|
||||
<!-- Copyright (C) 2007 Kovid Goyal, kovid@kovidgoyal.net -->
|
||||
<Project version="4.0">
|
||||
<ProgLanguage mixed="0">Python</ProgLanguage>
|
||||
<UIType>Qt4</UIType>
|
||||
@ -84,6 +84,15 @@
|
||||
<Dir>gui</Dir>
|
||||
<Name>widgets.py</Name>
|
||||
</Source>
|
||||
<Source>
|
||||
<Dir>libprs500</Dir>
|
||||
<Dir>lrf</Dir>
|
||||
<Name>makelrf.py</Name>
|
||||
</Source>
|
||||
<Source>
|
||||
<Dir>libprs500</Dir>
|
||||
<Name>ptempfile.py</Name>
|
||||
</Source>
|
||||
</Sources>
|
||||
<Forms>
|
||||
<Form>
|
||||
@ -230,10 +239,10 @@
|
||||
</VcsOtherData>
|
||||
</Vcs>
|
||||
<FiletypeAssociations>
|
||||
<FiletypeAssociation pattern="*.py" type="SOURCES" />
|
||||
<FiletypeAssociation pattern="*.ui.h" type="FORMS" />
|
||||
<FiletypeAssociation pattern="*.idl" type="INTERFACES" />
|
||||
<FiletypeAssociation pattern="*.ui" type="FORMS" />
|
||||
<FiletypeAssociation pattern="*.idl" type="INTERFACES" />
|
||||
<FiletypeAssociation pattern="*.py" type="SOURCES" />
|
||||
<FiletypeAssociation pattern="*.ptl" type="SOURCES" />
|
||||
</FiletypeAssociations>
|
||||
</Project>
|
||||
|
33
setup.py
33
setup.py
@ -13,18 +13,25 @@
|
||||
## with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
#!/usr/bin/env python2.5
|
||||
import sys
|
||||
|
||||
import ez_setup
|
||||
ez_setup.use_setuptools()
|
||||
|
||||
# Try to install the Python imaging library as the package name (PIL) doesn't match the distributionfile name, thus declaring itas a dependency is useless
|
||||
#from setuptools.command.easy_install import main as easy_install
|
||||
#try:
|
||||
# try:
|
||||
# import Image
|
||||
# except ImportError:
|
||||
# print "Trying to install thePython Imaging Library"
|
||||
# easy_install(["-f", "http://www.pythonware.com/products/pil/", "Imaging"])
|
||||
#except: pass
|
||||
# Try to install the Python imaging library as the package name (PIL) doesn't
|
||||
# match the distribution file name, thus declaring itas a dependency is useless
|
||||
from setuptools.command.easy_install import main as easy_install
|
||||
try:
|
||||
try:
|
||||
import Image
|
||||
except ImportError:
|
||||
print "Trying to install the Python Imaging Library"
|
||||
easy_install(["-f", "http://www.pythonware.com/products/pil/", "Imaging"])
|
||||
except Exception, e:
|
||||
print >> sys.stderr, e
|
||||
print >> sys.stderr, \
|
||||
"WARNING: Could not install the Python Imaging Library.", \
|
||||
"Some functionality will be unavailable"
|
||||
|
||||
import sys
|
||||
from setuptools import setup, find_packages
|
||||
@ -43,11 +50,15 @@ setup(
|
||||
author='Kovid Goyal',
|
||||
author_email='kovid@kovidgoyal.net',
|
||||
url = 'http://libprs500.kovidgoyal.net',
|
||||
package_data = { 'libprs500.gui' : ['*.ui'] },
|
||||
package_data = { \
|
||||
'libprs500.gui' : ['*.ui'], \
|
||||
'libprs500.lrf' : ['*.jar', '*.jpg'] \
|
||||
},
|
||||
entry_points = {
|
||||
'console_scripts': [ \
|
||||
'prs500 = libprs500.cli.main:main', \
|
||||
'lrf-meta = libprs500.lrf.meta:main' \
|
||||
'lrf-meta = libprs500.lrf.meta:main', \
|
||||
'makelrf = libprs500.lrf.makelrf:main'\
|
||||
],
|
||||
'gui_scripts' : [ 'prs500-gui = libprs500.gui.main:main']
|
||||
},
|
||||
|
Loading…
x
Reference in New Issue
Block a user