Merge from trunk

This commit is contained in:
Charles Haley 2012-07-31 13:56:19 +02:00
commit 22213a91d5
8 changed files with 121 additions and 72 deletions

View File

@ -734,7 +734,11 @@ If this property is detected by |app|, the following custom properties are recog
opf.pubdate
opf.isbn
opf.language
opf.series
opf.seriesindex
In addition to this, you can specify the picture to use as the cover by naming it ``opf.cover`` (right click, Picture->Options->Name) in the ODT. If no picture with this name is found, the 'smart' method is used.
To prevent this you can set the custom property ``opf.nocover`` ('Yes or No' type) to Yes.
As the cover detection might result in double covers in certain output formats, the process will remove the paragraph (only if the only content is the cover!) from the document. But this works only with the named picture!
To disable cover detection you can set the custom property ``opf.nocover`` ('Yes or No' type) to Yes in advanced mode.

View File

@ -140,7 +140,7 @@ extensions = [
['calibre/utils/podofo/podofo.cpp'],
libraries=['podofo'],
lib_dirs=[podofo_lib],
inc_dirs=[podofo_inc],
inc_dirs=[podofo_inc, os.path.dirname(podofo_inc)],
optional=True,
error=podofo_error),

View File

@ -32,7 +32,7 @@ binary_includes = [
'/usr/lib/libunrar.so',
'/usr/lib/libsqlite3.so.0',
'/usr/lib/libmng.so.1',
'/usr/lib/libpodofo.so.0.8.4',
'/usr/lib/libpodofo.so.0.9.1',
'/lib/libz.so.1',
'/usr/lib/libtiff.so.5',
'/lib/libbz2.so.1',

View File

@ -243,9 +243,6 @@ class Py2App(object):
@flush
def get_local_dependencies(self, path_to_lib):
for x in self.get_dependencies(path_to_lib):
if x.startswith('libpodofo'):
yield x, x
continue
for y in (SW+'/lib/', '/usr/local/lib/', SW+'/qt/lib/',
'/opt/local/lib/',
SW+'/python/Python.framework/', SW+'/freetype/lib/'):
@ -330,10 +327,6 @@ class Py2App(object):
for f in glob.glob('src/calibre/plugins/*.so'):
shutil.copy2(f, dest)
self.fix_dependencies_in_lib(join(dest, basename(f)))
if 'podofo' in f:
self.change_dep('libpodofo.0.8.4.dylib',
self.FID+'/'+'libpodofo.0.8.4.dylib', join(dest, basename(f)))
@flush
def create_plist(self):
@ -380,7 +373,7 @@ class Py2App(object):
@flush
def add_podofo(self):
info('\nAdding PoDoFo')
pdf = join(SW, 'lib', 'libpodofo.0.8.4.dylib')
pdf = join(SW, 'lib', 'libpodofo.0.9.1.dylib')
self.install_dylib(pdf)
@flush

View File

@ -322,24 +322,7 @@ cp build/podofo-*/build/src/Release/podofo.exp lib/
cp build/podofo-*/build/podofo_config.h include/podofo/
cp -r build/podofo-*/src/* include/podofo/
You have to use >=0.8.2
The following patch (against -r1269) was required to get it to compile:
Index: src/PdfFiltersPrivate.cpp
===================================================================
--- src/PdfFiltersPrivate.cpp (revision 1261)
+++ src/PdfFiltersPrivate.cpp (working copy)
@@ -1019,7 +1019,7 @@
/*
* Prepare for input from a memory buffer.
*/
-GLOBAL(void)
+void
jpeg_memory_src (j_decompress_ptr cinfo, const JOCTET * buffer, size_t bufsize)
{
my_src_ptr src;
You have to use >=0.9.1
ImageMagick

View File

@ -1,3 +1,7 @@
#!/usr/bin/env python
# vim:fileencoding=UTF-8:ts=4:sw=4:sta:et:sts=4:ai
from __future__ import (unicode_literals, division, absolute_import,
print_function)
'''
Created on 29 Jun 2012
@ -8,6 +12,7 @@ import hashlib, threading
from base64 import b64encode, b64decode
from functools import wraps
from calibre import prints
from calibre.constants import numeric_version, DEBUG
from calibre.devices.interface import DevicePlugin
from calibre.devices.usbms.books import Book, BookList
@ -23,8 +28,8 @@ from calibre.utils.ipc import eintr_retry_call
from calibre.utils.config import from_json, tweaks
from calibre.utils.date import isoformat, now
from calibre.utils.filenames import ascii_filename as sanitize, shorten_components_to
from calibre.utils.mdns import publish as publish_zeroconf
from calibre.utils.mdns import unpublish as unpublish_zeroconf
from calibre.utils.mdns import (publish as publish_zeroconf, unpublish as
unpublish_zeroconf)
def synchronous(tlockname):
"""A decorator to place an instance based lock around a method """
@ -132,11 +137,11 @@ class SMART_DEVICE_APP (DeviceConfig, DevicePlugin):
return
total_elapsed = time.time() - self.debug_start_time
elapsed = time.time() - self.debug_time
print 'SMART_DEV (%7.2f:%7.3f) %s'%(total_elapsed, elapsed,
inspect.stack()[1][3]),
prints('SMART_DEV (%7.2f:%7.3f) %s'%(total_elapsed, elapsed,
inspect.stack()[1][3]), end='')
for a in args:
print a,
print
prints(a, end='')
print()
self.debug_time = time.time()
# Various methods required by the plugin architecture

View File

@ -196,6 +196,13 @@ def get_metadata(stream, extract_cover=True):
mi.publisher = data['opf.publisher']
if data.get('opf.pubdate', ''):
mi.pubdate = parse_date(data['opf.pubdate'], assume_utc=True)
if data.get('opf.series', ''):
mi.series = data['opf.series']
if data.get('opf.seriesindex', ''):
try:
mi.series_index = float(data['opf.seriesindex'])
except ValueError:
mi.series_index = 1.0
if data.get('opf.language', ''):
cl = canonicalize_lang(data['opf.language'])
if cl:
@ -216,10 +223,9 @@ def read_cover(stream, zin, mi, opfmeta, extract_cover):
otext = odLoad(stream)
cover_href = None
cover_data = None
# check that it's really a ODT
if otext.mimetype == u'application/vnd.oasis.opendocument.text':
for elem in otext.text.getElementsByType(odFrame):
img = elem.getElementsByType(odImage)
cover_frame = None
for frm in otext.topnode.getElementsByType(odFrame):
img = frm.getElementsByType(odImage)
if len(img) > 0: # there should be only one
i_href = img[0].getAttribute('href')
try:
@ -232,9 +238,10 @@ def read_cover(stream, zin, mi, opfmeta, extract_cover):
continue
else:
continue
if opfmeta and elem.getAttribute('name').lower() == u'opf.cover':
if opfmeta and frm.getAttribute('name').lower() == u'opf.cover':
cover_href = i_href
cover_data = (fmt, raw)
cover_frame = frm.getAttribute('name') # could have upper case
break
if cover_href is None and 0.8 <= height/width <= 1.8 and height*width >= 12000:
cover_href = i_href
@ -244,6 +251,7 @@ def read_cover(stream, zin, mi, opfmeta, extract_cover):
if cover_href is not None:
mi.cover = cover_href
mi.odf_cover_frame = cover_frame
if extract_cover:
if not cover_data:
raw = zin.read(cover_href)

View File

@ -10,6 +10,9 @@ import os
from lxml import etree
from odf.odf2xhtml import ODF2XHTML
from odf.opendocument import load as odLoad
from odf.draw import Frame as odFrame, Image as odImage
from odf.namespaces import TEXTNS as odTEXTNS
from calibre import CurrentDir, walk
@ -138,22 +141,84 @@ class Extract(ODF2XHTML):
r.selectorText = '.'+replace_name
return sheet.cssText, sel_map
def search_page_img(self, mi, log):
for frm in self.document.topnode.getElementsByType(odFrame):
try:
if frm.getAttrNS(odTEXTNS,u'anchor-type') == 'page':
log.warn('Document has Pictures anchored to Page, will all end up before first page!')
break
except ValueError:
pass
def filter_cover(self, mi, log):
# filter the Element tree (remove the detected cover)
if mi.cover and mi.odf_cover_frame:
for frm in self.document.topnode.getElementsByType(odFrame):
# search the right frame
if frm.getAttribute('name') == mi.odf_cover_frame:
img = frm.getElementsByType(odImage)
# only one draw:image allowed in the draw:frame
if len(img) == 1 and img[0].getAttribute('href') == mi.cover:
# ok, this is the right frame with the right image
# check if there are more childs
if len(frm.childNodes) != 1:
break
# check if the parent paragraph more childs
para = frm.parentNode
if para.tagName != 'text:p' or len(para.childNodes) != 1:
break
# now it should be safe to remove the text:p
parent = para.parentNode
parent.removeChild(para)
log("Removed cover image paragraph from document...")
break
def filter_load(self, odffile, mi, log):
""" This is an adaption from ODF2XHTML. It adds a step between
load and parse of the document where the Element tree can be
modified.
"""
# first load the odf structure
self.lines = []
self._wfunc = self._wlines
if isinstance(odffile, basestring) \
or hasattr(odffile, 'read'): # Added by Kovid
self.document = odLoad(odffile)
else:
self.document = odffile
# filter stuff
self.search_page_img(mi, log)
try:
self.filter_cover(mi, log)
except:
pass
# parse the modified tree and generate xhtml
self._walknode(self.document.topnode)
def __call__(self, stream, odir, log):
from calibre.utils.zipfile import ZipFile
from calibre.ebooks.metadata.meta import get_metadata
from calibre.ebooks.metadata.odt import get_metadata
from calibre.ebooks.metadata.opf2 import OPFCreator
from calibre.customize.ui import quick_metadata
if not os.path.exists(odir):
os.makedirs(odir)
with CurrentDir(odir):
log('Extracting ODT file...')
html = self.odf2xhtml(stream)
stream.seek(0)
mi = get_metadata(stream, 'odt')
if not mi.title:
mi.title = _('Unknown')
if not mi.authors:
mi.authors = [_('Unknown')]
self.filter_load(stream, mi, log)
html = self.xhtml()
# A blanket img specification like this causes problems
# with EPUB output as the containing element often has
# an absolute height and width set that is larger than
# the available screen real estate
html = html.replace('img { width: 100%; height: 100%; }', '')
# odf2xhtml creates empty title tag
html = html.replace('<title></title>','<title>%s</title>'%(mi.title,))
try:
html = self.fix_markup(html, log)
except:
@ -162,15 +227,6 @@ class Extract(ODF2XHTML):
f.write(html.encode('utf-8'))
zf = ZipFile(stream, 'r')
self.extract_pictures(zf)
stream.seek(0)
with quick_metadata:
# We dont want the cover, as it will lead to a duplicated image
# if no external cover is specified.
mi = get_metadata(stream, 'odt')
if not mi.title:
mi.title = _('Unknown')
if not mi.authors:
mi.authors = [_('Unknown')]
opf = OPFCreator(os.path.abspath(os.getcwdu()), mi)
opf.create_manifest([(os.path.abspath(f), None) for f in
walk(os.getcwdu())])