Fix all issues with rotations
All tests now pass
This commit is contained in:
@@ -49,7 +49,7 @@ def _gs_error_reported(stream):
|
||||
|
||||
|
||||
def rasterize_pdf(input_file, output_file, xres, yres, raster_device, log,
|
||||
pageno=1, page_dpi=None):
|
||||
pageno=1, page_dpi=None, rotation=None):
|
||||
"""
|
||||
Rasterize one page of a PDF at resolution (xres, yres) in canvas units.
|
||||
|
||||
@@ -71,6 +71,9 @@ def rasterize_pdf(input_file, output_file, xres, yres, raster_device, log,
|
||||
int_res = round(xres), round(yres)
|
||||
if not page_dpi:
|
||||
page_dpi = res
|
||||
|
||||
autorotate = '/PageByPage' if rotation is None else '/None'
|
||||
|
||||
with NamedTemporaryFile(delete=True) as tmp:
|
||||
args_gs = [
|
||||
'gs',
|
||||
@@ -83,9 +86,12 @@ def rasterize_pdf(input_file, output_file, xres, yres, raster_device, log,
|
||||
'-dLastPage=%i' % pageno,
|
||||
'-r{0}x{1}'.format(str(int_res[0]), str(int_res[1])),
|
||||
'-o', tmp.name,
|
||||
'-dAutoRotatePages=%s' % autorotate,
|
||||
'-f',
|
||||
fspath(input_file)
|
||||
]
|
||||
|
||||
log.debug(args_gs)
|
||||
p = run(args_gs, stdout=PIPE, stderr=STDOUT,
|
||||
universal_newlines=True)
|
||||
if _gs_error_reported(p.stdout):
|
||||
@@ -110,10 +116,21 @@ def rasterize_pdf(input_file, output_file, xres, yres, raster_device, log,
|
||||
log.debug(
|
||||
"Ghostscript: resize output image {} -> {}".format(
|
||||
im.size, expected_size))
|
||||
im.resize(expected_size).save(
|
||||
fspath(output_file), dpi=page_dpi)
|
||||
else:
|
||||
copy(tmp.name, fspath(output_file))
|
||||
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
|
||||
# counterclockwise so this cancels out the rotation
|
||||
# if rotation == 90:
|
||||
# im = im.transpose(Image.ROTATE_90)
|
||||
# elif rotation == 180:
|
||||
# im = im.transpose(Image.ROTATE_180)
|
||||
# elif rotation == 270:
|
||||
# im = im.transpose(Image.ROTATE_270)
|
||||
# if rotation % 180 == 90:
|
||||
# page_dpi = page_dpi[1], page_dpi[0]
|
||||
im.save(fspath(output_file), dpi=page_dpi)
|
||||
|
||||
|
||||
def generate_pdfa(pdf_pages, output_file, compression, log,
|
||||
|
||||
+28
-11
@@ -66,6 +66,7 @@ class JobContext:
|
||||
self.pdfinfo = None
|
||||
self.options = None
|
||||
self.work_folder = None
|
||||
self.rotations = {}
|
||||
|
||||
def generate_pdfinfo(self, infile):
|
||||
self.pdfinfo = PdfInfo(infile)
|
||||
@@ -89,6 +90,12 @@ class JobContext:
|
||||
def set_work_folder(self, work_folder):
|
||||
self.work_folder = work_folder
|
||||
|
||||
def get_rotation(self, pageno):
|
||||
return self.rotations.get(pageno, 0)
|
||||
|
||||
def set_rotation(self, pageno, value):
|
||||
self.rotations[pageno] = value
|
||||
|
||||
|
||||
from multiprocessing.managers import SyncManager
|
||||
class JobContextManager(SyncManager):
|
||||
@@ -418,7 +425,7 @@ def rasterize_preview(
|
||||
ghostscript.rasterize_pdf(
|
||||
input_file, output_file, xres=canvas_dpi, yres=canvas_dpi,
|
||||
raster_device='jpeggray', log=log, page_dpi=(page_dpi, page_dpi),
|
||||
pageno=page_number(input_file))
|
||||
pageno=page_number(input_file), rotation=pageinfo.rotation)
|
||||
|
||||
|
||||
def orient_page(
|
||||
@@ -475,8 +482,8 @@ def orient_page(
|
||||
if apply_correction:
|
||||
pageno = page_number(page_pdf) - 1
|
||||
pdfinfo = context.get_pdfinfo()
|
||||
pdfinfo[pageno].rotation = orient_conf.angle
|
||||
context.set_pdfinfo(pdfinfo) # This is expensive for large files
|
||||
correction = (pdfinfo[pageno].rotation - orient_conf.angle) % 360
|
||||
context.set_rotation(pageno, correction)
|
||||
|
||||
|
||||
def rasterize_with_ghostscript(
|
||||
@@ -507,10 +514,12 @@ def rasterize_with_ghostscript(
|
||||
canvas_dpi = get_canvas_square_dpi(pageinfo, options)
|
||||
page_dpi = get_page_square_dpi(pageinfo, options)
|
||||
|
||||
correction = context.get_rotation(page_number(input_file))
|
||||
|
||||
ghostscript.rasterize_pdf(
|
||||
input_file, output_file, xres=canvas_dpi, yres=canvas_dpi,
|
||||
raster_device=device, log=log, page_dpi=(page_dpi, page_dpi),
|
||||
pageno=page_number(input_file))
|
||||
pageno=page_number(input_file), rotation=correction)
|
||||
|
||||
|
||||
def preprocess_remove_background(
|
||||
@@ -720,7 +729,7 @@ def render_hocr_debug_page(
|
||||
interwordSpaces=True)
|
||||
|
||||
|
||||
def _weave_layers_graft(pdf_base, page_num, text, font, font_key, log):
|
||||
def _weave_layers_graft(pdf_base, page_num, text, font, font_key, rotation, log):
|
||||
from math import cos, sin, pi
|
||||
|
||||
log.info("Graft")
|
||||
@@ -732,8 +741,6 @@ def _weave_layers_graft(pdf_base, page_num, text, font, font_key, log):
|
||||
pdf_text_contents = pdf_text.pages[0].Contents.read_bytes()
|
||||
|
||||
base_page = pdf_base.pages.p(page_num)
|
||||
rotation = int(base_page.get('/Rotate', 0))
|
||||
rotation = rotation % 360
|
||||
|
||||
# The text page always will be oriented up by this stage but the original
|
||||
# content may have a rotation applied. Wrap the text stream with a rotation
|
||||
@@ -878,15 +885,25 @@ def weave_layers(
|
||||
keep_open.append(pdf_image)
|
||||
image_page = pdf_image.pages[0]
|
||||
pdf_base.pages[page_num - 1] = image_page
|
||||
#pdfinfo[page_num - 1].rotation = 0
|
||||
|
||||
log.info("Content rotation " + str(pdfinfo[page_num - 1].rotation))
|
||||
|
||||
text_content_rotation = 0 #pdfinfo[page_num - 1].rotation
|
||||
log.info("Text content rotation ±" + str(text_content_rotation))
|
||||
|
||||
ctx_rotation = context.get_rotation(page_num - 1)
|
||||
log.info("Saved correction ±" + str(ctx_rotation))
|
||||
|
||||
if text and font:
|
||||
# Graft the text layer onto this page, whether new or old
|
||||
_weave_layers_graft(
|
||||
pdf_base, page_num, text, font, font_key, log)
|
||||
pdf_base, page_num, text, font, font_key, text_content_rotation,
|
||||
log
|
||||
)
|
||||
|
||||
# Correct the rotation
|
||||
rotation = pdfinfo[page_num - 1].rotation
|
||||
rotation = -rotation % 360
|
||||
# Correct the rotation if applicable
|
||||
rotation = context.get_rotation(page_num - 1)
|
||||
if rotation != 0:
|
||||
pdf_base.pages[page_num - 1].Rotate = rotation
|
||||
|
||||
|
||||
+4
-6
@@ -639,15 +639,16 @@ def test_rotated_skew_timeout(resources, outpdf):
|
||||
'--deskew', '--tesseract-timeout', '0')
|
||||
|
||||
out_pageinfo = PdfInfo(out)[0]
|
||||
w, h = out_pageinfo.width_pixels, out_pageinfo.height_pixels
|
||||
|
||||
assert out_pageinfo.height_pixels > out_pageinfo.width_pixels, \
|
||||
assert h > w, \
|
||||
"Expected the output page to be portrait"
|
||||
|
||||
assert out_pageinfo.rotation == 0, \
|
||||
"Expected no page rotation for output"
|
||||
|
||||
assert in_pageinfo.width_pixels == out_pageinfo.height_pixels and \
|
||||
in_pageinfo.height_pixels == out_pageinfo.width_pixels, \
|
||||
assert in_pageinfo.width_pixels == h and \
|
||||
in_pageinfo.height_pixels == w, \
|
||||
"Expected page rotation to be baked in"
|
||||
|
||||
|
||||
@@ -986,9 +987,6 @@ def test_bad_utf8(spoof_tess_bad_utf8, renderer, resources, no_outpdf):
|
||||
assert '\\x96' in err, 'should repeat backslash encoded output'
|
||||
|
||||
|
||||
@pytest.mark.skipif(
|
||||
not tesseract.has_textonly_pdf(),
|
||||
reason="issue only affects sandwich")
|
||||
def test_rotate_deskew_timeout(resources, outdir):
|
||||
check_ocrmypdf(
|
||||
resources / 'rotated_skew.pdf',
|
||||
|
||||
Reference in New Issue
Block a user