Also process art and bleed boxes
This commit is contained in:
+31
-10
@@ -39,6 +39,7 @@ from ocrmypdf.hocrtransform import DebugRenderOptions, HocrTransform
|
||||
from ocrmypdf.hocrtransform._font import Courier
|
||||
from ocrmypdf.pdfa import generate_pdfa_ps
|
||||
from ocrmypdf.pdfinfo import Colorspace, Encoding, PageInfo, PdfInfo
|
||||
from ocrmypdf.pdfinfo.info import FloatRect
|
||||
from ocrmypdf.pluginspec import OrientationConfidence
|
||||
|
||||
try:
|
||||
@@ -832,6 +833,23 @@ def _offset_rect(rect: tuple[float, float, float, float], offset: tuple[float, f
|
||||
)
|
||||
|
||||
|
||||
def _adjust_pagebox(
|
||||
page: pikepdf.Page,
|
||||
media_box: FloatRect,
|
||||
name: pikepdf.Name,
|
||||
target_box: FloatRect,
|
||||
offset: tuple[float, float],
|
||||
swap_axis: bool,
|
||||
):
|
||||
if media_box == target_box:
|
||||
return
|
||||
box = _offset_rect(target_box, offset)
|
||||
if swap_axis:
|
||||
box = box[1], box[0], box[3], box[2]
|
||||
page[name] = box
|
||||
log.debug(f"{str(name)} = {target_box}")
|
||||
|
||||
|
||||
def fix_pagepdf_boxes(
|
||||
infile: Path | BinaryIO,
|
||||
out_file: Path,
|
||||
@@ -856,22 +874,25 @@ def fix_pagepdf_boxes(
|
||||
"""
|
||||
with pikepdf.open(infile) as pdf:
|
||||
for page in pdf.pages:
|
||||
# page.BleedBox = page_context.pageinfo.bleedbox
|
||||
# page.ArtBox = page_context.pageinfo.artbox
|
||||
log.debug(
|
||||
f"initial mediabox={page.MediaBox} and pageinfo mediabox={page_context.pageinfo.mediabox}"
|
||||
f"initial mediabox={page.MediaBox} and pageinfo "
|
||||
f"mediabox={page_context.pageinfo.mediabox}"
|
||||
)
|
||||
mediabox = page_context.pageinfo.mediabox
|
||||
offset = -mediabox[0], -mediabox[1]
|
||||
cropbox = _offset_rect(page_context.pageinfo.cropbox, offset)
|
||||
trimbox = _offset_rect(page_context.pageinfo.trimbox, offset)
|
||||
if swap_axis:
|
||||
cropbox = cropbox[1], cropbox[0], cropbox[3], cropbox[2]
|
||||
trimbox = trimbox[1], trimbox[0], trimbox[3], trimbox[2]
|
||||
mediabox = mediabox[1], mediabox[0], mediabox[3], mediabox[2]
|
||||
page.CropBox = cropbox
|
||||
page.TrimBox = trimbox
|
||||
log.debug(f"cropbox={cropbox}, trimbox={trimbox}, mediabox={mediabox}")
|
||||
boxes = ['CropBox', 'TrimBox', 'ArtBox', 'BleedBox']
|
||||
for box_name in boxes:
|
||||
_adjust_pagebox(
|
||||
page,
|
||||
mediabox,
|
||||
pikepdf.Name(f"/{box_name}"),
|
||||
getattr(page_context.pageinfo, box_name.lower()),
|
||||
offset,
|
||||
swap_axis,
|
||||
)
|
||||
|
||||
pdf.save(out_file)
|
||||
return out_file
|
||||
|
||||
|
||||
@@ -901,8 +901,8 @@ class PageInfo:
|
||||
width_pt = mediabox[2] - mediabox[0]
|
||||
height_pt = mediabox[3] - mediabox[1]
|
||||
|
||||
# self._artbox = [float(d) for d in page.artbox.as_list()]
|
||||
# self._bleedbox = [float(d) for d in page.bleedbox.as_list()]
|
||||
self._artbox = [float(d) for d in page.artbox.as_list()]
|
||||
self._bleedbox = [float(d) for d in page.bleedbox.as_list()]
|
||||
self._cropbox = [float(d) for d in page.cropbox.as_list()]
|
||||
self._mediabox = [float(d) for d in page.mediabox.as_list()]
|
||||
self._trimbox = [float(d) for d in page.trimbox.as_list()]
|
||||
@@ -1039,6 +1039,16 @@ class PageInfo:
|
||||
"""Return trimbox of page in PDF coordinates."""
|
||||
return self._trimbox
|
||||
|
||||
@property
|
||||
def artbox(self) -> FloatRect:
|
||||
"""Return artbox of page in PDF coordinates."""
|
||||
return self._artbox
|
||||
|
||||
@property
|
||||
def bleedbox(self) -> FloatRect:
|
||||
"""Return bleedbox of page in PDF coordinates."""
|
||||
return self._bleedbox
|
||||
|
||||
@property
|
||||
def images(self) -> list[ImageInfo]:
|
||||
"""Return images."""
|
||||
|
||||
@@ -102,7 +102,6 @@ def test_crop_box(
|
||||
page = pdf.pages[0]
|
||||
page.CropBox = crop_to
|
||||
pdf.save(outdir / 'cropped.pdf')
|
||||
pdf.save('cropped.pdf')
|
||||
args = [
|
||||
'--jobs',
|
||||
'1',
|
||||
@@ -110,6 +109,8 @@ def test_crop_box(
|
||||
renderer,
|
||||
'--output-type',
|
||||
output_type,
|
||||
'--optimize',
|
||||
'0',
|
||||
]
|
||||
if mode:
|
||||
args.append(mode)
|
||||
@@ -118,5 +119,4 @@ def test_crop_box(
|
||||
|
||||
with pikepdf.open(outdir / 'processed.pdf') as pdf:
|
||||
page = pdf.pages[0]
|
||||
pdf.save('processed.pdf')
|
||||
assert page.CropBox == crop_expected
|
||||
|
||||
+56
-9
@@ -51,20 +51,27 @@ def compare_images_monochrome(
|
||||
|
||||
with Image.open(reference_png) as reference_im, Image.open(test_png) as test_im:
|
||||
assert reference_im.mode == test_im.mode == '1'
|
||||
difference = ImageChops.logical_xor(reference_im, test_im)
|
||||
assert difference.mode == '1'
|
||||
# Pillow uses black is 0 for '1'. Invert so that foreground is 1, then
|
||||
# compare
|
||||
inv_ref_im = ImageChops.invert(reference_im)
|
||||
inv_test_im = ImageChops.invert(test_im)
|
||||
foreground_match = ImageChops.logical_and(inv_ref_im, inv_test_im)
|
||||
foreground_total = ImageChops.logical_or(inv_ref_im, inv_test_im)
|
||||
assert foreground_match.mode == '1'
|
||||
|
||||
histogram = difference.histogram()
|
||||
histogram = foreground_match.histogram()
|
||||
histogram_total = foreground_total.histogram()
|
||||
assert (
|
||||
len(histogram) == 256
|
||||
), "Expected Pillow to convert to grayscale for histogram"
|
||||
|
||||
# All entries other than first and last will be 0
|
||||
count_same = histogram[0]
|
||||
count_different = histogram[-1]
|
||||
total = count_same + count_different
|
||||
|
||||
return count_same / (total)
|
||||
# count_same = histogram[0]
|
||||
# count_different = histogram[-1]
|
||||
# total = count_same + count_different
|
||||
# print(f"{count_same / (total)}")
|
||||
# return count_same / (total)
|
||||
return histogram[-1] / (histogram_total[-1] + 1)
|
||||
|
||||
|
||||
def test_monochrome_comparison(resources, outdir):
|
||||
@@ -211,7 +218,7 @@ def test_rotate_deskew_ocr_timeout(resources, outdir):
|
||||
assert cmp > 0.95
|
||||
|
||||
|
||||
def make_rotate_test(imagefile, outdir, prefix, image_angle, page_angle):
|
||||
def make_rotate_test(imagefile, outdir, prefix, image_angle, page_angle, cropbox=None):
|
||||
memimg = BytesIO()
|
||||
with Image.open(fspath(imagefile)) as im:
|
||||
if image_angle != 0:
|
||||
@@ -230,6 +237,8 @@ def make_rotate_test(imagefile, outdir, prefix, image_angle, page_angle):
|
||||
with pikepdf.open(mempdf) as pdf:
|
||||
pdf.pages[0].Rotate = page_angle
|
||||
target = outdir / f'{prefix}_{image_angle}_{page_angle}.pdf'
|
||||
if cropbox:
|
||||
pdf.pages[0].CropBox = cropbox
|
||||
pdf.save(target)
|
||||
return target
|
||||
|
||||
@@ -284,6 +293,44 @@ def test_page_rotate_tag(page_rotate_angle, resources, outdir, caplog):
|
||||
assert 'is a' in test_text, test_text
|
||||
|
||||
|
||||
@pytest.mark.parametrize('page_rotate_angle', (0, 90, 180, 270))
|
||||
@pytest.mark.parametrize('renderer', ['sandwich', 'hocr'])
|
||||
@pytest.mark.parametrize('output_type', ['pdf', 'pdfa'])
|
||||
def test_rotate_and_crop(
|
||||
resources, outdir, page_rotate_angle, renderer, output_type, caplog
|
||||
):
|
||||
cropbox = (100, 200, 1000, 800)
|
||||
reference = make_rotate_test(
|
||||
resources / 'typewriter.png', outdir, 'ref', 0, 0, cropbox
|
||||
)
|
||||
test = make_rotate_test(
|
||||
resources / 'typewriter.png',
|
||||
outdir,
|
||||
'test',
|
||||
-page_rotate_angle,
|
||||
page_rotate_angle,
|
||||
cropbox,
|
||||
)
|
||||
out = test.with_suffix('.out.pdf')
|
||||
|
||||
exitcode = run_ocrmypdf_api(
|
||||
test,
|
||||
out,
|
||||
'-O0',
|
||||
'--rotate-pages',
|
||||
'--rotate-pages-threshold',
|
||||
'0',
|
||||
'--pdf-renderer',
|
||||
renderer,
|
||||
'--output-type',
|
||||
output_type,
|
||||
'--no-progress-bar',
|
||||
)
|
||||
assert exitcode == 0, caplog.text
|
||||
|
||||
assert compare_images_monochrome(outdir, reference, 1, out, 1) > 0.9
|
||||
|
||||
|
||||
def test_rasterize_rotates(resources, tmp_path):
|
||||
pm = get_plugin_manager([])
|
||||
|
||||
|
||||
Reference in New Issue
Block a user