Refactor xy-pair for resolution to tuple

This commit is contained in:
James R. Barlow
2020-04-16 15:38:33 -07:00
parent 4581027246
commit 57771f06a3
9 changed files with 57 additions and 76 deletions
+15 -18
View File
@@ -201,12 +201,12 @@ def validate_pdfinfo_options(context):
def get_page_dpi(pageinfo, options):
"Get the DPI when nonsquare DPI is tolerable"
xres = max(
pageinfo.xres or VECTOR_PAGE_DPI,
pageinfo.xyres[0] or VECTOR_PAGE_DPI,
options.oversample or 0,
VECTOR_PAGE_DPI if pageinfo.has_vector else 0,
)
yres = max(
pageinfo.yres or VECTOR_PAGE_DPI,
pageinfo.xyres[1] or VECTOR_PAGE_DPI,
options.oversample or 0,
VECTOR_PAGE_DPI if pageinfo.has_vector else 0,
)
@@ -215,8 +215,8 @@ def get_page_dpi(pageinfo, options):
def get_page_square_dpi(pageinfo, options):
"Get the DPI when we require xres == yres, scaled to physical units"
xres = pageinfo.xres or 0
yres = pageinfo.yres or 0
xres = pageinfo.xyres[0] or 0
yres = pageinfo.xyres[1] or 0
userunit = pageinfo.userunit or 1
return float(
max(
@@ -232,8 +232,8 @@ 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,
(pageinfo.xyres[0]) or VECTOR_PAGE_DPI,
(pageinfo.xyres[1]) or VECTOR_PAGE_DPI,
VECTOR_PAGE_DPI if pageinfo.has_vector else 0,
options.oversample or 0,
)
@@ -321,9 +321,8 @@ def rasterize_preview(input_file, page_context):
ghostscript.rasterize_pdf(
input_file,
output_file,
xres=canvas_dpi,
yres=canvas_dpi,
raster_device='jpeggray',
xyres=(canvas_dpi, canvas_dpi),
page_dpi=(page_dpi, page_dpi),
pageno=page_context.pageinfo.pageno + 1,
)
@@ -436,9 +435,8 @@ def rasterize(
ghostscript.rasterize_pdf(
input_file,
output_file,
xres=canvas_dpi,
yres=canvas_dpi,
raster_device=device,
xyres=(canvas_dpi, canvas_dpi),
page_dpi=(page_dpi, page_dpi),
pageno=pageinfo.pageno + 1,
rotation=correction,
@@ -488,8 +486,7 @@ def create_ocr_image(image, page_context):
# pink = ImageColor.getcolor('#ff0080', im.mode)
draw = ImageDraw.ImageDraw(im)
xres, yres = im.info['dpi']
log.debug('resolution %r %r' % (xres, yres))
log.debug('resolution %r', im.info['dpi'])
if not options.force_ocr:
# Do not mask text areas when forcing OCR, because we need to OCR
@@ -505,12 +502,12 @@ def create_ocr_image(image, page_context):
# without regard whatever resolution is in pageinfo (may differ or
# be None)
bbox = [float(v) for v in textarea]
xscale, yscale = float(xres) / 72.0, float(yres) / 72.0
xyscale = tuple(float(coord) / 72.0 for coord in im.info['dpi'])
pixcoords = [
bbox[0] * xscale,
im.height - bbox[3] * yscale,
bbox[2] * xscale,
im.height - bbox[1] * yscale,
bbox[0] * xyscale[0],
im.height - bbox[3] * xyscale[1],
bbox[2] * xyscale[0],
im.height - bbox[1] * xyscale[1],
]
pixcoords = [int(round(c)) for c in pixcoords]
log.debug('blanking %r', pixcoords)
@@ -524,7 +521,7 @@ def create_ocr_image(image, page_context):
del draw
# Pillow requires integer DPI
dpi = round(xres), round(yres)
dpi = tuple(round(coord) for coord in im.info['dpi'])
im.save(output_file, dpi=dpi)
return output_file
+6 -7
View File
@@ -135,32 +135,31 @@ def extract_text(input_file, pageno=1):
def rasterize_pdf(
input_file,
output_file,
xres,
yres,
*,
raster_device,
xyres,
pageno=1,
page_dpi=None,
rotation=None,
filter_vector=False,
):
"""Rasterize one page of a PDF at resolution (xres, yres) in canvas units.
"""Rasterize one page of a PDF at resolution xyres 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
(xyres[0], xyres[1]) even if those numbers are noninteger. The image's DPI will
be overridden with the values in page_dpi.
:param input_file: pathlike
:param output_file: pathlike
:param xres: resolution at which to rasterize page
:param yres:
:param raster_device:
:param xyres: resolution at which to rasterize page
:param pageno: page number to rasterize (beginning at page 1)
:param page_dpi: resolution tuple (x, y) overriding output image DPI
:param rotation: 0, 90, 180, 270: clockwise angle to rotate page
:param filter_vector: if True, remove vector graphics objects
:return:
"""
res = round(xres, 6), round(yres, 6)
res = round(xyres[0], 6), round(xyres[1], 6)
if not page_dpi:
page_dpi = res
+15 -21
View File
@@ -356,12 +356,11 @@ class ImageInfo:
return self._enc
@property
def xres(self):
return _get_dpi(self._shorthand, (self._width, self._height))[0]
@property
def yres(self):
return _get_dpi(self._shorthand, (self._width, self._height))[1]
def xyres(self):
return (
_get_dpi(self._shorthand, (self._width, self._height))[0],
_get_dpi(self._shorthand, (self._width, self._height))[1],
)
def __repr__(self):
class_locals = {
@@ -371,7 +370,7 @@ class ImageInfo:
}
return (
"<ImageInfo '{name}' {type_} {width}x{height} {color} "
"{comp} {bpc} {enc} {xres}x{yres}>"
"{comp} {bpc} {enc} {xyres}>"
).format(**class_locals)
@@ -607,9 +606,9 @@ def _pdf_get_pageinfo(pdf, pageno: int, infile: PathLike, xmltext: str):
pageinfo['images'] = [im for im in contentsinfo if isinstance(im, ImageInfo)]
if pageinfo['images']:
xres = Decimal(max(image.xres for image in pageinfo['images']))
yres = Decimal(max(image.yres for image in pageinfo['images']))
pageinfo['xres'], pageinfo['yres'] = xres, yres
xres = Decimal(max(image.xyres[0] for image in pageinfo['images']))
yres = Decimal(max(image.xyres[1] for image in pageinfo['images']))
pageinfo['xyres'] = xres, yres
pageinfo['width_pixels'] = int(round(xres * pageinfo['width_inches']))
pageinfo['height_pixels'] = int(round(yres * pageinfo['height_inches']))
@@ -679,11 +678,11 @@ class PageInfo:
@property
def width_pixels(self):
return int(round(self.width_inches * self.xres))
return int(round(self.width_inches * self.xyres[0]))
@property
def height_pixels(self):
return int(round(self.height_inches * self.yres))
return int(round(self.height_inches * self.xyres[1]))
@property
def rotation(self):
@@ -723,12 +722,8 @@ class PageInfo:
)
@property
def xres(self):
return self._pageinfo.get('xres', None)
@property
def yres(self):
return self._pageinfo.get('yres', None)
def xyres(self):
return self._pageinfo.get('xyres', (0, 0))
@property
def userunit(self):
@@ -743,14 +738,13 @@ class PageInfo:
def __repr__(self):
return (
'<PageInfo ' 'pageno={} {}"x{}" rotation={} res={}x{} has_text={}>'
'<PageInfo ' 'pageno={} {}"x{}" rotation={} res={} has_text={}>'
).format(
self.pageno,
self.width_inches,
self.height_inches,
self.rotation,
self.xres,
self.yres,
self.xyres,
self.has_text,
)
+2 -4
View File
@@ -76,9 +76,8 @@ def test_rasterize_size(francais, outdir, caplog):
rasterize_pdf(
path,
outdir / 'out.png',
target_size[0] / page_size[0],
target_size[1] / page_size[1],
raster_device='pngmono',
xyres=(target_size[0] / page_size[0], target_size[1] / page_size[1]),
page_dpi=forced_dpi,
)
@@ -99,9 +98,8 @@ def test_rasterize_rotated(francais, outdir, caplog):
rasterize_pdf(
path,
outdir / 'out.png',
target_size[0] / page_size[0],
target_size[1] / page_size[1],
raster_device='pngmono',
xyres=(target_size[0] / page_size[0], target_size[1] / page_size[1]),
page_dpi=forced_dpi,
rotation=90,
)
+4 -4
View File
@@ -74,8 +74,8 @@ def test_oversample(spoof_tesseract_cache, renderer, resources, outpdf):
pdfinfo = PdfInfo(oversampled_pdf)
print(pdfinfo[0].xres)
assert abs(pdfinfo[0].xres - 350) < 1
print(pdfinfo[0].xyres[0])
assert abs(pdfinfo[0].xyres[0] - 350) < 1
def test_repeat_ocr(resources, no_outpdf):
@@ -393,8 +393,8 @@ def test_very_high_dpi(spoof_tesseract_cache, resources, outpdf):
pdfinfo = PdfInfo(outpdf)
image = pdfinfo[0].images[0]
assert isclose(image.xres, image.yres)
assert isclose(image.xres, 2400)
assert isclose(image.xyres[0], image.xyres[1])
assert isclose(image.xyres[0], 2400)
def test_overlay(spoof_tesseract_noop, resources, outpdf):
+1 -1
View File
@@ -43,7 +43,7 @@ def test_mono_not_inverted(resources, outdir):
opt.main(infile, outdir / 'out.pdf', level=3)
rasterize_pdf(
outdir / 'out.pdf', outdir / 'im.png', xres=10, yres=10, raster_device='pnggray'
outdir / 'out.pdf', outdir / 'im.png', raster_device='pnggray', xyres=(10, 10)
)
with Image.open(fspath(outdir / 'im.png')) as im:
+5 -5
View File
@@ -85,8 +85,8 @@ def test_single_page_image(outdir):
assert pdfimage.color == Colorspace.gray
# DPI in a 1"x1" is the image width
assert isclose(pdfimage.xres, 8)
assert isclose(pdfimage.yres, 8)
assert isclose(pdfimage.xyres[0], 8)
assert isclose(pdfimage.xyres[1], 8)
def test_single_page_inline_image(outdir):
@@ -105,7 +105,7 @@ def test_single_page_inline_image(outdir):
info = pdfinfo.PdfInfo(filename)
print(info)
pdfimage = info[0].images[0]
assert isclose(pdfimage.xres, 8)
assert isclose(pdfimage.xyres[0], 8)
assert pdfimage.color == Colorspace.gray
assert pdfimage.width == 8
@@ -117,7 +117,7 @@ def test_jpeg(resources, outdir):
pdfimage = pdf[0].images[0]
assert pdfimage.enc == Encoding.jpeg
assert isclose(pdfimage.xres, 150)
assert isclose(pdfimage.xyres[0], 150)
def test_form_xobject(resources):
@@ -139,7 +139,7 @@ def test_no_contents(resources):
def test_oversized_page(resources):
pdf = pdfinfo.PdfInfo(resources / 'poster.pdf')
image = pdf[0].images[0]
assert image.width * image.xres > 200, "this is supposed to be oversized"
assert image.width * image.xyres[0] > 200, "this is supposed to be oversized"
def test_pickle(resources):
+8 -14
View File
@@ -50,12 +50,7 @@ def test_deskew(spoof_tesseract_noop, resources, outdir):
deskewed_png = outdir / 'deskewed.png'
ghostscript.rasterize_pdf(
deskewed_pdf,
deskewed_png,
xres=150,
yres=150,
raster_device='pngmono',
pageno=1,
deskewed_pdf, deskewed_png, raster_device='pngmono', xyres=(150, 150), pageno=1
)
pix = Pix.open(deskewed_png)
@@ -82,7 +77,7 @@ def test_remove_background(spoof_tesseract_noop, resources, outdir):
output_png = outdir / 'remove_bg.png'
ghostscript.rasterize_pdf(
output_pdf, output_png, xres=100, yres=100, raster_device='png16m', pageno=1
output_pdf, output_png, raster_device='png16m', xyres=(100, 100), pageno=1
)
# The output image should contain pure white and black
@@ -122,7 +117,7 @@ def test_exotic_image(
def test_non_square_resolution(renderer, spoof_tesseract_cache, resources, outpdf):
# Confirm input image is non-square resolution
in_pageinfo = PdfInfo(resources / 'aspect.pdf')
assert in_pageinfo[0].xres != in_pageinfo[0].yres
assert in_pageinfo[0].xyres[0] != in_pageinfo[0].xyres[1]
check_ocrmypdf(
resources / 'aspect.pdf',
@@ -135,8 +130,7 @@ def test_non_square_resolution(renderer, spoof_tesseract_cache, resources, outpd
out_pageinfo = PdfInfo(outpdf)
# Confirm resolution was kept the same
assert in_pageinfo[0].xres == out_pageinfo[0].xres
assert in_pageinfo[0].yres == out_pageinfo[0].yres
assert in_pageinfo[0].xyres == out_pageinfo[0].xyres
@pytest.mark.parametrize('renderer', RENDERERS)
@@ -145,7 +139,7 @@ def test_convert_to_square_resolution(
):
# Confirm input image is non-square resolution
in_pageinfo = PdfInfo(resources / 'aspect.pdf')
assert in_pageinfo[0].xres != in_pageinfo[0].yres
assert in_pageinfo[0].xyres[0] != in_pageinfo[0].xyres[1]
# --force-ocr requires means forced conversion to square resolution
check_ocrmypdf(
@@ -162,7 +156,7 @@ def test_convert_to_square_resolution(
in_p0, out_p0 = in_pageinfo[0], out_pageinfo[0]
# Resolution show now be equal
assert out_p0.xres == out_p0.yres
assert out_p0.xyres[0] == out_p0.xyres[1]
# Page size should match input page size
assert isclose(in_p0.width_inches, out_p0.width_inches)
@@ -170,7 +164,7 @@ def test_convert_to_square_resolution(
# Because we rasterized the page to produce a new image, it should occupy
# the entire page
out_im_w = out_p0.images[0].width / out_p0.images[0].xres
out_im_h = out_p0.images[0].height / out_p0.images[0].yres
out_im_w = out_p0.images[0].width / out_p0.images[0].xyres[0]
out_im_h = out_p0.images[0].height / out_p0.images[0].xyres[1]
assert isclose(out_p0.width_inches, out_im_w)
assert isclose(out_p0.height_inches, out_im_h)
+1 -2
View File
@@ -58,9 +58,8 @@ def check_monochrome_correlation(
ghostscript.rasterize_pdf(
pdf,
png,
xres=100,
yres=100,
raster_device='pngmono',
xyres=(100, 100),
pageno=pageno,
rotation=0,
)