From 0b3a526049f10032a29939a82dcd5113cd895935 Mon Sep 17 00:00:00 2001 From: "James R. Barlow" Date: Fri, 1 Jan 2021 01:11:32 -0800 Subject: [PATCH] Partial fix crash on 'userunit' None (#700) Our method of getting data from pdfminer would silently consume a StopIteration if pdfminer returned no processed pages, leading to odd error message. We improve an error from pdfminer properly, and returning a more descriptive error of our own. It would be possible for ocrmypdf to repair the file before sending it to pdfminer, but this seems to be rare enough that we won't do that yet. --- src/ocrmypdf/pdfinfo/info.py | 4 +++- src/ocrmypdf/pdfinfo/layout.py | 11 ++++++++--- tests/test_pdfinfo.py | 19 +++++++++++++++++++ 3 files changed, 30 insertions(+), 4 deletions(-) diff --git a/src/ocrmypdf/pdfinfo/info.py b/src/ocrmypdf/pdfinfo/info.py index dc80fd12..ae02fb98 100644 --- a/src/ocrmypdf/pdfinfo/info.py +++ b/src/ocrmypdf/pdfinfo/info.py @@ -22,7 +22,7 @@ import pikepdf from pikepdf import Object, Pdf, PdfMatrix from ocrmypdf._concurrent import exec_progress_pool -from ocrmypdf.exceptions import EncryptedPdfError +from ocrmypdf.exceptions import EncryptedPdfError, InputFileError from ocrmypdf.helpers import Resolution, available_cpu_count, pikepdf_enable_mmap from ocrmypdf.pdfinfo.layout import get_page_analysis, get_text_boxes @@ -598,6 +598,8 @@ def _pdf_pageinfo_concurrent( def update_pageinfo(result, pbar): page = result + if not page: + raise InputFileError("Could read a page in the PDF") pages[page.pageno] = page pbar.update() diff --git a/src/ocrmypdf/pdfinfo/layout.py b/src/ocrmypdf/pdfinfo/layout.py index 36b15d5d..4159a1cb 100644 --- a/src/ocrmypdf/pdfinfo/layout.py +++ b/src/ocrmypdf/pdfinfo/layout.py @@ -21,7 +21,7 @@ from pdfminer.pdffont import PDFSimpleFont, PDFUnicodeNotDefined from pdfminer.pdfpage import PDFPage from pdfminer.utils import bbox2str, matrix2str -from ocrmypdf.exceptions import EncryptedPdfError +from ocrmypdf.exceptions import EncryptedPdfError, InputFileError STRIP_NAME = re.compile(r'[0-9]+') @@ -236,8 +236,13 @@ def get_page_analysis(infile, pageno, pscript5_mode): try: with Path(infile).open('rb') as f: - page = PDFPage.get_pages(f, pagenos=[pageno], maxpages=0) - interp.process_page(next(page)) + page_iter = PDFPage.get_pages(f, pagenos=[pageno], maxpages=0) + page = next(page_iter, None) + if page is None: + raise InputFileError( + f"pdfminer could not process page {pageno} (counting from 0)." + ) + interp.process_page(page) except PDFTextExtractionNotAllowed as e: raise EncryptedPdfError() from e finally: diff --git a/tests/test_pdfinfo.py b/tests/test_pdfinfo.py index 16ec12fd..4e6e53ce 100644 --- a/tests/test_pdfinfo.py +++ b/tests/test_pdfinfo.py @@ -15,7 +15,11 @@ from PIL import Image from reportlab.pdfgen.canvas import Canvas from ocrmypdf import pdfinfo +from ocrmypdf.exceptions import InputFileError from ocrmypdf.pdfinfo import Colorspace, Encoding +from ocrmypdf.pdfinfo.layout import PDFPage + +run_ocrmypdf_api = pytest.helpers.run_ocrmypdf_api # pylint: disable=protected-access @@ -179,3 +183,18 @@ def test_stack_abuse(): with pytest.warns(None): with pytest.raises(RuntimeError): pdfinfo.info._interpret_contents(stream) + + +def test_pages_issue700(monkeypatch, resources): + def get_no_pages(*args, **kwargs): + return iter([]) + + monkeypatch.setattr(PDFPage, 'get_pages', get_no_pages) + + with pytest.raises(InputFileError, match="pdfminer"): + pdfinfo.PdfInfo( + resources / 'cardinal.pdf', + detailed_analysis=True, + progbar=False, + max_workers=1, + )