Fix Ghostscript rasterizing of UserUnit pages and related sizing issues
This commit is contained in:
@@ -35,9 +35,28 @@ def _gs_error_reported(stream):
|
||||
|
||||
|
||||
def rasterize_pdf(input_file, output_file, xres, yres, raster_device, log,
|
||||
pageno=1):
|
||||
pageno=1, page_dpi=None):
|
||||
"""
|
||||
Rasterize one page of a PDF at resolution (xres, yres) in canvas units.
|
||||
|
||||
The image is sized to match the integer pixels dimensions implied by
|
||||
(xres, yres) even if those numbers are noninteger. The image's DPI will
|
||||
be overridden with the values in page_dpi.
|
||||
|
||||
:param input_file:
|
||||
:param output_file:
|
||||
:param xres: resolution at which to rasterize page
|
||||
:param yres:
|
||||
:param raster_device:
|
||||
:param log:
|
||||
:param pageno: page number to rasterize
|
||||
:param page_dpi: resolution tuple (x, y) overriding output image DPI
|
||||
:return:
|
||||
"""
|
||||
res = xres, yres
|
||||
int_res = round(xres), round(yres)
|
||||
if not page_dpi:
|
||||
page_dpi = res
|
||||
with NamedTemporaryFile(delete=True) as tmp:
|
||||
args_gs = [
|
||||
get_program('gs'),
|
||||
@@ -64,20 +83,19 @@ def rasterize_pdf(input_file, output_file, xres, yres, raster_device, log,
|
||||
log.error('Ghostscript rasterizing failed')
|
||||
raise SubprocessOutputError()
|
||||
|
||||
tmp.seek(0)
|
||||
|
||||
# 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:
|
||||
if expected_size != im.size or page_dpi != (xres, yres):
|
||||
log.debug(
|
||||
"Ghostscript: resize output image {} -> {}".format(
|
||||
im.size, expected_size))
|
||||
im.resize(expected_size).save(output_file)
|
||||
im.resize(expected_size).save(output_file, dpi=page_dpi)
|
||||
else:
|
||||
copy(tmp.name, output_file)
|
||||
|
||||
|
||||
+1
-1
@@ -695,7 +695,7 @@ class PdfInfo:
|
||||
|
||||
@property
|
||||
def has_userunit(self):
|
||||
return any(page.userunit for page in self.pages)
|
||||
return any(page.userunit != 1.0 for page in self.pages)
|
||||
|
||||
def __getitem__(self, item):
|
||||
return self._pages[item]
|
||||
|
||||
+13
-21
@@ -215,15 +215,18 @@ def get_page_dpi(pageinfo, options):
|
||||
|
||||
|
||||
def get_page_square_dpi(pageinfo, options):
|
||||
"Get the working DPI when we require xres == yres"
|
||||
"Get the DPI when we require xres == yres, scaled to physical units"
|
||||
xres = pageinfo.xres or 0
|
||||
yres = pageinfo.yres or 0
|
||||
userunit = pageinfo.userunit or 1
|
||||
return float(max(
|
||||
(pageinfo.xres * pageinfo.userunit) or VECTOR_PAGE_DPI,
|
||||
(pageinfo.yres * pageinfo.userunit) or VECTOR_PAGE_DPI,
|
||||
(xres * userunit) or VECTOR_PAGE_DPI,
|
||||
(yres * userunit) or VECTOR_PAGE_DPI,
|
||||
options.oversample or 0))
|
||||
|
||||
|
||||
def get_page_true_square_dpi(pageinfo, options):
|
||||
"Get the true DPI when we require xres == yres, and scaled in userunits"
|
||||
def get_canvas_square_dpi(pageinfo, options):
|
||||
"""Get the DPI when we require xres == yres, in Postscript units"""
|
||||
return float(max(
|
||||
(pageinfo.xres) or VECTOR_PAGE_DPI,
|
||||
(pageinfo.yres) or VECTOR_PAGE_DPI,
|
||||
@@ -433,23 +436,12 @@ def rasterize_with_ghostscript(
|
||||
|
||||
# Produce the page image with square resolution or else deskew and OCR
|
||||
# will not work properly.
|
||||
true_dpi = get_page_true_square_dpi(pageinfo, options)
|
||||
working_dpi = get_page_square_dpi(pageinfo, options)
|
||||
canvas_dpi = get_canvas_square_dpi(pageinfo, options)
|
||||
page_dpi = get_page_square_dpi(pageinfo, options)
|
||||
|
||||
if true_dpi == working_dpi:
|
||||
dpi = true_dpi
|
||||
ghostscript.rasterize_pdf(
|
||||
input_file, output_file, xres=dpi, yres=dpi,
|
||||
raster_device=device, log=log)
|
||||
else:
|
||||
# Ghostscript respects /UserUnit when rasterizing. Rasterize at
|
||||
# the true DPI but rewrite the output image to the working DPI.
|
||||
ghostscript.rasterize_pdf(
|
||||
input_file, output_file + '.jpg', xres=true_dpi, yres=true_dpi,
|
||||
raster_device=device, log=log)
|
||||
|
||||
with Image.open(output_file + ".jpg") as im:
|
||||
im.save(output_file, dpi=(working_dpi, working_dpi))
|
||||
ghostscript.rasterize_pdf(
|
||||
input_file, output_file, xres=canvas_dpi, yres=canvas_dpi,
|
||||
raster_device=device, log=log, page_dpi=(page_dpi, page_dpi))
|
||||
|
||||
|
||||
def preprocess_remove_background(
|
||||
|
||||
Reference in New Issue
Block a user