mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
PDF Output: Add a new "page number map" setting to easily modify page numbers as needed in headers/fotters and the generated inline table of contents.
Fixes #1796902 [Feature: shift for page numbers in pdf](https://bugs.launchpad.net/calibre/+bug/1796902)
This commit is contained in:
parent
eeff70325d
commit
d32a5ecfc7
@ -303,7 +303,7 @@ OPTIONS = {
|
|||||||
'pdf_footer_template', 'pdf_header_template', 'pdf_add_toc',
|
'pdf_footer_template', 'pdf_header_template', 'pdf_add_toc',
|
||||||
'toc_title', 'pdf_page_margin_left', 'pdf_page_margin_top',
|
'toc_title', 'pdf_page_margin_left', 'pdf_page_margin_top',
|
||||||
'pdf_page_margin_right', 'pdf_page_margin_bottom',
|
'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'),
|
'pml': ('inline_toc', 'full_image_depth', 'pml_output_encoding'),
|
||||||
|
|
||||||
|
@ -148,6 +148,10 @@ class PDFOutput(OutputFormatPlugin):
|
|||||||
' This will cause the margins specified in the conversion settings to be ignored.'
|
' 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.')
|
' 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):
|
def specialize_options(self, log, opts, input_fmt):
|
||||||
|
@ -254,9 +254,10 @@ class PDFWriter(QObject):
|
|||||||
raise Exception('PDF Output failed, see log for details')
|
raise Exception('PDF Output failed, see log for details')
|
||||||
|
|
||||||
def render_inline_toc(self):
|
def render_inline_toc(self):
|
||||||
|
evaljs = self.view.page().mainFrame().evaluateJavaScript
|
||||||
self.rendered_inline_toc = True
|
self.rendered_inline_toc = True
|
||||||
from calibre.ebooks.pdf.render.toc import toc_as_html
|
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 = PersistentTemporaryFile('_pdf_itoc.htm')
|
||||||
pt.write(raw)
|
pt.write(raw)
|
||||||
pt.close()
|
pt.close()
|
||||||
@ -460,12 +461,15 @@ class PDFWriter(QObject):
|
|||||||
if idx is not None:
|
if idx is not None:
|
||||||
setattr(self, attr, sections[idx][0])
|
setattr(self, attr, sections[idx][0])
|
||||||
|
|
||||||
|
from calibre.ebooks.pdf.render.toc import calculate_page_number
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
set_section(col, sections, 'current_section')
|
set_section(col, sections, 'current_section')
|
||||||
set_section(col, tl_sections, 'current_tl_section')
|
set_section(col, tl_sections, 'current_tl_section')
|
||||||
self.doc.init_page(page_margins)
|
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 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.load_header_footer_images()
|
||||||
|
|
||||||
self.painter.save()
|
self.painter.save()
|
||||||
|
@ -12,7 +12,14 @@ from lxml.html import tostring
|
|||||||
from lxml.html.builder import (HTML, HEAD, BODY, TABLE, TR, TD, H2, STYLE)
|
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(
|
tr = TR(
|
||||||
TD(toc.text or _('Unknown')), TD(),
|
TD(toc.text or _('Unknown')), TD(),
|
||||||
)
|
)
|
||||||
@ -28,18 +35,18 @@ def convert_node(toc, table, level, pdf):
|
|||||||
return None
|
return None
|
||||||
a = anchors[path]
|
a = anchors[path]
|
||||||
dest = a.get(frag, a[None])
|
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)
|
tr[1].text = type('')(num)
|
||||||
table.append(tr)
|
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:
|
for child in toc:
|
||||||
convert_node(child, table, level, pdf)
|
convert_node(child, table, level, pdf, pdf_page_number_map, evaljs)
|
||||||
process_children(child, table, level+1, pdf)
|
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
|
pdf = pdf.engine.pdf
|
||||||
indents = []
|
indents = []
|
||||||
for i in xrange(1, 7):
|
for i in xrange(1, 7):
|
||||||
@ -73,6 +80,6 @@ def toc_as_html(toc, pdf, opts):
|
|||||||
body = html[1]
|
body = html[1]
|
||||||
body.set('class', 'calibre-pdf-toc')
|
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')
|
return tostring(html, pretty_print=True, include_meta_content_type=True, encoding='utf-8')
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>638</width>
|
<width>638</width>
|
||||||
<height>588</height>
|
<height>634</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<property name="windowTitle">
|
<property name="windowTitle">
|
||||||
@ -197,14 +197,27 @@
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="16" column="0" colspan="2">
|
<item row="16" column="0">
|
||||||
|
<widget class="QLabel" name="label_9">
|
||||||
|
<property name="text">
|
||||||
|
<string>Page &number map:</string>
|
||||||
|
</property>
|
||||||
|
<property name="buddy">
|
||||||
|
<cstring>opt_pdf_page_number_map</cstring>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="16" column="1">
|
||||||
|
<widget class="QLineEdit" name="opt_pdf_page_number_map"/>
|
||||||
|
</item>
|
||||||
|
<item row="17" column="0" colspan="2">
|
||||||
<widget class="QGroupBox" name="page_margins_box">
|
<widget class="QGroupBox" name="page_margins_box">
|
||||||
<property name="title">
|
<property name="title">
|
||||||
<string>Page margins</string>
|
<string>Page margins</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="17" column="0" colspan="2">
|
<item row="18" column="0" colspan="2">
|
||||||
<widget class="QGroupBox" name="template_box">
|
<widget class="QGroupBox" name="template_box">
|
||||||
<property name="title">
|
<property name="title">
|
||||||
<string>Page headers and footers</string>
|
<string>Page headers and footers</string>
|
||||||
|
@ -658,6 +658,7 @@ def pdf_output(container):
|
|||||||
g.appendChild(choices('pdf_standard_font', _('S&tandard font:'), ui_data.font_types))
|
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_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(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(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_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))
|
g.appendChild(float_spin('pdf_page_margin_top', indent + _('Top page margin'), unit='pt', min=-100, max=500))
|
||||||
|
Loading…
x
Reference in New Issue
Block a user