Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6af7d61ee5 | ||
|
|
bafd08391d | ||
|
|
82ebd8ef1a | ||
|
|
4ed1aa4d23 | ||
|
|
d04e43d46d | ||
|
|
952f0cca15 | ||
|
|
f6a4d8f1f8 | ||
|
|
b3097a2384 | ||
|
|
6d9ddbe98b | ||
|
|
9bb42c0229 | ||
|
|
bd7226b27a | ||
|
|
5b413e3873 | ||
|
|
be5831a629 | ||
|
|
084d2bf8e2 | ||
|
|
da79e6bac7 | ||
|
|
c4831ac00c | ||
|
|
93a954ef9f | ||
|
|
f7ce8f44e9 | ||
|
|
0b012697e5 | ||
|
|
58e357c992 | ||
|
|
71fbad83ad | ||
|
|
52483072dc | ||
|
|
7f0b8621f3 | ||
|
|
cd8db60b06 | ||
|
|
1aa34f5d2e | ||
|
|
dfa1d88ce9 | ||
|
|
dd38519f07 | ||
|
|
098f5d4f0b | ||
|
|
ffc685d536 | ||
|
|
cd1a99a0de | ||
|
|
48e3b267fc | ||
|
|
37ebcadfa1 |
@@ -43,6 +43,7 @@ install:
|
|||||||
|
|
||||||
script:
|
script:
|
||||||
- mv ocrmypdf dont_import_this_ocrmypdf
|
- mv ocrmypdf dont_import_this_ocrmypdf
|
||||||
|
- tesseract --version
|
||||||
- pytest -n auto
|
- pytest -n auto
|
||||||
- mv dont_import_this_ocrmypdf ocrmypdf
|
- mv dont_import_this_ocrmypdf ocrmypdf
|
||||||
|
|
||||||
|
|||||||
+3
-1
@@ -6,7 +6,9 @@ set -x
|
|||||||
pip3 install homebrew-pypi-poet
|
pip3 install homebrew-pypi-poet
|
||||||
python3 .travis/autobrew.py
|
python3 .travis/autobrew.py
|
||||||
cat ocrmypdf.rb
|
cat ocrmypdf.rb
|
||||||
brew audit ocrmypdf.rb
|
|
||||||
|
# brew audit crashes Travis
|
||||||
|
#brew audit ocrmypdf.rb
|
||||||
|
|
||||||
# Important: disable debug output so token is hidden
|
# Important: disable debug output so token is hidden
|
||||||
set +x
|
set +x
|
||||||
|
|||||||
@@ -20,6 +20,8 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
|
|||||||
tesseract-ocr-spa \
|
tesseract-ocr-spa \
|
||||||
tesseract-ocr-deu
|
tesseract-ocr-deu
|
||||||
|
|
||||||
|
ENV LANG=C.UTF-8
|
||||||
|
|
||||||
RUN python3 -m venv --system-site-packages /appenv
|
RUN python3 -m venv --system-site-packages /appenv
|
||||||
|
|
||||||
# This installs the latest binary wheel instead of the code in the current
|
# This installs the latest binary wheel instead of the code in the current
|
||||||
|
|||||||
@@ -30,6 +30,8 @@ RUN apt-get update \
|
|||||||
tesseract-ocr-rus \
|
tesseract-ocr-rus \
|
||||||
tesseract-ocr-chi-sim
|
tesseract-ocr-chi-sim
|
||||||
|
|
||||||
|
ENV LANG=C.UTF-8
|
||||||
|
|
||||||
RUN python3 -m venv --system-site-packages /appenv
|
RUN python3 -m venv --system-site-packages /appenv
|
||||||
|
|
||||||
# This installs the latest binary wheel instead of the code in the current
|
# This installs the latest binary wheel instead of the code in the current
|
||||||
|
|||||||
@@ -4,6 +4,12 @@ OCRmyPDF
|
|||||||
.. image:: https://travis-ci.org/jbarlow83/OCRmyPDF.svg?branch=master
|
.. image:: https://travis-ci.org/jbarlow83/OCRmyPDF.svg?branch=master
|
||||||
:target: https://travis-ci.org/jbarlow83/OCRmyPDF
|
:target: https://travis-ci.org/jbarlow83/OCRmyPDF
|
||||||
|
|
||||||
|
.. image:: https://img.shields.io/pypi/v/ocrmypdf.svg
|
||||||
|
:target: https://pypi.org/project/ocrmypdf/
|
||||||
|
|
||||||
|
.. image:: https://img.shields.io/docker/build/jbarlow83/ocrmypdf.svg
|
||||||
|
:target: https://hub.docker.com/r/jbarlow83/ocrmypdf/
|
||||||
|
|
||||||
OCRmyPDF adds an OCR text layer to scanned PDF files, allowing them to
|
OCRmyPDF adds an OCR text layer to scanned PDF files, allowing them to
|
||||||
be searched or copy-pasted.
|
be searched or copy-pasted.
|
||||||
|
|
||||||
|
|||||||
+26
-5
@@ -33,9 +33,17 @@ If you want to adjust the amount of time spent on OCR, change ``--tesseract-time
|
|||||||
Overriding default tesseract
|
Overriding default tesseract
|
||||||
""""""""""""""""""""""""""""
|
""""""""""""""""""""""""""""
|
||||||
|
|
||||||
OCRmyPDF checks the environment variable ``OCRMYPDF_TESSERACT`` for the full path *to the tesseract executable* first.
|
OCRmyPDF checks the environment variable ``OCRMYPDF_TESSERACT`` for the full path *to the tesseract binary* first.
|
||||||
|
|
||||||
For example, if you are testing tesseract 4.00 and don't wish to disturb your tesseract 3.04 installation, you can launch OCRmyPDF as follows:
|
.. envvar:: OCRMYPDF_TESSERACT
|
||||||
|
|
||||||
|
Specify the location of the Tesseract binary.
|
||||||
|
|
||||||
|
.. envvar:: TESSDATA_PREFIX
|
||||||
|
|
||||||
|
A Tesseract environment variable that overrides the path to Tesseract's data files.
|
||||||
|
|
||||||
|
For example, if you are testing tesseract 4.00 and don't wish to disturb use an existing tesseract 3.04 installation, you can launch OCRmyPDF as follows:
|
||||||
|
|
||||||
.. code-block:: bash
|
.. code-block:: bash
|
||||||
|
|
||||||
@@ -44,8 +52,8 @@ For example, if you are testing tesseract 4.00 and don't wish to disturb your te
|
|||||||
TESSDATA_PREFIX=/home/user/src/tesseract4 \
|
TESSDATA_PREFIX=/home/user/src/tesseract4 \
|
||||||
ocrmypdf --tesseract-oem 2 input.pdf output.pdf
|
ocrmypdf --tesseract-oem 2 input.pdf output.pdf
|
||||||
|
|
||||||
* ``TESSDATA_PREFIX`` directs tesseract 4.0 to use LSTM training data. This is a tesseract environment variable.
|
In this example ``TESSDATA_PREFIX`` directs tesseract 4.0 to use LSTM training data. ``--tesseract-oem 1`` requests tesseract 4.0's new LSTM engine. (Tesseract 4.0 only.)
|
||||||
* ``--tesseract-oem 1`` requests tesseract 4.0's new LSTM engine. (Tesseract 4.0 only.)
|
|
||||||
|
|
||||||
Overriding other support programs
|
Overriding other support programs
|
||||||
"""""""""""""""""""""""""""""""""
|
"""""""""""""""""""""""""""""""""
|
||||||
@@ -56,7 +64,20 @@ In addition to tesseract, OCRmyPDF uses the following external binaries:
|
|||||||
* ``unpaper``
|
* ``unpaper``
|
||||||
* ``qpdf``
|
* ``qpdf``
|
||||||
|
|
||||||
In each case OCRmyPDF will check the environment variable ``OCRMYPDF_{program}`` before asking the system to find ``{program}`` on the PATH. For example, you could redirect OCRmyPDF to ``OCRMYPDF_GS`` to override Ghostscript.
|
In each case OCRmyPDF will check the environment variable ``OCRMYPDF_{program}`` before asking the system to find ``{program}`` on the PATH. For example, you could redirect OCRmyPDF to ``OCRMYPDF_GS`` to override Ghostscript. The full list is below:
|
||||||
|
|
||||||
|
.. envvar:: OCRMYPDF_GS
|
||||||
|
|
||||||
|
Specify the location of the Ghostscript binary.
|
||||||
|
|
||||||
|
.. envvar:: OCRMYPDF_UNPAPER
|
||||||
|
|
||||||
|
Specify the location of the unpaper binary.
|
||||||
|
|
||||||
|
.. envvar:: OCRMYPDF_QPDF
|
||||||
|
|
||||||
|
Specify the location of the qpdf binary.
|
||||||
|
|
||||||
|
|
||||||
Changing tesseract configuration variables
|
Changing tesseract configuration variables
|
||||||
""""""""""""""""""""""""""""""""""""""""""
|
""""""""""""""""""""""""""""""""""""""""""
|
||||||
|
|||||||
+12
-10
@@ -72,19 +72,11 @@ Language packs must be installed for all languages specified. See :ref:`Installi
|
|||||||
Produce PDF and text file containing OCR text
|
Produce PDF and text file containing OCR text
|
||||||
"""""""""""""""""""""""""""""""""""""""""""""
|
"""""""""""""""""""""""""""""""""""""""""""""
|
||||||
|
|
||||||
This produces a file named "output.pdf" and a companion text file named "output.txt". The ``pdftotext`` program from
|
This produces a file named "output.pdf" and a companion text file named "output.txt".
|
||||||
`Poppler <https://poppler.freedesktop.org/>`_ is used to extract text from the finished PDF.
|
|
||||||
|
|
||||||
|
|
||||||
.. code-block:: bash
|
.. code-block:: bash
|
||||||
|
|
||||||
ocrmypdf input.pdf - | tee output.pdf | pdftotext - output.txt
|
ocrmypdf --sidecar output.txt input.pdf output.pdf
|
||||||
|
|
||||||
.. note::
|
|
||||||
|
|
||||||
To get pdftotext, Debian/Ubuntu users may ``apt-get install poppler-utils``
|
|
||||||
and macOS users may ``brew install poppler`` respectively.
|
|
||||||
|
|
||||||
|
|
||||||
OCR images, not PDFs
|
OCR images, not PDFs
|
||||||
--------------------
|
--------------------
|
||||||
@@ -155,6 +147,16 @@ Image processing commands can be combined. The order in which options are given
|
|||||||
ocrmypdf --deskew --clean --rotate-pages input.pdf output.pdf
|
ocrmypdf --deskew --clean --rotate-pages input.pdf output.pdf
|
||||||
|
|
||||||
|
|
||||||
|
Don't actually OCR my PDF
|
||||||
|
"""""""""""""""""""""""""
|
||||||
|
|
||||||
|
If you set ``--tesseract-timeout 0`` OCRmyPDF will apply its image processing without performing OCR, if all you want to is to apply image processing or PDF/A conversion.
|
||||||
|
|
||||||
|
.. code-block:: bash
|
||||||
|
|
||||||
|
ocrmypdf --tesseract-timeout=0 --remove-background input.pdf output.pdf
|
||||||
|
|
||||||
|
|
||||||
Improving OCR quality
|
Improving OCR quality
|
||||||
---------------------
|
---------------------
|
||||||
|
|
||||||
|
|||||||
+28
-36
@@ -214,15 +214,8 @@ follow these steps.
|
|||||||
Installing on Ubuntu 14.04 LTS
|
Installing on Ubuntu 14.04 LTS
|
||||||
------------------------------
|
------------------------------
|
||||||
|
|
||||||
Installing on Ubuntu 14.04 LTS (trusty) is more difficult than some other options, because of bugs in Python package installation and because OCRmyPDF depends on some packages newer than are available in the main distribution.
|
Installing on Ubuntu 14.04 LTS (trusty) is more difficult than some other options,
|
||||||
|
because it is older.
|
||||||
Add new "apt" repositories needed for backports of Ghostscript 9.16, libav-11 (for unpaper 6.1) and Tesseract 4.00 (alpha). This will replace Ghostscript and Tesseract 3.x on your system. If you prefer to not modify your system in this matter, consider using a Docker container.
|
|
||||||
|
|
||||||
.. code-block:: bash
|
|
||||||
|
|
||||||
sudo add-apt-repository ppa:vshn/ghostscript -y
|
|
||||||
sudo add-apt-repository ppa:heyarje/libav-11 -y
|
|
||||||
sudo add-apt-repository ppa:alex-p/tesseract-ocr
|
|
||||||
|
|
||||||
Update apt-get:
|
Update apt-get:
|
||||||
|
|
||||||
@@ -239,39 +232,38 @@ Install system dependencies:
|
|||||||
zlib1g-dev \
|
zlib1g-dev \
|
||||||
libjpeg-dev \
|
libjpeg-dev \
|
||||||
libffi-dev \
|
libffi-dev \
|
||||||
libavformat56 libavcodec56 libavutil54 \
|
qpdf
|
||||||
|
|
||||||
|
We will need backports of Ghostscript 9.16, libav-11 (for unpaper 6.1),
|
||||||
|
Tesseract 4.00 (alpha), and Python 3.6. This will replace Ghostscript and
|
||||||
|
Tesseract 3.x on your system. Python 3.6 will be installed alongside the system
|
||||||
|
Python 3.
|
||||||
|
|
||||||
|
If you prefer to not modify your system in this matter, consider using a Docker container.
|
||||||
|
|
||||||
|
.. code-block:: bash
|
||||||
|
|
||||||
|
sudo add-apt-repository ppa:vshn/ghostscript -y
|
||||||
|
sudo add-apt-repository ppa:heyarje/libav-11 -y
|
||||||
|
sudo add-apt-repository ppa:alex-p/tesseract-ocr -y
|
||||||
|
sudo add-apt-repository ppa:jonathonf/python-3.6 -y
|
||||||
|
|
||||||
|
sudo apt-get update
|
||||||
|
|
||||||
|
sudo apt-get install \
|
||||||
|
python3.6 \
|
||||||
ghostscript \
|
ghostscript \
|
||||||
qpdf \
|
|
||||||
python3-pip \
|
|
||||||
python3-pil \
|
|
||||||
python3-pytest \
|
|
||||||
python3-reportlab \
|
|
||||||
python3-wheel \
|
|
||||||
python3-venv \
|
|
||||||
tesseract-ocr \
|
tesseract-ocr \
|
||||||
tesseract-ocr-eng
|
tesseract-ocr-eng \
|
||||||
|
libavformat56 libavcodec56 libavutil54 \
|
||||||
|
wget
|
||||||
|
|
||||||
If you wish install OCRmyPDF to the system Python, then install as follows (note this installs new packages
|
Now we need to install ``pip`` and let it install ocrmypdf:
|
||||||
into your system Python, which could interfere with other programs):
|
|
||||||
|
|
||||||
.. code-block:: bash
|
.. code-block:: bash
|
||||||
|
|
||||||
sudo pip3 install ocrmypdf
|
wget -O - -o /dev/null https://bootstrap.pypa.io/get-pip.py | python3.6
|
||||||
|
pip3.6 install ocrmypdf
|
||||||
If you wish to install OCRmyPDF to a virtual environment to isolate the system Python, you can
|
|
||||||
follow these steps. This includes a workaround `for a known, unresolved issue in Ubuntu 14.04's ensurepip
|
|
||||||
package <http://www.thefourtheye.in/2014/12/Python-venv-problem-with-ensurepip-in-Ubuntu.html>`_:
|
|
||||||
|
|
||||||
.. code-block:: bash
|
|
||||||
|
|
||||||
sudo apt-get install python3-venv
|
|
||||||
python3 -m venv venv-ocrmypdf --without-pip
|
|
||||||
source venv-ocrmypdf/bin/activate
|
|
||||||
wget -O - -o /dev/null https://bootstrap.pypa.io/get-pip.py | python
|
|
||||||
deactivate
|
|
||||||
python3 -m venv --system-site-packages venv-ocrmypdf
|
|
||||||
source venv-ocrmypdf/bin/activate
|
|
||||||
pip install ocrmypdf
|
|
||||||
|
|
||||||
These installation instructions omit the optional dependency ``unpaper``, which is only available at version 0.4.2 in Ubuntu 14.04. The author could not find a backport of ``unpaper``, and created a .deb package to do the job of installing unpaper 6.1 (for x86 64-bit only):
|
These installation instructions omit the optional dependency ``unpaper``, which is only available at version 0.4.2 in Ubuntu 14.04. The author could not find a backport of ``unpaper``, and created a .deb package to do the job of installing unpaper 6.1 (for x86 64-bit only):
|
||||||
|
|
||||||
|
|||||||
@@ -6,6 +6,36 @@ OCRmyPDF uses `semantic versioning <http://semver.org/>`_ for its command line i
|
|||||||
The OCRmyPDF package itself does not contain a public API, although it is fairly stable and breaking changes are usually timed with a major release. A future release will clearly define the stable public API.
|
The OCRmyPDF package itself does not contain a public API, although it is fairly stable and breaking changes are usually timed with a major release. A future release will clearly define the stable public API.
|
||||||
|
|
||||||
|
|
||||||
|
v5.3.3
|
||||||
|
------
|
||||||
|
|
||||||
|
- Fixed missing error message that should occur when trying to force ``--pdf-renderer sandwich`` on old versions of Tesseract
|
||||||
|
- Update copyright information in test files
|
||||||
|
- Set system ``LANG`` to UTF-8 in Dockerfiles to avoid UTF-8 encoding errors
|
||||||
|
|
||||||
|
|
||||||
|
v5.3.2
|
||||||
|
------
|
||||||
|
|
||||||
|
- Fixed a broken test case related to language packs
|
||||||
|
|
||||||
|
|
||||||
|
v5.3.1
|
||||||
|
------
|
||||||
|
|
||||||
|
- Fixed wrong return code given for missing Tesseract language packs
|
||||||
|
- Fixed "brew audit" crashing on Travis when trying to auto-brew
|
||||||
|
|
||||||
|
|
||||||
|
v5.3
|
||||||
|
----
|
||||||
|
|
||||||
|
- Added ``--user-words`` and ``--user-patterns`` arguments which are forwarded to Tesseract OCR as words and regular expressions respective to use to guide OCR. Supplying a list of subject-domain words should assist Tesseract with resolving words. (#165)
|
||||||
|
- Using a non Latin-1 language with the "hocr" renderer now warns about possible OCR quality and recommends workarounds (#176)
|
||||||
|
- Output file path added to error message when that location is not writable (#175)
|
||||||
|
- Otherwise valid PDFs with leading whitespace at the beginning of the file are now accepted
|
||||||
|
|
||||||
|
|
||||||
v5.2
|
v5.2
|
||||||
----
|
----
|
||||||
|
|
||||||
|
|||||||
+35
-9
@@ -41,6 +41,9 @@ warnings.simplefilter('ignore', pypdf.utils.PdfReadWarning)
|
|||||||
|
|
||||||
MINIMUM_TESS_VERSION = '3.04'
|
MINIMUM_TESS_VERSION = '3.04'
|
||||||
|
|
||||||
|
HOCR_OK_LANGS = frozenset([
|
||||||
|
'eng', 'deu', 'spa', 'ita', 'por'
|
||||||
|
])
|
||||||
|
|
||||||
def complain(message):
|
def complain(message):
|
||||||
print(*textwrap.wrap(message), file=sys.stderr)
|
print(*textwrap.wrap(message), file=sys.stderr)
|
||||||
@@ -281,6 +284,15 @@ advanced.add_argument(
|
|||||||
"are applied to all pages, including those for which OCR was "
|
"are applied to all pages, including those for which OCR was "
|
||||||
"skipped. Not supported for --output-type=pdf ; that setting "
|
"skipped. Not supported for --output-type=pdf ; that setting "
|
||||||
"preserves the original compression of all images.")
|
"preserves the original compression of all images.")
|
||||||
|
advanced.add_argument(
|
||||||
|
'--user-words', metavar='FILE',
|
||||||
|
help="Specify the location of the Tesseract user words file. This is a "
|
||||||
|
"list of words Tesseract should consider while performing OCR in "
|
||||||
|
"addition to its standard language dictionaries. This can improve "
|
||||||
|
"OCR quality especially for specialized and technical documents.")
|
||||||
|
advanced.add_argument(
|
||||||
|
'--user-patterns', metavar='FILE',
|
||||||
|
help="Specify the location of the Tesseract user patterns file.")
|
||||||
|
|
||||||
debugging = parser.add_argument_group(
|
debugging = parser.add_argument_group(
|
||||||
"Debugging",
|
"Debugging",
|
||||||
@@ -310,7 +322,7 @@ def check_options_languages(options, _log):
|
|||||||
"data for the following requested languages: \n")
|
"data for the following requested languages: \n")
|
||||||
for lang in (set(options.language) - tesseract.languages()):
|
for lang in (set(options.language) - tesseract.languages()):
|
||||||
msg += lang + '\n'
|
msg += lang + '\n'
|
||||||
raise argparse.ArgumentError(None, msg)
|
raise MissingDependencyError(msg)
|
||||||
|
|
||||||
|
|
||||||
def check_options_output(options, log):
|
def check_options_output(options, log):
|
||||||
@@ -320,6 +332,11 @@ def check_options_output(options, log):
|
|||||||
else:
|
else:
|
||||||
options.pdf_renderer = 'hocr'
|
options.pdf_renderer = 'hocr'
|
||||||
|
|
||||||
|
if options.pdf_renderer == 'sandwich' and not tesseract.has_textonly_pdf():
|
||||||
|
raise MissingDependencyError(
|
||||||
|
"The 'sandwich' renderer requires Tesseract 3.05.01 or newer; "
|
||||||
|
"or Tesseract 4.00 alpha newer than February 2017.")
|
||||||
|
|
||||||
if options.pdf_renderer == 'tess4':
|
if options.pdf_renderer == 'tess4':
|
||||||
log.warning("The 'tess4' PDF renderer has been renamed to 'sandwich'. "
|
log.warning("The 'tess4' PDF renderer has been renamed to 'sandwich'. "
|
||||||
"Please use --pdf-renderer=sandwich.")
|
"Please use --pdf-renderer=sandwich.")
|
||||||
@@ -386,12 +403,20 @@ def check_options_ocr_behavior(options, log):
|
|||||||
# raise argparse.ArgumentError(
|
# raise argparse.ArgumentError(
|
||||||
# "Error: --redo-ocr and other OCR options are incompatible.")
|
# "Error: --redo-ocr and other OCR options are incompatible.")
|
||||||
|
|
||||||
if set(options.language) & {'chi_sim', 'chi_tra'} and \
|
if options.pdf_renderer == 'hocr' and \
|
||||||
(options.pdf_renderer == 'hocr' or options.output_type == 'pdfa'):
|
not set(options.language).issubset(HOCR_OK_LANGS):
|
||||||
log.warning(
|
msg = (
|
||||||
"Your settings are known to cause problems with OCR of Chinese text. "
|
"The 'hocr' PDF renderer is known to cause problems with one "
|
||||||
"Try adding these arguments: "
|
"or more of the languages in your document. ")
|
||||||
" ocrmypdf --pdf-renderer tesseract --output-type pdf")
|
|
||||||
|
if tesseract.has_textonly_pdf():
|
||||||
|
msg += (
|
||||||
|
"Use --pdf-renderer auto (the default) to avoid this issue.")
|
||||||
|
else:
|
||||||
|
msg += (
|
||||||
|
"Use --pdf-renderer tesseract --output-type pdf to avoid "
|
||||||
|
"this issue")
|
||||||
|
log.warning(msg)
|
||||||
|
|
||||||
|
|
||||||
def check_options_advanced(options, log):
|
def check_options_advanced(options, log):
|
||||||
@@ -666,8 +691,9 @@ def run_pipeline():
|
|||||||
file."""))
|
file."""))
|
||||||
return ExitCode.bad_args
|
return ExitCode.bad_args
|
||||||
elif not is_file_writable(options.output_file):
|
elif not is_file_writable(options.output_file):
|
||||||
_log.error(textwrap.dedent("""\
|
_log.error(
|
||||||
Output file location is not writable."""))
|
"Output file location (" + options.output_file + ") " +
|
||||||
|
"is not writable.")
|
||||||
return ExitCode.file_access_error
|
return ExitCode.file_access_error
|
||||||
|
|
||||||
manager = JobContextManager()
|
manager = JobContextManager()
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import sys
|
|||||||
from . import get_program
|
from . import get_program
|
||||||
from ..exceptions import SubprocessOutputError
|
from ..exceptions import SubprocessOutputError
|
||||||
from PIL import Image
|
from PIL import Image
|
||||||
|
from ..helpers import fspath
|
||||||
|
|
||||||
|
|
||||||
@lru_cache(maxsize=1)
|
@lru_cache(maxsize=1)
|
||||||
@@ -43,8 +44,8 @@ def rasterize_pdf(input_file, output_file, xres, yres, raster_device, log,
|
|||||||
(xres, yres) even if those numbers are noninteger. The image's DPI will
|
(xres, yres) even if those numbers are noninteger. The image's DPI will
|
||||||
be overridden with the values in page_dpi.
|
be overridden with the values in page_dpi.
|
||||||
|
|
||||||
:param input_file:
|
:param input_file: pathlike
|
||||||
:param output_file:
|
:param output_file: pathlike
|
||||||
:param xres: resolution at which to rasterize page
|
:param xres: resolution at which to rasterize page
|
||||||
:param yres:
|
:param yres:
|
||||||
:param raster_device:
|
:param raster_device:
|
||||||
@@ -69,7 +70,7 @@ def rasterize_pdf(input_file, output_file, xres, yres, raster_device, log,
|
|||||||
'-dLastPage=%i' % pageno,
|
'-dLastPage=%i' % pageno,
|
||||||
'-o', tmp.name,
|
'-o', tmp.name,
|
||||||
'-r{0}x{1}'.format(str(int_res[0]), str(int_res[1])),
|
'-r{0}x{1}'.format(str(int_res[0]), str(int_res[1])),
|
||||||
input_file
|
fspath(input_file)
|
||||||
]
|
]
|
||||||
|
|
||||||
p = run(args_gs, stdout=PIPE, stderr=STDOUT,
|
p = run(args_gs, stdout=PIPE, stderr=STDOUT,
|
||||||
@@ -95,9 +96,10 @@ def rasterize_pdf(input_file, output_file, xres, yres, raster_device, log,
|
|||||||
log.debug(
|
log.debug(
|
||||||
"Ghostscript: resize output image {} -> {}".format(
|
"Ghostscript: resize output image {} -> {}".format(
|
||||||
im.size, expected_size))
|
im.size, expected_size))
|
||||||
im.resize(expected_size).save(output_file, dpi=page_dpi)
|
im.resize(expected_size).save(
|
||||||
|
fspath(output_file), dpi=page_dpi)
|
||||||
else:
|
else:
|
||||||
copy(tmp.name, output_file)
|
copy(tmp.name, fspath(output_file))
|
||||||
|
|
||||||
|
|
||||||
def generate_pdfa(pdf_pages, output_file, compression, log,
|
def generate_pdfa(pdf_pages, output_file, compression, log,
|
||||||
|
|||||||
@@ -213,7 +213,8 @@ def _generate_null_hocr(output_hocr, output_sidecar, image):
|
|||||||
|
|
||||||
def generate_hocr(input_file, output_files, language: list, engine_mode,
|
def generate_hocr(input_file, output_files, language: list, engine_mode,
|
||||||
tessconfig: list,
|
tessconfig: list,
|
||||||
timeout: float, pagesegmode: int, log):
|
timeout: float, pagesegmode: int, user_words, user_patterns,
|
||||||
|
log):
|
||||||
|
|
||||||
output_hocr = next(o for o in output_files if o.endswith('.hocr'))
|
output_hocr = next(o for o in output_files if o.endswith('.hocr'))
|
||||||
output_sidecar = next(o for o in output_files if o.endswith('.txt'))
|
output_sidecar = next(o for o in output_files if o.endswith('.txt'))
|
||||||
@@ -224,10 +225,17 @@ def generate_hocr(input_file, output_files, language: list, engine_mode,
|
|||||||
if pagesegmode is not None:
|
if pagesegmode is not None:
|
||||||
args_tesseract.extend([psm(), str(pagesegmode)])
|
args_tesseract.extend([psm(), str(pagesegmode)])
|
||||||
|
|
||||||
|
if user_words:
|
||||||
|
args_tesseract.extend(['--user-words', user_words])
|
||||||
|
|
||||||
|
if user_patterns:
|
||||||
|
args_tesseract.extend(['--user-patterns', user_patterns])
|
||||||
|
|
||||||
# Reminder: test suite tesseract spoofers will break after any changes
|
# Reminder: test suite tesseract spoofers will break after any changes
|
||||||
# to the number of order parameters here
|
# to the number of order parameters here
|
||||||
# Tesseract 3.04 requires the order here to be "hocr txt" and will fail
|
# Tesseract 3.04 requires the order here to be "hocr txt" and will fail
|
||||||
# on "txt hocr"
|
# on "txt hocr"
|
||||||
|
|
||||||
args_tesseract.extend([
|
args_tesseract.extend([
|
||||||
input_file,
|
input_file,
|
||||||
prefix,
|
prefix,
|
||||||
@@ -285,7 +293,8 @@ def use_skip_page(text_only, skip_pdf, output_pdf, output_text):
|
|||||||
|
|
||||||
def generate_pdf(*, input_image, skip_pdf, output_pdf, output_text,
|
def generate_pdf(*, input_image, skip_pdf, output_pdf, output_text,
|
||||||
language: list, engine_mode, text_only: bool,
|
language: list, engine_mode, text_only: bool,
|
||||||
tessconfig: list, timeout: float, pagesegmode: int, log):
|
tessconfig: list, timeout: float, pagesegmode: int,
|
||||||
|
user_words, user_patterns, log):
|
||||||
'''Use Tesseract to render a PDF.
|
'''Use Tesseract to render a PDF.
|
||||||
|
|
||||||
input_image -- image to analyze
|
input_image -- image to analyze
|
||||||
@@ -308,10 +317,17 @@ def generate_pdf(*, input_image, skip_pdf, output_pdf, output_text,
|
|||||||
if text_only:
|
if text_only:
|
||||||
args_tesseract.extend(['-c', 'textonly_pdf=1'])
|
args_tesseract.extend(['-c', 'textonly_pdf=1'])
|
||||||
|
|
||||||
|
if user_words:
|
||||||
|
args_tesseract.extend(['--user-words', user_words])
|
||||||
|
|
||||||
|
if user_patterns:
|
||||||
|
args_tesseract.extend(['--user-patterns', user_patterns])
|
||||||
|
|
||||||
prefix = os.path.splitext(output_pdf)[0] # Tesseract appends suffixes
|
prefix = os.path.splitext(output_pdf)[0] # Tesseract appends suffixes
|
||||||
|
|
||||||
# Reminder: test suite tesseract spoofers will break after any changes
|
# Reminder: test suite tesseract spoofers might break after any changes
|
||||||
# to the number of order parameters here
|
# to the number of order parameters here
|
||||||
|
|
||||||
args_tesseract.extend([
|
args_tesseract.extend([
|
||||||
input_image,
|
input_image,
|
||||||
prefix,
|
prefix,
|
||||||
|
|||||||
+37
-4
@@ -79,10 +79,43 @@ def is_file_writable(test_file):
|
|||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
@contextmanager
|
if sys.version_info[0:2] <= (3, 5):
|
||||||
def universal_open(p, *args, **kwargs):
|
def universal_open(p, *args, **kwargs):
|
||||||
"Work around Python 3.5's inability to open(pathlib.Path())"
|
"Work around Python 3.5's inability to open(pathlib.Path())"
|
||||||
try:
|
try:
|
||||||
yield p.open(*args, **kwargs)
|
return p.open(*args, **kwargs)
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
yield open(p, *args, **kwargs)
|
return open(p, *args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
def fspath(path):
|
||||||
|
import pathlib
|
||||||
|
'''https://www.python.org/dev/peps/pep-0519/#os'''
|
||||||
|
if isinstance(path, (str, bytes)):
|
||||||
|
return path
|
||||||
|
|
||||||
|
# Work from the object's type to match method resolution of other magic
|
||||||
|
# methods.
|
||||||
|
path_type = type(path)
|
||||||
|
try:
|
||||||
|
path = path_type.__fspath__(path)
|
||||||
|
except AttributeError:
|
||||||
|
# Added for Python 3.5 support.
|
||||||
|
if isinstance(path, pathlib.Path):
|
||||||
|
return str(path)
|
||||||
|
elif hasattr(path_type, '__fspath__'):
|
||||||
|
raise
|
||||||
|
else:
|
||||||
|
if isinstance(path, (str, bytes)):
|
||||||
|
return path
|
||||||
|
else:
|
||||||
|
raise TypeError("expected __fspath__() to return str or bytes, "
|
||||||
|
"not " + type(path).__name__)
|
||||||
|
|
||||||
|
raise TypeError(
|
||||||
|
"expected str, bytes, pathlib.Path or os.PathLike object, not "
|
||||||
|
+ path_type.__name__)
|
||||||
|
|
||||||
|
else:
|
||||||
|
universal_open = open
|
||||||
|
fspath = os.fspath
|
||||||
@@ -14,6 +14,7 @@ from ctypes.util import find_library
|
|||||||
from .lib._leptonica import ffi
|
from .lib._leptonica import ffi
|
||||||
from functools import lru_cache
|
from functools import lru_cache
|
||||||
from enum import Enum
|
from enum import Enum
|
||||||
|
from .helpers import fspath
|
||||||
|
|
||||||
lept = ffi.dlopen(find_library('lept'))
|
lept = ffi.dlopen(find_library('lept'))
|
||||||
|
|
||||||
@@ -208,26 +209,27 @@ class Pix:
|
|||||||
return 'P'
|
return 'P'
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def read(cls, filename):
|
def read(cls, path):
|
||||||
"""Load an image file into a PIX object.
|
"""Load an image file into a PIX object.
|
||||||
|
|
||||||
Leptonica can load TIFF, PNM (PBM, PGM, PPM), PNG, and JPEG. If
|
Leptonica can load TIFF, PNM (PBM, PGM, PPM), PNG, and JPEG. If
|
||||||
loading fails then the object will wrap a C null pointer.
|
loading fails then the object will wrap a C null pointer.
|
||||||
"""
|
"""
|
||||||
|
filename = fspath(path)
|
||||||
with LeptonicaErrorTrap():
|
with LeptonicaErrorTrap():
|
||||||
return cls(lept.pixRead(
|
return cls(lept.pixRead(os.fsencode(filename)))
|
||||||
filename.encode(sys.getfilesystemencoding())))
|
|
||||||
|
|
||||||
def write_implied_format(
|
def write_implied_format(
|
||||||
self, filename, jpeg_quality=0, jpeg_progressive=0):
|
self, path, jpeg_quality=0, jpeg_progressive=0):
|
||||||
"""Write pix to the filename, with the extension indicating format.
|
"""Write pix to the filename, with the extension indicating format.
|
||||||
|
|
||||||
jpeg_quality -- quality (iff JPEG; 1 - 100, 0 for default)
|
jpeg_quality -- quality (iff JPEG; 1 - 100, 0 for default)
|
||||||
jpeg_progressive -- (iff JPEG; 0 for baseline seq., 1 for progressive)
|
jpeg_progressive -- (iff JPEG; 0 for baseline seq., 1 for progressive)
|
||||||
"""
|
"""
|
||||||
|
filename = fspath(path)
|
||||||
with LeptonicaErrorTrap():
|
with LeptonicaErrorTrap():
|
||||||
lept.pixWriteImpliedFormat(
|
lept.pixWriteImpliedFormat(
|
||||||
filename.encode(sys.getfilesystemencoding()),
|
os.fsencode(filename),
|
||||||
self._pix, jpeg_quality, jpeg_progressive)
|
self._pix, jpeg_quality, jpeg_progressive)
|
||||||
|
|
||||||
def topil(self):
|
def topil(self):
|
||||||
|
|||||||
+12
-6
@@ -165,8 +165,8 @@ def triage(
|
|||||||
options = context.get_options()
|
options = context.get_options()
|
||||||
try:
|
try:
|
||||||
with open(input_file, 'rb') as f:
|
with open(input_file, 'rb') as f:
|
||||||
signature = f.read(4)
|
signature = f.read(1024)
|
||||||
if signature == b'%PDF':
|
if b'%PDF' in signature:
|
||||||
if options.image_dpi:
|
if options.image_dpi:
|
||||||
log.warning("Argument --image-dpi ignored because the "
|
log.warning("Argument --image-dpi ignored because the "
|
||||||
"input file is a PDF, not an image.")
|
"input file is a PDF, not an image.")
|
||||||
@@ -202,7 +202,7 @@ def repair_pdf(
|
|||||||
|
|
||||||
|
|
||||||
def get_pageinfo(input_file, context):
|
def get_pageinfo(input_file, context):
|
||||||
pageno = int(os.path.basename(input_file)[0:6]) - 1
|
pageno = page_number(input_file) - 1
|
||||||
pageinfo = context.get_pdfinfo()[pageno]
|
pageinfo = context.get_pdfinfo()[pageno]
|
||||||
return pageinfo
|
return pageinfo
|
||||||
|
|
||||||
@@ -406,7 +406,7 @@ def orient_page(
|
|||||||
with open(output_file, 'wb') as out:
|
with open(output_file, 'wb') as out:
|
||||||
writer.write(out)
|
writer.write(out)
|
||||||
|
|
||||||
pageno = int(os.path.basename(page_pdf)[0:6]) - 1
|
pageno = page_number(page_pdf) - 1
|
||||||
pdfinfo = context.get_pdfinfo()
|
pdfinfo = context.get_pdfinfo()
|
||||||
pdfinfo[pageno].rotation = orient_conf.angle
|
pdfinfo[pageno].rotation = orient_conf.angle
|
||||||
context.set_pdfinfo(pdfinfo)
|
context.set_pdfinfo(pdfinfo)
|
||||||
@@ -525,6 +525,8 @@ def ocr_tesseract_hocr(
|
|||||||
tessconfig=options.tesseract_config,
|
tessconfig=options.tesseract_config,
|
||||||
timeout=options.tesseract_timeout,
|
timeout=options.tesseract_timeout,
|
||||||
pagesegmode=options.tesseract_pagesegmode,
|
pagesegmode=options.tesseract_pagesegmode,
|
||||||
|
user_words=options.user_words,
|
||||||
|
user_patterns=options.user_patterns,
|
||||||
log=log
|
log=log
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -755,6 +757,8 @@ def ocr_tesseract_and_render_pdf(
|
|||||||
tessconfig=options.tesseract_config,
|
tessconfig=options.tesseract_config,
|
||||||
timeout=options.tesseract_timeout,
|
timeout=options.tesseract_timeout,
|
||||||
pagesegmode=options.tesseract_pagesegmode,
|
pagesegmode=options.tesseract_pagesegmode,
|
||||||
|
user_words=options.user_words,
|
||||||
|
user_patterns=options.user_patterns,
|
||||||
log=log)
|
log=log)
|
||||||
|
|
||||||
|
|
||||||
@@ -783,6 +787,8 @@ def ocr_tesseract_textonly_pdf(
|
|||||||
tessconfig=options.tesseract_config,
|
tessconfig=options.tesseract_config,
|
||||||
timeout=options.tesseract_timeout,
|
timeout=options.tesseract_timeout,
|
||||||
pagesegmode=options.tesseract_pagesegmode,
|
pagesegmode=options.tesseract_pagesegmode,
|
||||||
|
user_words=options.user_words,
|
||||||
|
user_patterns=options.user_patterns,
|
||||||
log=log)
|
log=log)
|
||||||
|
|
||||||
|
|
||||||
@@ -863,7 +869,7 @@ def merge_pages_ghostscript(
|
|||||||
right that way.'''
|
right that way.'''
|
||||||
if s.endswith('.ps'):
|
if s.endswith('.ps'):
|
||||||
return 99999999
|
return 99999999
|
||||||
key = int(os.path.basename(s)[0:6]) * 10
|
key = page_number(s) * 10
|
||||||
if 'debug' in os.path.basename(s):
|
if 'debug' in os.path.basename(s):
|
||||||
key += 1
|
key += 1
|
||||||
return key
|
return key
|
||||||
@@ -898,7 +904,7 @@ def merge_pages_qpdf(
|
|||||||
def input_file_order(s):
|
def input_file_order(s):
|
||||||
'''Sort order: All rendered pages followed
|
'''Sort order: All rendered pages followed
|
||||||
by their debug page.'''
|
by their debug page.'''
|
||||||
key = int(os.path.basename(s)[0:6]) * 10
|
key = page_number(s) * 10
|
||||||
if 'debug' in os.path.basename(s):
|
if 'debug' in os.path.basename(s):
|
||||||
key += 1
|
key += 1
|
||||||
return key
|
return key
|
||||||
|
|||||||
@@ -185,9 +185,15 @@ if 'upload' in sys.argv[1:]:
|
|||||||
|
|
||||||
tests_require = open('test_requirements.txt').read().splitlines()
|
tests_require = open('test_requirements.txt').read().splitlines()
|
||||||
|
|
||||||
|
|
||||||
|
def readme():
|
||||||
|
with open('README.rst') as f:
|
||||||
|
return f.read()
|
||||||
|
|
||||||
setup(
|
setup(
|
||||||
name='ocrmypdf',
|
name='ocrmypdf',
|
||||||
description='OCRmyPDF adds an OCR text layer to scanned PDF files, allowing them to be searched',
|
description='OCRmyPDF adds an OCR text layer to scanned PDF files, allowing them to be searched',
|
||||||
|
long_description=readme(),
|
||||||
url='https://github.com/jbarlow83/OCRmyPDF',
|
url='https://github.com/jbarlow83/OCRmyPDF',
|
||||||
author='James R. Barlow',
|
author='James R. Barlow',
|
||||||
author_email='jim@purplerock.ca',
|
author_email='jim@purplerock.ca',
|
||||||
|
|||||||
+2
-1
@@ -129,7 +129,8 @@ def run_ocrmypdf(input_file, output_file, *args, env=None):
|
|||||||
if env is None:
|
if env is None:
|
||||||
env = os.environ
|
env = os.environ
|
||||||
|
|
||||||
p_args = OCRMYPDF + list(args) + [str(input_file), str(output_file)]
|
p_args = OCRMYPDF + [str(arg) for arg in args] + \
|
||||||
|
[str(input_file), str(output_file)]
|
||||||
p = Popen(
|
p = Popen(
|
||||||
p_args, close_fds=True, stdout=PIPE, stderr=PIPE,
|
p_args, close_fds=True, stdout=PIPE, stderr=PIPE,
|
||||||
universal_newlines=True, env=env)
|
universal_newlines=True, env=env)
|
||||||
|
|||||||
@@ -88,14 +88,18 @@ under the terms of the license in LICENSE.rst.
|
|||||||
* - overlay.pdf
|
* - overlay.pdf
|
||||||
- @maxandersen
|
- @maxandersen
|
||||||
- PDF file generated by PDFPen pro that triggered content stream parse errors
|
- PDF file generated by PDFPen pro that triggered content stream parse errors
|
||||||
* - no_conentes.pdf
|
* - no_contents.pdf
|
||||||
- @jbarlow83
|
- @jbarlow83
|
||||||
- synthetic PDF with a blank page that has no /Contents entry
|
- synthetic PDF with a blank page that has no /Contents entry
|
||||||
|
* - crom.png
|
||||||
|
- @jbarlow83
|
||||||
|
- test for non-dictionary words
|
||||||
|
|
||||||
|
|
||||||
Assemblies
|
Assemblies
|
||||||
==========
|
==========
|
||||||
|
|
||||||
These test resources are assemblies from other previously mentioned files, released under the same license terms as their input files.
|
These test resources are assemblies or derivatives from other previously mentioned files, released under the same license terms as their input files.
|
||||||
|
|
||||||
- cardinal.pdf (four cardinal directions, baked-in rotated copies of LinnSequencer.jpg)
|
- cardinal.pdf (four cardinal directions, baked-in rotated copies of LinnSequencer.jpg)
|
||||||
- ccitt.pdf (LinnSequencer.jpg, converted to CCITT encoding)
|
- ccitt.pdf (LinnSequencer.jpg, converted to CCITT encoding)
|
||||||
@@ -107,6 +111,9 @@ These test resources are assemblies from other previously mentioned files, relea
|
|||||||
- rotated_skew.pdf (a /Rotate'd and skewed document from LinnSequencer.jpg)
|
- rotated_skew.pdf (a /Rotate'd and skewed document from LinnSequencer.jpg)
|
||||||
- skew.pdf (from LinnSequencer.jpg, skew simulated by adjusting the transformation matrix)
|
- skew.pdf (from LinnSequencer.jpg, skew simulated by adjusting the transformation matrix)
|
||||||
- skew-encrypted.pdf (skew.pdf with encryption - access supported by PyPDF2)
|
- skew-encrypted.pdf (skew.pdf with encryption - access supported by PyPDF2)
|
||||||
|
- baiona_gray.png (from baiona.png)
|
||||||
|
- poster.pdf (from LinnSequencer.jpg)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
.. _`Wikimedia: LinnSequencer`: https://upload.wikimedia.org/wikipedia/en/b/b7/LinnSequencer_hardware_MIDI_sequencer_brochure_page_2_300dpi.jpg
|
.. _`Wikimedia: LinnSequencer`: https://upload.wikimedia.org/wikipedia/en/b/b7/LinnSequencer_hardware_MIDI_sequencer_brochure_page_2_300dpi.jpg
|
||||||
|
|||||||
Binary file not shown.
|
After Width: | Height: | Size: 1.3 KiB |
@@ -4,9 +4,9 @@
|
|||||||
import sys
|
import sys
|
||||||
|
|
||||||
|
|
||||||
VERSION_STRING = '''tesseract 3.04.00
|
VERSION_STRING = '''tesseract 3.05.01
|
||||||
leptonica-1.72
|
leptonica-1.74.4
|
||||||
libjpeg 8d : libpng 1.6.19 : libtiff 4.0.6 : zlib 1.2.5
|
libjpeg 9b : libpng 1.6.32 : libtiff 4.0.8 : zlib 1.2.8
|
||||||
SPOOFED: return error claiming image too big
|
SPOOFED: return error claiming image too big
|
||||||
'''
|
'''
|
||||||
|
|
||||||
@@ -20,10 +20,10 @@ def main():
|
|||||||
print(VERSION_STRING, file=sys.stderr)
|
print(VERSION_STRING, file=sys.stderr)
|
||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
elif sys.argv[1] == '--list-langs':
|
elif sys.argv[1] == '--list-langs':
|
||||||
print('List of available languages (1):\neng', file=sys.stderr)
|
print('List of available languages (1):\neng\n', file=sys.stderr)
|
||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
elif sys.argv[1] == '--print-parameters':
|
elif sys.argv[1] == '--print-parameters':
|
||||||
print('A parameter list would go here', file=sys.stderr)
|
print('A parameter list would go here\ntextonly_pdf 0\n', file=sys.stderr)
|
||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
elif sys.argv[-2] == 'hocr':
|
elif sys.argv[-2] == 'hocr':
|
||||||
print("Image too large: (33830, 14959)\n"
|
print("Image too large: (33830, 14959)\n"
|
||||||
|
|||||||
@@ -5,9 +5,9 @@ import os
|
|||||||
import signal
|
import signal
|
||||||
|
|
||||||
|
|
||||||
VERSION_STRING = '''tesseract 3.04.00
|
VERSION_STRING = '''tesseract 3.05.01
|
||||||
leptonica-1.72
|
leptonica-1.74.4
|
||||||
libjpeg 8d : libpng 1.6.19 : libtiff 4.0.6 : zlib 1.2.5
|
libjpeg 9b : libpng 1.6.32 : libtiff 4.0.8 : zlib 1.2.8
|
||||||
SPOOFED: CRASH ON OCR or -psm 0
|
SPOOFED: CRASH ON OCR or -psm 0
|
||||||
'''
|
'''
|
||||||
|
|
||||||
@@ -30,7 +30,8 @@ def main():
|
|||||||
print('List of available languages (1):\neng', file=sys.stderr)
|
print('List of available languages (1):\neng', file=sys.stderr)
|
||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
elif sys.argv[1] == '--print-parameters':
|
elif sys.argv[1] == '--print-parameters':
|
||||||
print('List of parameters would go here', file=sys.stderr)
|
print('A parameter list would go here\ntextonly_pdf 0\n',
|
||||||
|
file=sys.stderr)
|
||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
elif sys.argv[-2] == 'hocr':
|
elif sys.argv[-2] == 'hocr':
|
||||||
print("KABOOM! Tesseract failed for some reason", file=sys.stderr)
|
print("KABOOM! Tesseract failed for some reason", file=sys.stderr)
|
||||||
|
|||||||
+48
-17
@@ -77,8 +77,8 @@ def test_deskew(spoof_tesseract_noop, resources, outdir):
|
|||||||
deskewed_png = outdir / 'deskewed.png'
|
deskewed_png = outdir / 'deskewed.png'
|
||||||
|
|
||||||
ghostscript.rasterize_pdf(
|
ghostscript.rasterize_pdf(
|
||||||
str(deskewed_pdf),
|
deskewed_pdf,
|
||||||
str(deskewed_png),
|
deskewed_png,
|
||||||
xres=150,
|
xres=150,
|
||||||
yres=150,
|
yres=150,
|
||||||
raster_device='pngmono',
|
raster_device='pngmono',
|
||||||
@@ -116,8 +116,8 @@ def test_remove_background(spoof_tesseract_noop, resources, outdir):
|
|||||||
output_png = outdir / 'remove_bg.png'
|
output_png = outdir / 'remove_bg.png'
|
||||||
|
|
||||||
ghostscript.rasterize_pdf(
|
ghostscript.rasterize_pdf(
|
||||||
str(output_pdf),
|
output_pdf,
|
||||||
str(output_png),
|
output_png,
|
||||||
xres=100,
|
xres=100,
|
||||||
yres=100,
|
yres=100,
|
||||||
raster_device='png16m',
|
raster_device='png16m',
|
||||||
@@ -270,9 +270,7 @@ def check_monochrome_correlation(
|
|||||||
print(png)
|
print(png)
|
||||||
return
|
return
|
||||||
ghostscript.rasterize_pdf(
|
ghostscript.rasterize_pdf(
|
||||||
str(pdf),
|
pdf, png, xres=100, yres=100,
|
||||||
str(png),
|
|
||||||
xres=100, yres=100,
|
|
||||||
raster_device='pngmono', log=gslog, pageno=pageno)
|
raster_device='pngmono', log=gslog, pageno=pageno)
|
||||||
|
|
||||||
rasterize(reference_pdf, reference_pageno, reference_png)
|
rasterize(reference_pdf, reference_pageno, reference_png)
|
||||||
@@ -406,9 +404,13 @@ def test_force_ocr_on_pdf_with_no_images(spoof_tesseract_crash, resources,
|
|||||||
@pytest.mark.skipif(
|
@pytest.mark.skipif(
|
||||||
pytest.helpers.is_macos() and pytest.helpers.running_in_travis(),
|
pytest.helpers.is_macos() and pytest.helpers.running_in_travis(),
|
||||||
reason="takes too long to install language packs in Travis macOS homebrew")
|
reason="takes too long to install language packs in Travis macOS homebrew")
|
||||||
def test_french(spoof_tesseract_cache, resources, outpdf):
|
def test_french(spoof_tesseract_cache, resources, outdir):
|
||||||
|
# Produce a sidecar too - implicit test that system locale is set up
|
||||||
|
# properly
|
||||||
|
sidecar = outdir / 'francais.txt'
|
||||||
p, out, err = run_ocrmypdf(
|
p, out, err = run_ocrmypdf(
|
||||||
resources / 'francais.pdf', outpdf, '-l', 'fra',
|
resources / 'francais.pdf', outdir / 'francais.pdf', '-l', 'fra',
|
||||||
|
'--sidecar', sidecar,
|
||||||
env=spoof_tesseract_cache)
|
env=spoof_tesseract_cache)
|
||||||
print(os.environ)
|
print(os.environ)
|
||||||
assert p.returncode == ExitCode.ok, \
|
assert p.returncode == ExitCode.ok, \
|
||||||
@@ -418,7 +420,7 @@ def test_french(spoof_tesseract_cache, resources, outpdf):
|
|||||||
def test_klingon(resources, outpdf):
|
def test_klingon(resources, outpdf):
|
||||||
p, out, err = run_ocrmypdf(
|
p, out, err = run_ocrmypdf(
|
||||||
resources / 'francais.pdf', outpdf, '-l', 'klz')
|
resources / 'francais.pdf', outpdf, '-l', 'klz')
|
||||||
assert p.returncode == ExitCode.bad_args
|
assert p.returncode == ExitCode.missing_dependency
|
||||||
|
|
||||||
|
|
||||||
def test_missing_docinfo(spoof_tesseract_noop, resources, outpdf):
|
def test_missing_docinfo(spoof_tesseract_noop, resources, outpdf):
|
||||||
@@ -485,10 +487,7 @@ def test_pagesegmode(renderer, spoof_tesseract_cache, resources, outpdf):
|
|||||||
'--pdf-renderer', renderer, env=spoof_tesseract_cache)
|
'--pdf-renderer', renderer, env=spoof_tesseract_cache)
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize('renderer', [
|
@pytest.mark.parametrize('renderer', RENDERERS)
|
||||||
'hocr',
|
|
||||||
'tesseract',
|
|
||||||
])
|
|
||||||
def test_tesseract_crash(renderer, spoof_tesseract_crash,
|
def test_tesseract_crash(renderer, spoof_tesseract_crash,
|
||||||
resources, no_outpdf):
|
resources, no_outpdf):
|
||||||
p, out, err = run_ocrmypdf(
|
p, out, err = run_ocrmypdf(
|
||||||
@@ -760,7 +759,7 @@ language_model_penalty_non_freq_dict_word 0
|
|||||||
|
|
||||||
check_ocrmypdf(
|
check_ocrmypdf(
|
||||||
resources / 'ccitt.pdf', outdir / 'out.pdf',
|
resources / 'ccitt.pdf', outdir / 'out.pdf',
|
||||||
'--tesseract-config', str(cfg_file))
|
'--tesseract-config', cfg_file)
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize('renderer', RENDERERS)
|
@pytest.mark.parametrize('renderer', RENDERERS)
|
||||||
@@ -770,7 +769,7 @@ def test_tesseract_config_notfound(renderer, resources, outdir):
|
|||||||
p, out, err = run_ocrmypdf(
|
p, out, err = run_ocrmypdf(
|
||||||
resources / 'ccitt.pdf', outdir / 'out.pdf',
|
resources / 'ccitt.pdf', outdir / 'out.pdf',
|
||||||
'--pdf-renderer', renderer,
|
'--pdf-renderer', renderer,
|
||||||
'--tesseract-config', str(cfg_file))
|
'--tesseract-config', cfg_file)
|
||||||
assert "Can't open" in err, "No error message about missing config file"
|
assert "Can't open" in err, "No error message about missing config file"
|
||||||
assert p.returncode == ExitCode.ok
|
assert p.returncode == ExitCode.ok
|
||||||
|
|
||||||
@@ -786,11 +785,43 @@ THIS FILE IS INVALID
|
|||||||
p, out, err = run_ocrmypdf(
|
p, out, err = run_ocrmypdf(
|
||||||
resources / 'ccitt.pdf', outdir / 'out.pdf',
|
resources / 'ccitt.pdf', outdir / 'out.pdf',
|
||||||
'--pdf-renderer', renderer,
|
'--pdf-renderer', renderer,
|
||||||
'--tesseract-config', str(cfg_file))
|
'--tesseract-config', cfg_file)
|
||||||
assert "parameter not found" in err, "No error message"
|
assert "parameter not found" in err, "No error message"
|
||||||
assert p.returncode == ExitCode.invalid_config
|
assert p.returncode == ExitCode.invalid_config
|
||||||
|
|
||||||
|
|
||||||
|
def test_user_words(resources, outdir):
|
||||||
|
word_list = outdir / 'wordlist.txt'
|
||||||
|
sidecar_before = outdir / 'sidecar_before.txt'
|
||||||
|
sidecar_after = outdir / 'sidecar_after.txt'
|
||||||
|
|
||||||
|
# Don't know how to make this test pass on various versions and platforms
|
||||||
|
# so weaken to merely testing that the argument is accepted
|
||||||
|
consistent = False
|
||||||
|
|
||||||
|
if consistent:
|
||||||
|
check_ocrmypdf(
|
||||||
|
resources / 'crom.png', outdir / 'out.pdf',
|
||||||
|
'--image-dpi', 150,
|
||||||
|
'--sidecar', sidecar_before
|
||||||
|
)
|
||||||
|
|
||||||
|
assert 'cromulent' not in sidecar_before.open().read()
|
||||||
|
|
||||||
|
with word_list.open('w') as f:
|
||||||
|
f.write('cromulent\n') # a perfectly cromulent word
|
||||||
|
|
||||||
|
check_ocrmypdf(
|
||||||
|
resources / 'crom.png', outdir / 'out.pdf',
|
||||||
|
'--image-dpi', 150,
|
||||||
|
'--sidecar', sidecar_after,
|
||||||
|
'--user-words', word_list
|
||||||
|
)
|
||||||
|
|
||||||
|
if consistent:
|
||||||
|
assert 'cromulent' in sidecar_after.open().read()
|
||||||
|
|
||||||
|
|
||||||
def test_form_xobject(spoof_tesseract_noop, resources, outpdf):
|
def test_form_xobject(spoof_tesseract_noop, resources, outpdf):
|
||||||
check_ocrmypdf(resources / 'formxobject.pdf', outpdf,
|
check_ocrmypdf(resources / 'formxobject.pdf', outpdf,
|
||||||
'--force-ocr',
|
'--force-ocr',
|
||||||
|
|||||||
Reference in New Issue
Block a user