Remove last vestiges of command line usage of qpdf - change to check_pdf

This commit is contained in:
James R. Barlow
2020-04-26 05:33:26 -07:00
parent 168fc60774
commit 8f5c95f0f4
13 changed files with 63 additions and 95 deletions
+2 -1
View File
@@ -148,7 +148,8 @@ In addition to tesseract, OCRmyPDF uses the following external binaries:
- ``gs`` (Ghostscript)
- ``unpaper``
- ``qpdf``
- ``pngquant``
- ``jbig2``
In each case OCRmyPDF will search the ``PATH`` environment variable to
locate the binaries.
+4 -4
View File
@@ -32,10 +32,10 @@ As the error message suggests, your options are:
Input file 'filename' is not a valid PDF
========================================
OCRmyPDF passes files through qpdf, a program that fixes errors in PDFs,
before it tries to work on them. In most cases this happens because the
PDF is corrupt and truncated (incomplete file copying) and not much can
be done.
OCRmyPDF checks files with pikepdf, a library that in turn uses libqpdf to fixes
errors in PDFs, before it tries to work on them. In most cases this happens
because the PDF is corrupt and truncated (incomplete file copying) and not much
can be done.
You can try rewriting the file with Ghostscript:
+1
View File
@@ -30,6 +30,7 @@ v10.0.0 (not yet released)
``ocrmypdf.helpers.Resolution`` class.
- A deprecated parameter in ``ocrmypdf.exec.ghostscript.generate_pdfa`` was
removed.
- The deprecated module ``ocrmypdf.exec.qpdf`` was removed.
- The ``ocrmypdf.hocrtransform`` module has been updated to follow PEP8 naming
conventions.
+4 -5
View File
@@ -68,7 +68,7 @@ license, OCRmyPDF's GPL license, and any other licenses.
Setting aside these concerns, a side effect of OCRmyPDF is it may
incidentally sanitize PDFs that contain certain types of malware. It
runs ``qpdf`` to repair the PDF, which could correct malformed PDF
repairs the PDF with pikepdf/libqpdf, which could correct malformed PDF
structures that are part of an attack. When PDF/A output is selected
(the default), the input PDF is partially reconstructed by Ghostscript.
When ``--force-ocr`` is used, all pages are rasterized and reconverted
@@ -144,10 +144,9 @@ set, the document cannot be viewed without the password.
Either way, OCRmyPDF does not remove passwords from PDFs and exits with
an error on encountering them.
``qpdf``, one of OCRmyPDF's dependencies, can remove passwords. If the
owner and user password are set, a password is required for ``qpdf``. If
only the owner password is set, then the password can be stripped, even
if one does not have the owner password.
``qpdf`` can remove passwords. If the owner and user password are set, a
password is required for ``qpdf``. If only the owner password is set, then the
password can be stripped, even if one does not have the owner password.
After OCR is applied, password protection is not permitted on PDF/A
documents but the file can be converted to regular PDF.
+2 -3
View File
@@ -64,8 +64,7 @@ from ._validation import (
report_output_file_size,
)
from .exceptions import ExitCode, ExitCodeException
from .exec import qpdf
from .helpers import available_cpu_count
from .helpers import available_cpu_count, check_pdf
from .pdfa import file_claims_pdfa
log = logging.getLogger(__name__)
@@ -357,7 +356,7 @@ def run_pipeline(options, api=False):
pdfa_info['conformance'],
)
return ExitCode.pdfa_conversion_failed
if not qpdf.check(options.output_file):
if not check_pdf(options.output_file):
log.warning('Output file: The generated PDF is INVALID')
return ExitCode.invalid_output_pdf
report_output_file_size(options, start_input_file, options.output_file)
-7
View File
@@ -38,7 +38,6 @@ from .exec import (
ghostscript,
jbig2enc,
pngquant,
qpdf,
tesseract,
unpaper,
)
@@ -473,9 +472,3 @@ def check_dependency_versions(options):
"supported. Please upgrade to a newer version, or downgrade to the "
"previous version."
)
check_external_program(
program='qpdf',
package='qpdf',
version_checker=qpdf.version,
need_version='8.0.2',
)
-63
View File
@@ -1,63 +0,0 @@
# © 2017 James R. Barlow: github.com/jbarlow83
#
# This file is part of OCRmyPDF.
#
# OCRmyPDF is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# OCRmyPDF is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with OCRmyPDF. If not, see <http://www.gnu.org/licenses/>.
"""Interface to qpdf executable"""
import logging
from io import StringIO
import pikepdf
log = logging.getLogger(__name__)
def version():
return pikepdf.__libqpdf_version__
def check(input_file):
pdf = None
try:
pdf = pikepdf.open(input_file)
except pikepdf.PdfError as e:
log.error(e)
return False
else:
messages = pdf.check()
for msg in messages:
if 'error' in msg.lower():
log.error(msg)
else:
log.warning(msg)
sio = StringIO()
linearize = None
try:
pdf.check_linearization(sio)
except RuntimeError:
pass
else:
linearize = sio.getvalue()
if linearize:
log.warning(linearize)
if not messages and not linearize:
return True
return False
finally:
if pdf:
pdf.close()
+37
View File
@@ -24,9 +24,12 @@ from collections import namedtuple
from collections.abc import Iterable
from contextlib import suppress
from functools import wraps
from io import StringIO
from math import inf, isclose
from pathlib import Path
import pikepdf
log = logging.getLogger(__name__)
@@ -165,6 +168,40 @@ def is_file_writable(test_file: os.PathLike):
return False
def check_pdf(input_file):
pdf = None
try:
pdf = pikepdf.open(input_file)
except pikepdf.PdfError as e:
log.error(e)
return False
else:
messages = pdf.check()
for msg in messages:
if 'error' in msg.lower():
log.error(msg)
else:
log.warning(msg)
sio = StringIO()
linearize = None
try:
pdf.check_linearization(sio)
except RuntimeError:
pass
else:
linearize = sio.getvalue()
if linearize:
log.warning(linearize)
if not messages and not linearize:
return True
return False
finally:
if pdf:
pdf.close()
def deprecated(func):
"""Warn that function is deprecated"""
@@ -17,9 +17,9 @@
import pytest
import ocrmypdf.exec.qpdf as qpdf
from ocrmypdf.helpers import check_pdf
def test_qpdf_error(resources):
assert qpdf.check(resources / 'blank.pdf')
assert not qpdf.check(__file__)
def test_pdf_error(resources):
assert check_pdf(resources / 'blank.pdf')
assert not check_pdf(__file__)
+2 -2
View File
@@ -21,8 +21,8 @@ import pytest
from PIL import Image
from ocrmypdf import hocrtransform
from ocrmypdf.exec import qpdf
from ocrmypdf.exec.tesseract import HOCR_TEMPLATE
from ocrmypdf.helpers import check_pdf
# pylint: disable=redefined-outer-name
@@ -43,4 +43,4 @@ def test_mono_image(blank_hocr, outdir):
hocr = hocrtransform.HocrTransform(str(blank_hocr), 300)
hocr.to_pdf(str(outdir / 'mono.pdf'), image_filename=str(outdir / 'mono.tif'))
qpdf.check(str(outdir / 'mono.pdf'))
check_pdf(str(outdir / 'mono.pdf'))
+4 -3
View File
@@ -29,7 +29,8 @@ from PIL import Image
import ocrmypdf
from ocrmypdf.exceptions import ExitCode, MissingDependencyError
from ocrmypdf.exec import ghostscript, qpdf, tesseract
from ocrmypdf.exec import ghostscript, tesseract
from ocrmypdf.helpers import check_pdf
from ocrmypdf.pdfa import file_claims_pdfa
from ocrmypdf.pdfinfo import Colorspace, Encoding, PdfInfo
@@ -529,8 +530,8 @@ def test_skip_big_with_no_images(spoof_tesseract_noop, resources, outpdf):
@pytest.mark.skipif(
'8.0.0' <= qpdf.version() <= '8.0.1',
reason="qpdf regression on pages with no contents",
'8.0.0' <= pikepdf.__libqpdf_version__ <= '8.0.1',
reason="libqpdf regression on pages with no contents",
)
def test_no_contents(spoof_tesseract_noop, resources, outpdf):
check_ocrmypdf(
+2 -2
View File
@@ -23,7 +23,7 @@ from subprocess import DEVNULL, PIPE, CalledProcessError, Popen, run
import pytest
from ocrmypdf.exceptions import ExitCode
from ocrmypdf.exec import qpdf
from ocrmypdf.helpers import check_pdf
# pytest.helpers is dynamic
# pylint: disable=no-member,redefined-outer-name
@@ -74,7 +74,7 @@ def test_stdout(spoof_tesseract_noop, ocrmypdf_exec, resources, outpdf):
)
assert p.returncode == ExitCode.ok
assert qpdf.check(output_file)
assert check_pdf(output_file)
@pytest.mark.skipif(
+1 -1
View File
@@ -39,7 +39,7 @@ def test_userunit_ghostscript_fails(poster, no_outpdf, caplog):
assert 'not supported by Ghostscript' in caplog.text
def test_userunit_qpdf_passes(spoof_tesseract_cache, poster, outpdf):
def test_userunit_pdf_passes(spoof_tesseract_cache, poster, outpdf):
before = PdfInfo(poster)
check_ocrmypdf(poster, outpdf, '--output-type=pdf', env=spoof_tesseract_cache)