mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
PDF Output: Add an option to add page numbers to the bottom of every page in the generated PDF file
This commit is contained in:
parent
015f3d48a7
commit
f9a5cab366
Binary file not shown.
@ -99,6 +99,18 @@ class PDFOutput(OutputFormatPlugin):
|
|||||||
recommended_value=False, help=_(
|
recommended_value=False, help=_(
|
||||||
'Generate an uncompressed PDF, useful for debugging, '
|
'Generate an uncompressed PDF, useful for debugging, '
|
||||||
'only works with the new PDF engine.')),
|
'only works with the new PDF engine.')),
|
||||||
|
OptionRecommendation(name='pdf_page_numbers', recommended_value=False,
|
||||||
|
help=_('Add page numbers to the bottom of every page in the generated PDF file. If you '
|
||||||
|
'specify a footer template, it will take precedence '
|
||||||
|
'over this option.')),
|
||||||
|
OptionRecommendation(name='pdf_footer_template', recommended_value=None,
|
||||||
|
help=_('An HTML template used to generate footers on every page.'
|
||||||
|
' The string _PAGENUM_ will be replaced by the current page'
|
||||||
|
' number.')),
|
||||||
|
OptionRecommendation(name='pdf_header_template', recommended_value=None,
|
||||||
|
help=_('An HTML template used to generate headers on every page.'
|
||||||
|
' The string _PAGENUM_ will be replaced by the current page'
|
||||||
|
' number.')),
|
||||||
])
|
])
|
||||||
|
|
||||||
def convert(self, oeb_book, output_path, input_plugin, opts, log):
|
def convert(self, oeb_book, output_path, input_plugin, opts, log):
|
||||||
|
@ -29,6 +29,10 @@ class PagedDisplay
|
|||||||
this.current_page_height = null
|
this.current_page_height = null
|
||||||
this.document_margins = null
|
this.document_margins = null
|
||||||
this.use_document_margins = false
|
this.use_document_margins = false
|
||||||
|
this.footer_template = null
|
||||||
|
this.header_template = null
|
||||||
|
this.header = null
|
||||||
|
this.footer = null
|
||||||
|
|
||||||
read_document_margins: () ->
|
read_document_margins: () ->
|
||||||
# Read page margins from the document. First checks for an @page rule.
|
# Read page margins from the document. First checks for an @page rule.
|
||||||
@ -102,6 +106,7 @@ class PagedDisplay
|
|||||||
# than max_col_width
|
# than max_col_width
|
||||||
sm += Math.ceil( (col_width - this.max_col_width) / 2*n )
|
sm += Math.ceil( (col_width - this.max_col_width) / 2*n )
|
||||||
col_width = Math.max(100, ((ww - adjust)/n) - 2*sm)
|
col_width = Math.max(100, ((ww - adjust)/n) - 2*sm)
|
||||||
|
this.col_width = col_width
|
||||||
this.page_width = col_width + 2*sm
|
this.page_width = col_width + 2*sm
|
||||||
this.screen_width = this.page_width * this.cols_per_screen
|
this.screen_width = this.page_width * this.cols_per_screen
|
||||||
this.current_page_height = window.innerHeight - this.margin_top - this.margin_bottom
|
this.current_page_height = window.innerHeight - this.margin_top - this.margin_bottom
|
||||||
@ -171,6 +176,30 @@ class PagedDisplay
|
|||||||
# log('Time to layout:', new Date().getTime() - start_time)
|
# log('Time to layout:', new Date().getTime() - start_time)
|
||||||
return sm
|
return sm
|
||||||
|
|
||||||
|
create_header_footer: () ->
|
||||||
|
if this.header_template != null
|
||||||
|
this.header = document.createElement('div')
|
||||||
|
this.header.setAttribute('style', "overflow:hidden; display:block; position:absolute; left:#{ this.side_margin }px; top: 0px; height: #{ this.margin_top }px; width: #{ this.col_width }px; margin: 0; padding: 0")
|
||||||
|
document.body.appendChild(this.header)
|
||||||
|
if this.footer_template != null
|
||||||
|
this.footer = document.createElement('div')
|
||||||
|
this.footer.setAttribute('style', "overflow:hidden; display:block; position:absolute; left:#{ this.side_margin }px; top: #{ window.innerHeight - this.margin_bottom }px; height: #{ this.margin_bottom }px; width: #{ this.col_width }px; margin: 0; padding: 0")
|
||||||
|
document.body.appendChild(this.footer)
|
||||||
|
this.update_header_footer(1)
|
||||||
|
|
||||||
|
position_header_footer: () ->
|
||||||
|
[left, top] = calibre_utils.viewport_to_document(0, 0, document.body.ownerDocument)
|
||||||
|
if this.header != null
|
||||||
|
this.header.style.setProperty('left', left+'px')
|
||||||
|
if this.footer != null
|
||||||
|
this.footer.style.setProperty('left', left+'px')
|
||||||
|
|
||||||
|
update_header_footer: (pagenum) ->
|
||||||
|
if this.header != null
|
||||||
|
this.header.innerHTML = this.header_template.replace(/_PAGENUM_/g, pagenum+"")
|
||||||
|
if this.footer != null
|
||||||
|
this.footer.innerHTML = this.footer_template.replace(/_PAGENUM_/g, pagenum+"")
|
||||||
|
|
||||||
fit_images: () ->
|
fit_images: () ->
|
||||||
# Ensure no images are wider than the available width in a column. Note
|
# Ensure no images are wider than the available width in a column. Note
|
||||||
# that this method use getBoundingClientRect() which means it will
|
# that this method use getBoundingClientRect() which means it will
|
||||||
|
@ -161,6 +161,17 @@ class PDFWriter(QObject):
|
|||||||
debug=self.log.debug, compress=not
|
debug=self.log.debug, compress=not
|
||||||
opts.uncompressed_pdf,
|
opts.uncompressed_pdf,
|
||||||
mark_links=opts.pdf_mark_links)
|
mark_links=opts.pdf_mark_links)
|
||||||
|
self.footer = opts.pdf_footer_template
|
||||||
|
if self.footer is None and opts.pdf_page_numbers:
|
||||||
|
self.footer = '<p style="text-align:center; text-indent: 0">_PAGENUM_</p>'
|
||||||
|
self.header = opts.pdf_header_template
|
||||||
|
min_margin = 36
|
||||||
|
if self.footer and opts.margin_bottom < min_margin:
|
||||||
|
self.log.warn('Bottom margin is too small for footer, increasing it.')
|
||||||
|
opts.margin_bottom = min_margin
|
||||||
|
if self.header and opts.margin_top < min_margin:
|
||||||
|
self.log.warn('Top margin is too small for header, increasing it.')
|
||||||
|
opts.margin_top = min_margin
|
||||||
|
|
||||||
self.page.setViewportSize(QSize(self.doc.width(), self.doc.height()))
|
self.page.setViewportSize(QSize(self.doc.width(), self.doc.height()))
|
||||||
self.render_queue = items
|
self.render_queue = items
|
||||||
@ -264,6 +275,15 @@ class PDFWriter(QObject):
|
|||||||
py_bridge.value = book_indexing.all_links_and_anchors();
|
py_bridge.value = book_indexing.all_links_and_anchors();
|
||||||
'''%(self.margin_top, 0, self.margin_bottom))
|
'''%(self.margin_top, 0, self.margin_bottom))
|
||||||
|
|
||||||
|
if self.header:
|
||||||
|
self.bridge_value = self.header
|
||||||
|
evaljs('paged_display.header_template = py_bridge.value')
|
||||||
|
if self.footer:
|
||||||
|
self.bridge_value = self.footer
|
||||||
|
evaljs('paged_display.footer_template = py_bridge.value')
|
||||||
|
if self.header or self.footer:
|
||||||
|
evaljs('paged_display.create_header_footer();')
|
||||||
|
|
||||||
amap = self.bridge_value
|
amap = self.bridge_value
|
||||||
if not isinstance(amap, dict):
|
if not isinstance(amap, dict):
|
||||||
amap = {'links':[], 'anchors':{}} # Some javascript error occurred
|
amap = {'links':[], 'anchors':{}} # Some javascript error occurred
|
||||||
@ -272,6 +292,8 @@ class PDFWriter(QObject):
|
|||||||
mf = self.view.page().mainFrame()
|
mf = self.view.page().mainFrame()
|
||||||
while True:
|
while True:
|
||||||
self.doc.init_page()
|
self.doc.init_page()
|
||||||
|
if self.header or self.footer:
|
||||||
|
evaljs('paged_display.update_header_footer(%d)'%self.current_page_num)
|
||||||
self.painter.save()
|
self.painter.save()
|
||||||
mf.render(self.painter)
|
mf.render(self.painter)
|
||||||
self.painter.restore()
|
self.painter.restore()
|
||||||
@ -279,7 +301,7 @@ class PDFWriter(QObject):
|
|||||||
self.doc.end_page()
|
self.doc.end_page()
|
||||||
if not nsl[1] or nsl[0] <= 0:
|
if not nsl[1] or nsl[0] <= 0:
|
||||||
break
|
break
|
||||||
evaljs('window.scrollTo(%d, 0)'%nsl[0])
|
evaljs('window.scrollTo(%d, 0); paged_display.position_header_footer();'%nsl[0])
|
||||||
if self.doc.errors_occurred:
|
if self.doc.errors_occurred:
|
||||||
break
|
break
|
||||||
|
|
||||||
|
@ -22,7 +22,7 @@ class PluginWidget(Widget, Ui_Form):
|
|||||||
'override_profile_size', 'paper_size', 'custom_size',
|
'override_profile_size', 'paper_size', 'custom_size',
|
||||||
'preserve_cover_aspect_ratio', 'pdf_serif_family', 'unit',
|
'preserve_cover_aspect_ratio', 'pdf_serif_family', 'unit',
|
||||||
'pdf_sans_family', 'pdf_mono_family', 'pdf_standard_font',
|
'pdf_sans_family', 'pdf_mono_family', 'pdf_standard_font',
|
||||||
'pdf_default_font_size', 'pdf_mono_font_size'])
|
'pdf_default_font_size', 'pdf_mono_font_size', 'pdf_page_numbers'])
|
||||||
self.db, self.book_id = db, book_id
|
self.db, self.book_id = db, book_id
|
||||||
|
|
||||||
for x in get_option('paper_size').option.choices:
|
for x in get_option('paper_size').option.choices:
|
||||||
|
@ -84,7 +84,7 @@
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="5" column="0">
|
<item row="6" column="0">
|
||||||
<widget class="QLabel" name="label_4">
|
<widget class="QLabel" name="label_4">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Se&rif family:</string>
|
<string>Se&rif family:</string>
|
||||||
@ -94,10 +94,10 @@
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="5" column="1">
|
<item row="6" column="1">
|
||||||
<widget class="QFontComboBox" name="opt_pdf_serif_family"/>
|
<widget class="QFontComboBox" name="opt_pdf_serif_family"/>
|
||||||
</item>
|
</item>
|
||||||
<item row="6" column="0">
|
<item row="7" column="0">
|
||||||
<widget class="QLabel" name="label_5">
|
<widget class="QLabel" name="label_5">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>&Sans family:</string>
|
<string>&Sans family:</string>
|
||||||
@ -107,10 +107,10 @@
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="6" column="1">
|
<item row="7" column="1">
|
||||||
<widget class="QFontComboBox" name="opt_pdf_sans_family"/>
|
<widget class="QFontComboBox" name="opt_pdf_sans_family"/>
|
||||||
</item>
|
</item>
|
||||||
<item row="7" column="0">
|
<item row="8" column="0">
|
||||||
<widget class="QLabel" name="label_6">
|
<widget class="QLabel" name="label_6">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>&Monospace family:</string>
|
<string>&Monospace family:</string>
|
||||||
@ -120,10 +120,10 @@
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="7" column="1">
|
<item row="8" column="1">
|
||||||
<widget class="QFontComboBox" name="opt_pdf_mono_family"/>
|
<widget class="QFontComboBox" name="opt_pdf_mono_family"/>
|
||||||
</item>
|
</item>
|
||||||
<item row="8" column="0">
|
<item row="9" column="0">
|
||||||
<widget class="QLabel" name="label_7">
|
<widget class="QLabel" name="label_7">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>S&tandard font:</string>
|
<string>S&tandard font:</string>
|
||||||
@ -133,10 +133,10 @@
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="8" column="1">
|
<item row="9" column="1">
|
||||||
<widget class="QComboBox" name="opt_pdf_standard_font"/>
|
<widget class="QComboBox" name="opt_pdf_standard_font"/>
|
||||||
</item>
|
</item>
|
||||||
<item row="9" column="0">
|
<item row="10" column="0">
|
||||||
<widget class="QLabel" name="label_8">
|
<widget class="QLabel" name="label_8">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Default font si&ze:</string>
|
<string>Default font si&ze:</string>
|
||||||
@ -146,14 +146,14 @@
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="9" column="1">
|
<item row="10" column="1">
|
||||||
<widget class="QSpinBox" name="opt_pdf_default_font_size">
|
<widget class="QSpinBox" name="opt_pdf_default_font_size">
|
||||||
<property name="suffix">
|
<property name="suffix">
|
||||||
<string> px</string>
|
<string> px</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="10" column="0">
|
<item row="11" column="0">
|
||||||
<widget class="QLabel" name="label_9">
|
<widget class="QLabel" name="label_9">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Monospace &font size:</string>
|
<string>Monospace &font size:</string>
|
||||||
@ -163,14 +163,14 @@
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="10" column="1">
|
<item row="11" column="1">
|
||||||
<widget class="QSpinBox" name="opt_pdf_mono_font_size">
|
<widget class="QSpinBox" name="opt_pdf_mono_font_size">
|
||||||
<property name="suffix">
|
<property name="suffix">
|
||||||
<string> px</string>
|
<string> px</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="11" column="0">
|
<item row="12" column="0">
|
||||||
<spacer name="verticalSpacer">
|
<spacer name="verticalSpacer">
|
||||||
<property name="orientation">
|
<property name="orientation">
|
||||||
<enum>Qt::Vertical</enum>
|
<enum>Qt::Vertical</enum>
|
||||||
@ -183,6 +183,13 @@
|
|||||||
</property>
|
</property>
|
||||||
</spacer>
|
</spacer>
|
||||||
</item>
|
</item>
|
||||||
|
<item row="5" column="0" colspan="2">
|
||||||
|
<widget class="QCheckBox" name="opt_pdf_page_numbers">
|
||||||
|
<property name="text">
|
||||||
|
<string>Add page &numbers to the bottom of every page</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
<resources/>
|
<resources/>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user