From 22ba6c3ab7b3b9363e6d81e6d99af173d96687eb Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Tue, 9 Jul 2019 16:05:30 +0530 Subject: [PATCH] Pass JPEG images unmodified when creating PDF image pages --- .../ebooks/conversion/plugins/pdf_output.py | 2 +- src/calibre/ebooks/pdf/html_writer.py | 32 ++++++---------- src/calibre/ebooks/pdf/image_writer.py | 37 ++++++++++++++++--- src/calibre/ebooks/pdf/render/serialize.py | 3 ++ 4 files changed, 47 insertions(+), 27 deletions(-) diff --git a/src/calibre/ebooks/conversion/plugins/pdf_output.py b/src/calibre/ebooks/conversion/plugins/pdf_output.py index e10a94aad5..a0c1c40ee4 100644 --- a/src/calibre/ebooks/conversion/plugins/pdf_output.py +++ b/src/calibre/ebooks/conversion/plugins/pdf_output.py @@ -178,7 +178,7 @@ class PDFOutput(OutputFormatPlugin): def convert_images(self, images): from calibre.ebooks.pdf.image_writer import convert - convert(images, self.output_path, self.opts, self.metadata) + convert(images, self.output_path, self.opts, self.metadata, self.report_progress) def get_cover_data(self): oeb = self.oeb diff --git a/src/calibre/ebooks/pdf/html_writer.py b/src/calibre/ebooks/pdf/html_writer.py index 87c633566b..ef163d4b96 100644 --- a/src/calibre/ebooks/pdf/html_writer.py +++ b/src/calibre/ebooks/pdf/html_writer.py @@ -5,22 +5,20 @@ from __future__ import absolute_import, division, print_function, unicode_literals import os +from io import BytesIO -from PyQt5.Qt import ( - QApplication, QBuffer, QMarginsF, QPageLayout, QPainter, QPdfWriter, QTimer, - QUrl -) +from PyQt5.Qt import QApplication, 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, draw_image_page, get_page_layout, update_metadata + Image, PDFMetadata, draw_image_page, get_page_layout, update_metadata ) +from calibre.ebooks.pdf.render.serialize import PDFStream 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 @@ -103,20 +101,14 @@ class Renderer(QWebEnginePage): 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() + buf = BytesIO() + page_size = page_layout.fullRectPoints().size() + img = Image(cover_data) + writer = PDFStream(buf, (page_size.width(), page_size.height()), compress=True) + writer.apply_fill(color=(1, 1, 1)) + draw_image_page(writer, img, preserve_aspect_ratio=opts.preserve_cover_aspect_ratio) + writer.end() + cover_pdf = buf.getvalue() podofo = get_podofo() cover_pdf_doc = podofo.PDFDoc() cover_pdf_doc.load(cover_pdf) diff --git a/src/calibre/ebooks/pdf/image_writer.py b/src/calibre/ebooks/pdf/image_writer.py index cb5441b255..de2a21d3cb 100644 --- a/src/calibre/ebooks/pdf/image_writer.py +++ b/src/calibre/ebooks/pdf/image_writer.py @@ -8,11 +8,14 @@ from io import BytesIO from PyQt5.Qt import QMarginsF, QPageLayout, QPageSize, QSize -from calibre.ebooks.pdf.render.common import cicero, cm, didot, inch, mm, pica +from calibre.constants import filesystem_encoding from calibre.ebooks.metadata.xmp import metadata_to_xmp_packet +from calibre.ebooks.pdf.render.common import cicero, cm, didot, inch, mm, pica from calibre.ebooks.pdf.render.serialize import PDFStream -from calibre.utils.img import image_from_path +from calibre.utils.img import image_and_format_from_data +from calibre.utils.imghdr import identify from calibre.utils.podofo import get_podofo, set_metadata_implementation +from polyglot.builtins import as_unicode class PDFMetadata(object): # {{{ @@ -89,12 +92,34 @@ def get_page_layout(opts, for_comic=False): # }}} +class Image(object): # {{{ + + def __init__(self, path_or_bytes): + if not isinstance(path_or_bytes, bytes): + with open(path_or_bytes, 'rb') as f: + path_or_bytes = f.read() + self.img_data = path_or_bytes + fmt, width, height = identify(path_or_bytes) + if width > 0 and height > 0 and fmt == 'jpeg': + self.fmt = fmt + self.width, self.height = width, height + self.cache_key = None + else: + self.img, self.fmt = image_and_format_from_data(path_or_bytes) + self.width, self.height = self.img.width(), self.img.height() + self.cache_key = self.img.cacheKey() +# }}} + + def draw_image_page(writer, img, preserve_aspect_ratio=True): - ref = writer.add_image(img, img.cacheKey()) + if img.fmt == 'jpeg': + ref = writer.add_jpeg_image(img.img_data, img.width, img.height, img.cache_key) + else: + ref = writer.add_image(img.img, img.cache_key) page_size = tuple(writer.page_size) scaling = list(writer.page_size) translation = [0, 0] - img_ar = img.width() / img.height() + img_ar = img.width / img.height page_ar = page_size[0]/page_size[1] if preserve_aspect_ratio and page_ar != img_ar: if page_ar > img_ar: @@ -114,7 +139,7 @@ def update_metadata(pdf_doc, pdf_metadata): pdf_metadata.mi.book_producer, pdf_metadata.mi.tags, xmp_packet) -def convert(images, output_path, opts, metadata): +def convert(images, output_path, opts, metadata, report_progress): buf = BytesIO() page_layout = get_page_layout(opts, for_comic=True) page_size = page_layout.fullRectPoints().size() @@ -122,7 +147,7 @@ def convert(images, output_path, opts, metadata): writer.apply_fill(color=(1, 1, 1)) pdf_metadata = PDFMetadata(metadata) for i, path in enumerate(images): - img = image_from_path(path) + img = Image(as_unicode(path, filesystem_encoding)) draw_image_page(writer, img) writer.end_page() writer.end() diff --git a/src/calibre/ebooks/pdf/render/serialize.py b/src/calibre/ebooks/pdf/render/serialize.py index 62dbc2a11d..027ecaf838 100644 --- a/src/calibre/ebooks/pdf/render/serialize.py +++ b/src/calibre/ebooks/pdf/render/serialize.py @@ -416,6 +416,9 @@ class PDFStream(object): self.objects.commit(r, self.stream) return r + def add_jpeg_image(self, img_data, w, h, cache_key=None): + return self.write_image(img_data, w, h, 32, dct=True) + def add_image(self, img, cache_key): ref = self.get_image(cache_key) if ref is not None: