diff --git a/src/calibre/ebooks/conversion/plugins/pdf_output.py b/src/calibre/ebooks/conversion/plugins/pdf_output.py index c5f5450986..e10a94aad5 100644 --- a/src/calibre/ebooks/conversion/plugins/pdf_output.py +++ b/src/calibre/ebooks/conversion/plugins/pdf_output.py @@ -238,4 +238,7 @@ class PDFOutput(OutputFormatPlugin): oeb_output = plugin_for_output_format('oeb') oeb_output.convert(oeb_book, oeb_dir, self.input_plugin, self.opts, self.log) opfpath = glob.glob(os.path.join(oeb_dir, '*.opf'))[0] - convert(opfpath, self.opts, metadata=self.metadata, output_path=self.output_path, log=self.log) + convert( + opfpath, self.opts, metadata=self.metadata, output_path=self.output_path, + log=self.log, cover_data=self.cover_data + ) diff --git a/src/calibre/ebooks/pdf/html_writer.py b/src/calibre/ebooks/pdf/html_writer.py index 1c8a39144d..87c633566b 100644 --- a/src/calibre/ebooks/pdf/html_writer.py +++ b/src/calibre/ebooks/pdf/html_writer.py @@ -6,17 +6,21 @@ from __future__ import absolute_import, division, print_function, unicode_litera import os -from PyQt5.Qt import QApplication, QTimer, QUrl +from PyQt5.Qt import ( + QApplication, QBuffer, QMarginsF, QPageLayout, QPainter, QPdfWriter, QTimer, + QUrl +) from PyQt5.QtWebEngineWidgets import QWebEnginePage from calibre.constants import iswindows from calibre.ebooks.oeb.polish.container import Container as ContainerBase from calibre.ebooks.oeb.polish.split import merge_html from calibre.ebooks.pdf.image_writer import ( - PDFMetadata, get_page_layout, update_metadata + PDFMetadata, draw_image_page, get_page_layout, update_metadata ) from calibre.gui2 import setup_unix_signals from calibre.gui2.webengine import secure_webengine +from calibre.utils.img import image_from_data from calibre.utils.logging import default_log from calibre.utils.podofo import get_podofo from polyglot.builtins import range @@ -98,7 +102,28 @@ class Renderer(QWebEnginePage): return self.pdf_data -def convert(opf_path, opts, metadata=None, output_path=None, log=default_log): +def add_cover(pdf_doc, cover_data, page_layout, opts): + buf = QBuffer() + buf.open(QBuffer.ReadWrite) + cover_layout = QPageLayout(page_layout) + cover_layout.setMargins(QMarginsF(0, 0, 0, 0)) + img = image_from_data(cover_data) + writer = QPdfWriter(buf) + writer.setPageLayout(cover_layout) + painter = QPainter() + painter.begin(writer) + try: + draw_image_page(painter, img, preserve_aspect_ratio=opts.preserve_cover_aspect_ratio) + finally: + painter.end() + cover_pdf = buf.data().data() + podofo = get_podofo() + cover_pdf_doc = podofo.PDFDoc() + cover_pdf_doc.load(cover_pdf) + pdf_doc.insert_existing_page(cover_pdf_doc) + + +def convert(opf_path, opts, metadata=None, output_path=None, log=default_log, cover_data=None): container = Container(opf_path, log) spine_names = [name for name, is_linear in container.spine_names] master = spine_names[0] @@ -115,6 +140,9 @@ def convert(opf_path, opts, metadata=None, output_path=None, log=default_log): pdf_doc = podofo.PDFDoc() pdf_doc.load(pdf_data) + if cover_data: + add_cover(pdf_doc, cover_data, page_layout, opts) + if metadata is not None: update_metadata(pdf_doc, PDFMetadata(metadata)) diff --git a/src/calibre/utils/podofo/doc.cpp b/src/calibre/utils/podofo/doc.cpp index da0f6161c2..cadbcd1a2c 100644 --- a/src/calibre/utils/podofo/doc.cpp +++ b/src/calibre/utils/podofo/doc.cpp @@ -219,6 +219,24 @@ PDFDoc_append(PDFDoc *self, PyObject *args) { Py_RETURN_NONE; } // }}} +// insert_existing_page() {{{ +static PyObject * +PDFDoc_insert_existing_page(PDFDoc *self, PyObject *args) { + PDFDoc *src_doc; + int src_page = 0, at = 0; + + if (!PyArg_ParseTuple(args, "O!|ii", &PDFDocType, &src_doc, &src_page, &at)) return NULL; + + try { + self->doc->InsertExistingPageAt(*src_doc->doc, src_page, at); + } catch (const PdfError & err) { + podofo_set_exception(err); + return NULL; + } + + Py_RETURN_NONE; +} // }}} + // set_box() {{{ static PyObject * PDFDoc_set_box(PDFDoc *self, PyObject *args) { @@ -629,6 +647,9 @@ static PyMethodDef PDFDoc_methods[] = { {"append", (PyCFunction)PDFDoc_append, METH_VARARGS, "append(doc) -> Append doc (which must be a PDFDoc) to this document." }, + {"insert_existing_page", (PyCFunction)PDFDoc_insert_existing_page, METH_VARARGS, + "insert_existing_page(src_doc, src_page, at) -> Insert the page src_page from src_doc at index: at." + }, {"set_box", (PyCFunction)PDFDoc_set_box, METH_VARARGS, "set_box(page_num, box, left, bottom, width, height) -> Set the PDF bounding box for the page numbered nu, box must be one of: MediaBox, CropBox, TrimBox, BleedBox, ArtBox. The numbers are interpreted as pts." },