diff --git a/resources/compiled_coffeescript.zip b/resources/compiled_coffeescript.zip index 8186cccaa6..8948c66f69 100644 Binary files a/resources/compiled_coffeescript.zip and b/resources/compiled_coffeescript.zip differ diff --git a/src/calibre/ebooks/conversion/plugins/pdf_output.py b/src/calibre/ebooks/conversion/plugins/pdf_output.py index b9d016de2d..c473931aef 100644 --- a/src/calibre/ebooks/conversion/plugins/pdf_output.py +++ b/src/calibre/ebooks/conversion/plugins/pdf_output.py @@ -99,6 +99,18 @@ class PDFOutput(OutputFormatPlugin): recommended_value=False, help=_( 'Generate an uncompressed PDF, useful for debugging, ' '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): diff --git a/src/calibre/ebooks/oeb/display/paged.coffee b/src/calibre/ebooks/oeb/display/paged.coffee index aea51b5b23..aae9aeddd2 100644 --- a/src/calibre/ebooks/oeb/display/paged.coffee +++ b/src/calibre/ebooks/oeb/display/paged.coffee @@ -29,6 +29,10 @@ class PagedDisplay this.current_page_height = null this.document_margins = null this.use_document_margins = false + this.footer_template = null + this.header_template = null + this.header = null + this.footer = null read_document_margins: () -> # Read page margins from the document. First checks for an @page rule. @@ -102,6 +106,7 @@ class PagedDisplay # than max_col_width sm += Math.ceil( (col_width - this.max_col_width) / 2*n ) col_width = Math.max(100, ((ww - adjust)/n) - 2*sm) + this.col_width = col_width this.page_width = col_width + 2*sm this.screen_width = this.page_width * this.cols_per_screen 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) 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: () -> # Ensure no images are wider than the available width in a column. Note # that this method use getBoundingClientRect() which means it will diff --git a/src/calibre/ebooks/pdf/render/from_html.py b/src/calibre/ebooks/pdf/render/from_html.py index 6beedc5dd4..2cdc804a9e 100644 --- a/src/calibre/ebooks/pdf/render/from_html.py +++ b/src/calibre/ebooks/pdf/render/from_html.py @@ -161,6 +161,17 @@ class PDFWriter(QObject): debug=self.log.debug, compress=not opts.uncompressed_pdf, mark_links=opts.pdf_mark_links) + self.footer = opts.pdf_footer_template + if self.footer is None and opts.pdf_page_numbers: + self.footer = '

_PAGENUM_

' + 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.render_queue = items @@ -264,6 +275,15 @@ class PDFWriter(QObject): py_bridge.value = book_indexing.all_links_and_anchors(); '''%(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 if not isinstance(amap, dict): amap = {'links':[], 'anchors':{}} # Some javascript error occurred @@ -272,6 +292,8 @@ class PDFWriter(QObject): mf = self.view.page().mainFrame() while True: self.doc.init_page() + if self.header or self.footer: + evaljs('paged_display.update_header_footer(%d)'%self.current_page_num) self.painter.save() mf.render(self.painter) self.painter.restore() @@ -279,7 +301,7 @@ class PDFWriter(QObject): self.doc.end_page() if not nsl[1] or nsl[0] <= 0: 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: break diff --git a/src/calibre/gui2/convert/pdf_output.py b/src/calibre/gui2/convert/pdf_output.py index e0674d066c..98334d1709 100644 --- a/src/calibre/gui2/convert/pdf_output.py +++ b/src/calibre/gui2/convert/pdf_output.py @@ -22,7 +22,7 @@ class PluginWidget(Widget, Ui_Form): 'override_profile_size', 'paper_size', 'custom_size', 'preserve_cover_aspect_ratio', 'pdf_serif_family', 'unit', '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 for x in get_option('paper_size').option.choices: diff --git a/src/calibre/gui2/convert/pdf_output.ui b/src/calibre/gui2/convert/pdf_output.ui index 5e3c4c9137..a4d184d6bc 100644 --- a/src/calibre/gui2/convert/pdf_output.ui +++ b/src/calibre/gui2/convert/pdf_output.ui @@ -84,7 +84,7 @@ - + Se&rif family: @@ -94,10 +94,10 @@ - + - + &Sans family: @@ -107,10 +107,10 @@ - + - + &Monospace family: @@ -120,10 +120,10 @@ - + - + S&tandard font: @@ -133,10 +133,10 @@ - + - + Default font si&ze: @@ -146,14 +146,14 @@ - + px - + Monospace &font size: @@ -163,14 +163,14 @@ - + px - + Qt::Vertical @@ -183,6 +183,13 @@ + + + + Add page &numbers to the bottom of every page + + +