mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-06-23 15:30:45 -04:00
Add support for page number mapping
This commit is contained in:
parent
43d7e2119a
commit
e575be49e3
@ -33,7 +33,7 @@ from calibre.gui2.webengine import secure_webengine
|
||||
from calibre.utils.logging import default_log
|
||||
from calibre.utils.podofo import get_podofo, set_metadata_implementation
|
||||
from calibre.utils.short_uuid import uuid4
|
||||
from polyglot.builtins import iteritems, range
|
||||
from polyglot.builtins import iteritems, range, unicode_type
|
||||
from polyglot.urllib import urlparse
|
||||
|
||||
OK, KILL_SIGNAL = range(0, 2)
|
||||
@ -175,6 +175,19 @@ class RenderManager(QObject):
|
||||
raise SystemExit('Unknown error occurred')
|
||||
return self.results
|
||||
|
||||
def evaljs(self, js):
|
||||
if not self.workers:
|
||||
self.create_worker()
|
||||
w = self.workers[0]
|
||||
self.evaljs_result = None
|
||||
w.runJavaScript(js, self.evaljs_callback)
|
||||
QApplication.exec_()
|
||||
return self.evaljs_result
|
||||
|
||||
def evaljs_callback(self, result):
|
||||
self.evaljs_result = result
|
||||
QApplication.instance().exit(0)
|
||||
|
||||
def assign_work(self):
|
||||
free_workers = [w for w in self.workers if not w.working]
|
||||
while free_workers and self.pending:
|
||||
@ -423,7 +436,30 @@ def add_toc(pdf_parent, toc_parent):
|
||||
add_toc(pdf_child, child)
|
||||
|
||||
|
||||
def add_pagenum_toc(root, toc, opts):
|
||||
def get_page_number_display_map(render_manager, opts, num_pages, log):
|
||||
num_pages *= 2
|
||||
default_map = {n:n for n in range(1, num_pages + 1)}
|
||||
if opts.pdf_page_number_map:
|
||||
js = '''
|
||||
function map_num(n) { return eval(MAP_EXPRESSION); }
|
||||
var ans = {};
|
||||
for (var i=1; i <= NUM_PAGES; i++) ans[i] = map_num(i);
|
||||
JSON.stringify(ans);
|
||||
'''.replace('MAP_EXPRESSION', json.dumps(opts.pdf_page_number_map), 1).replace(
|
||||
'NUM_PAGES', unicode_type(num_pages), 1)
|
||||
result = render_manager.evaljs(js)
|
||||
try:
|
||||
result = json.loads(result)
|
||||
if not isinstance(result, dict):
|
||||
raise ValueError('Not a dict')
|
||||
except Exception:
|
||||
log.warn('Could not do page number mapping, got unexpected result: {}'.format(repr(result)))
|
||||
else:
|
||||
default_map = {int(k): int(v) for k, v in iteritems(result)}
|
||||
return default_map
|
||||
|
||||
|
||||
def add_pagenum_toc(root, toc, opts, page_number_display_map):
|
||||
body = root[-1]
|
||||
indents = []
|
||||
for i in range(1, 7):
|
||||
@ -464,7 +500,9 @@ def add_pagenum_toc(root, toc, opts):
|
||||
for level, node in toc.iterdescendants(level=0):
|
||||
tr = E('tr', cls='level-%d' % level, parent=table)
|
||||
E('td', text=node.title or _('Unknown'), parent=tr)
|
||||
E('td', text='{}'.format(node.pdf_loc.pagenum), parent=tr)
|
||||
num = node.pdf_loc.pagenum
|
||||
num = page_number_display_map.get(num, num)
|
||||
E('td', text='{}'.format(num), parent=tr)
|
||||
|
||||
# }}}
|
||||
|
||||
@ -504,12 +542,14 @@ def convert(opf_path, opts, metadata=None, output_path=None, log=default_log, co
|
||||
else:
|
||||
pdf_doc.append(doc)
|
||||
|
||||
page_number_display_map = get_page_number_display_map(manager, opts, num_pages, log)
|
||||
|
||||
if has_toc:
|
||||
annotate_toc(toc, anchor_locations, name_anchor_map, log)
|
||||
if opts.pdf_add_toc:
|
||||
tocname = create_skeleton(container)
|
||||
root = container.parsed(tocname)
|
||||
add_pagenum_toc(root, toc, opts)
|
||||
add_pagenum_toc(root, toc, opts, page_number_display_map)
|
||||
container.commit()
|
||||
jobs = [job_for_name(container, tocname, None, page_layout)]
|
||||
results = manager.convert_html_files(jobs, settle_time=1)
|
||||
@ -526,6 +566,7 @@ def convert(opf_path, opts, metadata=None, output_path=None, log=default_log, co
|
||||
# TODO: Remove unused fonts
|
||||
# TODO: Remove duplicate fonts
|
||||
# TODO: Subset and embed fonts before rendering PDF
|
||||
# TODO: Support for mathematics
|
||||
|
||||
if cover_data:
|
||||
add_cover(pdf_doc, cover_data, page_layout, opts)
|
||||
|
@ -1,86 +0,0 @@
|
||||
#!/usr/bin/env python2
|
||||
# vim:fileencoding=utf-8
|
||||
from __future__ import absolute_import, division, print_function, unicode_literals
|
||||
|
||||
__license__ = 'GPL v3'
|
||||
__copyright__ = '2013, Kovid Goyal <kovid at kovidgoyal.net>'
|
||||
|
||||
import os
|
||||
|
||||
from lxml.html import tostring
|
||||
from lxml.html.builder import (HTML, HEAD, BODY, TABLE, TR, TD, H2, STYLE)
|
||||
|
||||
from polyglot.builtins import range, unicode_type
|
||||
|
||||
|
||||
def calculate_page_number(num, map_expression, evaljs):
|
||||
if map_expression:
|
||||
num = int(evaljs('(function(){{var n={}; return {};}})()'.format(
|
||||
num, map_expression)))
|
||||
return num
|
||||
|
||||
|
||||
def convert_node(toc, table, level, pdf, pdf_page_number_map, evaljs):
|
||||
tr = TR(
|
||||
TD(toc.text or _('Unknown')), TD(),
|
||||
)
|
||||
tr.set('class', 'level-%d' % level)
|
||||
anchors = pdf.links.anchors
|
||||
|
||||
path = toc.abspath or None
|
||||
frag = toc.fragment or None
|
||||
if path is None:
|
||||
return
|
||||
path = os.path.normcase(os.path.abspath(path))
|
||||
if path not in anchors:
|
||||
return None
|
||||
a = anchors[path]
|
||||
dest = a.get(frag, a[None])
|
||||
num = calculate_page_number(pdf.page_tree.obj.get_num(dest[0]), pdf_page_number_map, evaljs)
|
||||
tr[1].text = unicode_type(num)
|
||||
table.append(tr)
|
||||
|
||||
|
||||
def process_children(toc, table, level, pdf, pdf_page_number_map, evaljs):
|
||||
for child in toc:
|
||||
convert_node(child, table, level, pdf, pdf_page_number_map, evaljs)
|
||||
process_children(child, table, level+1, pdf, pdf_page_number_map, evaljs)
|
||||
|
||||
|
||||
def toc_as_html(toc, pdf, opts, evaljs):
|
||||
pdf = pdf.engine.pdf
|
||||
indents = []
|
||||
for i in range(1, 7):
|
||||
indents.extend((i, 1.4*i))
|
||||
html = HTML(
|
||||
HEAD(
|
||||
STYLE(
|
||||
'''
|
||||
.calibre-pdf-toc table { width: 100%% }
|
||||
|
||||
.calibre-pdf-toc table tr td:last-of-type { text-align: right }
|
||||
|
||||
.calibre-pdf-toc .level-0 {
|
||||
font-size: larger;
|
||||
}
|
||||
|
||||
.calibre-pdf-toc .level-%d td:first-of-type { padding-left: %.1gem }
|
||||
.calibre-pdf-toc .level-%d td:first-of-type { padding-left: %.1gem }
|
||||
.calibre-pdf-toc .level-%d td:first-of-type { padding-left: %.1gem }
|
||||
.calibre-pdf-toc .level-%d td:first-of-type { padding-left: %.1gem }
|
||||
.calibre-pdf-toc .level-%d td:first-of-type { padding-left: %.1gem }
|
||||
.calibre-pdf-toc .level-%d td:first-of-type { padding-left: %.1gem }
|
||||
''' % tuple(indents) + (opts.extra_css or '')
|
||||
)
|
||||
),
|
||||
BODY(
|
||||
H2(opts.toc_title or _('Table of Contents')),
|
||||
TABLE(),
|
||||
)
|
||||
)
|
||||
body = html[1]
|
||||
body.set('class', 'calibre-pdf-toc')
|
||||
|
||||
process_children(toc, body[1], 0, pdf, opts.pdf_page_number_map, evaljs)
|
||||
|
||||
return tostring(html, pretty_print=True, include_meta_content_type=True, encoding='utf-8')
|
Loading…
x
Reference in New Issue
Block a user