Compare commits

...
14 Commits
14 changed files with 158 additions and 19 deletions
+36
View File
@@ -0,0 +1,36 @@
---
name: Bug report
about: Create a report to help us improve
title: ''
labels: ''
assignees: ''
---
**Describe the bug**
A clear and concise description of what the bug is.
**To Reproduce**
What command line or API call were you trying to run?
```bash
ocrmypdf ...arguments... input.pdf output.pdf
```
Run with verbosity or higher `-v1` to see more detailed logging. This information may be helpful.
**Example file**
Please include an example *input* PDF (or image). The input file is more helpful.
If possible, use an input file with no personal or confidential information. At your option you may GPG-encrypt the file for OCRmyPDF's author only.
**Expected behavior**
A clear and concise description of what you expected to happen.
**Screenshots**
If applicable, add screenshots to help explain your problem.
**System**
- OS: [e.g. Linux, Windows, macOS]
- OCRmyPDF Version: ``ocrmypdf --version``
- How did you install ocrmypdf? Did you use a system package manager, `pip`, or a Docker image?
+17
View File
@@ -0,0 +1,17 @@
---
name: Feature request
about: Suggest an idea for this project
title: ''
labels: enhancement
assignees: ''
---
**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
**Describe the solution you'd like**
A clear and concise description of what you want to happen.
**Additional context**
Add any other context or screenshots about the feature request here.
+8
View File
@@ -51,6 +51,14 @@ Forking a child process to call ``ocrmypdf.ocr()`` is suggested. That
way your application will survive and remain interactive even if
OCRmyPDF does not.
.. warning::
On Windows, the script that calls ``ocrmypdf.ocr()`` must be protected
by an "ifmain" guard (``if __name__ == '__main__'``) or you must use
``ocrmypdf.ocr(...use_threads=True)``. If you do not take at least one
of these steps, Windows fork semantics will prevent OCRmyPDF from working
correct.
Logging
-------
+7
View File
@@ -202,6 +202,13 @@ Alternatives
- `Watchman <https://facebook.github.io/watchman/>`__ is a more
powerful alternative to ``watchmedo``.
AWS Lambda is not viable
------------------------
AWS Lambda and its equivalents have low limits on execution time and payload
size, relative to OCRmyPDF's needs. As of this writing, the request/response
payload for AWS Lambda was 6 MB, which means many PDFs will not fit.
macOS Automator
===============
+2 -4
View File
@@ -90,10 +90,8 @@ Docker volume:
.. code-block:: bash
docker run --rm -v $(pwd):/data ocrmypdf /data/input.pdf /data/output.pdf
(However, when done this way, ``output.pdf`` may be owned by the root
user.)
alias docker_ocrmypdf='docker run --rm -i --user "$(id -u):$(id -g)" --workdir /data -v "$PWD:/data" ocrmypdf'
docker_ocrmypdf /data/input.pdf /data/output.pdf
.. _docker-lang-packs:
+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.7.2
======
- Fixed an issue with ``ocrmypdf.ocr(...language=)`` not accepting a list of
languages as documented.
- Updated setup.py to confirm that pdfminer.six version 20200402 is supported.
v9.7.1
======
- Fixed version check failing when used with qpdf 10.0.0.
- Added some missing type annotations.
- Updated documentation to warn about need for "ifmain" guard and Windows.
v9.7.0
======
+1 -1
View File
@@ -3,7 +3,7 @@
# installation
cffi == 1.14.0
img2pdf == 0.3.3
pdfminer.six == 20200124
pdfminer.six == 20200402
pikepdf == 1.10.2
Pillow == 7.0.0
reportlab == 3.5.34
+1 -1
View File
@@ -98,7 +98,7 @@ setup(
'chardet >= 3.0.4, < 4', # unlisted requirement of pdfminer.six 20181108
'cffi >= 1.9.1', # must be a setup and install requirement
'img2pdf >= 0.3.0, < 0.4', # pure Python, so track HEAD closely
'pdfminer.six >= 20181108, <= 20200124',
'pdfminer.six >= 20181108, <= 20200402',
'pikepdf >= 1.8.1, < 2',
'Pillow >= 6.2.0',
'reportlab >= 3.3.0', # oldest released version with sane image handling
+15 -5
View File
@@ -21,7 +21,7 @@ import sys
from contextlib import suppress
from enum import IntEnum
from pathlib import Path
from typing import Dict, List
from typing import Dict, Iterable
from tqdm import tqdm
@@ -67,7 +67,11 @@ class Verbosity(IntEnum):
debug_all = 2 #: More detailed debugging from ocrmypdf and dependent modules
def configure_logging(verbosity, progress_bar_friendly=True, manage_root_logger=False):
def configure_logging(
verbosity: Verbosity,
progress_bar_friendly: bool = True,
manage_root_logger: bool = False,
):
"""Set up logging.
Library users may wish to use this function if they want their log output to be
@@ -128,7 +132,7 @@ def configure_logging(verbosity, progress_bar_friendly=True, manage_root_logger=
return log
def create_options(*, input_file, output_file, **kwargs):
def create_options(*, input_file: os.PathLike, output_file: os.PathLike, **kwargs):
cmdline = []
deferred = []
@@ -150,6 +154,12 @@ def create_options(*, input_file, output_file, **kwargs):
cmdline.append(f"--{cmd_style_arg}")
continue
if isinstance(val, Iterable) and not isinstance(val, str):
for elem in val:
cmdline.append(f"--{cmd_style_arg}")
cmdline.append(elem)
continue
# We have a parameter
cmdline.append(f"--{cmd_style_arg}")
if isinstance(val, (int, float)):
@@ -180,7 +190,7 @@ def ocr( # pylint: disable=unused-argument
input_file: os.PathLike,
output_file: os.PathLike,
*,
language: List[str] = None,
language: Iterable[str] = None,
image_dpi: int = None,
output_type=None,
sidecar: os.PathLike = None,
@@ -210,7 +220,7 @@ def ocr( # pylint: disable=unused-argument
jbig2_page_group_size: int = None,
pages: str = None,
max_image_mpixels: float = None,
tesseract_config: List[str] = None,
tesseract_config: Iterable[str] = None,
tesseract_pagesegmode: int = None,
tesseract_oem: int = None,
pdf_renderer=None,
+10 -1
View File
@@ -23,6 +23,7 @@ import re
import shutil
import sys
from collections.abc import Mapping
from distutils.version import LooseVersion
from functools import lru_cache
from subprocess import PIPE, STDOUT, CalledProcessError
from subprocess import run as subprocess_run
@@ -270,7 +271,15 @@ def check_external_program(
raise MissingDependencyError()
return
if found_version < need_version:
def remove_leading_v(s):
if s.startswith('v'):
return s[1:]
return s
found_version = remove_leading_v(found_version)
need_version = remove_leading_v(need_version)
if LooseVersion(found_version) < LooseVersion(need_version):
_error_old_version(program, package, need_version, found_version, required_for)
if not recommended:
raise MissingDependencyError()
+4 -4
View File
@@ -28,7 +28,7 @@ from pathlib import Path
log = logging.getLogger(__name__)
def safe_symlink(input_file, soft_link_name, *args, **kwargs):
def safe_symlink(input_file: os.PathLike, soft_link_name: os.PathLike, *args, **kwargs):
"""
Helper function: relinks soft symbolic link if necessary
"""
@@ -76,12 +76,12 @@ def is_iterable_notstr(thing):
return isinstance(thing, Iterable) and not isinstance(thing, str)
def monotonic(L):
def monotonic(L: Iterable):
"""Does list increase monotonically?"""
return all(b > a for a, b in zip(L, L[1:]))
def page_number(input_file):
def page_number(input_file: os.PathLike):
"""Get one-based page number implied by filename (000002.pdf -> 2)"""
return int(os.path.basename(os.fspath(input_file))[0:6])
@@ -97,7 +97,7 @@ def available_cpu_count():
return 1
def is_file_writable(test_file):
def is_file_writable(test_file: os.PathLike):
"""Intentionally racy test if target is writable.
We intend to write to the output file if and only if we succeed and
+3 -3
View File
@@ -22,7 +22,7 @@ from collections import defaultdict, namedtuple
from decimal import Decimal
from enum import Enum
from math import hypot, isclose
from os import fspath
from os import PathLike, fspath
from pathlib import Path
from warnings import warn
@@ -40,7 +40,7 @@ logger = logging.getLogger()
Colorspace = Enum('Colorspace', 'gray rgb cmyk lab icc index sep devn pattern jpeg2000')
Encoding = Enum(
'Encoding', 'ccitt jpeg jpeg2000 jbig2 asciihex ascii85 lzw flate ' + 'runlength'
'Encoding', 'ccitt jpeg jpeg2000 jbig2 asciihex ascii85 lzw flate runlength'
)
FRIENDLY_COLORSPACE = {
@@ -558,7 +558,7 @@ def simplify_textboxes(miner, textbox_getter):
yield TextboxInfo(box.bbox, visible, corrupt)
def _pdf_get_pageinfo(pdf, pageno: int, infile, xmltext):
def _pdf_get_pageinfo(pdf, pageno: int, infile: PathLike, xmltext: str):
pageinfo = {}
pageinfo['pageno'] = pageno
pageinfo['images'] = []
+7
View File
@@ -59,3 +59,10 @@ def test_tqdm_console():
log.info("done")
assert not before_pbar("done")
def test_language_list():
with pytest.raises(
(ocrmypdf.exceptions.InputFileError, ocrmypdf.exceptions.MissingDependencyError)
):
ocrmypdf.ocr('doesnotexist.pdf', '_.pdf', language=['eng', 'deu'])
+34
View File
@@ -176,3 +176,37 @@ def test_language_warning(caplog):
vd.check_options_languages(opts)
assert opts.language == ['eng']
assert 'assuming --language' in caplog.text
def test_version_comparison():
vd.check_external_program(
program="dummy_basic",
package="dummy",
version_checker=lambda: '9.0',
need_version='8.0.2',
)
vd.check_external_program(
program="dummy_doubledigit",
package="dummy",
version_checker=lambda: '10.0',
need_version='8.0.2',
)
vd.check_external_program(
program="tesseract",
package="tesseract",
version_checker=lambda: '4.0.0-beta.1',
need_version='4.0.0',
)
vd.check_external_program(
program="tesseract",
package="tesseract",
version_checker=lambda: 'v5.0.0-alpha.20200201',
need_version='4.0.0',
)
with pytest.raises(MissingDependencyError):
vd.check_external_program(
program="dummy_fails",
package="dummy",
version_checker=lambda: '1.0',
need_version='2.0',
)