Compare commits

...
8 Commits
Author SHA1 Message Date
James R. Barlow a9e1d19b78 v16.1.2 release notes 2024-03-20 12:56:13 -07:00
James R. Barlow f95aa63718 Merge branch 'main' of github.com:ocrmypdf/OCRmyPDF 2024-03-20 12:26:02 -07:00
James Barlow 855de287b2 Fix test suite failure with Ghostscript >= 10.3
Ghostscript is more picky about a specific case with SMask that cannot be converted to PDF/A

Details here
https://github.com/ArtifexSoftware/ghostpdl/commit/4dcfae36bb4dcbc4ef3b5e5afc98bcde0d6b9ddc
2024-03-19 17:20:33 -07:00
NilsRoandGitHub feeb9f213f batch example: added archive, small corrections and optimizations (#1277)
* Added archive, small corrections

Added a function to archive originals and avoid calling ocrmypdf if they are still is PDF/A.

* Added Copyright
2024-03-18 13:22:24 -07:00
Emiel MolenaarandGitHub e7eb8fa805 Update Dockerfile.alpine (#1268)
Use Alpine 3.19 as base image to ensure we get GhostScript 10.2.1 to eliminate serious regressions that corrupt PDFs with existing text.
2024-03-13 14:49:42 -07:00
James R. Barlow 8a747f005a pixels -> megapixels
Fixes #1265
2024-02-29 15:31:07 -08:00
James R. Barlow 16ab4a8b4e Fix error message about missing Python exec
Message is
unable to start container process: exec: "python": executable file not found in $PATH: unknown.

Closes #1260
2024-02-21 23:54:41 -08:00
James R. Barlow 8d30cff4ef Undo future annotations from watcher.py till Typer fixes its issue
Fixes #1258
2024-02-20 19:14:39 -08:00
8 changed files with 61 additions and 17 deletions
+1
View File
@@ -64,6 +64,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
img2pdf \ img2pdf \
libsm6 libxext6 libxrender-dev \ libsm6 libxext6 libxrender-dev \
pngquant \ pngquant \
python-is-python3 \
tesseract-ocr \ tesseract-ocr \
tesseract-ocr-chi-sim \ tesseract-ocr-chi-sim \
tesseract-ocr-deu \ tesseract-ocr-deu \
+1 -1
View File
@@ -1,7 +1,7 @@
# SPDX-FileCopyrightText: 2023 James R. Barlow # SPDX-FileCopyrightText: 2023 James R. Barlow
# SPDX-License-Identifier: MPL-2.0 # SPDX-License-Identifier: MPL-2.0
FROM alpine:3.18 as base FROM alpine:3.19 as base
ENV LANG=C.UTF-8 ENV LANG=C.UTF-8
ENV TZ=UTC ENV TZ=UTC
+6
View File
@@ -30,6 +30,12 @@ OCRmyPDF typically supports the three most recent Python versions.
.. |OCRmyPDF PyPI| image:: https://img.shields.io/pypi/v/ocrmypdf.svg .. |OCRmyPDF PyPI| image:: https://img.shields.io/pypi/v/ocrmypdf.svg
v16.1.2
=======
- Fixed test suite failure when using Ghostscript 10.3.
- Other minor corrections.
v16.1.1 v16.1.1
======= =======
+45 -10
View File
@@ -1,5 +1,6 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
# SPDX-FileCopyrightText: 2016 findingorder <https://github.com/findingorder> # SPDX-FileCopyrightText: 2016 findingorder <https://github.com/findingorder>
# SPDX-FileCopyrightText: 2024 nilsro <https://github.com/nilsro>
# SPDX-License-Identifier: MIT # SPDX-License-Identifier: MIT
"""Example of using ocrmypdf as a library in a script. """Example of using ocrmypdf as a library in a script.
@@ -15,6 +16,10 @@ from __future__ import annotations
import logging import logging
import sys import sys
import os
import posixpath
import shutil
import filecmp
from pathlib import Path from pathlib import Path
import ocrmypdf import ocrmypdf
@@ -22,32 +27,62 @@ import ocrmypdf
# pylint: disable=logging-format-interpolation # pylint: disable=logging-format-interpolation
# pylint: disable=logging-not-lazy # pylint: disable=logging-not-lazy
def filecompare(a,b):
try:
return filecmp.cmp(a, b, shallow=True)
except FileNotFoundError:
return False
script_dir = Path(__file__).parent script_dir = Path(__file__).parent
# set archive_dir to a path for backup original documents. Leave empty if not required.
archive_dir = "/pdfbak"
if len(sys.argv) > 1: if len(sys.argv) > 1:
start_dir = Path(sys.argv[1]) start_dir = Path(sys.argv[1])
else: else:
start_dir = Path('.') start_dir = Path(".")
if len(sys.argv) > 2: if len(sys.argv) > 2:
log_file = Path(sys.argv[2]) log_file = Path(sys.argv[2])
else: else:
log_file = script_dir.with_name('ocr-tree.log') log_file = script_dir.with_name("ocr-tree.log")
logging.basicConfig( logging.basicConfig(
level=logging.INFO, level=logging.INFO,
format='%(asctime)s %(message)s', format="%(asctime)s %(message)s",
filename=log_file, filename=log_file,
filemode='a', filemode="a",
) )
logging.info(f"Start directory {start_dir}")
ocrmypdf.configure_logging(ocrmypdf.Verbosity.default) ocrmypdf.configure_logging(ocrmypdf.Verbosity.default)
for filename in start_dir.glob("**/*.py"): for filename in start_dir.glob("**/*.pdf"):
logging.info(f"Processing {filename}") logging.info(f"Processing {filename}")
result = ocrmypdf.ocr(filename, filename, deskew=True) if ocrmypdf.pdfa.file_claims_pdfa(filename)["pass"]:
if result == ocrmypdf.ExitCode.already_done_ocr: logging.info("Skipped document because it already contained text")
logging.error("Skipped document because it already contained text") else:
elif result == ocrmypdf.ExitCode.ok: archive_filename = archive_dir + str(filename)
if len(archive_dir) > 0 and not filecompare(filename, archive_filename):
logging.info(f"Archiving document to {archive_filename}")
try:
shutil.copy2(filename, posixpath.dirname(archive_filename))
except IOError as io_err:
os.makedirs(posixpath.dirname(archive_filename))
shutil.copy2(filename, posixpath.dirname(archive_filename))
try:
result = ocrmypdf.ocr(filename, filename, deskew=True)
logging.info(result)
except ocrmypdf.exceptions.EncryptedPdfError:
logging.info("Skipped document because it is encrypted")
except ocrmypdf.exceptions.PriorOcrFoundError:
logging.info("Skipped document because it already contained text")
except ocrmypdf.exceptions.DigitalSignatureError:
logging.info("Skipped document because it has a digital signature")
except ocrmypdf.exceptions.TaggedPDFError:
logging.info("Skipped document because it does not need ocr as it is tagged")
except:
logging.error("Unhandled error occured")
logging.info("OCR complete") logging.info("OCR complete")
logging.info(result)
-2
View File
@@ -7,8 +7,6 @@
# Do not enable annotations! # Do not enable annotations!
# https://github.com/tiangolo/typer/discussions/598 # https://github.com/tiangolo/typer/discussions/598
# from __future__ import annotations
from __future__ import annotations
import json import json
import logging import logging
-1
View File
@@ -167,7 +167,6 @@ target-version = "py310"
[tool.ruff.lint.isort] [tool.ruff.lint.isort]
known-first-party = ["ocrmypdf"] known-first-party = ["ocrmypdf"]
required-imports = ["from __future__ import annotations"]
[tool.ruff.lint.pydocstyle] [tool.ruff.lint.pydocstyle]
convention = "google" convention = "google"
+1 -1
View File
@@ -390,7 +390,7 @@ Online documentation is located at:
action='store', action='store',
type=numeric(float, 0), type=numeric(float, 0),
metavar='MPixels', metavar='MPixels',
help="Set maximum number of pixels to unpack before treating an image as a " help="Set maximum number of megapixels to unpack before treating an image as a "
"decompression bomb", "decompression bomb",
default=250.0, default=250.0,
) )
+7 -2
View File
@@ -9,10 +9,11 @@ import pytest
from PIL import Image from PIL import Image
from ocrmypdf._exec import ghostscript, tesseract from ocrmypdf._exec import ghostscript, tesseract
from ocrmypdf.exceptions import ExitCode
from ocrmypdf.helpers import Resolution from ocrmypdf.helpers import Resolution
from ocrmypdf.pdfinfo import PdfInfo from ocrmypdf.pdfinfo import PdfInfo
from .conftest import check_ocrmypdf, have_unpaper from .conftest import check_ocrmypdf, have_unpaper, run_ocrmypdf
RENDERERS = ['hocr', 'sandwich'] RENDERERS = ['hocr', 'sandwich']
@@ -107,7 +108,7 @@ def test_non_square_resolution(renderer, resources, outpdf):
in_pageinfo = PdfInfo(resources / 'aspect.pdf') in_pageinfo = PdfInfo(resources / 'aspect.pdf')
assert in_pageinfo[0].dpi.x != in_pageinfo[0].dpi.y assert in_pageinfo[0].dpi.x != in_pageinfo[0].dpi.y
check_ocrmypdf( proc = run_ocrmypdf(
resources / 'aspect.pdf', resources / 'aspect.pdf',
outpdf, outpdf,
'--pdf-renderer', '--pdf-renderer',
@@ -115,6 +116,10 @@ def test_non_square_resolution(renderer, resources, outpdf):
'--plugin', '--plugin',
'tests/plugins/tesseract_cache.py', 'tests/plugins/tesseract_cache.py',
) )
# PDF/A conversion can fail for this file if Ghostscript >= 10.3, so don't test
# exit code in that case
if proc.returncode != ExitCode.pdfa_conversion_failed:
proc.check_returncode()
out_pageinfo = PdfInfo(outpdf) out_pageinfo = PdfInfo(outpdf)