"Fossies" - the Fresh Open Source Software Archive

Member "OCRmyPDF-8.3.0/tests/test_rotation.py" (13 May 2019, 8235 Bytes) of package /linux/privat/OCRmyPDF-8.3.0.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) Python source code syntax highlighting (style: standard) with prefixed line numbers. Alternatively you can here view or download the uninterpreted source code file. See also the last Fossies "Diffs" side-by-side code changes report for "test_rotation.py": 7.4.0_vs_8.0.0.

    1 # © 2018 James R. Barlow: github.com/jbarlow83
    2 #
    3 # This file is part of OCRmyPDF.
    4 #
    5 # OCRmyPDF is free software: you can redistribute it and/or modify
    6 # it under the terms of the GNU General Public License as published by
    7 # the Free Software Foundation, either version 3 of the License, or
    8 # (at your option) any later version.
    9 #
   10 # OCRmyPDF is distributed in the hope that it will be useful,
   11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
   12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   13 # GNU General Public License for more details.
   14 #
   15 # You should have received a copy of the GNU General Public License
   16 # along with OCRmyPDF.  If not, see <http://www.gnu.org/licenses/>.
   17 
   18 import logging
   19 from io import BytesIO
   20 from os import fspath
   21 from unittest.mock import Mock
   22 
   23 import img2pdf
   24 import pytest
   25 from PIL import Image
   26 
   27 import pikepdf
   28 from ocrmypdf import leptonica
   29 from ocrmypdf.exec import ghostscript, tesseract
   30 from ocrmypdf.pdfinfo import PdfInfo
   31 
   32 # pytest.helpers is dynamic
   33 # pylint: disable=no-member
   34 # pylint: disable=w0612
   35 
   36 pytestmark = pytest.mark.skipif(
   37     leptonica.get_leptonica_version() < 'leptonica-1.72',
   38     reason="Leptonica is too old, correlation doesn't work",
   39 )
   40 
   41 check_ocrmypdf = pytest.helpers.check_ocrmypdf
   42 run_ocrmypdf = pytest.helpers.run_ocrmypdf
   43 
   44 
   45 RENDERERS = ['hocr', 'sandwich']
   46 
   47 
   48 def check_monochrome_correlation(
   49     outdir, reference_pdf, reference_pageno, test_pdf, test_pageno
   50 ):
   51     gslog = logging.getLogger()
   52 
   53     reference_png = outdir / f'{reference_pdf.name}.ref{reference_pageno:04d}.png'
   54     test_png = outdir / f'{test_pdf.name}.test{test_pageno:04d}.png'
   55 
   56     def rasterize(pdf, pageno, png):
   57         if png.exists():
   58             print(png)
   59             return
   60         ghostscript.rasterize_pdf(
   61             pdf,
   62             png,
   63             xres=100,
   64             yres=100,
   65             raster_device='pngmono',
   66             log=gslog,
   67             pageno=pageno,
   68             rotation=0,
   69         )
   70 
   71     rasterize(reference_pdf, reference_pageno, reference_png)
   72     rasterize(test_pdf, test_pageno, test_png)
   73 
   74     pix_ref = leptonica.Pix.open(reference_png)
   75     pix_test = leptonica.Pix.open(test_png)
   76 
   77     return leptonica.Pix.correlation_binary(pix_ref, pix_test)
   78 
   79 
   80 def test_monochrome_correlation(resources, outdir):
   81     # Verify leptonica: check that an incorrect rotated image has poor
   82     # correlation with reference
   83     corr = check_monochrome_correlation(
   84         outdir,
   85         reference_pdf=resources / 'cardinal.pdf',
   86         reference_pageno=1,  # north facing page
   87         test_pdf=resources / 'cardinal.pdf',
   88         test_pageno=3,  # south facing page
   89     )
   90     assert corr < 0.10
   91     corr = check_monochrome_correlation(
   92         outdir,
   93         reference_pdf=resources / 'cardinal.pdf',
   94         reference_pageno=2,
   95         test_pdf=resources / 'cardinal.pdf',
   96         test_pageno=2,
   97     )
   98     assert corr > 0.90
   99 
  100 
  101 @pytest.mark.slow
  102 @pytest.mark.parametrize('renderer', RENDERERS)
  103 def test_autorotate(spoof_tesseract_cache, renderer, resources, outdir):
  104     # cardinal.pdf contains four copies of an image rotated in each cardinal
  105     # direction - these ones are "burned in" not tagged with /Rotate
  106     out = check_ocrmypdf(
  107         resources / 'cardinal.pdf',
  108         outdir / 'out.pdf',
  109         '-r',
  110         '-v',
  111         '1',
  112         '--pdf-renderer',
  113         renderer,
  114         env=spoof_tesseract_cache,
  115     )
  116     for n in range(1, 4 + 1):
  117         correlation = check_monochrome_correlation(
  118             outdir,
  119             reference_pdf=resources / 'cardinal.pdf',
  120             reference_pageno=1,
  121             test_pdf=outdir / 'out.pdf',
  122             test_pageno=n,
  123         )
  124         assert correlation > 0.80
  125 
  126 
  127 @pytest.mark.parametrize(
  128     'threshold, correlation_test',
  129     [
  130         ('1', 'correlation > 0.80'),  # Low thresh -> always rotate -> high corr
  131         ('99', 'correlation < 0.10'),  # High thres -> never rotate -> low corr
  132     ],
  133 )
  134 def test_autorotate_threshold(
  135     spoof_tesseract_cache, threshold, correlation_test, resources, outdir
  136 ):
  137     out = check_ocrmypdf(
  138         resources / 'cardinal.pdf',
  139         outdir / 'out.pdf',
  140         '--rotate-pages-threshold',
  141         threshold,
  142         '-r',
  143         '-v',
  144         '1',
  145         env=spoof_tesseract_cache,
  146     )
  147 
  148     correlation = check_monochrome_correlation(
  149         outdir,
  150         reference_pdf=resources / 'cardinal.pdf',
  151         reference_pageno=1,
  152         test_pdf=outdir / 'out.pdf',
  153         test_pageno=3,
  154     )
  155     assert eval(correlation_test)  # pylint: disable=w0123
  156 
  157 
  158 def test_rotated_skew_timeout(resources, outpdf):
  159     """This document contains an image that is rotated 90 into place with a
  160     /Rotate tag and intentionally skewed by altering the transformation matrix.
  161 
  162     This tests for a bug where the combination of preprocessing and a tesseract
  163     timeout produced a page whose dimensions did not match the original's.
  164     """
  165 
  166     input_file = resources / 'rotated_skew.pdf'
  167     in_pageinfo = PdfInfo(input_file)[0]
  168 
  169     assert (
  170         in_pageinfo.height_pixels < in_pageinfo.width_pixels
  171     ), "Expected the input page to be landscape"
  172     assert in_pageinfo.rotation == 90, "Expected a rotated page"
  173 
  174     out = check_ocrmypdf(
  175         input_file,
  176         outpdf,
  177         '--pdf-renderer',
  178         'hocr',
  179         '--deskew',
  180         '--tesseract-timeout',
  181         '0',
  182     )
  183 
  184     out_pageinfo = PdfInfo(out)[0]
  185     w, h = out_pageinfo.width_pixels, out_pageinfo.height_pixels
  186 
  187     assert h > w, "Expected the output page to be portrait"
  188 
  189     assert out_pageinfo.rotation == 0, "Expected no page rotation for output"
  190 
  191     assert (
  192         in_pageinfo.width_pixels == h and in_pageinfo.height_pixels == w
  193     ), "Expected page rotation to be baked in"
  194 
  195 
  196 def test_rotate_deskew_timeout(resources, outdir):
  197     check_ocrmypdf(
  198         resources / 'rotated_skew.pdf',
  199         outdir / 'deskewed.pdf',
  200         '--rotate-pages',
  201         '--rotate-pages-threshold',
  202         '0',
  203         '--deskew',
  204         '--tesseract-timeout',
  205         '0',
  206         '--pdf-renderer',
  207         'sandwich',
  208     )
  209 
  210     correlation = check_monochrome_correlation(
  211         outdir,
  212         reference_pdf=resources / 'ccitt.pdf',
  213         reference_pageno=1,
  214         test_pdf=outdir / 'deskewed.pdf',
  215         test_pageno=1,
  216     )
  217 
  218     # Confirm that the page still got deskewed
  219     assert correlation > 0.50
  220 
  221 
  222 @pytest.mark.slow
  223 @pytest.mark.parametrize('page_angle', (0, 90, 180, 270))
  224 @pytest.mark.parametrize('image_angle', (0, 90, 180, 270))
  225 def test_rotate_page_level(image_angle, page_angle, resources, outdir):
  226     def make_rotate_test(prefix, image_angle, page_angle):
  227         im = Image.open(fspath(resources / 'typewriter.png'))
  228         if image_angle != 0:
  229             ccw_angle = -image_angle % 360
  230             im = im.transpose(getattr(Image, f'ROTATE_{ccw_angle}'))
  231         memimg = BytesIO()
  232         im.save(memimg, format='PNG')
  233         memimg.seek(0)
  234         mempdf = BytesIO()
  235         img2pdf.convert(
  236             memimg.read(),
  237             layout_fun=img2pdf.get_fixed_dpi_layout_fun((200, 200)),
  238             outputstream=mempdf,
  239         )
  240         mempdf.seek(0)
  241         pike = pikepdf.open(mempdf)
  242         pike.pages[0].Rotate = page_angle
  243         target = outdir / f'{prefix}_{image_angle}_{page_angle}.pdf'
  244         pike.save(target)
  245         return target
  246 
  247     reference = make_rotate_test('ref', 0, 0)
  248     test = make_rotate_test('test', image_angle, page_angle)
  249     out = test.with_suffix('.out.pdf')
  250 
  251     p, _, err = run_ocrmypdf(
  252         test,
  253         out,
  254         '-O0',
  255         '--rotate-pages',
  256         '--rotate-pages-threshold',
  257         '0.001',
  258         universal_newlines=False,
  259     )
  260     err = err.decode('utf-8', errors='replace')
  261     assert p.returncode == 0, err
  262 
  263     assert check_monochrome_correlation(outdir, reference, 1, out, 1) > 0.2
  264 
  265 
  266 def test_tesseract_orientation(resources, tmpdir):
  267     pix = leptonica.Pix.open(resources / 'crom.png')
  268     pix_rotated = pix.rotate_orth(2)  # 180 degrees clockwise
  269     pix_rotated.write_implied_format(tmpdir / '000001.png')
  270 
  271     log = Mock()
  272     tesseract.get_orientation(  # Test results of this are unreliable
  273         tmpdir / '000001.png', engine_mode='3', timeout=10, log=log
  274     )