mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Merge from trunk
This commit is contained in:
commit
22213a91d5
@ -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.
|
||||
|
||||
|
@ -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),
|
||||
|
||||
|
@ -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',
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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())])
|
||||
|
Loading…
x
Reference in New Issue
Block a user