Compare commits

..
14 Commits
Author SHA1 Message Date
James R. Barlow 054c0773a3 Update completions 2019-12-29 02:40:55 -08:00
James R. Barlow 89aa78b724 docs: fix obsolete statement to "brew install tesseract-lang"
Closes #469
2019-12-29 02:37:10 -08:00
James R. Barlow 708113a514 Windows: Remove Program Files cache from ocrmypdf.exec
@lru_cache doesn't work here, so let's just remove it.
2019-12-29 02:36:20 -08:00
James R. Barlow 95ef5410c2 azure: tweak windows script 2019-12-28 16:12:53 -08:00
James R. Barlow 868b3b4abd exec/init: os.get_exec_path() returns list not str 2019-12-28 16:11:08 -08:00
James R. Barlow 045bdff95a azure: homebrew broke something to do with python@2? 2019-12-28 16:10:43 -08:00
James R. Barlow d12b27ac1d v9.3.0 release notes 2019-12-28 15:42:24 -08:00
James R. Barlow e4e00de79f Add improved example demonstrating watched folder functionality
Closes #466
2019-12-28 15:37:42 -08:00
James R. Barlow a53a3937c2 Fix exception on parsing Ghostscript error messages 2019-12-20 11:25:45 -08:00
James R. Barlow 343424b4d2 azure: only publish code coverage for macOS
macOS (due to Homebrew) currently has the most comprehensive code
coverage. Azure's code coverage feature does not merge code coverage,
so last task to finish wins.
2019-12-20 10:56:10 -08:00
James R. Barlow c5edff2c2f Sort imports 2019-12-19 15:31:18 -08:00
James R. Barlow 8c5f8b8ddd Add isort to precommit 2019-12-19 15:29:38 -08:00
James R. Barlow 39da931a56 Look in Program Files for executables and liblept5.dll 2019-12-19 12:11:32 -08:00
James R. Barlow 9fe354359b Generally update documentation about available platforms 2019-12-19 00:27:37 -08:00
45 changed files with 335 additions and 102 deletions
+2
View File
@@ -39,6 +39,7 @@ RUN pip3 install --no-cache-dir \
-r requirements/main.txt \
-r requirements/webservice.txt \
-r requirements/test.txt \
-r requirements/watcher.txt \
.
FROM base
@@ -69,6 +70,7 @@ COPY --from=builder /usr/local/lib/ /usr/local/lib/
COPY --from=builder /usr/local/bin/ /usr/local/bin/
COPY --from=builder /app/misc/webservice.py /app/
COPY --from=builder /app/misc/watcher.py /app/
# Copy minimal project files to get the test suite.
COPY --from=builder /app/setup.cfg /app/setup.py /app/README.md /app/
+14 -8
View File
@@ -1,10 +1,4 @@
repos:
- repo: https://github.com/psf/black
rev: stable
hooks:
- id: black
language_version: python3.7
exclude: ^src/ocrmypdf/lib/_leptonica.py
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v2.4.0
hooks:
@@ -13,5 +7,17 @@ repos:
- id: check-toml
- id: check-yaml
- id: debug-statements
- id: name-tests-test
args: ["--django"]
- repo: https://github.com/asottile/seed-isort-config
rev: v1.9.3
hooks:
- id: seed-isort-config
- repo: https://github.com/pre-commit/mirrors-isort
rev: v4.3.21 # pick the isort version you'd like to use from https://github.com/pre-commit/mirrors-isort/releases
hooks:
- id: isort
- repo: https://github.com/psf/black
rev: stable
hooks:
- id: black
language_version: python3.7
exclude: ^src/ocrmypdf/lib/_leptonica.py
+3 -9
View File
@@ -79,7 +79,7 @@ and users of Fedora 29 or later may simply
dnf install ocrmypdf
```
and macOS users with Homebrew may simply
and Homebrew users (macOS, Linux, Windows Subsystem for Linux) may simply
```bash
brew install ocrmypdf
@@ -113,18 +113,12 @@ ocrmypdf --help
Our [documentation is served on Read the Docs](https://ocrmypdf.readthedocs.io/en/latest/index.html).
If you detect an issue, please:
- Check whether your issue is already known
- If no problem report exists on github, please create one here: <https://github.com/jbarlow83/OCRmyPDF/issues>
- Describe your problem thoroughly
- Append the console output of the script when running the debug mode (`-v 1` option)
- If possible provide your input PDF file as well as the content of the temporary folder (using a file sharing service like Dropbox)
Please report issues on our [GitHub issues](https://github.com/jbarlow83/OCRmyPDF/issues) page, and follow the issue template for quick response.
Requirements
------------
In addition to the required Python version (3.6+), OCRmyPDF requires external program installations of Ghostscript, Tesseract OCR, QPDF, and Leptonica. ocrmypdf is pure Python, but uses CFFI to portably generate library bindings.
In addition to the required Python version (3.6+), OCRmyPDF requires external program installations of Ghostscript, Tesseract OCR, QPDF, and Leptonica. ocrmypdf is pure Python, but uses CFFI to portably generate library bindings. OCRmyPDF works on pretty much everything: Linux, macOS, Windows and FreeBSD.
Press & Media
-------------
+4 -18
View File
@@ -34,27 +34,20 @@ stages:
displayName: "Install system packages"
- pwsh: |
refreshenv
$env:path = "C:\Program Files\Tesseract-OCR;C:\Program Files\gs\gs9.50\bin;" + $env:path
pip install --upgrade pip wheel
pip install -r requirements/main.txt -r requirements/test.txt .
tesseract --version
python -m pip install --upgrade pip wheel
python -m pip install -r requirements/main.txt -r requirements/test.txt .
displayName: "Install Python packages"
- pwsh: |
refreshenv
$env:path = "C:\Program Files\Tesseract-OCR;C:\Program Files\gs\gs9.50\bin;" + $env:path
$env:pathext += ';.py'
# -n auto helps Windows
pytest -n auto --junitxml=test.xml --cov=ocrmypdf --cov-report=xml
python -m pytest -n auto --junitxml=test.xml --cov=ocrmypdf --cov-report=xml
displayName: "Test"
- task: PublishTestResults@2
inputs:
testResultsFiles: "test.xml"
testRunTitle: "$(Agent.OS) - $(Build.DefinitionName) - Python $(python.version)"
condition: succeededOrFailed()
- task: PublishCodeCoverageResults@1
inputs:
codeCoverageTool: Cobertura
summaryFileLocation: "$(System.DefaultWorkingDirectory)/**/coverage.xml"
- job: "Ubuntu_1804"
pool:
vmImage: "ubuntu-18.04"
@@ -105,10 +98,6 @@ stages:
testResultsFiles: "test.xml"
testRunTitle: "$(Agent.OS) - $(Build.DefinitionName) - Python $(python.version)"
condition: succeededOrFailed()
- task: PublishCodeCoverageResults@1
inputs:
codeCoverageTool: Cobertura
summaryFileLocation: "$(System.DefaultWorkingDirectory)/**/coverage.xml"
- job: "Ubuntu_1604"
pool:
vmImage: "ubuntu-16.04"
@@ -157,10 +146,6 @@ stages:
testResultsFiles: "test.xml"
testRunTitle: "$(Agent.OS) - $(Build.DefinitionName) - Python $(python.version)"
condition: succeededOrFailed()
- task: PublishCodeCoverageResults@1
inputs:
codeCoverageTool: Cobertura
summaryFileLocation: "$(System.DefaultWorkingDirectory)/**/coverage.xml"
- job: "macOS_Mojave"
pool:
vmImage: "macos-10.14"
@@ -176,6 +161,7 @@ stages:
versionSpec: "$(python.version)"
- bash: |
brew update
brew unlink python@2
brew install \
exempi \
ghostscript \
+52 -4
View File
@@ -198,6 +198,54 @@ and all inquiries are appreciated.
Hot (watched) folders
=====================
Watched folders with Docker
---------------------------
The OCRmyPDF Docker image includes a watcher service. This service can
be launched as follows:
.. code-block:: bash
docker run \
-v <path to files to convert>:/input \
-v <path to store results>:/output \
-e OCR_OUTPUT_DIRECTORY_YEAR_MONTH=1 \
-it --entrypoint python3 \
jbarlow83/ocrmypdf \
watcher.py
This service will watch for a file that matches ``/input/\*.pdf`` and will
convert it to a OCRed PDF in ``/output/``. The parameters to this image are:
.. csv-table:: watcher.py parameters for Docker
:header: "Parameter", "Description"
:widths: 50, 50
"``-v <path to files to convert>:/input``", "Files placed in this location will be OCRed"
"``-v <path to store results>:/output``", "This is where OCRed files will be stored"
"``-e OCR_OUTPUT_DIRECTORY_YEAR_MONTH=1``", "This will place files in the output in {output}/{year}/{month}/{filename}"
This service relies on polling to check for changes to the filesystem. It
may not be suitable for some environments, such as filesystems shared on a
slow network.
Watched folders with watcher.py
-------------------------------
The watcher service may also be run natively.
.. code-block:: bash
pip3 install -r reqs/watcher.txt
env OCR_INPUT_DIRECTORY=/mnt/input-pdfs \
OCR_OUTPUT_DIRECTORY=/mnt/output-pdfs \
OCR_OUTPUT_DIRECTORY_YEAR_MONTH=1 \
python3 watcher.py
Watched folders with CLI
------------------------
To set up a "hot folder" that will trigger OCR for every file inserted,
use a program like Python
`watchdog <https://pypi.python.org/pypi/watchdog>`__ (supports all major
@@ -225,12 +273,12 @@ told to run ``ocrmypdf`` on any .pdf added to the current directory
--command='ocrmypdf "${watch_src_path}" "out/${watch_src_path}" ' \
. # don't forget the final dot
For more complex behavior you can write a Python script around to use
the watchdog API.
On file servers, you could configure watchmedo as a system service so it
will run all the time.
For more complex behavior you can write a Python script around to use
the watchdog API. You can refer to the watcher.py script as an example.
Caveats
-------
@@ -250,7 +298,7 @@ Caveats
Alternatives
------------
- `systemd user services <https://wiki.archlinux.org/index.php/Systemd/User>`__
- On Linux, `systemd user services <https://wiki.archlinux.org/index.php/Systemd/User>`__
can be configured to automatically perform OCR on a collection of files.
- `Watchman <https://facebook.github.io/watchman/>`__ is a more
+20 -1
View File
@@ -15,7 +15,10 @@ Code style
==========
We use PEP8, ``black`` for code formatting and ``isort`` for import sorting. The
settings for programs are in ``pyproject.toml`` and ``setup.cfg``.
settings for these programs are in ``pyproject.toml`` and ``setup.cfg``. Pull
requests should follow the style guide. One difference we use from "black" style
is that strings shown to the user are always in double quotes (``"``) and strings
for internal uses are in single quotes (``'``).
Tests
=====
@@ -36,3 +39,19 @@ New non-Python dependencies
OCRmyPDF uses several external programs (Tesseract, Ghostscript and others) for
its functionality. In general we prefer to avoid adding new external programs.
Style guide: Is it OCRmyPDF or ocrmypdf?
========================================
The program/project is OCRmyPDF and the name of the executable or library is ocrmypdf.
Known ports/packagers
=====================
OCRmyPDF has been ported to many platforms already. If you are interesting in
porting to a new platform, check with
`Repology <https://repology.org/projects/?search=ocrmypdf>`__ to see the status
of that platform.
Packager maintainers, please ensure that the command line completion scripts in
``misc/`` are installed.
+38 -14
View File
@@ -8,11 +8,20 @@ Installing OCRmyPDF
|latest|
The easiest way to install OCRmyPDF is to follow the steps for your operating
system/platform, although sometimes this version may be out of date.
system/platform, although sometimes this version may be out of date. This
installation guide provides information allowing you to compare the current
version to the one provided by your platform.
If you want to use the latest version of OCRmyPDF, your best bet is to install
the most recent version your platform provides, and then upgrade that version by
installing the Python binary wheels.
If you want to use the latest version of OCRmyPDF and all of its optional
dependencies, the easiest way to get that is install the Homebrew package. Homebrew
is best known as a macOS package manger, but also works for
`Linux and Windows Subsystem for Linux <https://docs.brew.sh/Homebrew-on-Linux>`__.
After Homebrew is installed, simply run ``brew install ocrmypdf``.
You can also use the more detailed procedures here to manually install OCRmyPDF
from source or with the ``pip`` package manager for binary wheels. The reason
for these varied steps is that OCRmyPDF requires third-party executables that are
not part of Python.
.. contents:: Platform-specific steps
:depth: 2
@@ -55,8 +64,8 @@ Debian and Ubuntu 18.04 or newer
| |ubu-1804| |ubu-1810| |ubu-1904| |ubu-1910| |
+-----------------------------------------------+
Users of Debian 9 ("stretch") or later or Ubuntu 18.04 or later may
simply
Users of Debian 9 ("stretch") or later or Ubuntu 18.04 or later, including users
of Windows Subsystem for Linux, may simply
.. code-block:: bash
@@ -303,6 +312,19 @@ the following command.
If you have any difficulties with installation, check the repository
package page.
Alpine Linux
------------
.. image:: https://repology.org/badge/version-for-repo/alpine_edge/ocrmypdf.svg
:alt: Alpine Linux
:target: https://repology.org/metapackage/ocrmypdf
To install OCRmyPDF for Alpine Linux:
.. code-block:: bash
apk add ocrmypdf
Other Linux packages
--------------------
@@ -380,7 +402,7 @@ packs. If you need other languages you can optionally install them all:
.. code-block:: bash
brew install tesseract --with-all-languages # Option 2: for all language packs
brew install tesseract-lang # Option 2: for all language packs
Update the homebrew pip:
@@ -427,8 +449,7 @@ Installing the Docker image
===========================
For some users, installing the Docker image will be easier than
installing all of OCRmyPDF's dependencies. For Windows, it is the only
option.
installing all of OCRmyPDF's dependencies.
See `OCRmyPDF Docker Image <docker>`__ for more information.
@@ -448,7 +469,7 @@ Installing on Windows
You must install the following for Windows:
* Python 3.7 (64-bit recommended)
* Python 3.7 (64-bit)
* Tesseract 4.0 or later
* Ghostscript 9.50 or later
@@ -463,11 +484,14 @@ Also consider adding:
* ``choco install pngquant``
Windows 10 64-bit and 64-bit versions of applications are recommended. Earlier
versions of Windows and 32-bit versions of these programs are not tested.
versions of Windows and 32-bit versions of these programs are not tested, and not
supported at this time.
Modify your ``PATH`` environment variable so that Tesseract and Ghostscript, and
any optional executables can be found. You can enter it in the command line
or `follow these directions <https://www.computerhope.com/issues/ch000549.htm#dospath>`_
OCRmyPDF will check for Tesseract-OCR and Ghostscript in your Program Files folder.
If they are in some other location, you may need to modify the ``PATH``
environment variable so Tesseract, Ghostscript, and other any optional executables can
be found. You can enter it in the command line or
`follow these directions <https://www.computerhope.com/issues/ch000549.htm#dospath>`_
to make the change persistent and system-wide.
You may then use pip to install ocrmypdf:
+1 -1
View File
@@ -2,7 +2,7 @@
Introduction
============
OCRmyPDF is a Python 3 package that adds OCR layers to PDFs.
OCRmyPDF is a Python 3 application and library that adds OCR layers to PDFs.
About OCR
=========
+13
View File
@@ -13,6 +13,19 @@ Note that it is licensed under GPLv3, so scripts that
``import ocrmypdf`` and are released publicly should probably also be
licensed under GPLv3.
v9.3.0
======
- Improved native Windows support: we now check in the obvious places in
the "Program Files" folders installations of Tesseract and Ghostscript,
rather than relying on the user to edit ``PATH`` to specify their location.
The ``PATH`` environment variable can still be used to differentiate when
multiple installations are present or the programs are installed to non-
standard locations.
- Fixed an exception on parsing Ghostscript error messages.
- Added an improved example demonstrating how to set up a watched folder
for automated OCR processing (thanks to @ianalexander for the contribution).
v9.2.0
======
+3 -2
View File
@@ -58,7 +58,7 @@ _ocrmypdf()
COMPREPLY=( $( compgen -W '{1..13}' -- "$cur" ) )
return
;;
--sidecar|--title|--author|--subject|--keywords|--unpaper-args|--pages)
--sidecar|--title|--author|--subject|--keywords|--unpaper-args|--pages|--fast-web-view)
# argument required but no completions available
return
;;
@@ -76,7 +76,8 @@ _ocrmypdf()
--max-image-mpixels --tesseract-config --tesseract-pagesegmode
--help --tesseract-oem --pdf-renderer --tesseract-timeout
--rotate-pages-threshold --pdfa-image-compression --user-words
--user-patterns --keep-temporary-files --output-type' \
--user-patterns --keep-temporary-files --output-type
--no-progress-bar --pages --fast-web-view' \
-- "$cur" ) )
return
else
+3
View File
@@ -59,6 +59,8 @@ function __fish_ocrmypdf_verbose
end
complete -c ocrmypdf -x -s v -l verbose -a '(__fish_ocrmypdf_verbose)' -d "set verbosity level"
complete -c ocrmypdf -x -l no-progress-bar -d "disable the progress bar"
function __fish_ocrmypdf_pdfa_compression
echo -e "auto\t"(_ "let Ghostscript decide how to compress images")
echo -e "jpeg\t"(_ "convert color and grayscale images to JPEG")
@@ -111,5 +113,6 @@ complete -c ocrmypdf -x -l rotate-pages-threshold -d "page rotation confidence"
complete -c ocrmypdf -r -l user-words -d "specify location of user words file"
complete -c ocrmypdf -r -l user-patterns -d "specify location of user patterns file"
complete -c ocrmypdf -x -l fast-web-view -d "if file size if above this amount in MB, linearize PDF"
complete -c ocrmypdf -x -a "(__fish_complete_suffix .pdf)"
+70
View File
@@ -0,0 +1,70 @@
# Copyright (C) 2019 Ian Alexander: https://github.com/ianalexander
#
# This program 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.
#
# This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
import os
import time
from datetime import datetime
from pathlib import Path
from watchdog.events import PatternMatchingEventHandler
from watchdog.observers import Observer
import ocrmypdf
INPUT_DIRECTORY = os.getenv('OCR_INPUT_DIRECTORY', '/input')
OUTPUT_DIRECTORY = os.getenv('OCR_OUTPUT_DIRECTORY', '/output')
OUTPUT_DIRECTORY_YEAR_MONTH = bool(os.getenv('OCR_OUTPUT_DIRECTORY_YEAR_MONTH', False))
PATTERNS = ['*.pdf']
def execute_ocrmypdf(file_path):
filename = Path(file_path).name
if OUTPUT_DIRECTORY_YEAR_MONTH:
today = datetime.today()
output_directory_year_month = Path(
f'{OUTPUT_DIRECTORY}/{today.year}/{today.month}'
)
if not output_directory_year_month.exists():
output_directory_year_month.mkdir(parents=True, exist_ok=True)
output_path = Path(output_directory_year_month) / filename
else:
output_path = Path(OUTPUT_DIRECTORY) / filename
print(f'New file: {file_path}.\nAttempting to OCRmyPDF to: {output_path}')
ocrmypdf.ocr(file_path, output_path)
class HandleObserverEvent(PatternMatchingEventHandler):
def on_any_event(self, event):
if event.event_type in ['created', 'modified']:
execute_ocrmypdf(event.src_path)
if __name__ == "__main__":
print(
f"Starting OCRmyPDF watcher with config:\n"
f"Input Directory: {INPUT_DIRECTORY}\n"
f"Output Directory: {OUTPUT_DIRECTORY}\n"
f"Output Directory Year & Month: {OUTPUT_DIRECTORY_YEAR_MONTH}"
)
handler = HandleObserverEvent(patterns=PATTERNS)
observer = Observer()
observer.schedule(handler, INPUT_DIRECTORY, recursive=True)
observer.start()
try:
while True:
time.sleep(1)
except KeyboardInterrupt:
observer.stop()
observer.join()
+2 -1
View File
@@ -10,7 +10,8 @@ build-backend = "setuptools.build_meta"
[tool.black]
line-length = 88
target-version = ["py36", "py37", "py38"]
target-version = ["py36",
"py37", "py38"]
skip-string-normalization = true
include = '\.pyi?$'
exclude = '''
+1
View File
@@ -0,0 +1 @@
watchdog >= 0.8.2, < 1.0
+2
View File
@@ -22,6 +22,8 @@ include_trailing_comma=True
force_grid_wrap=0
use_parentheses=True
line_length=88
known_first_party = ocrmypdf
known_third_party = PIL,PyPDF2,_cffi_backend,cffi,flask,gs,img2pdf,pdfminer,pikepdf,pkg_resources,pytest,reportlab,setuptools,sphinx_rtd_theme,tqdm,watchdog,werkzeug
[metadata]
license_file = LICENSE
+1 -1
View File
@@ -41,7 +41,7 @@ from .helpers import safe_symlink
from .hocrtransform import HocrTransform
from .optimize import optimize
from .pdfa import generate_pdfa_ps
from .pdfinfo import Colorspace, PdfInfo, Encoding
from .pdfinfo import Colorspace, Encoding, PdfInfo
VECTOR_PAGE_DPI = 400
+1 -1
View File
@@ -25,8 +25,8 @@ import threading
from collections import namedtuple
from tempfile import mkdtemp
from tqdm import tqdm
import PIL
from tqdm import tqdm
from ._graft import OcrGrafter
from ._jobcontext import PDFContext, cleanup_working_files, make_logger
+10
View File
@@ -58,6 +58,15 @@ log = logging.getLogger(__name__)
verify_python3_env()
def check_platform():
if os.name == 'nt' and sys.maxsize <= 2 ** 32: # pragma: no cover
# 32-bit interpreter on Windows
log.error(
"You are running OCRmyPDF in a 32-bit (x86) Python interpreter."
"Please use a 64-bit (x86-64) version of Python."
)
def check_options_languages(options):
if not options.language:
options.language = [DEFAULT_LANGUAGE]
@@ -292,6 +301,7 @@ def check_options_pillow(options):
def check_options(options):
check_platform()
check_options_languages(options)
check_options_metadata(options)
check_options_output(options)
+1 -1
View File
@@ -21,7 +21,7 @@ import sys
import warnings
from enum import IntEnum
from pathlib import Path
from typing import List, Optional, Dict
from typing import Dict, List, Optional
from tqdm import tqdm
+60 -3
View File
@@ -20,10 +20,12 @@
import logging
import os
import re
import sys
import shutil
import sys
from collections.abc import Mapping
from subprocess import PIPE, STDOUT, CalledProcessError, run as subprocess_run
from functools import lru_cache
from subprocess import PIPE, STDOUT, CalledProcessError
from subprocess import run as subprocess_run
from ..exceptions import ExitCode, MissingDependencyError
@@ -39,13 +41,42 @@ def _get_program(args, env=None):
def run(args, *, env=None, **kwargs):
"""Wrapper around subprocess.run()
The main purpose of this wrapper is to allow us to substitute the main program
for a spoof in the test suite. The hidden variable _OCRMYPDF_TEST_PATH replaces
the main PATH as a location to check for programs to run.
Secondly we have to account for behavioral differences in Windows in particular.
Creating symbolic links in Windows requires administrator privileges and
may not work if for some reason we're using a FAT file system or the temporary
folder is on a different drive from the working folder. The test suite
works around this by creating shim Python scripts that perform the same function
as a symbolic link, but those shims require support on this side, to ensure
we call them with Python.
"""
if not env:
env = os.environ
# Search in spoof path if necessary
program = _get_program(args, env)
# If we are running a .py on Windows, ensure we call it with this Python
# (to support test suite shims)
if os.name == 'nt' and program.lower().endswith('.py'):
args = [sys.executable, program] + args[1:]
else:
args = [program] + args[1:]
if os.name == 'nt':
paths = os.pathsep.join(os.get_exec_path(env))
if not shutil.which(args[0], path=paths):
shimmed_path = shim_paths_with_program_files(env)
new_args0 = shutil.which(args[0], path=shimmed_path)
if new_args0:
args[0] = new_args0
log.debug(args)
if sys.version_info < (3, 7) and os.name == 'nt':
# Can't use close_fds=True on Windows with Python 3.6 or older
@@ -55,7 +86,7 @@ def run(args, *, env=None, **kwargs):
def get_version(program, *, version_arg='--version', regex=r'(\d+(\.\d+)*)', env=None):
"Get the version of the specified program"
"""Get the version of the specified program"""
args_prog = [program, version_arg]
try:
proc = run(
@@ -91,6 +122,32 @@ def get_version(program, *, version_arg='--version', regex=r'(\d+(\.\d+)*)', env
return version
def shim_paths_with_program_files(env=None):
if not env:
env = os.environ
program_files = env.get('PROGRAMFILES', '')
if not program_files:
return env.get('PATH', '')
paths = []
try:
for dirname in os.listdir(program_files):
if dirname.lower() == 'tesseract-ocr':
paths.append(os.path.join(program_files, dirname))
elif dirname.lower() == 'gs':
try:
latest_gs = max(
os.listdir(os.path.join(program_files, dirname)),
key=lambda d: float(d[2:]),
)
except (FileNotFoundError, NotADirectoryError):
continue
paths.append(os.path.join(program_files, dirname, latest_gs, 'bin'))
except EnvironmentError:
pass
paths.extend(path for path in os.get_exec_path(env) if path not in set(paths))
return os.pathsep.join(paths)
missing_program = '''
The program '{program}' could not be executed or was not found on your
system PATH.
+4 -4
View File
@@ -18,20 +18,20 @@
"""Interface to Ghostscript executable"""
import logging
import re
import os
import re
import warnings
from contextlib import suppress
from functools import lru_cache
from io import BytesIO
from os import fspath
from pathlib import Path
from subprocess import PIPE, CalledProcessError
from shutil import which
from subprocess import PIPE, CalledProcessError
from PIL import Image
from ..exceptions import SubprocessOutputError, MissingDependencyError
from ..exceptions import MissingDependencyError, SubprocessOutputError
from . import get_version, run
gslog = logging.getLogger()
@@ -329,7 +329,7 @@ def generate_pdfa(
if _gs_error_reported(stderr):
last_part = None
repcount = 0
for part in p.stdout.split('****'):
for part in stderr.split('****'):
if part != last_part:
if repcount > 1:
log.error(f"(previous error message repeated {repcount} times)")
+1 -1
View File
@@ -17,11 +17,11 @@
"""Interface to Tesseract executable"""
import logging
import os
import shutil
from collections import namedtuple
from contextlib import suppress
import logging
from os import fspath
from subprocess import PIPE, STDOUT, CalledProcessError, TimeoutExpired
+2 -1
View File
@@ -29,7 +29,8 @@ from tempfile import TemporaryDirectory
from PIL import Image
from ..exceptions import MissingDependencyError, SubprocessOutputError
from . import get_version, run as external_run
from . import get_version
from . import run as external_run
@lru_cache(maxsize=1)
+3 -1
View File
@@ -33,8 +33,9 @@ from io import BytesIO
from os import fspath
from tempfile import TemporaryFile
from .lib._leptonica import ffi
from .exceptions import MissingDependencyError
from .exec import shim_paths_with_program_files
from .lib._leptonica import ffi
# pylint: disable=protected-access
@@ -42,6 +43,7 @@ logger = logging.getLogger(__name__)
if os.name == 'nt':
libname = 'liblept-5'
os.environ['PATH'] = shim_paths_with_program_files()
else:
libname = 'lept'
_libpath = find_library(libname)
+2 -1
View File
@@ -21,10 +21,11 @@ import platform
import sys
from pathlib import Path
from subprocess import PIPE, run
from ocrmypdf import api, cli
import pytest
from ocrmypdf import api, cli
pytest_plugins = ['helpers_namespace']
try:
+1 -3
View File
@@ -25,14 +25,12 @@ import os
import sys
from subprocess import check_call
from gs import real_ghostscript
"""Replicate one type of Ghostscript feature elision warning during
PDF/A creation."""
from gs import real_ghostscript
elision_warning = """GPL Ghostscript 9.20: Setting Overprint Mode to 1
not permitted in PDF/A-2, overprint mode not set"""
+2 -2
View File
@@ -23,12 +23,12 @@
import os
import sys
from gs import real_ghostscript
"""Replicate Ghostscript PDF/A conversion failure by suppressing some
arguments"""
from gs import real_ghostscript
def main():
if '--version' in sys.argv:
+2 -3
View File
@@ -24,11 +24,10 @@
import os
import sys
"""Replicate Ghostscript raster failure while allowing rendering"""
from gs import real_ghostscript
"""Replicate Ghostscript raster failure while allowing rendering"""
def main():
if '--version' in sys.argv:
-1
View File
@@ -25,7 +25,6 @@
import os
import sys
from gs import real_ghostscript
-1
View File
@@ -22,7 +22,6 @@
import sys
"""Tesseract bad utf8 spoof
In 'hocr' mode or 'pdf' mode, return error code 1 and some non-Unicode
-1
View File
@@ -59,7 +59,6 @@ import subprocess
import sys
from pathlib import Path
__version__ = subprocess.check_output(
['tesseract', '--version'], stderr=subprocess.STDOUT
).decode()
-1
View File
@@ -19,7 +19,6 @@ import pytest
import ocrmypdf
check_ocrmypdf = pytest.helpers.check_ocrmypdf
+1 -1
View File
@@ -15,7 +15,7 @@
# You should have received a copy of the GNU General Public License
# along with OCRmyPDF. If not, see <http://www.gnu.org/licenses/>.
from subprocess import run, PIPE
from subprocess import PIPE, run
import pytest
-1
View File
@@ -18,7 +18,6 @@
import logging
from decimal import Decimal
import pikepdf
import pytest
from PIL import Image
+1 -1
View File
@@ -18,10 +18,10 @@
import os
from unittest.mock import patch
import pikepdf
import pytest
import ocrmypdf
import pikepdf
def test_no_glyphless_graft(resources, outdir):
+2 -2
View File
@@ -17,10 +17,10 @@
from unittest.mock import patch
import pytest
from PIL import Image
import img2pdf
import pikepdf
import pytest
from PIL import Image
import ocrmypdf
+1 -1
View File
@@ -16,8 +16,8 @@
# along with OCRmyPDF. If not, see <http://www.gnu.org/licenses/>.
from os import fspath
import os
from os import fspath
from pickle import dumps, loads
from unittest.mock import patch
+5 -5
View File
@@ -17,22 +17,22 @@
import datetime
from datetime import timezone
import logging
import mmap
from os import fspath
import os
from datetime import timezone
from os import fspath
from pathlib import Path
from shutil import copyfile, move
from unittest.mock import MagicMock, patch
import pytest
import pikepdf
import pytest
from pikepdf.models.metadata import decode_pdf_date
from ocrmypdf._jobcontext import PDFContext
from ocrmypdf.exceptions import ExitCode
from ocrmypdf.pdfa import SRGB_ICC_PROFILE, file_claims_pdfa, generate_pdfa_ps
from pikepdf.models.metadata import decode_pdf_date
try:
import fitz
+1 -1
View File
@@ -19,10 +19,10 @@ import logging
from os import fspath
from pathlib import Path
import pikepdf
import pytest
from PIL import Image
import pikepdf
from ocrmypdf import optimize as opt
from ocrmypdf.exec import jbig2enc, pngquant
from ocrmypdf.exec.ghostscript import rasterize_pdf
+1 -1
View File
@@ -19,8 +19,8 @@ import pytest
import ocrmypdf
from ocrmypdf._validation import _pages_from_ranges
from ocrmypdf.pdfinfo import PdfInfo
from ocrmypdf.exceptions import BadArgsError
from ocrmypdf.pdfinfo import PdfInfo
@pytest.mark.parametrize(
+1 -1
View File
@@ -20,11 +20,11 @@ from math import isclose
from tempfile import NamedTemporaryFile
import img2pdf
import pikepdf
import pytest
from PIL import Image
from reportlab.pdfgen.canvas import Canvas
import pikepdf
from ocrmypdf import pdfinfo
from ocrmypdf.pdfinfo import Colorspace, Encoding
+1 -1
View File
@@ -21,10 +21,10 @@ from os import fspath
from unittest.mock import Mock
import img2pdf
import pikepdf
import pytest
from PIL import Image
import pikepdf
from ocrmypdf import leptonica
from ocrmypdf.exec import ghostscript, tesseract
from ocrmypdf.pdfinfo import PdfInfo
+1 -1
View File
@@ -18,7 +18,7 @@
import os
import sys
from pathlib import Path
from subprocess import DEVNULL, PIPE, run, Popen, CalledProcessError
from subprocess import DEVNULL, PIPE, CalledProcessError, Popen, run
import pytest
+1 -1
View File
@@ -20,8 +20,8 @@ from unittest.mock import patch
import pytest
from ocrmypdf.cli import parser
from ocrmypdf._validation import check_options
from ocrmypdf.cli import parser
from ocrmypdf.exceptions import ExitCode, MissingDependencyError
from ocrmypdf.exec import unpaper
+1 -1
View File
@@ -23,7 +23,7 @@ import pytest
import ocrmypdf._validation as vd
from ocrmypdf.api import create_options
from ocrmypdf.exceptions import MissingDependencyError, BadArgsError
from ocrmypdf.exceptions import BadArgsError, MissingDependencyError
from ocrmypdf.pdfinfo import PdfInfo