From cb1c6efd61241e04104bf7cdba5f340c09299702 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Fri, 19 May 2023 15:16:14 +0530 Subject: [PATCH] Podofo wrapper to add an image page --- src/calibre/utils/podofo/__init__.py | 17 ++++++++++++++ src/calibre/utils/podofo/doc.cpp | 33 ++++++++++++++++++++++++++++ 2 files changed, 50 insertions(+) diff --git a/src/calibre/utils/podofo/__init__.py b/src/calibre/utils/podofo/__init__.py index c57c943078..95f7fbc3a6 100644 --- a/src/calibre/utils/podofo/__init__.py +++ b/src/calibre/utils/podofo/__init__.py @@ -166,6 +166,23 @@ def test_dedup_type3_fonts(src): print(f'Modified pdf with {num} glyphs removed saved to:', dest) +def add_image_page(pdf_doc, image_data, page_size=None, page_num=1, preserve_aspect_ratio=True): + if page_size is None: + from qt.core import QPageSize + page_size = QPageSize(QPageSize.PageSizeId.A4) + page = page_size.rect(QPageSize.Unit.Point) + pdf_doc.add_image_page( + image_data, page.left(), page.top(), page.width(), page.height(), page.left(), page.top(), page.width(), page.height(), page_num, preserve_aspect_ratio) + + +def test_add_image_page(image='/t/t.jpg', dest='/t/t.pdf', **kw): + image_data = open(image, 'rb').read() + podofo = get_podofo() + p = podofo.PDFDoc() + add_image_page(p, image_data, **kw) + p.save(dest) + + def test_list_fonts(src): podofo = get_podofo() p = podofo.PDFDoc() diff --git a/src/calibre/utils/podofo/doc.cpp b/src/calibre/utils/podofo/doc.cpp index 1f6afacbe2..4b6a880225 100644 --- a/src/calibre/utils/podofo/doc.cpp +++ b/src/calibre/utils/podofo/doc.cpp @@ -407,6 +407,35 @@ PDFDoc_get_xmp_metadata(PDFDoc *self, PyObject *args) { Py_RETURN_NONE; } // }}} +// add_image_page() {{{ +static PyObject * +PDFDoc_add_image_page(PDFDoc *self, PyObject *args) { + const char *image_data; Py_ssize_t image_data_sz; + double page_x, page_y, page_width, page_height; + double image_x, image_y, image_canvas_width, image_canvas_height; + unsigned int page_num = 1; int preserve_aspect_ratio = 1; + if (!PyArg_ParseTuple(args, "y#dddddddd|Ip", &image_data, &image_data_sz, &page_x, &page_y, &page_width, &page_height, &image_x, &image_y, &image_canvas_width, &image_canvas_height, &page_num, &preserve_aspect_ratio)) return NULL; + auto img = self->doc->CreateImage(); + img->LoadFromBuffer(bufferview(image_data, image_data_sz)); + auto &page = self->doc->GetPages().CreatePageAt(page_num-1, Rect(page_x, page_y, page_width, page_height)); + PdfPainter painter; + painter.SetCanvas(page); + auto scaling_x = image_canvas_width, scaling_y = image_canvas_height; + if (preserve_aspect_ratio) { + auto page_ar = page_width / page_height, img_ar = img->GetRect().Width / img->GetRect().Height; + if (page_ar > img_ar) { + scaling_x = img_ar * image_canvas_height; + image_x = (image_canvas_width - scaling_x) / 2.; + } else if (page_ar < img_ar) { + scaling_y = image_canvas_width / img_ar; + image_y = (image_canvas_height - scaling_y) / 2.; + } + } + painter.DrawImage(*img, image_x, image_y, scaling_x / img->GetRect().Width, scaling_y / img->GetRect().Height); + return Py_BuildValue("dd", img->GetRect().Width, img->GetRect().Height); +} +// }}} + // set_xmp_metadata() {{{ static PyObject * PDFDoc_set_xmp_metadata(PDFDoc *self, PyObject *args) { @@ -809,6 +838,10 @@ static PyMethodDef PDFDoc_methods[] = { {"set_xmp_metadata", (PyCFunction)PDFDoc_set_xmp_metadata, METH_VARARGS, "set_xmp_metadata(raw) -> Set the XMP metadata to the raw bytes (which must be a valid XML packet)" }, + {"add_image_page", (PyCFunction)PDFDoc_add_image_page, METH_VARARGS, + "add_image_page(image_data, page_idx=0) -> Add the specified image as a full page image, will use the size of the first existing page as page size." + }, + {NULL} /* Sentinel */ };