Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
79b3472b26 | ||
|
|
f1b2f1ae08 | ||
|
|
ee7d97ae8c | ||
|
|
7d9f473bb1 | ||
|
|
e77a5e5e75 | ||
|
|
6ab19af122 | ||
|
|
276fe49867 | ||
|
|
acb31abe86 | ||
|
|
4f964a3c8a | ||
|
|
df1fda7438 | ||
|
|
d6124c1787 | ||
|
|
80d89b5420 | ||
|
|
74059eecf1 | ||
|
|
78697341a2 | ||
|
|
cfb56dd8ff | ||
|
|
b1769cbe18 | ||
|
|
955b801e7f | ||
|
|
3cea3f1afe | ||
|
|
fd4a227ccb | ||
|
|
19c3097483 | ||
|
|
cdd1a6d03c | ||
|
|
5fb8411571 | ||
|
|
334a15b8c7 | ||
|
|
6390736577 | ||
|
|
d55a214516 | ||
|
|
0994164b9a | ||
|
|
54ee0dd147 | ||
|
|
47c7990fb3 | ||
|
|
997e95de4d | ||
|
|
44204be256 | ||
|
|
9b1d9aa88a | ||
|
|
b775762f6a | ||
|
|
df1a28e319 | ||
|
|
c300b2802a | ||
|
|
01040ace4c | ||
|
|
8367172e0b | ||
|
|
09afd8d25d | ||
|
|
7ed60429b3 | ||
|
|
281eafada0 | ||
|
|
c14e10128a | ||
|
|
3270635192 | ||
|
|
3d26257710 | ||
|
|
c4f134d694 | ||
|
|
83f9dfbac4 | ||
|
|
3a445ad5f7 | ||
|
|
c6d106ec33 | ||
|
|
2ce6834be4 | ||
|
|
b376672dbc | ||
|
|
d07db8547f | ||
|
|
aab08bfcc7 | ||
|
|
e0a25494ee |
@@ -9,9 +9,15 @@ build/
|
|||||||
dist/
|
dist/
|
||||||
*.egg-info/
|
*.egg-info/
|
||||||
venv/
|
venv/
|
||||||
|
venv-3.4/
|
||||||
|
venv-3.5/
|
||||||
*/test/output
|
*/test/output
|
||||||
bin/
|
bin/
|
||||||
include/
|
include/
|
||||||
lib/
|
lib/
|
||||||
pip-selfcheck.json
|
pip-selfcheck.json
|
||||||
pyvenv.cfg
|
pyvenv.cfg
|
||||||
|
htmlcov/
|
||||||
|
.coverage
|
||||||
|
.cache/
|
||||||
|
.ipynb_checkpoints/
|
||||||
|
|||||||
+41
@@ -0,0 +1,41 @@
|
|||||||
|
language: python
|
||||||
|
|
||||||
|
cache:
|
||||||
|
directories:
|
||||||
|
- $HOME/.cache/pip
|
||||||
|
- $HOME/.ccache
|
||||||
|
- tarballs
|
||||||
|
|
||||||
|
python:
|
||||||
|
- 3.4
|
||||||
|
|
||||||
|
before_install:
|
||||||
|
# Ubuntu packages
|
||||||
|
- sudo add-apt-repository ppa:evl.ms/precise -y # for Ghostscript 9.15
|
||||||
|
- sudo add-apt-repository ppa:lyrasis/precise-backports -y # for Tesseract 3.03
|
||||||
|
- sudo add-apt-repository ppa:b-eltzner/qpdfview-exp -y # for QPDF 5
|
||||||
|
- sudo add-apt-repository ppa:itachi-san/ffmpeg -y # for libav 11.2 (for unpaper)
|
||||||
|
- sudo apt-get update -qq # must go after all add-apt-repo
|
||||||
|
- sudo apt-get install -y ghostscript tesseract-ocr tesseract-ocr-deu tesseract-ocr-eng tesseract-ocr-fra qpdf poppler-utils gcc libavformat-dev libavcodec-dev libavutil-dev automake make pkg-config xsltproc
|
||||||
|
|
||||||
|
# pip
|
||||||
|
- pip install --upgrade pip
|
||||||
|
|
||||||
|
# Download, make and install unpaper (using ccache)
|
||||||
|
- mkdir -p tarballs
|
||||||
|
- "[ -f tarballs/unpaper-6.1.tar.xz ] || wget -q https://www.flameeyes.eu/files/unpaper-6.1.tar.xz -O tarballs/unpaper-6.1.tar.xz"
|
||||||
|
- tar -xvf tarballs/unpaper-6.1.tar.xz
|
||||||
|
- export PATH="/usr/lib/ccache:$PATH"
|
||||||
|
- pushd unpaper-6.1 && ./configure --prefix=/usr && make -j && sudo make install && popd
|
||||||
|
|
||||||
|
install:
|
||||||
|
- pip install -r requirements.txt
|
||||||
|
- pip install -r test_requirements.txt
|
||||||
|
|
||||||
|
script:
|
||||||
|
- python setup.py clean
|
||||||
|
- python setup.py install
|
||||||
|
- py.test
|
||||||
|
|
||||||
|
os:
|
||||||
|
- linux
|
||||||
+3
-2
@@ -44,12 +44,13 @@ RUN apt-get install -y \
|
|||||||
xsltproc
|
xsltproc
|
||||||
|
|
||||||
WORKDIR /root
|
WORKDIR /root
|
||||||
RUN wget https://github.com/Flameeyes/unpaper/archive/unpaper-6.1.tar.gz
|
RUN wget -q https://github.com/Flameeyes/unpaper/archive/unpaper-6.1.tar.gz
|
||||||
RUN tar xf unpaper-6.1.tar.gz
|
RUN tar xf unpaper-6.1.tar.gz
|
||||||
WORKDIR /root/unpaper-unpaper-6.1
|
WORKDIR /root/unpaper-unpaper-6.1
|
||||||
RUN autoreconf -i
|
RUN autoreconf -i
|
||||||
RUN ./configure CFLAGS="-O2 -march=native -pipe -flto"
|
RUN ./configure CFLAGS="-O2 -march=native -pipe -flto"
|
||||||
RUN make -j install
|
RUN make -j install
|
||||||
|
WORKDIR /
|
||||||
|
|
||||||
RUN apt-get remove -y \
|
RUN apt-get remove -y \
|
||||||
gcc \
|
gcc \
|
||||||
@@ -59,7 +60,7 @@ RUN apt-get remove -y \
|
|||||||
xsltproc \
|
xsltproc \
|
||||||
make
|
make
|
||||||
RUN apt-get autoremove -y && apt-get clean -y
|
RUN apt-get autoremove -y && apt-get clean -y
|
||||||
RUN rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
|
RUN rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* /root/*
|
||||||
|
|
||||||
# Set up a Python virtualenv and take all of the system packages, so we can
|
# Set up a Python virtualenv and take all of the system packages, so we can
|
||||||
# rely on the platform packages rather than importing GCC and compiling them
|
# rely on the platform packages rather than importing GCC and compiling them
|
||||||
|
|||||||
@@ -1 +1,3 @@
|
|||||||
recursive-exclude tests/output *
|
recursive-exclude tests/output *
|
||||||
|
include requirements.txt
|
||||||
|
include test_requirements.txt
|
||||||
+51
-28
@@ -10,23 +10,25 @@ Main features
|
|||||||
- Generates a searchable
|
- Generates a searchable
|
||||||
`PDF/A <https://en.wikipedia.org/?title=PDF/A>`__ file from a regular PDF
|
`PDF/A <https://en.wikipedia.org/?title=PDF/A>`__ file from a regular PDF
|
||||||
only containing images
|
only containing images
|
||||||
- Places OCRed text accurately below the image to ease copy / paste
|
- Places OCR text accurately below the image to ease copy / paste
|
||||||
- Keeps the exact resolution of the original embedded images
|
- Keeps the exact resolution of the original embedded images
|
||||||
|
|
||||||
- or if requested oversamples the images before OCRing so as to get
|
- or if requested oversamples the images before OCRing so as to get
|
||||||
better results
|
better results
|
||||||
|
|
||||||
- When possible, copies input images directly to output without transcoding them,
|
- When possible, copies input images directly to output without transcoding,
|
||||||
to preserve image quality
|
to preserve image quality
|
||||||
- Keeps file size about the same
|
- Keeps file size about the same
|
||||||
- If requested deskews and/or cleans the image before performing OCR
|
- If requested deskews and/or cleans the image before performing OCR
|
||||||
- Validates input and output files
|
- Validates input and output files
|
||||||
- Provides debug mode to enable easy verification of the OCR results
|
- Provides debug mode to enable easy verification of the OCR results
|
||||||
- Processes several pages in parallel when more than one CPU core is
|
- Processes pages in parallel when more than one CPU core is
|
||||||
available
|
available
|
||||||
- Uses Tesseract OCR engine
|
- Uses `Tesseract OCR <https://github.com/tesseract-ocr/tesseract>`__ engine
|
||||||
|
- Supports the `39 languages <https://code.google.com/p/tesseract-ocr/downloads/list>`__ recognized by Tesseract
|
||||||
|
- Battle-tested on thousands of PDFs, a test suite and continuous integration
|
||||||
|
|
||||||
For details: please consult the `release notes <RELEASE_NOTES.rst>`__
|
For details: please consult the `release notes <RELEASE_NOTES.rst>`__.
|
||||||
|
|
||||||
Motivation
|
Motivation
|
||||||
----------
|
----------
|
||||||
@@ -48,14 +50,14 @@ as an inspiration)
|
|||||||
Installation
|
Installation
|
||||||
------------
|
------------
|
||||||
|
|
||||||
Download OCRmyPDF here: https://github.com/fritz-hh/OCRmyPDF/releases
|
Download OCRmyPDF here: https://github.com/jbarlow83/OCRmyPDF/releases
|
||||||
|
|
||||||
You can install it to a Python virtual environment or system-wide.
|
You can install it to a Python virtual environment or system-wide.
|
||||||
|
|
||||||
Installing the Docker container
|
Installing the Docker container
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
For many users, installing the Docker container will be easier than installing all of OCRmyPDF's dependencies.
|
For many users, installing the Docker container will be easier than installing all of OCRmyPDF's dependencies. For Windows, it is the only option.
|
||||||
|
|
||||||
If you have `Docker <https://docs.docker.com/>`__ installed on your system, you can install
|
If you have `Docker <https://docs.docker.com/>`__ installed on your system, you can install
|
||||||
a Docker container of the latest release.
|
a Docker container of the latest release.
|
||||||
@@ -65,33 +67,43 @@ successfully, your system is ready to download and execute the image::
|
|||||||
|
|
||||||
docker run hello-world
|
docker run hello-world
|
||||||
|
|
||||||
|
OCRmyPDF will use all available CPU cores. By default, the VirtualBox machine instance on Windows and OS X has only a single CPU core enabled. Use the VirtualBox Manager to determine the name of your Docker container host, and then follow these optional steps to enable multiple CPUs::
|
||||||
|
|
||||||
|
# Optional
|
||||||
|
docker-machine stop "yourVM"
|
||||||
|
VBoxManage modifyvm "yourVM" --cpus 2 # or whatever number of core is desired
|
||||||
|
docker-machine start "yourVM"
|
||||||
|
eval $(docker-machine env "yourVM")
|
||||||
|
|
||||||
Assuming you have a Docker engine running somewhere, you can run these commands to download
|
Assuming you have a Docker engine running somewhere, you can run these commands to download
|
||||||
the image::
|
the image::
|
||||||
|
|
||||||
docker pull jbarlow83/ocrmypdf
|
docker pull jbarlow83/ocrmypdf
|
||||||
|
|
||||||
Then give it a more friendly, local name::
|
Then tag it to give a more convenient name, just ocrmypdf::
|
||||||
|
|
||||||
docker tag jbarlow83/ocrmypdf ocrmypdf
|
docker tag jbarlow83/ocrmypdf ocrmypdf
|
||||||
|
|
||||||
You can then run using the simple command::
|
You can then run using the command::
|
||||||
|
|
||||||
docker run ocrmypdf --help
|
docker run ocrmypdf --help
|
||||||
|
|
||||||
To execute the OCRmyPDF on a local file, you must `provide a writable volume to the Docker image <https://docs.docker.com/userguide/dockervolumes/>`__, such as this in this template::
|
To execute the OCRmyPDF on a local file, you must `provide a writable volume to the Docker image <https://docs.docker.com/userguide/dockervolumes/>`__, such as this in this template::
|
||||||
|
|
||||||
docker run -v "$(pwd):/home/docker" ocrmypdf <your arguments>
|
docker run -v "$(pwd):/home/docker" <other docker arguments> ocrmypdf <your arguments to ocrmypdf>
|
||||||
|
|
||||||
In this worked example, the current working directory contains an input file called `test.pdf` and the output will go to `output.pdf`::
|
In this worked example, the current working directory contains an input file called ``test.pdf`` and the output will go to ``output.pdf``::
|
||||||
|
|
||||||
docker run -v "$(pwd):/home/docker" ocrmypdf --skip-text test.pdf output.pdf
|
docker run -v "$(pwd):/home/docker" ocrmypdf --skip-text test.pdf output.pdf
|
||||||
|
|
||||||
Note that `ocrmypdf` has its own separate -v argument to control debug verbosity.
|
Note that ``ocrmypdf`` has its own separate ``-v VERBOSITYLEVEL`` argument to control debug verbosity. All Docker arguments should before the ``ocrmypdf`` container name and all arguments to ``ocrmypdf`` should be listed after.
|
||||||
|
|
||||||
Installing on Mac OS X Yosemite
|
Installing on Mac OS X
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
If it's not already present, `install Homebrew <http://brew.sh/>`__
|
These instructions probably work on all Mac OS X versions later than 10.7 (Lion). OCRmyPDF is known to work on Yosemite and El Capitan, and regularly tested on El Capitan.
|
||||||
|
|
||||||
|
If it's not already present, `install Homebrew <http://brew.sh/>`__.
|
||||||
|
|
||||||
Update Homebrew::
|
Update Homebrew::
|
||||||
|
|
||||||
@@ -112,7 +124,7 @@ It is also recommended that install Pillow and confirm it can read and write JPE
|
|||||||
pip3 install --upgrade pip
|
pip3 install --upgrade pip
|
||||||
pip3 install --upgrade pillow
|
pip3 install --upgrade pillow
|
||||||
|
|
||||||
To test that your Python imaging library (Pillow) can access JPEG and PNG files, try this command::
|
Sometimes, the Python imaging library (Pillow) can end up being compiled and installed without support for JPEG and PNG files. (Arguably, this is an unfixed bug in Pillow's installer.) To confirm that Pillow is compiled correctly and can access JPEG and PNG files, try this command::
|
||||||
|
|
||||||
python3 -c "from PIL import Image; im = Image.new('1', (1, 1)); im.save('test.png'); im.save('test.jpg')"
|
python3 -c "from PIL import Image; im = Image.new('1', (1, 1)); im.save('test.png'); im.save('test.jpg')"
|
||||||
|
|
||||||
@@ -129,7 +141,7 @@ The command line program should now be available::
|
|||||||
Installing on Ubuntu 14.04 LTS
|
Installing on Ubuntu 14.04 LTS
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
Installing on Ubuntu 14.04 LTS (trusty) is more difficult than other options.
|
Installing on Ubuntu 14.04 LTS (trusty) is more difficult than other options, because of certain bugs in Python package installation.
|
||||||
|
|
||||||
Update apt-get::
|
Update apt-get::
|
||||||
|
|
||||||
@@ -168,34 +180,45 @@ package <http://www.thefourtheye.in/2014/12/Python-venv-problem-with-ensurepip-i
|
|||||||
source venv-ocrmypdf/bin/activate
|
source venv-ocrmypdf/bin/activate
|
||||||
pip install ocrmypdf
|
pip install ocrmypdf
|
||||||
|
|
||||||
Ubuntu 14.04 only installs `unpaper` version 0.4.2, which is not supported by OCRmyPDF because it is produces invalid output. This program is an optional dependency, and provides page deskewing and cleaning. See `Dockerfile <Dockerfile>`__ for an example of how to building unpaper 6.1 from source. If you choose to install unpaper later, OCRmyPDF will use the foremost version on the system PATH.
|
Ubuntu 14.04 only installs ``unpaper`` version 0.4.2, which is not supported by OCRmyPDF because it is produces invalid output. This program is an optional dependency, and provides page deskewing and cleaning. See `Dockerfile <Dockerfile>`__ for an example of how to building unpaper 6.1 from source. If you choose to install unpaper later, OCRmyPDF will use the foremost version on the system PATH.
|
||||||
|
|
||||||
|
|
||||||
Installing HEAD revision from sources
|
Installing HEAD revision from sources
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
To install the HEAD revision from sources in development mode::
|
If you have ``git`` and ``python3.4`` or ``python3.5`` installed, you can install from source. When the ``pip`` installer runs,
|
||||||
|
it will alert you if dependencies are missing.
|
||||||
|
|
||||||
git clone -b master https://github.com/fritz-hh/OCRmyPDF.git
|
First, clone the HEAD revision::
|
||||||
|
|
||||||
|
git clone -b master https://github.com/jbarlow83/OCRmyPDF.git
|
||||||
cd OCRmyPDF
|
cd OCRmyPDF
|
||||||
|
|
||||||
|
To install the HEAD revision from sources::
|
||||||
|
|
||||||
|
pip3 install .
|
||||||
|
|
||||||
|
Or, to install in `development mode <https://pythonhosted.org/setuptools/setuptools.html#development-mode>`__,
|
||||||
|
allowing customization of OCRmyPDF, use the ``-e`` flag::
|
||||||
|
|
||||||
pip3 install -e .
|
pip3 install -e .
|
||||||
|
|
||||||
On certain Linux/UNIX platforms such as Ubuntu, you may need to use
|
On certain Linux distributions such as Ubuntu, you may need to use
|
||||||
run the install command as superuser::
|
run the install command as superuser::
|
||||||
|
|
||||||
sudo pip3 install -e .
|
sudo pip3 install [-e] .
|
||||||
|
|
||||||
Note that this will alter your system's Python distribution. If you prefer
|
Note that this will alter your system's Python distribution. If you prefer
|
||||||
to not install as superuser, you can install the package in a Python virtual environment::
|
to not install as superuser, you can install the package in a Python virtual environment::
|
||||||
|
|
||||||
git clone -b master https://github.com/fritz-hh/OCRmyPDF.git
|
git clone -b master https://github.com/jbarlow83/OCRmyPDF.git
|
||||||
pyvenv venv
|
pyvenv venv
|
||||||
source venv/bin/activate
|
source venv/bin/activate
|
||||||
cd OCRmyPDF
|
cd OCRmyPDF
|
||||||
pip3 install -e .
|
pip3 install .
|
||||||
|
|
||||||
If your platform does not have ``pip3``, make sure that Python 3.4+ and the `pip`
|
However, ``ocrmypdf`` will only be accessible on the system PATH after
|
||||||
package are installed.
|
you activate the virtual environment.
|
||||||
|
|
||||||
To run the program::
|
To run the program::
|
||||||
|
|
||||||
@@ -213,10 +236,10 @@ In case you detect an issue, please:
|
|||||||
|
|
||||||
- Check if your issue is already known
|
- Check if your issue is already known
|
||||||
- If no problem report exists on github, please create one here:
|
- If no problem report exists on github, please create one here:
|
||||||
https://github.com/fritz-hh/OCRmyPDF/issues
|
https://github.com/jbarlow83/OCRmyPDF/issues
|
||||||
- Describe your problem thoroughly
|
- Describe your problem thoroughly
|
||||||
- Append the console output of the script when running the debug mode
|
- Append the console output of the script when running the debug mode
|
||||||
(-v 1 option)
|
(``-v 1`` option)
|
||||||
- If possible provide your input PDF file as well as the content of the
|
- If possible provide your input PDF file as well as the content of the
|
||||||
temporary folder (using a file sharing service like
|
temporary folder (using a file sharing service like
|
||||||
www.file-upload.net)
|
www.file-upload.net)
|
||||||
|
|||||||
+48
-3
@@ -3,7 +3,26 @@ RELEASE NOTES
|
|||||||
|
|
||||||
Please always read this file before installing the package
|
Please always read this file before installing the package
|
||||||
|
|
||||||
Download software here: https://github.com/fritz-hh/OCRmyPDF/tags
|
Download software here: https://github.com/jbarlow83/OCRmyPDF/tags
|
||||||
|
|
||||||
|
|
||||||
|
v3.1:
|
||||||
|
=====
|
||||||
|
|
||||||
|
Changes
|
||||||
|
-------
|
||||||
|
|
||||||
|
- Default output format is now PDF/A-2b instead of PDF/A-1b
|
||||||
|
- Python 3.5 and OS X El Capitan are now supported platforms - no changes were
|
||||||
|
needed to implement support
|
||||||
|
- Improved some error messages related to missing input files
|
||||||
|
- Fixed issue #20 - uppercase .PDF extension not accepted
|
||||||
|
- Fixed an issue where OCRmyPDF failed to text that certain pages contained previously OCR'ed text,
|
||||||
|
such as OCR text produced by Tesseract 3.04
|
||||||
|
- Inserts /Creator tag into PDFs so that errors can be traced back to this project
|
||||||
|
- Added new option --pdf-renderer=auto, to let OCRmyPDF pick the best PDF renderer.
|
||||||
|
Currently it always chooses the 'hocrtransform' renderer but that behavior may change.
|
||||||
|
- Set up Travis CI automatic integration testing
|
||||||
|
|
||||||
v3.0:
|
v3.0:
|
||||||
=====
|
=====
|
||||||
@@ -21,18 +40,23 @@ New features
|
|||||||
- PDF metadata (title, author, keywords) are now transferred to the
|
- PDF metadata (title, author, keywords) are now transferred to the
|
||||||
output PDF
|
output PDF
|
||||||
- PDF metadata can also be set from the command line (``--title``, etc.)
|
- PDF metadata can also be set from the command line (``--title``, etc.)
|
||||||
|
- Automatic repairs malformed input PDFs if possible
|
||||||
- Added test cases to confirm everything is working
|
- Added test cases to confirm everything is working
|
||||||
- Added option to skip extremely large pages that take too long to OCR and are
|
- Added option to skip extremely large pages that take too long to OCR and are
|
||||||
often not OCRable (e.g. large scanned maps or diagrams); other pages are still
|
often not OCRable (e.g. large scanned maps or diagrams); other pages are still
|
||||||
processed (``--skip-big``)
|
processed (``--skip-big``)
|
||||||
- Added option to kill Tesseract OCR process if it seems to be taking too long on
|
- Added option to kill Tesseract OCR process if it seems to be taking too long on
|
||||||
a page, while still processing other pages (``--tesseract-timeout``)
|
a page, while still processing other pages (``--tesseract-timeout``)
|
||||||
|
- Less common colorspaces (CMYK, palette) are now supported by conversion to RGB
|
||||||
|
- Multiple images on the same PDF page are now supported
|
||||||
|
|
||||||
Changes
|
Changes
|
||||||
-------
|
-------
|
||||||
|
|
||||||
- New, robust rewrite in Python 3.4+ with ruffus_ pipelines
|
- New, robust rewrite in Python 3.4+ with ruffus_ pipelines
|
||||||
- Now uses Ghostscript 9.14's improved color conversion model to preserve PDF colors
|
- Now uses Ghostscript 9.14's improved color conversion model to preserve PDF colors
|
||||||
|
- OCR text is now rendered in the PDF as invisible text. Previous versions of OCRmyPDF
|
||||||
|
incorrectly rendered visible text with an image on top.
|
||||||
- All "tasks" in the pipeline can be executed in parallel on any
|
- All "tasks" in the pipeline can be executed in parallel on any
|
||||||
available CPUs, increasing performance
|
available CPUs, increasing performance
|
||||||
- The ``-o DPI`` argument has been phased out, in favor of ``--oversample DPI``, in
|
- The ``-o DPI`` argument has been phased out, in favor of ``--oversample DPI``, in
|
||||||
@@ -67,6 +91,21 @@ Changes
|
|||||||
Release candidates
|
Release candidates
|
||||||
------------------
|
------------------
|
||||||
|
|
||||||
|
- rc9:
|
||||||
|
|
||||||
|
- fix issue #118: report error if ghostscript iccprofiles are missing
|
||||||
|
- fixed another issue related to #111: PDF rasterized to palette file
|
||||||
|
- add support image files with a palette
|
||||||
|
- don't try to validate PDF file after an exception occurs
|
||||||
|
|
||||||
|
- rc8:
|
||||||
|
|
||||||
|
- fix issue #111: exception thrown if PDF is missing DocumentInfo dictionary
|
||||||
|
|
||||||
|
- rc7:
|
||||||
|
|
||||||
|
- fix error when installing direct from pip, "no such file 'requirements.txt'"
|
||||||
|
|
||||||
- rc6:
|
- rc6:
|
||||||
|
|
||||||
- dropped libxml2 (Python lxml) since Python 3's internal XML parser is sufficient
|
- dropped libxml2 (Python lxml) since Python 3's internal XML parser is sufficient
|
||||||
@@ -122,12 +161,18 @@ Fixes
|
|||||||
|
|
||||||
- Handling of filenames containing spaces: fixed
|
- Handling of filenames containing spaces: fixed
|
||||||
|
|
||||||
Notes
|
Notes and known issues
|
||||||
-----
|
----------------------
|
||||||
|
|
||||||
- Some dependencies may work with lower versions than tested, so try
|
- Some dependencies may work with lower versions than tested, so try
|
||||||
overriding dependencies if they are "in the way" to see if they work.
|
overriding dependencies if they are "in the way" to see if they work.
|
||||||
|
|
||||||
|
- ``--pdf-renderer tesseract`` will output files with an incorrect page size in Tesseract 3.03,
|
||||||
|
due to a bug in Tesseract.
|
||||||
|
|
||||||
|
- PDF files containing "inline images" are not supported and won't be for the 3.0 release. Scanned
|
||||||
|
images almost never contain inline images.
|
||||||
|
|
||||||
|
|
||||||
v2.2-stable (2014-09-29):
|
v2.2-stable (2014-09-29):
|
||||||
=========================
|
=========================
|
||||||
|
|||||||
@@ -10,7 +10,9 @@ def rasterize_pdf(input_file, output_file, xres, yres, raster_device, log):
|
|||||||
with NamedTemporaryFile(delete=True) as tmp:
|
with NamedTemporaryFile(delete=True) as tmp:
|
||||||
args_gs = [
|
args_gs = [
|
||||||
'gs',
|
'gs',
|
||||||
'-dBATCH', '-dNOPAUSE',
|
'-dQUIET',
|
||||||
|
'-dBATCH',
|
||||||
|
'-dNOPAUSE',
|
||||||
'-sDEVICE=%s' % raster_device,
|
'-sDEVICE=%s' % raster_device,
|
||||||
'-o', tmp.name,
|
'-o', tmp.name,
|
||||||
'-r{0}x{1}'.format(str(xres), str(yres)),
|
'-r{0}x{1}'.format(str(xres), str(yres)),
|
||||||
@@ -42,7 +44,7 @@ def generate_pdfa(pdf_pages, output_file, threads=1):
|
|||||||
"-sDEVICE=pdfwrite",
|
"-sDEVICE=pdfwrite",
|
||||||
"-sColorConversionStrategy=/RGB",
|
"-sColorConversionStrategy=/RGB",
|
||||||
"-sProcessColorModel=DeviceRGB",
|
"-sProcessColorModel=DeviceRGB",
|
||||||
"-dPDFA",
|
"-dPDFA=2",
|
||||||
"-sPDFACompatibilityPolicy=2",
|
"-sPDFACompatibilityPolicy=2",
|
||||||
"-sOutputICCProfile=srgb.icc",
|
"-sOutputICCProfile=srgb.icc",
|
||||||
"-sOutputFile=" + gs_pdf.name,
|
"-sOutputFile=" + gs_pdf.name,
|
||||||
|
|||||||
+47
-18
@@ -39,9 +39,7 @@ warnings.simplefilter('ignore', pypdf.utils.PdfReadWarning)
|
|||||||
|
|
||||||
|
|
||||||
BASEDIR = os.path.dirname(os.path.realpath(__file__))
|
BASEDIR = os.path.dirname(os.path.realpath(__file__))
|
||||||
JHOVE_PATH = os.path.realpath(os.path.join(BASEDIR, 'jhove'))
|
VERSION = '3.1'
|
||||||
JHOVE_JAR = os.path.join(JHOVE_PATH, 'bin', 'JhoveApp.jar')
|
|
||||||
JHOVE_CFG = os.path.join(JHOVE_PATH, 'conf', 'jhove.conf')
|
|
||||||
|
|
||||||
|
|
||||||
# -------------
|
# -------------
|
||||||
@@ -103,12 +101,12 @@ check_pil_encoder('zlib', 'PNG')
|
|||||||
parser = cmdline.get_argparse(
|
parser = cmdline.get_argparse(
|
||||||
prog="ocrmypdf",
|
prog="ocrmypdf",
|
||||||
description="Generate searchable PDF file from an image-only PDF file.",
|
description="Generate searchable PDF file from an image-only PDF file.",
|
||||||
version='3.0rc6',
|
version=VERSION,
|
||||||
fromfile_prefix_chars='@',
|
fromfile_prefix_chars='@',
|
||||||
ignored_args=[
|
ignored_args=[
|
||||||
'touch_files_only', 'recreate_database', 'checksum_file_name',
|
'touch_files_only', 'recreate_database', 'checksum_file_name',
|
||||||
'key_legend_in_graph', 'draw_graph_horizontally', 'flowchart_format',
|
'key_legend_in_graph', 'draw_graph_horizontally', 'flowchart_format',
|
||||||
'forced_tasks', 'target_tasks'])
|
'forced_tasks', 'target_tasks', 'use_threads'])
|
||||||
|
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
'input_file',
|
'input_file',
|
||||||
@@ -176,7 +174,7 @@ advanced.add_argument(
|
|||||||
'--tesseract-config', default=[], type=list, action='append',
|
'--tesseract-config', default=[], type=list, action='append',
|
||||||
help="additional Tesseract configuration files")
|
help="additional Tesseract configuration files")
|
||||||
advanced.add_argument(
|
advanced.add_argument(
|
||||||
'--pdf-renderer', choices=['tesseract', 'hocr'], default='hocr',
|
'--pdf-renderer', choices=['auto', 'tesseract', 'hocr'], default='auto',
|
||||||
help='choose OCR PDF renderer')
|
help='choose OCR PDF renderer')
|
||||||
advanced.add_argument(
|
advanced.add_argument(
|
||||||
'--tesseract-timeout', default=180.0, type=float,
|
'--tesseract-timeout', default=180.0, type=float,
|
||||||
@@ -218,6 +216,8 @@ if not set(options.language).issubset(tesseract.languages()):
|
|||||||
# ----------
|
# ----------
|
||||||
# Arguments
|
# Arguments
|
||||||
|
|
||||||
|
if options.pdf_renderer == 'auto':
|
||||||
|
options.pdf_renderer = 'hocr'
|
||||||
|
|
||||||
if any((options.deskew, options.clean, options.clean_final)):
|
if any((options.deskew, options.clean, options.clean_final)):
|
||||||
try:
|
try:
|
||||||
@@ -341,9 +341,8 @@ def cleanup_working_files(*args):
|
|||||||
|
|
||||||
@transform(
|
@transform(
|
||||||
input=options.input_file,
|
input=options.input_file,
|
||||||
filter=suffix('.pdf'),
|
filter=formatter('(?i)\.pdf'),
|
||||||
output='.repaired.pdf',
|
output=work_folder + '{basename[0]}.repaired.pdf',
|
||||||
output_dir=work_folder,
|
|
||||||
extras=[_log, _pdfinfo, _pdfinfo_lock])
|
extras=[_log, _pdfinfo, _pdfinfo_lock])
|
||||||
def repair_pdf(
|
def repair_pdf(
|
||||||
input_file,
|
input_file,
|
||||||
@@ -468,17 +467,21 @@ def rasterize_with_ghostscript(
|
|||||||
log,
|
log,
|
||||||
pdfinfo,
|
pdfinfo,
|
||||||
pdfinfo_lock):
|
pdfinfo_lock):
|
||||||
|
|
||||||
pageinfo = get_pageinfo(input_file, pdfinfo, pdfinfo_lock)
|
pageinfo = get_pageinfo(input_file, pdfinfo, pdfinfo_lock)
|
||||||
|
|
||||||
device = 'png16m' # 24-bit
|
device = 'png16m' # 24-bit
|
||||||
if all(image['comp'] == 1 for image in pageinfo['images']):
|
if all(image['comp'] == 1 for image in pageinfo['images']):
|
||||||
if all(image['bpc'] == 1 for image in pageinfo['images']):
|
if all(image['bpc'] == 1 for image in pageinfo['images']):
|
||||||
device = 'pngmono'
|
device = 'pngmono'
|
||||||
elif not any(image['color'] == 'color'
|
elif all(image['bpc'] > 1 and image['color'] == 'index'
|
||||||
for image in pageinfo['images']):
|
for image in pageinfo['images']):
|
||||||
|
device = 'png256'
|
||||||
|
elif all(image['bpc'] > 1 and image['color'] == 'gray'
|
||||||
|
for image in pageinfo['images']):
|
||||||
device = 'pnggray'
|
device = 'pnggray'
|
||||||
|
|
||||||
|
log.debug("Rendering {0} with {1}".format(
|
||||||
|
os.path.basename(input_file), device))
|
||||||
xres = max(pageinfo['xres'], options.oversample or 0)
|
xres = max(pageinfo['xres'], options.oversample or 0)
|
||||||
yres = max(pageinfo['yres'], options.oversample or 0)
|
yres = max(pageinfo['yres'], options.oversample or 0)
|
||||||
|
|
||||||
@@ -729,11 +732,13 @@ def generate_postscript_stub(
|
|||||||
pdf = pypdf.PdfFileReader(input_file)
|
pdf = pypdf.PdfFileReader(input_file)
|
||||||
|
|
||||||
def from_document_info(key):
|
def from_document_info(key):
|
||||||
# pdf.documentInfo.get() DOES NOT work as expected
|
# pdf.documentInfo.get() DOES NOT behave as expected for a dict-like
|
||||||
|
# object, so call with precautions. TypeError may occur if the PDF
|
||||||
|
# is missing the optional document info section.
|
||||||
try:
|
try:
|
||||||
s = pdf.documentInfo[key]
|
s = pdf.documentInfo[key]
|
||||||
return str(s)
|
return str(s)
|
||||||
except KeyError:
|
except (KeyError, TypeError):
|
||||||
return ''
|
return ''
|
||||||
|
|
||||||
pdfmark = {
|
pdfmark = {
|
||||||
@@ -751,6 +756,11 @@ def generate_postscript_stub(
|
|||||||
if options.subject:
|
if options.subject:
|
||||||
pdfmark['subject'] = options.subject
|
pdfmark['subject'] = options.subject
|
||||||
|
|
||||||
|
pdfmark['creator'] = '{0} {1} / Tesseract OCR{2} {3}'.format(
|
||||||
|
parser.prog, VERSION,
|
||||||
|
'+PDF' if options.pdf_renderer == 'tesseract' else '',
|
||||||
|
tesseract.version())
|
||||||
|
|
||||||
generate_pdfa_def(output_file, pdfmark)
|
generate_pdfa_def(output_file, pdfmark)
|
||||||
|
|
||||||
|
|
||||||
@@ -874,10 +884,16 @@ def available_cpu_count():
|
|||||||
return 1
|
return 1
|
||||||
|
|
||||||
|
|
||||||
|
def cleanup_ruffus_error_message(msg):
|
||||||
|
msg = re.sub(r'\s+', r' ', msg, re.MULTILINE)
|
||||||
|
msg = re.sub(r"\((.+?)\)", r'\1', msg)
|
||||||
|
msg = msg.strip()
|
||||||
|
return msg
|
||||||
|
|
||||||
|
|
||||||
def run_pipeline():
|
def run_pipeline():
|
||||||
if not options.jobs or options.jobs == 1:
|
if not options.jobs or options.jobs == 1:
|
||||||
options.jobs = available_cpu_count()
|
options.jobs = available_cpu_count()
|
||||||
|
|
||||||
try:
|
try:
|
||||||
cmdline.run(options)
|
cmdline.run(options)
|
||||||
except ruffus_exceptions.RethrownJobError as e:
|
except ruffus_exceptions.RethrownJobError as e:
|
||||||
@@ -889,9 +905,22 @@ def run_pipeline():
|
|||||||
for exc in e.args:
|
for exc in e.args:
|
||||||
task_name, job_name, exc_name, exc_value, exc_stack = exc
|
task_name, job_name, exc_name, exc_value, exc_stack = exc
|
||||||
if exc_name == 'builtins.SystemExit':
|
if exc_name == 'builtins.SystemExit':
|
||||||
return eval(
|
match = re.search(r"\.(.+?)\)", exc_value)
|
||||||
exc_value,
|
exit_code_name = match.groups()[0]
|
||||||
{'ExitCode': ExitCode}, {'exc_value': exc_value})
|
exit_code = getattr(ExitCode, exit_code_name, 'other_error')
|
||||||
|
return exit_code
|
||||||
|
elif exc_name == 'ruffus.ruffus_exceptions.MissingInputFileError':
|
||||||
|
print(cleanup_ruffus_error_message(exc_value))
|
||||||
|
return ExitCode.input_file
|
||||||
|
elif exc_name == 'builtins.TypeError':
|
||||||
|
# Even though repair_pdf will fail, ruffus will still try
|
||||||
|
# to call split_pages with no input files, likely due to a bug
|
||||||
|
if task_name == 'split_pages':
|
||||||
|
print("Input file '{0}' is not a valid PDF".format(
|
||||||
|
options.input_file))
|
||||||
|
return ExitCode.input_file
|
||||||
|
|
||||||
|
return ExitCode.other_error
|
||||||
|
|
||||||
if not validate_pdfa(options.output_file, _log):
|
if not validate_pdfa(options.output_file, _log):
|
||||||
_log.warning('Output file: The generated PDF/A file is INVALID')
|
_log.warning('Output file: The generated PDF/A file is INVALID')
|
||||||
|
|||||||
+24
-2
@@ -34,6 +34,7 @@ FRIENDLY_COMP = {
|
|||||||
'rgb': 3,
|
'rgb': 3,
|
||||||
'cmyk': 4,
|
'cmyk': 4,
|
||||||
'lab': 3,
|
'lab': 3,
|
||||||
|
'index': 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -103,6 +104,28 @@ def _find_page_images(page, pageinfo):
|
|||||||
yield image
|
yield image
|
||||||
|
|
||||||
|
|
||||||
|
def _page_has_text(pdf, page):
|
||||||
|
# Simple test
|
||||||
|
text = page.extractText()
|
||||||
|
if text.strip() != '':
|
||||||
|
return True
|
||||||
|
|
||||||
|
# More nuanced test to deal with quirks of Tesseract PDF generation
|
||||||
|
# Check if there's a Glyphless font
|
||||||
|
try:
|
||||||
|
font = page['/Resources']['/Font']
|
||||||
|
except KeyError:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
font_objects = list(font.keys())
|
||||||
|
for font_object in font_objects:
|
||||||
|
basefont = font[font_object]['/BaseFont']
|
||||||
|
if basefont.endswith('GlyphLessFont'):
|
||||||
|
return True
|
||||||
|
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
def _pdf_get_pageinfo(infile, page: int):
|
def _pdf_get_pageinfo(infile, page: int):
|
||||||
pageinfo = {}
|
pageinfo = {}
|
||||||
pageinfo['pageno'] = page
|
pageinfo['pageno'] = page
|
||||||
@@ -111,8 +134,7 @@ def _pdf_get_pageinfo(infile, page: int):
|
|||||||
pdf = pypdf.PdfFileReader(infile)
|
pdf = pypdf.PdfFileReader(infile)
|
||||||
page = pdf.pages[page - 1]
|
page = pdf.pages[page - 1]
|
||||||
|
|
||||||
text = page.extractText()
|
pageinfo['has_text'] = _page_has_text(pdf, page)
|
||||||
pageinfo['has_text'] = (text.strip() != '')
|
|
||||||
|
|
||||||
width_pt = page['/MediaBox'][2] - page['/MediaBox'][0]
|
width_pt = page['/MediaBox'][2] - page['/MediaBox'][0]
|
||||||
height_pt = page['/MediaBox'][3] - page['/MediaBox'][1]
|
height_pt = page['/MediaBox'][3] - page['/MediaBox'][1]
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ def
|
|||||||
/Author <$author>
|
/Author <$author>
|
||||||
/Subject <$subject>
|
/Subject <$subject>
|
||||||
/Keywords <$keywords>
|
/Keywords <$keywords>
|
||||||
|
/Creator <$creator>
|
||||||
/DOCINFO pdfmark
|
/DOCINFO pdfmark
|
||||||
|
|
||||||
% Define an ICC profile :
|
% Define an ICC profile :
|
||||||
@@ -86,6 +87,7 @@ def _get_pdfa_def(icc_profile, icc_identifier, pdfmark):
|
|||||||
title=pdfmark_utf16.get('title', ''),
|
title=pdfmark_utf16.get('title', ''),
|
||||||
author=pdfmark_utf16.get('author', ''),
|
author=pdfmark_utf16.get('author', ''),
|
||||||
subject=pdfmark_utf16.get('subject', ''),
|
subject=pdfmark_utf16.get('subject', ''),
|
||||||
|
creator=pdfmark_utf16.get('creator', ''),
|
||||||
keywords=pdfmark_utf16.get('keywords', ''))
|
keywords=pdfmark_utf16.get('keywords', ''))
|
||||||
return result
|
return result
|
||||||
|
|
||||||
@@ -115,6 +117,8 @@ def _get_postscript_icc_path():
|
|||||||
if os.path.exists(path):
|
if os.path.exists(path):
|
||||||
return path
|
return path
|
||||||
|
|
||||||
|
raise FileNotFoundError("Could not find Ghostscript's iccprofiles")
|
||||||
|
|
||||||
|
|
||||||
def generate_pdfa_def(target_filename, pdfmark, icc='sRGB'):
|
def generate_pdfa_def(target_filename, pdfmark, icc='sRGB'):
|
||||||
if icc == 'sRGB':
|
if icc == 'sRGB':
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import shutil
|
|||||||
import pytest
|
import pytest
|
||||||
import img2pdf
|
import img2pdf
|
||||||
from pkg_resources import Requirement, resource_filename
|
from pkg_resources import Requirement, resource_filename
|
||||||
|
import pytest
|
||||||
|
|
||||||
req = Requirement.parse('ocrmypdf')
|
req = Requirement.parse('ocrmypdf')
|
||||||
|
|
||||||
@@ -99,6 +100,7 @@ def test_single_page_inline_image():
|
|||||||
pageinfo.pdf_get_all_pageinfo(filename)
|
pageinfo.pdf_get_all_pageinfo(filename)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.skipif(True, reason="need to fix packaging error")
|
||||||
def test_jpeg():
|
def test_jpeg():
|
||||||
filename = resource_filename(req, 'tests/resources/c02-22.pdf')
|
filename = resource_filename(req, 'tests/resources/c02-22.pdf')
|
||||||
|
|
||||||
|
|||||||
+20
-2
@@ -8,6 +8,7 @@ from tempfile import NamedTemporaryFile
|
|||||||
import sys
|
import sys
|
||||||
import os
|
import os
|
||||||
from functools import lru_cache
|
from functools import lru_cache
|
||||||
|
from . import ExitCode
|
||||||
|
|
||||||
|
|
||||||
@lru_cache(maxsize=1)
|
@lru_cache(maxsize=1)
|
||||||
@@ -38,10 +39,27 @@ def run(input_file, output_file, dpi, log, mode_args):
|
|||||||
] + mode_args
|
] + mode_args
|
||||||
|
|
||||||
SUFFIXES = {'1': '.pbm', 'L': '.pgm', 'RGB': '.ppm'}
|
SUFFIXES = {'1': '.pbm', 'L': '.pgm', 'RGB': '.ppm'}
|
||||||
suffix = ''
|
|
||||||
|
|
||||||
im = Image.open(input_file)
|
im = Image.open(input_file)
|
||||||
suffix = SUFFIXES[im.mode]
|
if im.mode not in SUFFIXES.keys():
|
||||||
|
log.info("Converting image to other colorspace")
|
||||||
|
try:
|
||||||
|
if im.mode == 'P' and len(im.getcolors()) == 2:
|
||||||
|
im = im.convert(mode='1')
|
||||||
|
else:
|
||||||
|
im = im.convert(mode='RGB')
|
||||||
|
except IOError:
|
||||||
|
log.error(
|
||||||
|
"Could not convert image with type " + im.mode)
|
||||||
|
sys.exit(ExitCode.missing_dependency)
|
||||||
|
|
||||||
|
try:
|
||||||
|
suffix = SUFFIXES[im.mode]
|
||||||
|
except KeyError:
|
||||||
|
log.error(
|
||||||
|
"Failed to convert image to a supported format.")
|
||||||
|
sys.exit(ExitCode.missing_dependency)
|
||||||
|
|
||||||
with NamedTemporaryFile(suffix=suffix) as input_pnm, \
|
with NamedTemporaryFile(suffix=suffix) as input_pnm, \
|
||||||
NamedTemporaryFile(suffix=suffix, mode="r+b") as output_pnm:
|
NamedTemporaryFile(suffix=suffix, mode="r+b") as output_pnm:
|
||||||
im.save(input_pnm, format='PPM')
|
im.save(input_pnm, format='PPM')
|
||||||
|
|||||||
@@ -1,2 +1,4 @@
|
|||||||
[bdist_wheel]
|
[bdist_wheel]
|
||||||
python-tag = py34
|
python-tag = py34
|
||||||
|
[pytest]
|
||||||
|
norecursedirs = lib
|
||||||
@@ -179,17 +179,17 @@ tests_require = open('test_requirements.txt').read().splitlines()
|
|||||||
|
|
||||||
setup(
|
setup(
|
||||||
name='ocrmypdf',
|
name='ocrmypdf',
|
||||||
version='3.0rc6', # also update: release notes, main.py
|
version='3.1', # also update: release notes, main.py
|
||||||
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',
|
||||||
url='https://github.com/fritz-hh/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',
|
||||||
license='Public Domain',
|
license='Public Domain',
|
||||||
packages=['ocrmypdf'],
|
packages=['ocrmypdf'],
|
||||||
keywords=['PDF', 'OCR', 'optical character recognition', 'PDF/A', 'scanning'],
|
keywords=['PDF', 'OCR', 'optical character recognition', 'PDF/A', 'scanning'],
|
||||||
classifiers=[
|
classifiers=[
|
||||||
"Programming Language :: Python :: 3",
|
"Programming Language :: Python :: 3",
|
||||||
"Development Status :: 4 - Beta",
|
"Development Status :: 5 - Production/Stable",
|
||||||
"Environment :: Console",
|
"Environment :: Console",
|
||||||
"Intended Audience :: End Users/Desktop",
|
"Intended Audience :: End Users/Desktop",
|
||||||
"Intended Audience :: Science/Research",
|
"Intended Audience :: Science/Research",
|
||||||
|
|||||||
Binary file not shown.
|
Before Width: | Height: | Size: 1.4 MiB After Width: | Height: | Size: 1.4 MiB |
+25
-23
@@ -4,29 +4,31 @@ copyright reasons.
|
|||||||
Test files do not necessarily produce perfect (or even good) OCR
|
Test files do not necessarily produce perfect (or even good) OCR
|
||||||
results.
|
results.
|
||||||
|
|
||||||
+-------------------+--------------------------------------------------------------------------------+
|
+---------------------+--------------------------------------------------------------------------------+
|
||||||
| File | Source |
|
| File | Source |
|
||||||
+===================+================================================================================+
|
+=====================+================================================================================+
|
||||||
| graph.pdf | Wikimedia |
|
| graph.pdf | Wikimedia |
|
||||||
+-------------------+--------------------------------------------------------------------------------+
|
+---------------------+--------------------------------------------------------------------------------+
|
||||||
| c02-22.pdf | Project Gutenberg: https://www.gutenberg.org/files/76/76-h/images/c02-22.jpg |
|
| c02-22.pdf | Project Gutenberg: https://www.gutenberg.org/files/76/76-h/images/c02-22.jpg |
|
||||||
+-------------------+--------------------------------------------------------------------------------+
|
+---------------------+--------------------------------------------------------------------------------+
|
||||||
| LinnSequencer.jpg | Wikimedia_ |
|
| LinnSequencer.jpg | Wikimedia_ |
|
||||||
+-------------------+--------------------------------------------------------------------------------+
|
+---------------------+--------------------------------------------------------------------------------+
|
||||||
| congress.jpg | http://www.baxleystamps.com/litho/meiji/courts_1871.jpg |
|
| congress.jpg | http://www.baxleystamps.com/litho/meiji/courts_1871.jpg |
|
||||||
+-------------------+--------------------------------------------------------------------------------+
|
+---------------------+--------------------------------------------------------------------------------+
|
||||||
| blank.pdf | Blank page from Adobe Illustrator CC 2015 |
|
| blank.pdf | Blank page from Adobe Illustrator CC 2015 |
|
||||||
+-------------------+--------------------------------------------------------------------------------+
|
+---------------------+--------------------------------------------------------------------------------+
|
||||||
| enormous.pdf | PNG file saved to PDF using img2pdf |
|
| enormous.pdf | PNG file saved to PDF using img2pdf |
|
||||||
+-------------------+--------------------------------------------------------------------------------+
|
+---------------------+--------------------------------------------------------------------------------+
|
||||||
| invalid.pdf | PDF file header followed by EOF marker; not valid |
|
| invalid.pdf | PDF file header followed by EOF marker; not valid |
|
||||||
+-------------------+--------------------------------------------------------------------------------+
|
+---------------------+--------------------------------------------------------------------------------+
|
||||||
| multipage.pdf | several other files concatenated |
|
| multipage.pdf | several other files concatenated |
|
||||||
+-------------------+--------------------------------------------------------------------------------+
|
+---------------------+--------------------------------------------------------------------------------+
|
||||||
| skew.pdf | skewed version of c02-22.PDF |
|
| skew.pdf | skewed version of c02-22.PDF |
|
||||||
+-------------------+--------------------------------------------------------------------------------+
|
+---------------------+--------------------------------------------------------------------------------+
|
||||||
| Test_Issue_28.pdf | file with some syntax errors |
|
| Test_Issue_28.pdf | file with some syntax errors |
|
||||||
+-------------------+--------------------------------------------------------------------------------+
|
+---------------------+--------------------------------------------------------------------------------+
|
||||||
|
| missing_docinfo.pdf | file missing its DocumentInfo dictionary |
|
||||||
|
+---------------------+--------------------------------------------------------------------------------+
|
||||||
|
|
||||||
|
|
||||||
.. _Wikimedia: https://upload.wikimedia.org/wikipedia/en/b/b7/LinnSequencer_hardware_MIDI_sequencer_brochure_page_2_300dpi.jpg
|
.. _Wikimedia: https://upload.wikimedia.org/wikipedia/en/b/b7/LinnSequencer_hardware_MIDI_sequencer_brochure_page_2_300dpi.jpg
|
||||||
File diff suppressed because one or more lines are too long
Binary file not shown.
Binary file not shown.
+49
-3
@@ -114,6 +114,21 @@ def test_clean():
|
|||||||
check_ocrmypdf('skew.pdf', 'test_clean.pdf', '-c')
|
check_ocrmypdf('skew.pdf', 'test_clean.pdf', '-c')
|
||||||
|
|
||||||
|
|
||||||
|
def check_exotic_image(pdf, renderer):
|
||||||
|
check_ocrmypdf(
|
||||||
|
pdf,
|
||||||
|
'test_{0}_{1}.pdf'.format(pdf, renderer),
|
||||||
|
'-dc',
|
||||||
|
'--pdf-renderer', renderer)
|
||||||
|
|
||||||
|
|
||||||
|
def test_exotic_image():
|
||||||
|
yield check_exotic_image, 'palette.pdf', 'hocr'
|
||||||
|
yield check_exotic_image, 'palette.pdf', 'tesseract'
|
||||||
|
yield check_exotic_image, 'cmyk.pdf', 'hocr'
|
||||||
|
yield check_exotic_image, 'cmyk.pdf', 'tesseract'
|
||||||
|
|
||||||
|
|
||||||
def test_preserve_metadata():
|
def test_preserve_metadata():
|
||||||
pdf_before = pypdf.PdfFileReader(_make_input('graph.pdf'))
|
pdf_before = pypdf.PdfFileReader(_make_input('graph.pdf'))
|
||||||
|
|
||||||
@@ -139,9 +154,7 @@ def test_override_metadata():
|
|||||||
'--author', chinese,
|
'--author', chinese,
|
||||||
'--subject', high_unicode)
|
'--subject', high_unicode)
|
||||||
|
|
||||||
if p.returncode == ExitCode.invalid_output_pdfa:
|
assert p.returncode == ExitCode.ok
|
||||||
print("Got invalid PDF return code, as expected - JHOVE bug")
|
|
||||||
assert p.returncode in (ExitCode.ok, ExitCode.invalid_output_pdfa)
|
|
||||||
|
|
||||||
pdf = output_file
|
pdf = output_file
|
||||||
|
|
||||||
@@ -308,3 +321,36 @@ def test_klingon():
|
|||||||
p, out, err = run_ocrmypdf_env(
|
p, out, err = run_ocrmypdf_env(
|
||||||
'francais.pdf', 'francais.pdf', '-l', 'klz')
|
'francais.pdf', 'francais.pdf', '-l', 'klz')
|
||||||
assert p.returncode == ExitCode.bad_args
|
assert p.returncode == ExitCode.bad_args
|
||||||
|
|
||||||
|
|
||||||
|
def test_missing_docinfo():
|
||||||
|
p, out, err = run_ocrmypdf_env(
|
||||||
|
'missing_docinfo.pdf', 'missing_docinfo.pdf', '-l', 'eng', '-c')
|
||||||
|
assert p.returncode == ExitCode.ok, err
|
||||||
|
|
||||||
|
|
||||||
|
def test_uppercase_extension():
|
||||||
|
shutil.copy(_make_input("skew.pdf"), _make_input("UPPERCASE.PDF"))
|
||||||
|
try:
|
||||||
|
check_ocrmypdf("UPPERCASE.PDF", "UPPERCASE_OUT.PDF")
|
||||||
|
finally:
|
||||||
|
os.unlink(_make_input("UPPERCASE.PDF"))
|
||||||
|
|
||||||
|
|
||||||
|
def test_input_file_not_found():
|
||||||
|
input_file = "does not exist.pdf"
|
||||||
|
sh, out, err = run_ocrmypdf_sh(
|
||||||
|
_make_input(input_file),
|
||||||
|
_make_output("will not happen.pdf"))
|
||||||
|
assert sh.returncode == ExitCode.input_file
|
||||||
|
assert (input_file in out or input_file in err)
|
||||||
|
|
||||||
|
|
||||||
|
def test_input_file_not_a_pdf():
|
||||||
|
input_file = __file__ # Try to OCR this file
|
||||||
|
sh, out, err = run_ocrmypdf_sh(
|
||||||
|
_make_input(input_file),
|
||||||
|
_make_output("will not happen.pdf"))
|
||||||
|
assert sh.returncode == ExitCode.input_file
|
||||||
|
assert (input_file in out or input_file in err)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user