diff --git a/src/ocrmypdf/__main__.py b/src/ocrmypdf/__main__.py index b051d90d..cd8889ae 100755 --- a/src/ocrmypdf/__main__.py +++ b/src/ocrmypdf/__main__.py @@ -357,14 +357,6 @@ advanced.add_argument( advanced.add_argument( '--user-patterns', metavar='FILE', help="Specify the location of the Tesseract user patterns file.") -advanced.add_argument( - '--skip-repair', action='store_true', - help="Normally OCRmyPDF automatically repairs PDFs using qpdf before " - "processing. If you have already run qpdf or a similar program " - "that repairs PDF errors, you can tell OCRmyPDF to skip repair with " - "this option. This may be helpful in batch processing where all " - "files are repaired prior to OCR occurs, since repair is single " - "threaded and time consuming for large files.") debugging = parser.add_argument_group( "Debugging", diff --git a/src/ocrmypdf/exec/qpdf.py b/src/ocrmypdf/exec/qpdf.py index fd6a5ae6..33bef631 100644 --- a/src/ocrmypdf/exec/qpdf.py +++ b/src/ocrmypdf/exec/qpdf.py @@ -54,45 +54,3 @@ def check(input_file, log=None): log.warning(e.output) return False return True - - -def _probably_encrypted(e): - """qpdf can report a false positive "file is encrypted" message for damaged - files - suppress this""" - return e.returncode == 2 and \ - 'invalid password' in e.output and \ - 'file is damaged' not in e.output - - -def repair(input_file, output_file, log): - args_qpdf = [ - 'qpdf', input_file, output_file - ] - try: - run(args_qpdf, stderr=STDOUT, stdout=PIPE, universal_newlines=True, - check=True) - except CalledProcessError as e: - if e.returncode == 3 and e.output.find("operation succeeded"): - log.debug('qpdf found and fixed errors: %s', e.output) - return - - if _probably_encrypted(e): - raise EncryptedPdfError() from e - elif e.returncode == 2: - log.error("%s: not a valid PDF, and could not repair it.", - input_file) - log.error("Details: %s", e.output) - raise InputFileError() from e - else: - log.error("%s: unknown error", input_file) - log.error(e.output) - raise SubprocessOutputError() from e - - -def extract_page(input_file, output_file, pageno): - args_qpdf = [ - 'qpdf', input_file, - '--pages', input_file, '{0}'.format(pageno + 1), '--', - output_file - ] - run(args_qpdf, check=True) diff --git a/src/ocrmypdf/pipeline.py b/src/ocrmypdf/pipeline.py index e353d800..56062bd5 100644 --- a/src/ocrmypdf/pipeline.py +++ b/src/ocrmypdf/pipeline.py @@ -16,7 +16,7 @@ # along with OCRmyPDF. If not, see . from contextlib import suppress -from shutil import copyfileobj +from shutil import copyfileobj, copyfile from pathlib import Path from datetime import datetime, timezone @@ -36,7 +36,7 @@ from .pdfa import generate_pdfa_ps, encode_pdf_date from .helpers import re_symlink, is_iterable_notstr, page_number, flatten_groups from .exec import ghostscript, tesseract, qpdf from .exceptions import UnsupportedImageFormatError, \ - DpiError, PriorOcrFoundError, InputFileError + DpiError, PriorOcrFoundError, InputFileError, EncryptedPdfError from . import leptonica from . import PROGRAM_NAME, VERSION from .optimize import optimize @@ -154,14 +154,15 @@ def repair_and_parse_pdf( log, context): options = context.get_options() - if not options.skip_repair: - log.debug("Beginning qpdf repair...") - qpdf.repair(input_file, output_file, log) - log.debug("Repair OK; beginning parse...") - else: - re_symlink(input_file, output_file, log) + copyfile(input_file, output_file) - pdfinfo = PdfInfo(output_file) + try: + pdfinfo = PdfInfo(output_file) + except pikepdf.PasswordError as e: + raise EncryptedPdfError() + except pikepdf.PdfError as e: + log.error(e) + raise InputFileError() if pdfinfo.has_userunit and options.output_type.startswith('pdfa'): log.error( diff --git a/tests/spoof/qpdf_dummy_return2.py b/tests/spoof/qpdf_dummy_return2.py deleted file mode 100755 index 528abd7d..00000000 --- a/tests/spoof/qpdf_dummy_return2.py +++ /dev/null @@ -1,36 +0,0 @@ -#!/usr/bin/env python3 -# © 2016 James R. Barlow: github.com/jbarlow83 -# -# Permission is hereby granted, free of charge, to any person obtaining a -# copy of this software and associated documentation files (the -# "Software"), to deal in the Software without restriction, including -# without limitation the rights to use, copy, modify, merge, publish, -# distribute, sublicense, and/or sell copies of the Software, and to -# permit persons to whom the Software is furnished to do so, subject to -# the following conditions: -# -# The above copyright notice and this permission notice shall be included -# in all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - - -import sys - - -def main(): - if sys.argv[-1] == '--version': - print('qpdf version 7.0.0') - sys.exit(0) - print('qpdf dummy') - sys.exit(2) - - -if __name__ == '__main__': - main() diff --git a/tests/test_main.py b/tests/test_main.py index 55a38493..b7e958f1 100644 --- a/tests/test_main.py +++ b/tests/test_main.py @@ -79,11 +79,6 @@ def spoof_tess_bad_utf8(tmpdir_factory): return spoof(tmpdir_factory, tesseract='tesseract_badutf8.py') -@pytest.fixture(scope='session') -def spoof_qpdf_always_error(tmpdir_factory): - return spoof(tmpdir_factory, qpdf='qpdf_dummy_return2.py') - - def test_quick(spoof_tesseract_cache, resources, outpdf): check_ocrmypdf(resources / 'ccitt.pdf', outpdf, env=spoof_tesseract_cache) @@ -330,15 +325,6 @@ def test_input_file_not_a_pdf(no_outpdf): assert (input_file in out or input_file in err) -def test_qpdf_repair_fails(spoof_qpdf_always_error, resources, no_outpdf): - p, out, err = run_ocrmypdf( - resources / 'c02-22.pdf', no_outpdf, - '-v', '1', - env=spoof_qpdf_always_error) - print(err) - assert p.returncode == ExitCode.input_file - - def test_encrypted(resources, no_outpdf): p, out, err = run_ocrmypdf( resources / 'skew-encrypted.pdf', no_outpdf) @@ -933,12 +919,3 @@ def test_output_is_symlink(spoof_tesseract_noop, resources, outdir): ) assert p.returncode == ExitCode.ok, err assert (outdir / 'out.pdf').stat().st_size > 0, 'target file not created' - - -def test_skip_repair(spoof_tesseract_noop, resources, outpdf): - check_ocrmypdf( - resources / 'trivial.pdf', - outpdf, - '--skip-repair', - env=spoof_tesseract_noop - )