diff --git a/src/calibre/ebooks/conversion/config.py b/src/calibre/ebooks/conversion/config.py
index 9fa74d3b45..cde5aecf59 100644
--- a/src/calibre/ebooks/conversion/config.py
+++ b/src/calibre/ebooks/conversion/config.py
@@ -303,7 +303,7 @@ OPTIONS = {
'pdf_footer_template', 'pdf_header_template', 'pdf_add_toc',
'toc_title', 'pdf_page_margin_left', 'pdf_page_margin_top',
'pdf_page_margin_right', 'pdf_page_margin_bottom',
- 'pdf_use_document_margins',),
+ 'pdf_use_document_margins', 'pdf_page_number_map',),
'pml': ('inline_toc', 'full_image_depth', 'pml_output_encoding'),
diff --git a/src/calibre/ebooks/conversion/plugins/pdf_output.py b/src/calibre/ebooks/conversion/plugins/pdf_output.py
index d797c5ffc7..dc344e6422 100644
--- a/src/calibre/ebooks/conversion/plugins/pdf_output.py
+++ b/src/calibre/ebooks/conversion/plugins/pdf_output.py
@@ -148,6 +148,10 @@ class PDFOutput(OutputFormatPlugin):
' This will cause the margins specified in the conversion settings to be ignored.'
' If the document does not specify page margins, the conversion settings will be used as a fallback.')
),
+ OptionRecommendation(name='pdf_page_number_map', recommended_value=None,
+ help=_('Adjust page numbers, as needed. Syntax is a JavaScript expression for the page number.'
+ ' For example, "if (n < 3) 0; else n - 3;", where n is current page number.')
+ ),
}
def specialize_options(self, log, opts, input_fmt):
diff --git a/src/calibre/ebooks/pdf/render/from_html.py b/src/calibre/ebooks/pdf/render/from_html.py
index 093cca34a5..1178cc89cd 100644
--- a/src/calibre/ebooks/pdf/render/from_html.py
+++ b/src/calibre/ebooks/pdf/render/from_html.py
@@ -254,9 +254,10 @@ class PDFWriter(QObject):
raise Exception('PDF Output failed, see log for details')
def render_inline_toc(self):
+ evaljs = self.view.page().mainFrame().evaluateJavaScript
self.rendered_inline_toc = True
from calibre.ebooks.pdf.render.toc import toc_as_html
- raw = toc_as_html(self.toc, self.doc, self.opts)
+ raw = toc_as_html(self.toc, self.doc, self.opts, evaljs)
pt = PersistentTemporaryFile('_pdf_itoc.htm')
pt.write(raw)
pt.close()
@@ -460,12 +461,15 @@ class PDFWriter(QObject):
if idx is not None:
setattr(self, attr, sections[idx][0])
+ from calibre.ebooks.pdf.render.toc import calculate_page_number
+
while True:
set_section(col, sections, 'current_section')
set_section(col, tl_sections, 'current_tl_section')
self.doc.init_page(page_margins)
+ num = calculate_page_number(self.current_page_num, self.opts.pdf_page_number_map, evaljs)
if self.header or self.footer:
- if evaljs('paged_display.update_header_footer(%d)'%self.current_page_num) is True:
+ if evaljs('paged_display.update_header_footer(%d)'%num) is True:
self.load_header_footer_images()
self.painter.save()
diff --git a/src/calibre/ebooks/pdf/render/toc.py b/src/calibre/ebooks/pdf/render/toc.py
index ea84f2b0a3..51faf445db 100644
--- a/src/calibre/ebooks/pdf/render/toc.py
+++ b/src/calibre/ebooks/pdf/render/toc.py
@@ -12,7 +12,14 @@ from lxml.html import tostring
from lxml.html.builder import (HTML, HEAD, BODY, TABLE, TR, TD, H2, STYLE)
-def convert_node(toc, table, level, pdf):
+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(),
)
@@ -28,18 +35,18 @@ def convert_node(toc, table, level, pdf):
return None
a = anchors[path]
dest = a.get(frag, a[None])
- num = pdf.page_tree.obj.get_num(dest[0])
+ num = calculate_page_number(pdf.page_tree.obj.get_num(dest[0]), pdf_page_number_map, evaljs)
tr[1].text = type('')(num)
table.append(tr)
-def process_children(toc, table, level, pdf):
+def process_children(toc, table, level, pdf, pdf_page_number_map, evaljs):
for child in toc:
- convert_node(child, table, level, pdf)
- process_children(child, table, level+1, pdf)
+ 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):
+def toc_as_html(toc, pdf, opts, evaljs):
pdf = pdf.engine.pdf
indents = []
for i in xrange(1, 7):
@@ -73,6 +80,6 @@ def toc_as_html(toc, pdf, opts):
body = html[1]
body.set('class', 'calibre-pdf-toc')
- process_children(toc, body[1], 0, pdf)
+ 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')
diff --git a/src/calibre/gui2/convert/pdf_output.ui b/src/calibre/gui2/convert/pdf_output.ui
index 45a35235a5..95a92a2344 100644
--- a/src/calibre/gui2/convert/pdf_output.ui
+++ b/src/calibre/gui2/convert/pdf_output.ui
@@ -7,7 +7,7 @@
0
0
638
- 588
+ 634
@@ -197,14 +197,27 @@
- -
+
-
+
+
+ Page &number map:
+
+
+ opt_pdf_page_number_map
+
+
+
+ -
+
+
+ -
Page margins
- -
+
-
Page headers and footers
diff --git a/src/pyj/book_list/conversion_widgets.pyj b/src/pyj/book_list/conversion_widgets.pyj
index 9d32786ab1..ef6068ef21 100644
--- a/src/pyj/book_list/conversion_widgets.pyj
+++ b/src/pyj/book_list/conversion_widgets.pyj
@@ -658,6 +658,7 @@ def pdf_output(container):
g.appendChild(choices('pdf_standard_font', _('S&tandard font:'), ui_data.font_types))
g.appendChild(int_spin('pdf_default_font_size', _('Default font si&ze:'), unit='px'))
g.appendChild(int_spin('pdf_mono_font_size', _('Default font si&ze:'), unit='px'))
+ g.appendChild(lineedit('pdf_page_number_map', _('Page number &map:')))
g.appendChild(checkbox('pdf_use_document_margins', _('Use page margins from the &document being converted')))
g.appendChild(float_spin('pdf_page_margin_left', indent + _('Left page margin'), unit='pt', min=-100, max=500))
g.appendChild(float_spin('pdf_page_margin_top', indent + _('Top page margin'), unit='pt', min=-100, max=500))