diff --git a/src/ocrmypdf/exec/ghostscript.py b/src/ocrmypdf/exec/ghostscript.py index af91960b..7973885a 100644 --- a/src/ocrmypdf/exec/ghostscript.py +++ b/src/ocrmypdf/exec/ghostscript.py @@ -129,8 +129,7 @@ def rasterize_pdf( :param filter_vector: if True, remove vector graphics objects :return: """ - res = xres, yres - int_res = round(xres), round(yres) + res = round(xres, 6), round(yres, 6) if not page_dpi: page_dpi = res @@ -145,7 +144,7 @@ def rasterize_pdf( f'-sDEVICE={raster_device}', f'-dFirstPage={pageno}', f'-dLastPage={pageno}', - f'-r{str(int_res[0])}x{str(int_res[1])}', + f'-r{res[0]:f}x{res[1]:f}', ] + (['-dFILTERVECTOR'] if filter_vector else []) + [ @@ -168,23 +167,8 @@ def rasterize_pdf( log.error('Ghostscript rasterizing failed') raise SubprocessOutputError() - # Ghostscript only accepts integers for output resolution - # if the resolution happens to be fractional, then the discrepancy - # would change the size of the output page, especially if the DPI - # is quite low. Resize the image to the expected size - tmp.seek(0) with Image.open(tmp) as im: - expected_size = ( - round(im.size[0] / int_res[0] * res[0]), - round(im.size[1] / int_res[1] * res[1]), - ) - if expected_size != im.size or page_dpi != (xres, yres): - log.debug( - f"Ghostscript: resize output image {im.size} -> {expected_size}" - ) - im = im.resize(expected_size) - if rotation is not None: log.debug("Rotating output by %i", rotation) # rotation is a clockwise angle and Image.ROTATE_* is diff --git a/tests/test_ghostscript.py b/tests/test_ghostscript.py new file mode 100644 index 00000000..8756e8a8 --- /dev/null +++ b/tests/test_ghostscript.py @@ -0,0 +1,81 @@ +# © 2019 James R. Barlow: github.com/jbarlow83 +# +# This file is part of OCRmyPDF. +# +# OCRmyPDF is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# OCRmyPDF is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with OCRmyPDF. If not, see . + +import logging +from decimal import Decimal + +import pikepdf +import pytest +from PIL import Image + +from ocrmypdf.exec.ghostscript import rasterize_pdf + + +@pytest.fixture +def linn(resources): + path = resources / 'linn.pdf' + return path, pikepdf.open(path) + + +def test_rasterize_size(linn, outdir, caplog): + path, pdf = linn + page_size_pts = (pdf.pages[0].MediaBox[2], pdf.pages[0].MediaBox[3]) + assert pdf.pages[0].MediaBox[0] == pdf.pages[0].MediaBox[1] == 0 + page_size = (page_size_pts[0] / Decimal(72), page_size_pts[1] / Decimal(72)) + target_size = Decimal('200.0'), Decimal('150.0') + target_dpi = 42.0, 4242.0 + + log = logging.getLogger() + rasterize_pdf( + path, + outdir / 'out.png', + target_size[0] / page_size[0], + target_size[1] / page_size[1], + raster_device='pngmono', + log=log, + page_dpi=target_dpi, + ) + + with Image.open(outdir / 'out.png') as im: + assert im.size == target_size + assert im.info['dpi'] == target_dpi + + +def test_rasterize_rotated(linn, outdir, caplog): + path, pdf = linn + page_size_pts = (pdf.pages[0].MediaBox[2], pdf.pages[0].MediaBox[3]) + assert pdf.pages[0].MediaBox[0] == pdf.pages[0].MediaBox[1] == 0 + page_size = (page_size_pts[0] / Decimal(72), page_size_pts[1] / Decimal(72)) + target_size = Decimal('200.0'), Decimal('150.0') + target_dpi = 42.0, 4242.0 + + log = logging.getLogger() + caplog.set_level(logging.DEBUG) + rasterize_pdf( + path, + outdir / 'out.png', + target_size[0] / page_size[0], + target_size[1] / page_size[1], + raster_device='pngmono', + log=log, + page_dpi=target_dpi, + rotation=90, + ) + + with Image.open(outdir / 'out.png') as im: + assert im.size == (target_size[1], target_size[0]) + assert im.info['dpi'] == (target_dpi[1], target_dpi[0])