Compare commits

...
25 Commits
Author SHA1 Message Date
James R. Barlow 72337094ca v8.0.0 release notes 2019-01-05 23:35:47 -08:00
James R. Barlow f472587d22 Bump pikepdf version, point to release notes 2019-01-05 16:48:13 -08:00
James R. Barlow f34b3015b2 Prevent Ghostscript from generating invalid XMP metadata
If DocumentInfo contains NULs Ghostscript will generate XMP with
NULs which is not allowed. Repair DocumentInfo before Ghostscript sees it.
2019-01-04 13:20:41 -08:00
James R. Barlow 089ece2715 use pikepdf 0.10.2 2019-01-03 12:08:43 -08:00
James R. Barlow 6438465e3f Add fish completions 2019-01-02 17:08:30 -08:00
James R. Barlow 7d330afd81 Delinting 2019-01-02 13:34:45 -08:00
James R. Barlow 68fbd9fcc9 pikepdf: version bump 2018-12-31 15:37:31 -08:00
James R. Barlow c771938907 Convert to f-strings where it makes sense 2018-12-31 15:01:19 -08:00
James R. Barlow c2a947acf4 travis: fix 2018-12-31 01:18:30 -08:00
James R. Barlow 8c0009c5c8 Make pdfminer.six optional
Mainly since the current release of pdfminer.six lacks a sdist, blocking
homebrew packaging. Also in case other distros don't accept pdfminer.six.
2018-12-31 01:08:43 -08:00
James R. Barlow cfc5cdf47d pdfa: remove a pile of deprecated code
It's now handled in pikepdf.
2018-12-31 00:05:13 -08:00
James R. Barlow 05152a8af9 Remove always-false Tess v3 tests 2018-12-30 02:01:05 -08:00
James R. Barlow 0880b16491 Sort imports with isort 2018-12-30 01:28:15 -08:00
James R. Barlow 06308a22ce Reformat with black 2018-12-30 01:27:49 -08:00
James R. Barlow 80bd7de580 Generate test cache 2018-12-30 01:02:37 -08:00
James R. Barlow 8b90c45437 Drop support for Tesseract 3 2018-12-30 00:47:12 -08:00
James R. Barlow 72b920eb16 Drop support for Python 3.5 2018-12-30 00:23:26 -08:00
James R. Barlow b4a51907d6 Detect when metadata is dropped during PDF/A conversion 2018-12-30 00:13:25 -08:00
James R. Barlow 1ca1221432 leptonica.py: Fix exception on certain types of barcode failures
Closes #322
2018-12-19 17:23:23 -08:00
James R. Barlow 40b72b0fa8 v7.4.1 release notes 2018-12-19 16:41:09 -08:00
James R. Barlow 0e55b4ad52 Travis: remove Brewfile 2018-12-19 16:40:48 -08:00
James R. Barlow 7b4f5a8fc4 docs: try to fix readthedocs
[ci skip]
2018-12-19 15:30:07 -08:00
James R. Barlow 9261a38493 Readme: more media 2018-12-19 15:27:54 -08:00
James R. Barlow cc8ff318ed New issue template 2018-12-19 15:27:44 -08:00
James R. Barlow ad15e845f9 docs: Ghostscript PDF/A XMP metadata loss; ocrmypdf-webservice
[ci skip]
2018-12-17 23:20:49 -08:00
190 changed files with 11017 additions and 4470 deletions
-5
View File
@@ -1,5 +0,0 @@
Please include the command line and a test file with your issue report.
If possible, please use a test file that we can include in future test cases (no personal information, no copyrighted material).
If you wish to encrypt a test file for the OCRmyPDF maintainer only, see the [Wiki](https://github.com/jbarlow83/OCRmyPDF/wiki).
+33
View File
@@ -0,0 +1,33 @@
**Describe the issue**
A clear and concise description of what the issue is.
**To Reproduce**
What command line were you trying to run?
```bash
ocrmypdf ...arguments... input.pdf output.pdf
```
**Example file**
Please include an example *input* PDF (or image). The input file is more helpful.
Please check any or all that apply about the test file:
- [ ] This is the input file
- [ ] The file contains no personal or confidential information
- [ ] I am the copyright holder for this file
- [ ] I permit this file to be included in the OCRmyPDF test suite under the CC-BY-SA 4.0 license
- [ ] I am not the copyright holder, but this file is available under a free software license
Files that are not free for inclusion in this project are quite welcome, but we like to collect free files for our test suite when possible. Please do *not* submit files with confidential information. At your option you may encrypt files for OCRmyPDF's author only.
**Expected behavior**
A clear and concise description of what you expected to happen. Include screenshots if applicable.
**System:**
- OS: [e.g. Linux, macOS]
- OCRmyPDF Version: [e.g. v7.4.0]
**Additional context**
Add any other context about the problem here.
+2
View File
@@ -39,3 +39,5 @@ log/
tests/output/
tests/resources/private/
tmp/
/debug_tests.py
*.traineddata
+38 -10
View File
@@ -9,7 +9,7 @@ matrix:
dist: trusty
sudo: required
language: python
python: "3.5"
python: "3.6"
env:
- DIST=trusty
addons: &trusty_apt
@@ -33,14 +33,6 @@ matrix:
- tesseract-ocr-deu
- tesseract-ocr-eng
- tesseract-ocr-fra
- os: linux
dist: trusty
sudo: required
language: python
python: "3.6"
env:
- DIST=trusty
addons: *trusty_apt
- os: linux
dist: xenial
sudo: required
@@ -68,6 +60,39 @@ matrix:
- os: osx
osx_image: xcode9.2
language: generic
addons:
homebrew:
update: true
packages:
- exempi
- ghostscript
- jbig2enc
- leptonica
- openjpeg
- pngquant
- python
- qpdf
- tesseract
- unpaper
- os: osx
osx_image: xcode9.2
language: generic
env:
- ADD_PDFMINER=1
addons:
homebrew:
update: true
packages:
- exempi
- ghostscript
- jbig2enc
- leptonica
- openjpeg
- pngquant
- python
- qpdf
- tesseract
- unpaper
before_cache:
- rm -f $HOME/.cache/pip/log/debug.log
@@ -83,7 +108,6 @@ before_install: |
sudo dpkg -i packages/unpaper_6.1-1.deb
fi
elif [[ "$TRAVIS_OS_NAME" == "osx" ]]; then
brew update --quiet && brew bundle --file=.travis/Brewfile --quiet
pip3 install --upgrade pip
pip3 install wheel
fi
@@ -93,6 +117,10 @@ install:
- pip3 install pycparser # py3.7 workaround for https://github.com/eliben/pycparser/issues/251
- pip3 install -r requirements/main.txt
- pip3 install --no-deps .
- |
if [[ "$ADD_PDFMINER" == "1" ]]; then
pip3 install --no-deps .[pdfminer]
fi
- pip3 install -r requirements/test.txt
script:
-11
View File
@@ -1,11 +0,0 @@
brew 'python'
brew 'exempi'
brew 'ghostscript'
brew 'jbig2enc'
brew 'leptonica'
brew 'openjpeg'
brew 'pngquant'
brew 'qpdf'
brew 'tesseract'
brew 'unpaper'
+29 -25
View File
@@ -25,20 +25,22 @@ ocrmypdf # it's a scriptable command line program
output_searchable.pdf # produces validated PDF output
```
[See the release notes for details on the latest changes](https://ocrmypdf.readthedocs.io/en/latest/release_notes.html).
Main features
-------------
- Generates a searchable [PDF/A](https://en.wikipedia.org/?title=PDF/A) file from a regular PDF
- Places OCR text accurately below the image to ease copy / paste
- Keeps the exact resolution of the original embedded images
- When possible, inserts OCR information as a "lossless" operation without disrupting any other content
- Optimizes PDF images, often producing files smaller than the input file
- If requested deskews and/or cleans the image before performing OCR
- Validates input and output files
- Distributes work across all available CPU cores
- Uses [Tesseract OCR](https://github.com/tesseract-ocr/tesseract) engine
- Supports more than [100 languages](https://github.com/tesseract-ocr/tessdata) recognized by Tesseract
- Battle-tested on thousands of PDFs, a test suite and continuous integration
- Generates a searchable [PDF/A](https://en.wikipedia.org/?title=PDF/A) file from a regular PDF
- Places OCR text accurately below the image to ease copy / paste
- Keeps the exact resolution of the original embedded images
- When possible, inserts OCR information as a "lossless" operation without disrupting any other content
- Optimizes PDF images, often producing files smaller than the input file
- If requested deskews and/or cleans the image before performing OCR
- Validates input and output files
- Distributes work across all available CPU cores
- Uses [Tesseract OCR](https://github.com/tesseract-ocr/tesseract) engine
- Supports more than [100 languages](https://github.com/tesseract-ocr/tessdata) recognized by Tesseract
- Battle-tested on thousands of PDFs, a test suite and continuous integration
For details: please consult the [documentation](https://ocrmypdf.readthedocs.io/en/latest/).
@@ -47,13 +49,13 @@ Motivation
I searched the web for a free command line tool to OCR PDF files on Linux/UNIX: I found many, but none of them were really satisfying.
- Either they produced PDF files with misplaced text under the image (making copy/paste impossible)
- Or they did not handle accents and multilingual characters
- Or they changed the resolution of the embedded images
- Or they generated ridiculously large PDF files
- Or they crashed when trying to OCR
- Or they did not produce valid PDF files
- On top of that none of them produced PDF/A files (format dedicated for long time storage)
- Either they produced PDF files with misplaced text under the image (making copy/paste impossible)
- Or they did not handle accents and multilingual characters
- Or they changed the resolution of the embedded images
- Or they generated ridiculously large PDF files
- Or they crashed when trying to OCR
- Or they did not produce valid PDF files
- On top of that none of them produced PDF/A files (format dedicated for long time storage)
...so I decided to develop my own tool.
@@ -110,11 +112,11 @@ Our [documentation is served on Read the Docs](https://ocrmypdf.readthedocs.io/e
If you detect an issue, please:
- Check whether your issue is already known
- If no problem report exists on github, please create one here: <https://github.com/jbarlow83/OCRmyPDF/issues>
- Describe your problem thoroughly
- Append the console output of the script when running the debug mode (`-v 1` option)
- If possible provide your input PDF file as well as the content of the temporary folder (using a file sharing service like Dropbox)
- Check whether your issue is already known
- If no problem report exists on github, please create one here: <https://github.com/jbarlow83/OCRmyPDF/issues>
- Describe your problem thoroughly
- Append the console output of the script when running the debug mode (`-v 1` option)
- If possible provide your input PDF file as well as the content of the temporary folder (using a file sharing service like Dropbox)
Requirements
------------
@@ -124,8 +126,10 @@ Runs on CPython 3.5, 3.6 and 3.7. Requires external program installations of Gho
Press & Media
-------------
- [c't 1-2014, page 59](http://heise.de/-2279695): Detailed presentation of OCRmyPDF v1.0 in the leading German IT magazine c't
- [heise Open Source, 09/2014: Texterkennung mit OCRmyPDF](http://heise.de/-2356670)
- [Going paperless with OCRmyPDF](https://medium.com/@ikirichenko/going-paperless-with-ocrmypdf-e2f36143f46a)
- [Converting a scanned document into a compressed searchable PDF with redactions](https://medium.com/@treyharris/converting-a-scanned-document-into-a-compressed-searchable-pdf-with-redactions-63f61c34fe4c)
- [c't 1-2014, page 59](http://heise.de/-2279695): Detailed presentation of OCRmyPDF v1.0 in the leading German IT magazine c't
- [heise Open Source, 09/2014: Texterkennung mit OCRmyPDF](http://heise.de/-2356670)
License
-------
+6
View File
@@ -95,6 +95,12 @@ Files: tests/resources/vector.pdf
Copyright: (C) 2018 Catscratch
License: Expat
Files: test/resources/enron*.pdf
Copyright: EnronData.org
License: CC-BY-3.0
See: https://enrondata.readthedocs.io/en/latest/data/edo-enron-email-pst-dataset/
Comment: Unprocessed.
Files: src/ocrmypdf/data/sRGB.icc
Copyright: Kai-Uwe Behrmann <www.behrmann.name>
Marti Maria <www.littlecms.com>
+6 -8
View File
@@ -47,16 +47,16 @@ Some relevant environment variables that influence Tesseract's behavior include:
Controls the number of threads Tesseract will use. OCRmyPDF will manage this environment if it is not already set. (Currently, it will set it to 1 because this gives the best results in testing.)
For example, if you are testing tesseract 4.00 and don't wish to use an existing tesseract 3.04 installation, you can launch OCRmyPDF as follows:
For example, if you have a development build of Tesseract don't wish to use the system installation, you can launch OCRmyPDF as follows:
.. code-block:: bash
env \
PATH=/home/user/src/tesseract4/api:$PATH \
TESSDATA_PREFIX=/home/user/src/tesseract4 \
ocrmypdf --tesseract-oem 2 input.pdf output.pdf
PATH=/home/user/src/tesseract/api:$PATH \
TESSDATA_PREFIX=/home/user/src/tesseract \
ocrmypdf input.pdf output.pdf
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.)
In this example ``TESSDATA_PREFIX`` is required to redirect Tesseract to an alternate folder for its "tessdata" files.
Overriding other support programs
@@ -107,7 +107,7 @@ rendering
Creating a new PDF from other data (such as an existing PDF).
OCRmyPDF has these PDF renderers: ``sandwich`` and ``hocr``. The renderer may be selected using ``--pdf-renderer``. The default is ``auto`` which lets OCRmyPDF select the renderer to use. Currently, ``auto`` selects ``sandwich`` for Tesseract 3.05.01 or newer, or ``hocr`` for older versions of Tesseract.
OCRmyPDF has these PDF renderers: ``sandwich`` and ``hocr``. The renderer may be selected using ``--pdf-renderer``. The default is ``auto`` which lets OCRmyPDF select the renderer to use. Currently, ``auto`` always selects ``sandwich``.
The ``sandwich`` renderer
"""""""""""""""""""""""""
@@ -118,8 +118,6 @@ Currently this is the best renderer for most uses, however it is implemented in
When image preprocessing features like ``--deskew`` are used, the original PDF will be rendered as a full page and the OCR layer will be placed on top.
If a PDF created with this renderer using Tesseract versions older than 3.05.00 is then passed through Ghostscript's pdfwrite feature, the OCR text *may* be corrupted. The ``--output-type=pdfa`` argument will produce a warning in this situation. For this reason, OCRmyPDF automatically selects the ``hocr`` for older Tesseract versions.
The ``hocr`` renderer
"""""""""""""""""""""
+6 -1
View File
@@ -74,7 +74,12 @@ if on_rtd:
def __getattr__(cls, name):
return MagicMock()
MOCK_MODULES = ['pikepdf', 'ocrmypdf.leptonica']
MOCK_MODULES = [
'pikepdf',
'pikepdf.models',
'pikepdf.models.metadata',
'ocrmypdf.leptonica'
]
sys.modules.update((mod_name, Mock()) for mod_name in MOCK_MODULES)
+1 -1
View File
@@ -81,7 +81,7 @@ This produces a file named "output.pdf" and a companion text file named "output.
OCR images, not PDFs
--------------------
If you are starting with images, you can just use Tesseract 3.04 or later directly to convert images to PDFs:
If you are starting with images, you can just use Tesseract directly to convert images to PDFs:
.. code-block:: bash
+7 -8
View File
@@ -377,6 +377,9 @@ Assuming you have a Docker engine running, you can download one of the three ava
* - ocrmypdf-polyglot
- ``docker pull jbarlow83/ocrmypdf-polyglot``
- As above, with all available language packs.
* - ocrmypdf-webservice
- ``docker pull jbarlow83/ocrmypdf-polyglot``
- All language packs, and a simple HTTP wrapper allowing OCRmyPDF to be used as a web service. Note that this component is licensed under AGPLv3.
For example:
@@ -490,21 +493,17 @@ Requirements for pip and HEAD install
OCRmyPDF currently requires these external programs and libraries to be installed, and must be satisfied using the operating system package manager. ``pip`` cannot provide them.
- Python 3.5 or newer
- Python 3.6 or newer
- Ghostscript 9.15 or newer
- libexempi3 2.2.0 or newer
- qpdf 8.1.0 or newer
- Tesseract 3.04 or newer
Using Python 3.5 in production is discouraged. Python 3.6 and 3.7 give much better performance.
- Tesseract 4.0.0-alpha or newer
As of ocrmypdf 7.2.1, the following versions are recommended:
- Python 3.7
- Ghostscript 9.23 or newer
- libexempi3 2.4.5 or newer
- qpdf 8.2.1
- Tesseract 4.0.0-rc1
- Tesseract 4.0.0 or newer
- jbig2enc 0.29 or newer
- pngquant 2.5 or newer
- unpaper 6.1
@@ -523,7 +522,7 @@ These are in addition to the Python packaging dependencies, meaning that unfortu
Installing HEAD revision from sources
-------------------------------------
If you have ``git`` and Python 3.5 or newer installed, you can install from source. When the ``pip`` installer runs, it will alert you if dependencies are missing.
If you have ``git`` and Python 3.6 or newer installed, you can install from source. When the ``pip`` installer runs, it will alert you if dependencies are missing.
If you prefer to build every from source, you will need to `build pikepdf from source <https://pikepdf.readthedocs.io/en/latest/installation.html#building-from-source>`_. First ensure you can build and install pikepdf.
+7 -3
View File
@@ -90,6 +90,7 @@ Ghostscript also imposes some limitations:
* PDFs containing JBIG2-encoded content will be converted to CCITT Group4 encoding, which has lower compression ratios, if Ghostscript PDF/A is enabled.
* PDFs containing JPEG 2000-encoded content will be converted to JPEG encoding, which may introduce compression artifacts, if Ghostscript PDF/A is enabled.
* Ghostscript may transcode grayscale and color images, either lossy to lossless or lossless to lossy, based on an internal algorithm. This behavior can be suppressed by setting ``--pdfa-image-compression`` to ``jpeg`` or ``lossless`` to set all images to one type or the other. Ghostscript has no option to maintain the input image's format. (Ghostscript 9.25+ can copy JPEG images without transcoding them; earlier versions will transcode.)
* Ghostscript's PDF/A conversion removes any XMP metadata that is not one of the standard XMP metadata namespaces for PDFs. In particular, PRISM Metdata is removed.
Regarding OCRmyPDF itself:
@@ -109,7 +110,10 @@ To the author's knowledge, OCRmyPDF is the most feature-rich and thoroughly test
Web front-ends
--------------
* `Nextcloud OCR <https://github.com/janis91/ocr>`_ is a free software plugin for the Nextcloud private cloud software
* `OCRmyPDF-web <https://github.com/sseemayer/OCRmyPDF-web>`_, a micro web-frontend for OCRmyPDF (third-party, not actively maintained)
The Docker image ocrmypdf-webservice provides a web service front-end that allows files to submitted over HTTP and the results "downloaded". This is an HTTP server intended to simplify web services deployments; it is not intended to be deployed on the public internet and no real security measures to speak of.
Bear in mind that OCRmyPDF is not designed to be secure against malware-bearing PDFs (see `Using OCRmyPDF online`_).
In addition, the following integrations are available:
* `Nextcloud OCR <https://github.com/janis91/ocr>`_ is a free software plugin for the Nextcloud private cloud software
Bear in mind that OCRmyPDF is not designed to be secure against malware-bearing PDFs (see `Using OCRmyPDF online`_). Users should ensure they comply with OCRmyPDF's licenses and the licenses of all dependencies. In particular, OCRmyPDF requires Ghostscript, which is licensed under AGPLv3.
+30
View File
@@ -13,6 +13,36 @@ Note that it is licensed under GPLv3, so scripts that ``import ocrmypdf`` and ar
find: [^`]\#([0-9]{1,3})[^0-9]
replace: `#$1 <https://github.com/jbarlow83/OCRmyPDF/issues/$1>`_
v8.0.0
------
No major features. The intent of this release is to sever support for older versions of certain dependencies.
**Breaking changes**
- Dropped support for Tesseract 3.x. Tesseract 4.0 or newer is now required.
- Dropped support for Python 3.5.
- Some ``ocrmypdf.pdfa`` APIs that were deprecated in v7.x were removed. This functionality has been moved to pikepdf.
**Other changes**
- Fixed an unhandled exception when attempting to mask barcodes. `#322 <https://github.com/jbarlow83/OCRmyPDF/issues/322>`_
- It is now possible to use ocrmypdf without pdfminer.six, to support distributions that do not have it or cannot currently use it (e.g. Homebrew). Downstream maintainers should include pdfminer.six if possible.
- A warning is now issue when PDF/A conversion removes some XMP metadata from the input PDF. (Only a "whitelist" of certain XMP metadata types are allowed in PDF/A.)
- Fixed several issues that caused PDF/As to be produced with nonconforming XMP metadata (would fail validation with veraPDF).
- Fixed some instances where invalid DocumentInfo from a PDF cause XMP metadata creation to fail.
- Fixed a few documentation problems.
- pikepdf 1.0.2 is now required.
v7.4.0
------
+70
View File
@@ -0,0 +1,70 @@
complete -c ocrmypdf -l version
complete -c ocrmypdf -l help
complete -c ocrmypdf -l sidecar -r -d "write OCR to text file"
complete -c ocrmypdf -s q -l quiet
complete -c ocrmypdf -s r -l rotate-pages -d "rotate pages to correct orientation"
complete -c ocrmypdf -s d -l deskew -d "fix small horizontal alignment skew"
complete -c ocrmypdf -s c -l clean -d "clean document images before OCR"
complete -c ocrmypdf -s i -l clean-final -d "clean document images and keep result"
complete -c ocrmypdf -l remove-vectors -d "don't send vector objects to OCR"
complete -c ocrmypdf -l mask-barcodes -d "mask barcodes from OCR"
complete -c ocrmypdf -l threshold -d "threshold images before OCR"
complete -c ocrmypdf -s f -l force-ocr -d "OCR documents that already have printable text"
complete -c ocrmypdf -s s -l skip-ocr -d "skip OCR on pages that text, otherwise try OCR"
complete -c ocrmypdf -l redo-ocr -d "redo OCR on any pages that seem to have OCR already"
complete -c ocrmypdf -s k -l keep-temporary-files -d "keep temporary files (debug)"
complete -c ocrmypdf -x -s l -l language -d 'language'
complete -c ocrmypdf -x -s l -l language -a '(tesseract --list-langs)'
complete -c ocrmypdf -x -l image-dpi -d "assume this DPI if input image DPI is unknown"
function __fish_ocrmypdf_output_type
echo -e "pdfa\t"(_ "output a PDF/A (default)")
echo -e "pdf\t"(_ "output a standard PDF")
echo -e "pdfa-1\t"(_ "output a PDF/A-1b")
echo -e "pdfa-2\t"(_ "output a PDF/A-2b")
echo -e "pdfa-3\t"(_ "output a PDF/A-3b")
end
complete -c ocrmypdf -x -l output-type -a '(__fish_ocrmypdf_output_type)' -d "select PDF output options"
function __fish_ocrmypdf_pdf_renderer
echo -e "auto\t"(_ "auto select PDF renderer")
echo -e "hocr\t"(_ "use hocr renderer")
echo -e "sandwich\t"(_ "use sandwich renderer")
end
complete -c ocrmypdf -x -l pdf-render -a '(__fish_ocrmypdf_pdf_renderer)' -d "select PDF renderer options"
function __fish_ocrmypdf_optimize
echo -e "0\t"(_ "do not optimize")
echo -e "1\t"(_ "do safe, lossless optimizations (default)")
echo -e "2\t"(_ "do some lossy optimizations")
echo -e "3\t"(_ "do aggressive lossy optimizations (including lossy JBIG2)")
end
complete -c ocrmypdf -x -s O -l optimize -a '(__fish_ocrmypdf_optimize)' -d "select optimization level"
complete -c ocrmypdf -x -s j -l jobs -d "how many worker processes to use"
complete -c ocrmypdf -x -s v -a '(seq 1 9)'
complete -c ocrmypdf -x -l title -d "set metadata"
complete -c ocrmypdf -x -l author -d "set metadata"
complete -c ocrmypdf -x -l subject -d "set metadata"
complete -c ocrmypdf -x -l keywords -d "set metadata"
complete -c ocrmypdf -x -l oversample -d "oversample images to this DPI"
complete -c ocrmypdf -x -l skip-big -d "skip OCR on pages larger than this many MPixels"
complete -c ocrmypdf -x -l jpeg-quality -d "JPEG quality [0..100]"
complete -c ocrmypdf -x -l png-quality -d "PNG quality [0..100]"
complete -c ocrmypdf -x -l jbig2-lossy -d "enable lossy JBIG2 (see docs)"
complete -c ocrmypdf -x -l max-image-mpixels -d "image decompression bomb threshold"
complete -c ocrmypdf -x -l tesseract-config -d "set custom tesseract config file"
complete -c ocrmypdf -x -l tesseract-pagesegmode -d "set tesseract --psm"
complete -c ocrmypdf -x -l tesseract-oem -d "set tesseract --oem"
complete -c ocrmypdf -x -l tesseract-timeout -d "maximum number of seconds to wait for OCR"
complete -c ocrmypdf -x -l rotate-pages-threshold -d "page rotation confidence"
complete -c ocrmypdf -x -l pdfa-image-compression -a 'auto jpeg lossless' -d "set PDF/A image compression options"
complete -c ocrmypdf -x -a "(__fish_complete_suffix .pdf)"
+1 -1
View File
@@ -5,7 +5,7 @@ chardet == 3.0.4
cffi == 1.11.5
img2pdf == 0.3.1
pdfminer.six == 20181108
pikepdf == 0.9.1
pikepdf == 1.0.2
Pillow >= 5.0.0, != 5.1.0 ; sys_platform == "darwin"
pycparser == 2.19
python-xmp-toolkit == 2.0.1
+7
View File
@@ -14,5 +14,12 @@ testpaths = tests
filterwarnings =
ignore:.*XMLParser.*:DeprecationWarning
[isort]
multi_line_output=3
include_trailing_comma=True
force_grid_wrap=0
use_parentheses=True
line_length=88
[metadata]
license_file = LICENSE
+18 -19
View File
@@ -20,15 +20,16 @@
from __future__ import print_function, unicode_literals
import sys
if sys.version_info < (3, 5):
print("Python 3.5 or newer is required", file=sys.stderr)
if sys.version_info < (3, 6):
print("Python 3.6 or newer is required", file=sys.stderr)
sys.exit(1)
from setuptools import setup, find_packages # nopep8
from subprocess import STDOUT, check_output, CalledProcessError # nopep8
from collections.abc import Mapping # nopep8
import re # nopep8
from setuptools import setup, find_packages
from subprocess import STDOUT, check_output, CalledProcessError
from collections.abc import Mapping
import re
# pylint: disable=w0613
missing_program = '''
The program '{program}' could not be executed or was not found on your
@@ -131,12 +132,12 @@ def check_external_program(
program,
need_version,
package,
version_check_args=['--version'],
version_check_args=None,
version_scrape_regex=re.compile(r'(\d+\.\d+(?:\.\d+)?)'),
optional=False):
print('Checking for {program} >= {need_version}...'.format(
program=program, need_version=need_version))
if not version_check_args:
version_check_args = ['--version']
print(f'Checking for {program} >= {need_version}...')
try:
result = check_output(
[program] + version_check_args,
@@ -145,7 +146,7 @@ def check_external_program(
error_missing_program(program, package, optional)
if not optional:
sys.exit(1)
print('Continuing install without {program}'.format(program=program))
print(f'Continuing install without {program}')
return
try:
@@ -158,8 +159,7 @@ def check_external_program(
error_old_version(program, package, optional, need_version,
found_version)
print('Found {program} {found_version}'.format(
program=program, found_version=found_version))
print(f'Found {program} {found_version}')
command = next((arg for arg in sys.argv[1:] if not arg.startswith('-')), '')
@@ -170,7 +170,7 @@ if not forced and command.startswith('install') or \
command in ['check', 'test', 'nosetests', 'easy_install']:
check_external_program(
program='tesseract',
need_version='3.04', # using backport for Travis CI
need_version='4.0.0', # using backport for Travis CI
package={'darwin': 'tesseract', 'linux': 'tesseract-ocr'}
)
check_external_program(
@@ -219,7 +219,6 @@ setup(
package_dir={'': 'src'},
keywords=['PDF', 'OCR', 'optical character recognition', 'PDF/A', 'scanning'],
classifiers=[
"Programming Language :: Python :: 3.5",
"Programming Language :: Python :: 3.6",
"Programming Language :: Python :: 3.7",
"Development Status :: 5 - Production/Stable",
@@ -236,7 +235,7 @@ setup(
"Topic :: Text Processing :: Indexing",
"Topic :: Text Processing :: Linguistic",
],
python_requires=' >= 3.5',
python_requires=' >= 3.6',
setup_requires=[
'cffi >= 1.9.1', # to build the leptonica module
'pytest-runner', # to enable python setup.py test
@@ -251,8 +250,8 @@ setup(
'chardet >= 3.0.4, < 4', # unlisted requirement of pdfminer.six 20181108
'cffi >= 1.9.1', # must be a setup and install requirement
'img2pdf >= 0.3.0, < 0.4', # pure Python, so track HEAD closely
'pdfminer.six == 20181108',
'pikepdf >= 0.9.1',
'pdfminer.six == 20181108 ; sys_platform != "darwin"',
'pikepdf >= 1.0.2, < 2',
'Pillow >= 4.0.0, != 5.1.0 ; sys_platform == "darwin"',
# Pillow < 4 has BytesIO/TIFF bug w/img2pdf 0.2.3
# block 5.1.0, broken wheels
@@ -260,7 +259,7 @@ setup(
'ruffus >= 2.7.0',
],
extras_require={
'fitz': [], # Backward compatibility
'pdfminer': ['pdfminer.six == 20181108'],
},
tests_require=tests_require,
entry_points={
+12 -4
View File
@@ -25,10 +25,18 @@ __version__ = pkg_resources.get_distribution('ocrmypdf').version
VERSION = __version__
from .exceptions import (
ExitCode, BadArgsError, PdfMergeFailedError, MissingDependencyError,
UnsupportedImageFormatError, DpiError, OutputFileAccessError,
PriorOcrFoundError, InputFileError, SubprocessOutputError,
EncryptedPdfError, TesseractConfigError
ExitCode,
BadArgsError,
PdfMergeFailedError,
MissingDependencyError,
UnsupportedImageFormatError,
DpiError,
OutputFileAccessError,
PriorOcrFoundError,
InputFileError,
SubprocessOutputError,
EncryptedPdfError,
TesseractConfigError,
)
from . import helpers
+398 -287
View File
File diff suppressed because it is too large Load Diff
+3 -4
View File
@@ -15,10 +15,10 @@
# You should have received a copy of the GNU General Public License
# along with OCRmyPDF. If not, see <http://www.gnu.org/licenses/>.
import shutil
import sys
from contextlib import suppress
from multiprocessing.managers import SyncManager
import sys
import shutil
from .pdfinfo import PdfInfo
@@ -77,8 +77,7 @@ class JobContextManager(SyncManager):
def cleanup_working_files(work_folder, options):
if options.keep_temporary_files:
print("Temporary working files saved at:\n{0}".format(work_folder),
file=sys.stderr)
print(f"Temporary working files saved at:\n{work_folder}", file=sys.stderr)
else:
with suppress(FileNotFoundError):
shutil.rmtree(work_folder)
+305 -314
View File
File diff suppressed because it is too large Load Diff
+11 -6
View File
@@ -33,9 +33,9 @@
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
import codecs
import os
import sys
import codecs
def verify_python3_env(): # pragma: no cover
@@ -47,6 +47,7 @@ def verify_python3_env(): # pragma: no cover
try:
import locale
fs_enc = codecs.lookup(locale.getpreferredencoding()).name
except Exception:
fs_enc = 'ascii'
@@ -56,8 +57,10 @@ def verify_python3_env(): # pragma: no cover
extra = ''
if os.name == 'posix':
import subprocess
rv = subprocess.Popen(['locale', '-a'], stdout=subprocess.PIPE,
stderr=subprocess.PIPE).communicate()[0]
rv = subprocess.Popen(
['locale', '-a'], stdout=subprocess.PIPE, stderr=subprocess.PIPE
).communicate()[0]
good_locales = set()
has_c_utf8 = False
@@ -108,6 +111,8 @@ def verify_python3_env(): # pragma: no cover
'is not supported'
) % bad_locale
raise RuntimeError('ocrmypdf will abort further execution because Python 3 '
'was configured to use ASCII as encoding for the '
'environment.' + extra)
raise RuntimeError(
'ocrmypdf will abort further execution because Python 3 '
'was configured to use ASCII as encoding for the '
'environment.' + extra
)
+33 -38
View File
@@ -15,13 +15,13 @@
# You should have received a copy of the GNU General Public License
# along with OCRmyPDF. If not, see <http://www.gnu.org/licenses/>.
from pathlib import Path
from itertools import groupby
from pathlib import Path
import pikepdf
from .helpers import flatten_groups, page_number
from .exec import tesseract
from .helpers import flatten_groups, page_number
def _update_page_resources(*, page, font, font_key, procset):
@@ -89,8 +89,8 @@ def strip_invisible_text(pdf, page, log):
def _weave_layers_graft(
*, pdf_base, page_num, text, font, font_key, procset, rotation,
strip_old_text, log):
*, pdf_base, page_num, text, font, font_key, procset, rotation, strip_old_text, log
):
"""Insert the text layer from text page 0 on to pdf_base at page_num"""
log.debug("Grafting")
@@ -108,7 +108,7 @@ def _weave_layers_graft(
stream = bytearray(pdf_text_contents)
pattern = b'/Im1 Do'
idx = stream.find(pattern)
stream[idx:(idx + len(pattern))] = b' ' * len(pattern)
stream[idx : (idx + len(pattern))] = b' ' * len(pattern)
pdf_text_contents = bytes(stream)
base_page = pdf_base.pages.p(page_num)
@@ -117,12 +117,10 @@ def _weave_layers_graft(
# content may have a rotation applied. Wrap the text stream with a rotation
# so it will be oriented the same way as the rest of the page content.
# (Previous versions OCRmyPDF rotated the content layer to match the text.)
mediabox = [float(pdf_text.pages[0].MediaBox[v])
for v in range(4)]
mediabox = [float(pdf_text.pages[0].MediaBox[v]) for v in range(4)]
wt, ht = mediabox[2] - mediabox[0], mediabox[3] - mediabox[1]
mediabox = [float(base_page.MediaBox[v])
for v in range(4)]
mediabox = [float(base_page.MediaBox[v]) for v in range(4)]
wp, hp = mediabox[2] - mediabox[0], mediabox[3] - mediabox[1]
translate = pikepdf.PdfMatrix().translated(-wt / 2, -ht / 2)
@@ -147,11 +145,7 @@ def _weave_layers_graft(
# for a size different between initial and text PDF, then untranslate
ctm = translate @ rotate @ scale @ untranslate
pdf_text_contents = (
b'q %s cm\n' % ctm.encode() +
pdf_text_contents +
b'\nQ\n'
)
pdf_text_contents = b'q %s cm\n' % ctm.encode() + pdf_text_contents + b'\nQ\n'
new_text_layer = pikepdf.Stream(pdf_base, pdf_text_contents)
@@ -254,8 +248,7 @@ def _fix_toc(pdf_base, pageref_remap, log):
if not isinstance(dest_node, pikepdf.Array):
return
pageref = dest_node[0]
if pageref['/Type'] == '/Page' and \
pageref.objgen in pageref_remap:
if pageref['/Type'] == '/Page' and pageref.objgen in pageref_remap:
new_objgen = pageref_remap[pageref.objgen]
dest_node[0] = pdf_base.get_object(new_objgen)
@@ -278,11 +271,7 @@ def _fix_toc(pdf_base, pageref_remap, log):
_traverse_toc(pdf_base, visit_remap_dest, log)
def weave_layers(
infiles,
output_file,
log,
context):
def weave_layers(infiles, output_file, log, context):
"""Apply text layer and/or image layer changes to baseline file
This is where the magic happens. infiles will be the main PDF to modify,
@@ -313,6 +302,7 @@ def weave_layers(
return page_number(key)
except ValueError:
return -1
flat_inputs = sorted(flatten_groups(infiles), key=input_sorter)
groups = groupby(flat_inputs, key=input_sorter)
@@ -333,7 +323,8 @@ def weave_layers(
_traverse_toc(pdf_base, None, log)
procset = pdf_base.make_indirect(
pikepdf.Object.parse(b'[ /PDF /Text /ImageB /ImageC /ImageI ]'))
pikepdf.Object.parse(b'[ /PDF /Text /ImageB /ImageC /ImageI ]')
)
# Iterate rest
for page_num, layers in groups:
@@ -341,12 +332,8 @@ def weave_layers(
log.debug(page_num)
log.debug(layers)
text = next(
(ii for ii in layers if ii.endswith('.text.pdf')), None
)
image = next(
(ii for ii in layers if ii.endswith('.image-layer.pdf')), None
)
text = next((ii for ii in layers if ii.endswith('.text.pdf')), None)
image = next((ii for ii in layers if ii.endswith('.image-layer.pdf')), None)
if text and not font:
font, font_key = _find_font(text, pdf_base)
@@ -378,23 +365,30 @@ def weave_layers(
content_rotation = autorotate_correction
text_rotation = autorotate_correction
text_misaligned = (text_rotation - content_rotation) % 360
log.debug('%r', [
text_rotation, autorotate_correction, text_misaligned,
content_rotation]
log.debug(
'%r',
[text_rotation, autorotate_correction, text_misaligned, content_rotation],
)
if text and font:
# Graft the text layer onto this page, whether new or old
strip_old = context.get_options().redo_ocr
_weave_layers_graft(
pdf_base=pdf_base, page_num=page_num, text=text, font=font,
font_key=font_key, rotation=text_misaligned, procset=procset,
strip_old_text=strip_old, log=log
pdf_base=pdf_base,
page_num=page_num,
text=text,
font=font,
font_key=font_key,
rotation=text_misaligned,
procset=procset,
strip_old_text=strip_old,
log=log,
)
# Correct the rotation if applicable
pdf_base.pages[page_num - 1].Rotate = \
(content_rotation - autorotate_correction) % 360
pdf_base.pages[page_num - 1].Rotate = (
content_rotation - autorotate_correction
) % 360
if len(keep_open) > 100:
# qpdf limitations require us to keep files open when we intend
@@ -404,8 +398,9 @@ def weave_layers(
# even if page 1 doesn't use it, so we have a way to get it back.
page0 = pdf_base.pages[0]
_update_page_resources(
page=page0, font=font, font_key=font_key, procset=procset)
interim = output_file + '_working{}.pdf'.format(page_num)
page=page0, font=font, font_key=font_key, procset=procset
)
interim = output_file + f'_working{page_num}.pdf'
pdf_base.save(interim)
del pdf_base
keep_open = []
+10 -4
View File
@@ -19,6 +19,7 @@
from enum import IntEnum
from textwrap import dedent
class ExitCode(IntEnum):
ok = 0
bad_args = 1
@@ -52,7 +53,8 @@ class BadArgsError(ExitCodeException):
class PdfMergeFailedError(ExitCodeException):
exit_code = ExitCode.input_file
message = dedent('''\
message = dedent(
'''\
Failed to merge PDF image layer with OCR layer
Usually this happens because the input PDF file is malformed and
@@ -60,7 +62,9 @@ class PdfMergeFailedError(ExitCodeException):
Try using
ocrmypdf --pdf-renderer sandwich [..other args..]
''')
'''
)
class MissingDependencyError(ExitCodeException):
exit_code = ExitCode.missing_dependency
@@ -92,7 +96,8 @@ class SubprocessOutputError(ExitCodeException):
class EncryptedPdfError(ExitCodeException):
exit_code = ExitCode.encrypted_pdf
message = dedent('''\
message = dedent(
'''\
Input PDF is encrypted. The encryption must be removed to
perform OCR.
@@ -101,7 +106,8 @@ class EncryptedPdfError(ExitCodeException):
You can remove the encryption using
qpdf --decrypt [--password=[password]] infilename
''')
'''
)
class TesseractConfigError(ExitCodeException):
+17 -16
View File
@@ -24,36 +24,37 @@ from subprocess import run, STDOUT, PIPE, CalledProcessError
from ..exceptions import MissingDependencyError
def get_version(program, *,
version_arg='--version', regex=r'(\d+(\.\d+)*)'):
def get_version(program, *, version_arg='--version', regex=r'(\d+(\.\d+)*)'):
"Get the version of the specified program"
args_prog = [
program,
version_arg
]
args_prog = [program, version_arg]
try:
proc = run(
args_prog, close_fds=True, universal_newlines=True,
stdout=PIPE, stderr=STDOUT, check=True)
args_prog,
close_fds=True,
universal_newlines=True,
stdout=PIPE,
stderr=STDOUT,
check=True,
)
output = proc.stdout
except FileNotFoundError as e:
raise MissingDependencyError(
"Could not find program '{}' on the PATH".format(
program)) from e
f"Could not find program '{program}' on the PATH"
) from e
except CalledProcessError as e:
if e.returncode < 0:
raise MissingDependencyError(
"Ran program '{}' but it exited with an error:\n{}".format(
program, e.output)) from e
f"Ran program '{program}' but it exited with an error:\n{e.output}"
) from e
raise MissingDependencyError(
"Could not find program '{}' on the PATH".format(
program)) from e
f"Could not find program '{program}' on the PATH"
) from e
try:
version = re.match(regex, output.strip()).group(1)
except AttributeError as e:
raise MissingDependencyError(
("The program '{}' did not report its version. "
"Message was:\n{}").format(program, output)
f"The program '{program}' did not report its version. "
f"Message was:\n{output}"
)
return version
+94 -69
View File
@@ -15,15 +15,17 @@
# You should have received a copy of the GNU General Public License
# along with OCRmyPDF. If not, see <http://www.gnu.org/licenses/>.
from tempfile import NamedTemporaryFile
from subprocess import run, PIPE, STDOUT
from shutil import copy
from functools import lru_cache
import re
from functools import lru_cache
from os import fspath
from shutil import copy
from subprocess import PIPE, STDOUT, run
from tempfile import NamedTemporaryFile
from PIL import Image
from . import get_version
from ..exceptions import SubprocessOutputError
from ..helpers import fspath
@lru_cache(maxsize=1)
@@ -69,39 +71,46 @@ def extract_text(input_file, pageno=1):
"""
if pageno is not None:
pages = [
'-dFirstPage=%i' % pageno,
'-dLastPage=%i' % pageno
]
pages = ['-dFirstPage=%i' % pageno, '-dLastPage=%i' % pageno]
else:
pages = []
args_gs = [
'gs',
'-dQUIET',
'-dSAFER',
'-dBATCH',
'-dNOPAUSE',
'-sDEVICE=txtwrite',
'-dTextFormat=0',
] + pages + [
'-o', '-',
fspath(input_file)
]
args_gs = (
[
'gs',
'-dQUIET',
'-dSAFER',
'-dBATCH',
'-dNOPAUSE',
'-sDEVICE=txtwrite',
'-dTextFormat=0',
]
+ pages
+ ['-o', '-', fspath(input_file)]
)
p = run(args_gs, stdout=PIPE, stderr=PIPE)
if p.returncode != 0:
raise SubprocessOutputError(
'Ghostscript text extraction failed\n%s\n%s\n%s' % (
input_file, p.stdout.decode(), p.stderr.decode()
)
'Ghostscript text extraction failed\n%s\n%s\n%s'
% (input_file, p.stdout.decode(), p.stderr.decode())
)
return p.stdout
def rasterize_pdf(input_file, output_file, xres, yres, raster_device, log,
pageno=1, page_dpi=None, rotation=None, filter_vector=False):
def rasterize_pdf(
input_file,
output_file,
xres,
yres,
raster_device,
log,
pageno=1,
page_dpi=None,
rotation=None,
filter_vector=False,
):
"""Rasterize one page of a PDF at resolution (xres, yres) in canvas units.
The image is sized to match the integer pixels dimensions implied by
@@ -126,26 +135,30 @@ def rasterize_pdf(input_file, output_file, xres, yres, raster_device, log,
page_dpi = res
with NamedTemporaryFile(delete=True) as tmp:
args_gs = [
'gs',
'-dQUIET',
'-dSAFER',
'-dBATCH',
'-dNOPAUSE',
'-sDEVICE=%s' % raster_device,
'-dFirstPage=%i' % pageno,
'-dLastPage=%i' % pageno,
'-r{0}x{1}'.format(str(int_res[0]), str(int_res[1])),
] + (['-dFILTERVECTOR'] if filter_vector else []) + [
'-o', tmp.name,
'-dAutoRotatePages=/None', # Probably has no effect on raster
'-f',
fspath(input_file)
]
args_gs = (
[
'gs',
'-dQUIET',
'-dSAFER',
'-dBATCH',
'-dNOPAUSE',
f'-sDEVICE={raster_device}',
f'-dFirstPage={pageno}',
f'-dLastPage={pageno}',
f'-r{str(int_res[0])}x{str(int_res[1])}',
]
+ (['-dFILTERVECTOR'] if filter_vector else [])
+ [
'-o',
tmp.name,
'-dAutoRotatePages=/None', # Probably has no effect on raster
'-f',
fspath(input_file),
]
)
log.debug(args_gs)
p = run(args_gs, stdout=PIPE, stderr=STDOUT,
universal_newlines=True)
p = run(args_gs, stdout=PIPE, stderr=STDOUT, universal_newlines=True)
if _gs_error_reported(p.stdout):
log.error(p.stdout)
else:
@@ -162,12 +175,14 @@ def rasterize_pdf(input_file, output_file, xres, yres, raster_device, log,
tmp.seek(0)
with Image.open(tmp) as im:
expected_size = round(im.size[0] / int_res[0] * res[0]), \
round(im.size[1] / int_res[1] * res[1])
expected_size = (
round(im.size[0] / int_res[0] * res[0]),
round(im.size[1] / int_res[1] * res[1]),
)
if expected_size != im.size or page_dpi != (xres, yres):
log.debug(
"Ghostscript: resize output image {} -> {}".format(
im.size, expected_size))
f"Ghostscript: resize output image {im.size} -> {expected_size}"
)
im = im.resize(expected_size)
if rotation is not None:
@@ -185,8 +200,15 @@ def rasterize_pdf(input_file, output_file, xres, yres, raster_device, log,
im.save(fspath(output_file), dpi=page_dpi)
def generate_pdfa(pdf_pages, output_file, compression, log,
threads=1, pdf_version='1.5', pdfa_part='2'):
def generate_pdfa(
pdf_pages,
output_file,
compression,
log,
threads=1,
pdf_version='1.5',
pdfa_part='2',
):
"""Generate a PDF/A.
The pdf_pages, a list files, will be merged into output_file. One or more
@@ -240,26 +262,29 @@ def generate_pdfa(pdf_pages, output_file, compression, log,
# nb no need to specify ProcessColorModel when ColorConversionStrategy
# is set; see:
# https://bugs.ghostscript.com/show_bug.cgi?id=699392
args_gs = [
"gs",
"-dQUIET",
"-dBATCH",
"-dNOPAUSE",
"-dCompatibilityLevel=" + str(pdf_version),
"-dNumRenderingThreads=" + str(threads),
"-sDEVICE=pdfwrite",
"-dAutoRotatePages=/None",
"-sColorConversionStrategy=" + strategy
] + compression_args + [
"-dJPEGQ=95",
"-dPDFA=" + pdfa_part,
"-dPDFACompatibilityPolicy=1",
"-sOutputFile=" + gs_pdf.name,
]
args_gs = (
[
"gs",
"-dQUIET",
"-dBATCH",
"-dNOPAUSE",
"-dCompatibilityLevel=" + str(pdf_version),
"-dNumRenderingThreads=" + str(threads),
"-sDEVICE=pdfwrite",
"-dAutoRotatePages=/None",
"-sColorConversionStrategy=" + strategy,
]
+ compression_args
+ [
"-dJPEGQ=95",
"-dPDFA=" + pdfa_part,
"-dPDFACompatibilityPolicy=1",
"-sOutputFile=" + gs_pdf.name,
]
)
args_gs.extend(fspath(s) for s in pdf_pages) # Stringify Path objs
log.debug(args_gs)
p = run(args_gs, stdout=PIPE, stderr=STDOUT,
universal_newlines=True)
p = run(args_gs, stdout=PIPE, stderr=STDOUT, universal_newlines=True)
if _gs_error_reported(p.stdout):
log.error(p.stdout)
@@ -270,7 +295,7 @@ def generate_pdfa(pdf_pages, output_file, compression, log,
log.debug(
"Ghostscript had to remove PDF 'overprinting' from the "
"input file to complete PDF/A conversion. "
)
)
else:
log.debug(p.stdout)
+3 -7
View File
@@ -15,8 +15,8 @@
# You should have received a copy of the GNU General Public License
# along with OCRmyPDF. If not, see <http://www.gnu.org/licenses/>.
from subprocess import run, PIPE
from functools import lru_cache
from subprocess import PIPE, run
from . import get_version
from ..exceptions import MissingDependencyError
@@ -42,7 +42,7 @@ def convert_group(*, cwd, infiles, out_prefix):
out_prefix,
'-s', # symbol mode (lossy)
# '-r', # refinement mode (lossless symbol mode, currently disabled in
# jbig2)
# jbig2)
'-p',
]
args.extend(infiles)
@@ -52,11 +52,7 @@ def convert_group(*, cwd, infiles, out_prefix):
def convert_single(*, cwd, infile, outfile):
args = [
'jbig2',
'-p',
infile
]
args = ['jbig2', '-p', infile]
with open(outfile, 'wb') as fstdout:
proc = run(args, cwd=cwd, stdout=fstdout, stderr=PIPE)
proc.check_returncode()
+6 -4
View File
@@ -15,8 +15,8 @@
# You should have received a copy of the GNU General Public License
# along with OCRmyPDF. If not, see <http://www.gnu.org/licenses/>.
from subprocess import run
from functools import lru_cache
from subprocess import run
from . import get_version
from ..exceptions import MissingDependencyError
@@ -40,10 +40,12 @@ def quantize(input_file, output_file, quality_min, quality_max):
'pngquant',
'--force',
'--skip-if-larger',
'--output', output_file,
'--quality', '{}-{}'.format(quality_min, quality_max),
'--output',
output_file,
'--quality',
f'{quality_min}-{quality_max}',
'--',
input_file
input_file,
]
proc = run(args)
proc.check_returncode()
+6 -12
View File
@@ -15,11 +15,11 @@
# You should have received a copy of the GNU General Public License
# along with OCRmyPDF. If not, see <http://www.gnu.org/licenses/>.
from subprocess import CalledProcessError, STDOUT, PIPE, run
from functools import lru_cache
from os import fspath
from subprocess import PIPE, STDOUT, CalledProcessError, run
from . import get_version
from ..helpers import fspath
from . import get_version
@lru_cache(maxsize=1)
@@ -28,22 +28,16 @@ def version():
def check(input_file, log=None):
args_qpdf = [
'qpdf',
'--check',
fspath(input_file)
]
args_qpdf = ['qpdf', '--check', fspath(input_file)]
if log is None:
import logging as log
try:
run(args_qpdf, stderr=STDOUT, stdout=PIPE, universal_newlines=True,
check=True)
run(args_qpdf, stderr=STDOUT, stdout=PIPE, universal_newlines=True, check=True)
except CalledProcessError as e:
if e.returncode == 2:
log.error("%s: not a valid PDF, and could not repair it.",
input_file)
log.error("%s: not a valid PDF, and could not repair it.", input_file)
log.error("Details:")
log.error(e.output)
elif e.returncode == 3:
+80 -92
View File
@@ -15,22 +15,28 @@
# You should have received a copy of the GNU General Public License
# along with OCRmyPDF. If not, see <http://www.gnu.org/licenses/>.
import sys
import os
import shutil
from functools import lru_cache
import sys
from collections import namedtuple
from textwrap import dedent
from subprocess import CalledProcessError, TimeoutExpired, check_output, STDOUT, run, PIPE
from contextlib import suppress
from functools import lru_cache
from os import fspath
from subprocess import (
PIPE,
STDOUT,
CalledProcessError,
TimeoutExpired,
check_output,
run,
)
from textwrap import dedent
from ..exceptions import MissingDependencyError, TesseractConfigError
from ..helpers import page_number, fspath
from . import get_version
from ..exceptions import MissingDependencyError, TesseractConfigError
from ..helpers import page_number
OrientationConfidence = namedtuple(
'OrientationConfidence',
('angle', 'confidence'))
OrientationConfidence = namedtuple('OrientationConfidence', ('angle', 'confidence'))
HOCR_TEMPLATE = """<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
@@ -39,8 +45,8 @@ HOCR_TEMPLATE = """<?xml version="1.0" encoding="UTF-8"?>
<head>
<title></title>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
<meta name='ocr-system' content='tesseract 3.05.00' />
<meta name='ocr-capabilities' content='ocr_page ocr_carea ocr_par ocr_line ocrx_word'/>
<meta name='ocr-system' content='tesseract 4.0.0' />
<meta name='ocr-capabilities' content='ocr_page ocr_carea ocr_par ocr_line ocrx_word ocrp_wconf'/>
</head>
<body>
<div class='ocr_page' id='page_1' title='image "_blank.png"; bbox 0 0 {0} {1}; ppageno 0'>
@@ -64,50 +70,37 @@ def v4():
def has_textonly_pdf():
"""Does Tesseract have textonly_pdf capability?
Available in 3.05.01, and v4.00.00alpha since January 2017. Best to
Available in v4.00.00alpha since January 2017. Best to
parse the parameter list
"""
args_tess = [
'tesseract',
'--print-parameters',
'pdf'
]
args_tess = ['tesseract', '--print-parameters', 'pdf']
params = ''
try:
params = check_output(
args_tess, universal_newlines=True, stderr=STDOUT)
params = check_output(args_tess, universal_newlines=True, stderr=STDOUT)
except CalledProcessError as e:
print("Could not --print-parameters from tesseract",
file=sys.stderr)
print("Could not --print-parameters from tesseract", file=sys.stderr)
raise MissingDependencyError from e
if 'textonly_pdf' in params:
return True
return False
def psm():
"If Tesseract 4.0, use argument --psm instead of -psm"
return '--psm' if v4() else '-psm'
@lru_cache(maxsize=1)
def languages():
def lang_error(output):
msg = dedent("""Tesseract failed to report available languages.
msg = dedent(
"""Tesseract failed to report available languages.
Output from Tesseract:
-----------
""")
"""
)
msg += output
print(msg, file=sys.stderr)
args_tess = [
'tesseract',
'--list-langs'
]
args_tess = ['tesseract', '--list-langs']
try:
proc = run(
args_tess, universal_newlines=True, stdout=PIPE, stderr=STDOUT,
check=True
args_tess, universal_newlines=True, stdout=PIPE, stderr=STDOUT, check=True
)
output = proc.stdout
except CalledProcessError as e:
@@ -122,9 +115,7 @@ def languages():
def tess_base_args(langs, engine_mode):
args = [
'tesseract',
]
args = ['tesseract']
if langs:
args.extend(['-l', '+'.join(langs)])
if engine_mode is not None and v4():
@@ -134,20 +125,22 @@ def tess_base_args(langs, engine_mode):
def get_orientation(input_file, engine_mode, timeout: float, log):
args_tesseract = tess_base_args(['osd'], engine_mode) + [
psm(), '0',
'--psm',
'0',
fspath(input_file),
'stdout'
'stdout',
]
try:
stdout = check_output(
args_tesseract, stderr=STDOUT, timeout=timeout)
stdout = check_output(args_tesseract, stderr=STDOUT, timeout=timeout)
except TimeoutExpired:
return OrientationConfidence(angle=0, confidence=0.0)
except CalledProcessError as e:
tesseract_log_output(log, e.output, input_file)
if (b'Too few characters. Skipping this page' in e.output or
b'Image too large' in e.output):
if (
b'Too few characters. Skipping this page' in e.output
or b'Image too large' in e.output
):
return OrientationConfidence(0, 0)
raise e from e
else:
@@ -159,32 +152,24 @@ def get_orientation(input_file, engine_mode, timeout: float, log):
osd[parts[0].strip()] = parts[1].strip()
angle = int(osd.get('Orientation in degrees', 0))
if 'Orientation' in osd:
# Tesseract < 3.04.01
# reports "Orientation in degrees" as a counterclockwise angle
# We keep it clockwise
assert 'Rotate' not in osd
angle = -angle % 360
else:
# Tesseract >= 3.04.01
# reports "Orientation in degrees" as a clockwise angle
assert 'Rotate' in osd
oc = OrientationConfidence(
angle=angle,
confidence=float(osd.get('Orientation confidence', 0)))
angle=angle, confidence=float(osd.get('Orientation confidence', 0))
)
return oc
def tesseract_log_output(log, stdout, input_file):
prefix = "{0:4d}: [tesseract] ".format(page_number(input_file))
prefix = f"{(page_number(input_file)):4d}: [tesseract] "
try:
text = stdout.decode()
except UnicodeDecodeError:
log.error(prefix + "command line output was not utf-8. " +
"This usually means Tesseract's language packs do not match "
"the installed version of Tesseract.")
log.error(
prefix
+ "command line output was not utf-8. "
+ "This usually means Tesseract's language packs do not match "
"the installed version of Tesseract."
)
text = stdout.decode('utf-8', 'backslashreplace')
lines = text.splitlines()
@@ -216,7 +201,7 @@ def tesseract_log_output(log, stdout, input_file):
def page_timedout(log, input_file):
prefix = "{0:4d}: [tesseract] ".format(page_number(input_file))
prefix = f"{(page_number(input_file)):4d}: [tesseract] "
log.warning(prefix + " took too long to OCR - skipping")
@@ -234,10 +219,18 @@ def _generate_null_hocr(output_hocr, output_sidecar, image):
f.write('[skipped page]')
def generate_hocr(input_file, output_files, language: list, engine_mode,
tessconfig: list,
timeout: float, pagesegmode: int, user_words, user_patterns,
log):
def generate_hocr(
input_file,
output_files,
language: list,
engine_mode,
tessconfig: list,
timeout: float,
pagesegmode: int,
user_words,
user_patterns,
log,
):
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'))
@@ -246,7 +239,7 @@ def generate_hocr(input_file, output_files, language: list, engine_mode,
args_tesseract = tess_base_args(language, engine_mode)
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])
@@ -256,20 +249,10 @@ def generate_hocr(input_file, output_files, language: list, engine_mode,
# Reminder: test suite tesseract spoofers will break after any changes
# to the number of order parameters here
# Tesseract 3.04 requires the order here to be "hocr txt" and will fail
# on "txt hocr"
args_tesseract.extend([
input_file,
prefix,
'hocr',
'txt'
] + tessconfig)
args_tesseract.extend([input_file, prefix, 'hocr', 'txt'] + tessconfig)
try:
log.debug(args_tesseract)
stdout = check_output(
args_tesseract, stderr=STDOUT,
timeout=timeout)
stdout = check_output(args_tesseract, stderr=STDOUT, timeout=timeout)
except TimeoutExpired:
# Generate a HOCR file with no recognized text if tesseract times out
# Temporary workaround to hocrTransform not being able to function if
@@ -307,10 +290,22 @@ def use_skip_page(text_only, skip_pdf, output_pdf, output_text):
out.write(b'')
def generate_pdf(*, input_image, skip_pdf=None, output_pdf, output_text,
language: list, engine_mode, text_only: bool,
tessconfig: list, timeout: float, pagesegmode: int,
user_words, user_patterns, log):
def generate_pdf(
*,
input_image,
skip_pdf=None,
output_pdf,
output_text,
language: list,
engine_mode,
text_only: bool,
tessconfig: list,
timeout: float,
pagesegmode: int,
user_words,
user_patterns,
log,
):
'''Use Tesseract to render a PDF.
input_image -- image to analyze
@@ -328,7 +323,7 @@ def generate_pdf(*, input_image, skip_pdf=None, output_pdf, output_text,
args_tesseract = tess_base_args(language, engine_mode)
if pagesegmode is not None:
args_tesseract.extend([psm(), str(pagesegmode)])
args_tesseract.extend(['--psm', str(pagesegmode)])
if text_only and has_textonly_pdf():
args_tesseract.extend(['-c', 'textonly_pdf=1'])
@@ -344,18 +339,11 @@ def generate_pdf(*, input_image, skip_pdf=None, output_pdf, output_text,
# Reminder: test suite tesseract spoofers might break after any changes
# to the number of order parameters here
args_tesseract.extend([
input_image,
prefix,
'pdf',
'txt'
] + tessconfig)
args_tesseract.extend([input_image, prefix, 'pdf', 'txt'] + tessconfig)
try:
log.debug(args_tesseract)
stdout = check_output(
args_tesseract, stderr=STDOUT,
timeout=timeout)
stdout = check_output(args_tesseract, stderr=STDOUT, timeout=timeout)
if os.path.exists(prefix + '.txt'):
shutil.move(prefix + '.txt', output_text)
except TimeoutExpired:
+28 -24
View File
@@ -18,14 +18,14 @@
# unpaper documentation:
# https://github.com/Flameeyes/unpaper/blob/master/doc/basic-concepts.md
from subprocess import CalledProcessError, STDOUT, check_output
from tempfile import NamedTemporaryFile
import sys
import os
import sys
from functools import lru_cache
from ..exceptions import MissingDependencyError
from . import get_version
from subprocess import STDOUT, CalledProcessError, check_output
from tempfile import NamedTemporaryFile
from . import get_version
from ..exceptions import MissingDependencyError
try:
from PIL import Image
@@ -40,11 +40,7 @@ def version():
def run(input_file, output_file, dpi, log, mode_args):
args_unpaper = [
'unpaper',
'-v',
'--dpi', str(dpi)
] + mode_args
args_unpaper = ['unpaper', '-v', '--dpi', str(dpi)] + mode_args
SUFFIXES = {'1': '.pbm', 'L': '.pgm', 'RGB': '.ppm'}
@@ -68,8 +64,9 @@ def run(input_file, output_file, dpi, log, mode_args):
im.close()
raise MissingDependencyError() from e
with NamedTemporaryFile(suffix=suffix) as input_pnm, \
NamedTemporaryFile(suffix=suffix, mode="r+b") as output_pnm:
with NamedTemporaryFile(suffix=suffix) as input_pnm, NamedTemporaryFile(
suffix=suffix, mode="r+b"
) as output_pnm:
im.save(input_pnm, format='PPM')
im.close()
@@ -78,9 +75,8 @@ def run(input_file, output_file, dpi, log, mode_args):
args_unpaper.extend([input_pnm.name, output_pnm.name])
try:
stdout = check_output(
args_unpaper, close_fds=True,
universal_newlines=True, stderr=STDOUT,
)
args_unpaper, close_fds=True, universal_newlines=True, stderr=STDOUT
)
except CalledProcessError as e:
log.debug(e.output)
raise e from e
@@ -91,12 +87,20 @@ def run(input_file, output_file, dpi, log, mode_args):
def clean(input_file, output_file, dpi, log):
run(input_file, output_file, dpi, log, [
'--layout', 'none',
'--mask-scan-size', '100', # don't blank out narrow columns
'--no-border-align', # don't align visible content to borders
'--no-mask-center', # don't center visible content within page
'--no-grayfilter', # don't remove light gray areas
'--no-blackfilter', # don't remove solid black areas
'--no-deskew', # don't deskew
])
run(
input_file,
output_file,
dpi,
log,
[
'--layout',
'none',
'--mask-scan-size',
'100', # don't blank out narrow columns
'--no-border-align', # don't align visible content to borders
'--no-mask-center', # don't center visible content within page
'--no-grayfilter', # don't remove light gray areas
'--no-blackfilter', # don't remove solid black areas
'--no-deskew', # don't deskew
],
)
+30 -66
View File
@@ -15,22 +15,22 @@
# You should have received a copy of the GNU General Public License
# along with OCRmyPDF. If not, see <http://www.gnu.org/licenses/>.
from functools import partial, wraps
import multiprocessing
import os
import sys
import warnings
from collections.abc import Iterable
from contextlib import suppress
from functools import partial, wraps
from pathlib import Path
import sys
import os
import multiprocessing
import warnings
def re_symlink(input_file, soft_link_name, log=None):
"""
Helper function: relinks soft symbolic link if necessary
"""
input_file = fspath(input_file) # For Py3.5
soft_link_name = fspath(soft_link_name)
input_file = os.fspath(input_file)
soft_link_name = os.fspath(soft_link_name)
if log is None:
prdebug = partial(print, file=sys.stderr)
else:
@@ -38,32 +38,29 @@ def re_symlink(input_file, soft_link_name, log=None):
# Guard against soft linking to oneself
if input_file == soft_link_name:
prdebug("Warning: No symbolic link made. You are using " +
"the original data directory as the working directory.")
prdebug(
"Warning: No symbolic link made. You are using "
+ "the original data directory as the working directory."
)
return
# Soft link already exists: delete for relink?
if os.path.lexists(soft_link_name):
# do not delete or overwrite real (non-soft link) file
if not os.path.islink(soft_link_name):
raise FileExistsError(
"%s exists and is not a link" % soft_link_name)
raise FileExistsError("%s exists and is not a link" % soft_link_name)
try:
os.unlink(soft_link_name)
except OSError:
prdebug("Can't unlink %s" % (soft_link_name))
if not os.path.exists(input_file):
raise FileNotFoundError(
"trying to create a broken symlink to %s" % input_file)
raise FileNotFoundError("trying to create a broken symlink to %s" % input_file)
prdebug("os.symlink(%s, %s)" % (input_file, soft_link_name))
# Create symbolic link using absolute path
os.symlink(
os.path.abspath(input_file),
soft_link_name
)
os.symlink(os.path.abspath(input_file), soft_link_name)
def is_iterable_notstr(thing):
@@ -72,7 +69,7 @@ def is_iterable_notstr(thing):
def page_number(input_file):
"""Get one-based page number implied by filename (000002.pdf -> 2)"""
return int(os.path.basename(fspath(input_file))[0:6])
return int(os.path.basename(os.fspath(input_file))[0:6])
def available_cpu_count():
@@ -83,13 +80,14 @@ def available_cpu_count():
try:
import psutil
return psutil.cpu_count()
except (ImportError, AttributeError):
pass
warnings.warn(
"Could not get CPU count. Assuming one (1) CPU."
"Use -j N to set manually.")
"Could not get CPU count. Assuming one (1) CPU." "Use -j N to set manually."
)
return 1
@@ -103,20 +101,15 @@ def is_file_writable(test_file):
p = Path(test_file)
if p.is_symlink():
# Python 3.5 does not accept parameters for Path.resolve() and behaves
# as if strict=True (throws an exception on failure). Python 3.6
# defaults to strict=False. This implements strict=False like behavior
# for Python 3.5.
if sys.version_info[0:2] <= (3, 5):
p = Path(os.path.realpath(fspath(p)))
else:
p = p.resolve(strict=False)
p = p.resolve(strict=False)
# p.is_file() throws an exception in some cases
if p.exists() and p.is_file():
return os.access(
fspath(p), os.W_OK,
effective_ids=(os.access in os.supports_effective_ids))
os.fspath(p),
os.W_OK,
effective_ids=(os.access in os.supports_effective_ids),
)
else:
try:
fp = p.open('wb')
@@ -129,39 +122,6 @@ def is_file_writable(test_file):
return True
if sys.version_info[0:2] <= (3, 5):
def fspath(path):
"""https://www.python.org/dev/peps/pep-0519/#os"""
import pathlib
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:
fspath = os.fspath
def flatten_groups(groups):
for obj in groups:
if is_iterable_notstr(obj):
@@ -172,12 +132,16 @@ def flatten_groups(groups):
def deprecated(func):
"""Warn that function is deprecated"""
@wraps(func)
def new_func(*args, **kwargs):
warnings.simplefilter('always', DeprecationWarning) # turn off filter
warnings.warn("Call to deprecated function {}.".format(func.__name__),
category=DeprecationWarning,
stacklevel=2)
warnings.warn(
"Call to deprecated function {}.".format(func.__name__),
category=DeprecationWarning,
stacklevel=2,
)
warnings.simplefilter('default', DeprecationWarning) # reset filter
return func(*args, **kwargs)
return new_func
+113 -73
View File
@@ -28,14 +28,14 @@
# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
from reportlab.pdfgen.canvas import Canvas
from reportlab.lib.units import inch
from xml.etree import ElementTree
from collections import namedtuple
from math import atan, sin, cos
import re
import argparse
import re
from collections import namedtuple
from math import atan, cos, sin
from xml.etree import ElementTree
from reportlab.lib.units import inch
from reportlab.pdfgen.canvas import Canvas
Rect = namedtuple('Rect', ['x1', 'y1', 'x2', 'y2'])
@@ -44,7 +44,7 @@ class HocrTransformError(Exception):
pass
class HocrTransform():
class HocrTransform:
"""
A class for converting documents from the hOCR format.
@@ -53,17 +53,16 @@ class HocrTransform():
"""
box_pattern = re.compile(r'bbox((\s+\d+){4})')
baseline_pattern = re.compile(r'''
baseline_pattern = re.compile(
r'''
baseline \s+
([\-\+]?\d*\.?\d*) \s+ # +/- decimal float
([\-\+]?\d+) # +/- int''', re.VERBOSE)
ligatures = str.maketrans({
'': 'ff',
'': 'ffi',
'': 'ffl',
'': 'fi',
'': 'fl',
})
([\-\+]?\d+) # +/- int''',
re.VERBOSE,
)
ligatures = str.maketrans(
{'': 'ff', '': 'ffi', '': 'ffl', '': 'fi', '': 'fl'}
)
def __init__(self, hocrFileName, dpi):
self.dpi = dpi
@@ -78,8 +77,7 @@ class HocrTransform():
# get dimension in pt (not pixel!!!!) of the OCRed image
self.width, self.height = None, None
for div in self.hocr.findall(
".//%sdiv[@class='ocr_page']" % (self.xmlns)):
for div in self.hocr.findall(".//%sdiv[@class='ocr_page']" % (self.xmlns)):
coords = self.element_coordinates(div)
pt_coords = self.pt_from_pixel(coords)
self.width = pt_coords.x2 - pt_coords.x1
@@ -144,8 +142,7 @@ class HocrTransform():
"""
Returns the quantity in PDF units (pt) given quantity in pixels
"""
return Rect._make(
(c / self.dpi * inch) for c in pxl)
return Rect._make((c / self.dpi * inch) for c in pxl)
@classmethod
def replace_unsupported_chars(cls, s):
@@ -156,8 +153,15 @@ class HocrTransform():
"""
return s.translate(cls.ligatures)
def to_pdf(self, outFileName, imageFileName=None, showBoundingboxes=False,
fontname="Helvetica", invisibleText=False, interwordSpaces=False):
def to_pdf(
self,
outFileName,
imageFileName=None,
showBoundingboxes=False,
fontname="Helvetica",
invisibleText=False,
interwordSpaces=False,
):
"""
Creates a PDF file with an image superimposed on top of the text.
Text is positioned according to the bounding box of the lines in
@@ -168,17 +172,15 @@ class HocrTransform():
"""
# create the PDF file
# page size in points (1/72 in.)
pdf = Canvas(
outFileName, pagesize=(self.width, self.height), pageCompression=1)
pdf = Canvas(outFileName, pagesize=(self.width, self.height), pageCompression=1)
# draw bounding box for each paragraph
# light blue for bounding box of paragraph
pdf.setStrokeColorRGB(0, 1, 1)
# light blue for bounding box of paragraph
pdf.setFillColorRGB(0, 1, 1)
pdf.setLineWidth(0) # no line for bounding box
for elem in self.hocr.findall(
".//%sp[@class='%s']" % (self.xmlns, "ocr_par")):
pdf.setLineWidth(0) # no line for bounding box
for elem in self.hocr.findall(".//%sp[@class='%s']" % (self.xmlns, "ocr_par")):
elemtxt = self._get_element_text(elem).rstrip()
if len(elemtxt) == 0:
@@ -190,38 +192,58 @@ class HocrTransform():
# draw the bbox border
if showBoundingboxes:
pdf.rect(
pt.x1, self.height - pt.y2, pt.x2 - pt.x1, pt.y2 - pt.y1,
fill=1)
pt.x1, self.height - pt.y2, pt.x2 - pt.x1, pt.y2 - pt.y1, fill=1
)
found_lines = False
for line in self.hocr.findall(
".//%sspan[@class='%s']" % (self.xmlns, "ocr_line")):
".//%sspan[@class='%s']" % (self.xmlns, "ocr_line")
):
found_lines = True
self._do_line(pdf, line, "ocrx_word", fontname, invisibleText,
interwordSpaces, showBoundingboxes)
self._do_line(
pdf,
line,
"ocrx_word",
fontname,
invisibleText,
interwordSpaces,
showBoundingboxes,
)
if not found_lines:
# Tesseract did not report any lines (just words)
root = self.hocr.find(".//%sdiv[@class='%s']" % (self.xmlns, "ocr_page"))
self._do_line(pdf, root, "ocrx_word", fontname, invisibleText,
interwordSpaces, showBoundingboxes)
self._do_line(
pdf,
root,
"ocrx_word",
fontname,
invisibleText,
interwordSpaces,
showBoundingboxes,
)
# put the image on the page, scaled to fill the page
if imageFileName is not None:
pdf.drawImage(imageFileName, 0, 0,
width=self.width, height=self.height)
pdf.drawImage(imageFileName, 0, 0, width=self.width, height=self.height)
# finish up the page and save it
pdf.showPage()
pdf.save()
@classmethod
def polyval(cls, poly, x):
return x * poly[0] + poly[1]
def _do_line(self, pdf, line, elemclass, fontname, invisibleText,
interwordSpaces, showBoundingboxes):
def _do_line(
self,
pdf,
line,
elemclass,
fontname,
invisibleText,
interwordSpaces,
showBoundingboxes,
):
pxl_line_coords = self.element_coordinates(line)
line_box = self.pt_from_pixel(pxl_line_coords)
line_height = line_box.y2 - line_box.y1
@@ -254,23 +276,20 @@ class HocrTransform():
pdf.setLineWidth(0.5)
# negate slope because it is defined as a rise/run in pixel
# coordinates and page coordinates have the y axis flipped
pdf.line(line_box.x1,
baseline_y2,
line_box.x2,
self.polyval((-slope, baseline_y2),
line_box.x2 - line_box.x1))
pdf.line(
line_box.x1,
baseline_y2,
line_box.x2,
self.polyval((-slope, baseline_y2), line_box.x2 - line_box.x1),
)
# light green for bounding box of word/line
pdf.setDash(6, 3)
pdf.setStrokeColorRGB(1, 0, 0)
text.setTextTransform(
cos_a, -sin_a, sin_a, cos_a,
line_box.x1, baseline_y2
)
text.setTextTransform(cos_a, -sin_a, sin_a, cos_a, line_box.x1, baseline_y2)
pdf.setFillColorRGB(0, 0, 0) # text in black
elements = line.findall(
".//%sspan[@class='%s']" % (self.xmlns, elemclass))
elements = line.findall(".//%sspan[@class='%s']" % (self.xmlns, elemclass))
for elem in elements:
elemtxt = self._get_element_text(elem).strip()
elemtxt = self.replace_unsupported_chars(elemtxt)
@@ -287,22 +306,22 @@ class HocrTransform():
# though it would look better, because it will interfere with
# naive text extraction. \n does not work either.
elemtxt += ' '
box = Rect._make((
box.x1,
line_box.y1,
box.x2 + pdf.stringWidth(' ', fontname, line_height),
line_box.y2))
box = Rect._make(
(
box.x1,
line_box.y1,
box.x2 + pdf.stringWidth(' ', fontname, line_height),
line_box.y2,
)
)
box_width = box.x2 - box.x1
font_width = pdf.stringWidth(elemtxt, fontname, fontsize)
# draw the bbox border
if showBoundingboxes:
pdf.rect(
box.x1,
self.height - line_box.y2,
box_width,
line_height,
fill=0)
box.x1, self.height - line_box.y2, box_width, line_height, fill=0
)
# Adjust relative position of cursor
# This is equivalent to:
@@ -331,19 +350,40 @@ class HocrTransform():
if __name__ == "__main__":
parser = argparse.ArgumentParser(description='Convert hocr file to PDF')
parser.add_argument('-b', '--boundingboxes', action="store_true",
default=False, help='Show bounding boxes borders')
parser.add_argument('-r', '--resolution', type=int,
default=300,
help='Resolution of the image that was OCRed')
parser.add_argument('-i', '--image', default=None,
help='Path to the image to be placed above the text')
parser.add_argument('--interword-spaces', action='store_true',
default=False, help='Add spaces between words')
parser.add_argument('hocrfile', help='Path to the hocr file to be parsed')
parser.add_argument(
'outputfile', help='Path to the PDF file to be generated')
'-b',
'--boundingboxes',
action="store_true",
default=False,
help='Show bounding boxes borders',
)
parser.add_argument(
'-r',
'--resolution',
type=int,
default=300,
help='Resolution of the image that was OCRed',
)
parser.add_argument(
'-i',
'--image',
default=None,
help='Path to the image to be placed above the text',
)
parser.add_argument(
'--interword-spaces',
action='store_true',
default=False,
help='Add spaces between words',
)
parser.add_argument('hocrfile', help='Path to the hocr file to be parsed')
parser.add_argument('outputfile', help='Path to the PDF file to be generated')
args = parser.parse_args()
hocr = HocrTransform(args.hocrfile, args.resolution)
hocr.to_pdf(args.outputfile, args.image, args.boundingboxes, interwordSpaces=args.interword_spaces)
hocr.to_pdf(
args.outputfile,
args.image,
args.boundingboxes,
interwordSpaces=args.interword_spaces,
)
+161 -106
View File
@@ -20,20 +20,20 @@
#
# Python FFI wrapper for Leptonica library
from collections.abc import Sequence
from contextlib import suppress
from ctypes.util import find_library
from functools import lru_cache
from io import BytesIO
from tempfile import TemporaryFile
import argparse
import logging
import os
import sys
import warnings
from collections.abc import Sequence
from contextlib import suppress
from ctypes.util import find_library
from functools import lru_cache
from io import BytesIO
from os import fspath
from tempfile import TemporaryFile
from .lib._leptonica import ffi
from .helpers import fspath
# pylint: disable=protected-access
@@ -69,14 +69,14 @@ class _LeptonicaErrorTrap:
def __enter__(self):
from io import UnsupportedOperation
self.tmpfile = TemporaryFile()
# Save the old stderr, and redirect stderr to temporary file
sys.stderr.flush()
try:
self.copy_of_stderr = os.dup(sys.stderr.fileno())
os.dup2(self.tmpfile.fileno(), sys.stderr.fileno(),
inheritable=False)
os.dup2(self.tmpfile.fileno(), sys.stderr.fileno(), inheritable=False)
except UnsupportedOperation:
self.copy_of_stderr = None
return
@@ -185,9 +185,13 @@ class Pix(LeptonicaObject):
def __repr__(self):
if self._cdata:
s = "<leptonica.Pix image size={0}x{1} depth={2}{4} at 0x{3:x}>"
return s.format(self._cdata.w, self._cdata.h, self._cdata.d,
int(ffi.cast('intptr_t', self._cdata)),
'(colormapped)' if self._cdata.colormap else '')
return s.format(
self._cdata.w,
self._cdata.h,
self._cdata.d,
int(ffi.cast('intptr_t', self._cdata)),
'(colormapped)' if self._cdata.colormap else '',
)
else:
return "<leptonica.Pix image NULL>"
@@ -289,8 +293,7 @@ class Pix(LeptonicaObject):
with _LeptonicaErrorTrap():
return cls(lept.pixRead(os.fsencode(filename)))
def write_implied_format(
self, path, jpeg_quality=0, jpeg_progressive=0):
def write_implied_format(self, path, jpeg_quality=0, jpeg_progressive=0):
"""Write pix to the filename, with the extension indicating format.
jpeg_quality -- quality (iff JPEG; 1 - 100, 0 for default)
@@ -299,8 +302,8 @@ class Pix(LeptonicaObject):
filename = fspath(path)
with _LeptonicaErrorTrap():
lept.pixWriteImpliedFormat(
os.fsencode(filename),
self._cdata, jpeg_quality, jpeg_progressive)
os.fsencode(filename), self._cdata, jpeg_quality, jpeg_progressive
)
@classmethod
def frompil(self, pillow_image):
@@ -401,11 +404,13 @@ class Pix(LeptonicaObject):
"""
with _LeptonicaErrorTrap():
return Pix(lept.pixRemoveColormapGeneral(
self._cdata, removal_type, lept.L_COPY))
return Pix(
lept.pixRemoveColormapGeneral(self._cdata, removal_type, lept.L_COPY)
)
def otsu_adaptive_threshold(
self, tile_size=(300, 300), kernel_size=(4, 4), scorefract=0.1):
self, tile_size=(300, 300), kernel_size=(4, 4), scorefract=0.1
):
with _LeptonicaErrorTrap():
sx, sy = tile_size
smoothx, smoothy = kernel_size
@@ -413,20 +418,23 @@ class Pix(LeptonicaObject):
pix = Pix(lept.pixConvertTo8(self._cdata, 0))
result = lept.pixOtsuAdaptiveThreshold(
pix._cdata,
sx, sy,
smoothx, smoothy,
scorefract,
ffi.NULL,
p_pix)
pix._cdata, sx, sy, smoothx, smoothy, scorefract, ffi.NULL, p_pix
)
if result == 0:
return Pix(p_pix[0])
else:
return None
def otsu_threshold_on_background_norm(
self, mask=None, tile_size=(10, 15), thresh=100, mincount=50,
bgval=255, kernel_size=(2, 2), scorefract=0.1):
self,
mask=None,
tile_size=(10, 15),
thresh=100,
mincount=50,
bgval=255,
kernel_size=(2, 2),
scorefract=0.1,
):
with _LeptonicaErrorTrap():
sx, sy = tile_size
smoothx, smoothy = kernel_size
@@ -438,17 +446,27 @@ class Pix(LeptonicaObject):
thresh_pix = lept.pixOtsuThreshOnBackgroundNorm(
pix._cdata,
mask,
sx, sy,
thresh, mincount, bgval,
smoothx, smoothy,
sx,
sy,
thresh,
mincount,
bgval,
smoothx,
smoothy,
scorefract,
ffi.NULL
ffi.NULL,
)
return Pix(thresh_pix)
def masked_threshold_on_background_norm(
self, mask=None, tile_size=(10, 15), thresh=100, mincount=50,
kernel_size=(2, 2), scorefract=0.1):
self,
mask=None,
tile_size=(10, 15),
thresh=100,
mincount=50,
kernel_size=(2, 2),
scorefract=0.1,
):
with _LeptonicaErrorTrap():
sx, sy = tile_size
smoothx, smoothy = kernel_size
@@ -460,74 +478,91 @@ class Pix(LeptonicaObject):
thresh_pix = lept.pixMaskedThreshOnBackgroundNorm(
pix._cdata,
mask,
sx, sy,
thresh, mincount,
smoothx, smoothy,
sx,
sy,
thresh,
mincount,
smoothx,
smoothy,
scorefract,
ffi.NULL
ffi.NULL,
)
return Pix(thresh_pix)
def crop_to_foreground(
self, threshold=128, mindist=70, erasedist=30, pagenum=0,
showmorph=0, display=0, pdfdir=ffi.NULL):
self,
threshold=128,
mindist=70,
erasedist=30,
pagenum=0,
showmorph=0,
display=0,
pdfdir=ffi.NULL,
):
with _LeptonicaErrorTrap():
cropbox = Box(lept.pixFindPageForeground(
self._cdata,
threshold,
mindist,
erasedist,
pagenum,
showmorph,
display,
pdfdir))
cropbox = Box(
lept.pixFindPageForeground(
self._cdata,
threshold,
mindist,
erasedist,
pagenum,
showmorph,
display,
pdfdir,
)
)
cropped_pix = lept.pixClipRectangle(
self._cdata,
cropbox._cdata,
ffi.NULL)
cropped_pix = lept.pixClipRectangle(self._cdata, cropbox._cdata, ffi.NULL)
return Pix(cropped_pix)
def clean_background_to_white(
self, mask=None, grayscale=None, gamma=1.0, black=0, white=255):
self, mask=None, grayscale=None, gamma=1.0, black=0, white=255
):
with _LeptonicaErrorTrap():
return Pix(lept.pixCleanBackgroundToWhite(
self._cdata,
mask or ffi.NULL,
grayscale or ffi.NULL,
gamma,
black,
white))
return Pix(
lept.pixCleanBackgroundToWhite(
self._cdata,
mask or ffi.NULL,
grayscale or ffi.NULL,
gamma,
black,
white,
)
)
def gamma_trc(self, gamma=1.0, minval=0, maxval=255):
with _LeptonicaErrorTrap():
return Pix(lept.pixGammaTRC(
ffi.NULL,
self._cdata,
gamma,
minval,
maxval
))
return Pix(lept.pixGammaTRC(ffi.NULL, self._cdata, gamma, minval, maxval))
def background_norm(
self, mask=None, grayscale=None, tile_size=(10, 15), fg_threshold=60,
min_count=40, bg_val=200, smooth_kernel=(2, 1)):
self,
mask=None,
grayscale=None,
tile_size=(10, 15),
fg_threshold=60,
min_count=40,
bg_val=200,
smooth_kernel=(2, 1),
):
# Background norm doesn't work on color mapped Pix, so remove colormap
target_pix = self.remove_colormap(lept.REMOVE_CMAP_BASED_ON_SRC)
with _LeptonicaErrorTrap():
return Pix(lept.pixBackgroundNorm(
target_pix._cdata,
mask or ffi.NULL,
grayscale or ffi.NULL,
tile_size[0],
tile_size[1],
fg_threshold,
min_count,
bg_val,
smooth_kernel[0],
smooth_kernel[1]
))
return Pix(
lept.pixBackgroundNorm(
target_pix._cdata,
mask or ffi.NULL,
grayscale or ffi.NULL,
tile_size[0],
tile_size[1],
fg_threshold,
min_count,
bg_val,
smooth_kernel[0],
smooth_kernel[1],
)
)
@staticmethod
@lru_cache(maxsize=1)
@@ -544,8 +579,7 @@ class Pix(LeptonicaObject):
raise LeptonicaError("Leptonica version is too old")
correlation = ffi.new('float *', 0.0)
result = lept.pixCorrelationBinary(pix1._cdata, pix2._cdata,
correlation)
result = lept.pixCorrelationBinary(pix1._cdata, pix2._cdata, correlation)
if result != 0:
raise LeptonicaError("Correlation failed")
return correlation[0]
@@ -553,8 +587,7 @@ class Pix(LeptonicaObject):
def generate_pdf_ci_data(self, type_, quality):
"Convert to PDF data, with transcoding"
p_compdata = ffi.new('L_COMP_DATA **')
result = lept.pixGenerateCIData(self._cdata, type_, quality, 0,
p_compdata)
result = lept.pixGenerateCIData(self._cdata, type_, quality, 0, p_compdata)
if result != 0:
raise LeptonicaError("Generate PDF data failed")
return CompressedData(p_compdata[0])
@@ -567,17 +600,23 @@ class Pix(LeptonicaObject):
with _LeptonicaErrorTrap():
pix = Pix(lept.pixConvertTo8(self._cdata, 0))
pixa_candidates = PixArray(lept.pixExtractBarcodes(pix._cdata, 0))
with suppress(FileNotFoundError):
os.unlink('junkpixt.png') # leptonica may produce this
sarray = StringArray(lept.pixReadBarcodes(
pixa_candidates._cdata,
lept.L_BF_ANY,
lept.L_USE_WIDTHS,
ffi.NULL,
0
))
except (LeptonicaError, ValueError) as e:
if not pixa_candidates:
return
sarray = StringArray(
lept.pixReadBarcodes(
pixa_candidates._cdata,
lept.L_BF_ANY,
lept.L_USE_WIDTHS,
ffi.NULL,
0,
)
)
except (LeptonicaError, ValueError, IndexError):
return
finally:
with suppress(FileNotFoundError):
os.unlink('junkpixt.png') # leptonica may produce this
os.unlink('junkpixt')
for n, s in enumerate(sarray):
decoded = s.decode()
@@ -631,7 +670,8 @@ class CompressedData(LeptonicaObject):
p_compdata = ffi.new('L_COMP_DATA **')
result = lept.l_generateCIDataForPdf(
os.fsencode(filename), ffi.NULL, jpeg_quality, p_compdata)
os.fsencode(filename), ffi.NULL, jpeg_quality, p_compdata
)
if result != 0:
raise LeptonicaError("CompressedData.open")
return CompressedData(p_compdata[0])
@@ -685,7 +725,8 @@ class Box(LeptonicaObject):
def __repr__(self):
if self._cdata:
return '<leptonica.Box x={0} y={1} w={2} h={3}>'.format(
self.x, self.y, self.w, self.h)
self.x, self.y, self.w, self.h
)
return '<leptonica.Box NULL>'
@property
@@ -804,15 +845,22 @@ def deskew(infile, outfile, dpi):
raise LeptonicaIOError("Failed to open destination file: %s" % outfile)
def remove_background(infile, outfile, tile_size=(40, 60), gamma=1.0,
black_threshold=70, white_threshold=190):
def remove_background(
infile,
outfile,
tile_size=(40, 60),
gamma=1.0,
black_threshold=70,
white_threshold=190,
):
try:
pix = Pix.open(infile)
except LeptonicaIOError:
raise LeptonicaIOError("Failed to open file: %s" % infile)
pix = pix.background_norm(tile_size=tile_size).gamma_trc(
gamma, black_threshold, white_threshold)
gamma, black_threshold, white_threshold
)
try:
pix.write_implied_format(outfile)
@@ -821,15 +869,22 @@ def remove_background(infile, outfile, tile_size=(40, 60), gamma=1.0,
if __name__ == '__main__':
parser = argparse.ArgumentParser(
description="Python wrapper to access Leptonica")
parser = argparse.ArgumentParser(description="Python wrapper to access Leptonica")
subparsers = parser.add_subparsers(title='commands',
description='supported operations')
subparsers = parser.add_subparsers(
title='commands', description='supported operations'
)
parser_deskew = subparsers.add_parser('deskew')
parser_deskew.add_argument('-r', '--dpi', dest='dpi', action='store',
type=int, default=300, help='input resolution')
parser_deskew.add_argument(
'-r',
'--dpi',
dest='dpi',
action='store',
type=int,
default=300,
help='input resolution',
)
parser_deskew.add_argument('infile', help='image to deskew')
parser_deskew.add_argument('outfile', help='deskewed output image')
parser_deskew.set_defaults(func=deskew)
+8 -4
View File
@@ -19,7 +19,8 @@
from cffi import FFI
ffibuilder = FFI()
ffibuilder.cdef("""
ffibuilder.cdef(
"""
typedef signed char l_int8;
typedef unsigned char l_uint8;
typedef short l_int16;
@@ -202,9 +203,11 @@ enum {
SEL_MISS = 2
};
""")
"""
)
ffibuilder.cdef("""
ffibuilder.cdef(
"""
PIX * pixRead ( const char *filename );
PIX * pixReadMem ( const l_uint8 *data, size_t size );
PIX * pixScale ( PIX *pixs, l_float32 scalex, l_float32 scaley );
@@ -480,7 +483,8 @@ void selDestroy ( SEL **psel );
l_int32
setMsgSeverity(l_int32 newsev);
""")
"""
)
ffibuilder.set_source("ocrmypdf.lib._leptonica", None)
+70 -81
View File
@@ -15,27 +15,28 @@
# You should have received a copy of the GNU General Public License
# along with OCRmyPDF. If not, see <http://www.gnu.org/licenses/>.
from pathlib import Path
import concurrent.futures
from collections import defaultdict
import logging
import sys
from collections import defaultdict
from os import fspath
from pathlib import Path
from PIL import Image
import pikepdf
from ._jobcontext import JobContext
from . import leptonica
from .helpers import re_symlink, fspath
from .exec import pngquant, jbig2enc
from ._jobcontext import JobContext
from .exec import jbig2enc, pngquant
from .helpers import re_symlink
DEFAULT_JPEG_QUALITY = 75
DEFAULT_PNG_QUALITY = 70
def img_name(root, xref, ext):
return fspath(root / '{:08d}{}'.format(xref, ext))
return fspath(root / f'{xref:08d}{ext}')
def png_name(root, xref):
@@ -79,11 +80,13 @@ def extract_image_jbig2(*, pike, root, log, image, xref, options):
return None
pim, filtdp = result
if pim.bits_per_component == 1 \
and filtdp != '/JBIG2Decode' \
and jbig2enc.available():
if (
pim.bits_per_component == 1
and filtdp != '/JBIG2Decode'
and jbig2enc.available()
):
try:
imgname = Path(root / '{:08d}'.format(xref))
imgname = Path(root / f'{xref:08d}')
with imgname.open('wb') as f:
ext = pim.extract_to(stream=f)
imgname.rename(imgname.with_suffix(ext))
@@ -99,8 +102,7 @@ def extract_image_generic(*, pike, root, log, image, xref, options):
return None
pim, filtdp = result
if filtdp[0] == '/DCTDecode' \
and options.optimize >= 2:
if filtdp[0] == '/DCTDecode' and options.optimize >= 2:
# This is a simple heuristic derived from some training data, that has
# about a 70% chance of guessing whether the JPEG is high quality,
# and possibly recompressible, or not. The number itself doesn't mean
@@ -118,16 +120,18 @@ def extract_image_generic(*, pike, root, log, image, xref, options):
# with Image.open(stream) as im:
# im.save(jpg_name(root, xref), icc_profile=iccbytes)
try:
imgname = Path(root / '{:08d}'.format(xref))
imgname = Path(root / f'{xref:08d}')
with imgname.open('wb') as f:
ext = pim.extract_to(stream=f)
imgname.rename(imgname.with_suffix(ext))
except pikepdf.UnsupportedImageTypeError:
return None
return xref, ext
elif pim.indexed \
and pim.colorspace in pim.SIMPLE_COLORSPACES \
and options.optimize >= 3:
elif (
pim.indexed
and pim.colorspace in pim.SIMPLE_COLORSPACES
and options.optimize >= 3
):
# Try to improve on indexed images - these are far from low hanging
# fruit in most cases
pim.as_pil_image().save(png_name(root, xref))
@@ -141,11 +145,10 @@ def extract_image_generic(*, pike, root, log, image, xref, options):
return None
def extract_images(pike, root, log, options, extract_fn):
"""Extract image using extract_fn
extract_fn decides where the image is interesting in this case
extract_fn decides whether the image is interesting in this case
"""
include_xrefs = set()
@@ -171,8 +174,7 @@ def extract_images(pike, root, log, options, extract_fn):
image = pike.get_object((xref, 0))
try:
result = extract_fn(
pike=pike, root=root, log=log, image=image,
xref=xref, options=options
pike=pike, root=root, log=log, image=image, xref=xref, options=options
)
except Exception as e:
log.debug("Image xref %s", xref)
@@ -189,17 +191,13 @@ def extract_images_generic(pike, root, log, options):
jpegs = []
pngs = []
for _, xref, ext in extract_images(
pike, root, log, options, extract_image_generic):
for _, xref, ext in extract_images(pike, root, log, options, extract_image_generic):
log.debug('xref = %s ext = %s', xref, ext)
if ext == '.png':
pngs.append(xref)
elif ext == '.jpg':
jpegs.append(xref)
log.debug(
"Optimizable images: "
"JPEGs: %s PNGs: %s", len(jpegs), len(pngs)
)
log.debug("Optimizable images: " "JPEGs: %s PNGs: %s", len(jpegs), len(pngs))
return jpegs, pngs
@@ -208,17 +206,16 @@ def extract_images_jbig2(pike, root, log, options):
jbig2_groups = defaultdict(list)
for pageno, xref, ext in extract_images(
pike, root, log, options, extract_image_jbig2):
pike, root, log, options, extract_image_jbig2
):
group = pageno // options.jbig2_page_group_size
jbig2_groups[group].append((xref, ext))
# Elide empty groups
jbig2_groups = {group: xrefs for group, xrefs in jbig2_groups.items()
if len(xrefs) > 0}
log.debug(
"Optimizable images: "
"JBIG2 groups: %s", (len(jbig2_groups),)
)
jbig2_groups = {
group: xrefs for group, xrefs in jbig2_groups.items() if len(xrefs) > 0
}
log.debug("Optimizable images: " "JBIG2 groups: %s", (len(jbig2_groups),))
return jbig2_groups
@@ -227,18 +224,18 @@ def _produce_jbig2_images(jbig2_groups, root, log, options):
def jbig2_group_futures(executor, root, groups):
for group, xref_exts in groups.items():
prefix = 'group{:08d}'.format(group)
prefix = f'group{group:08d}'
future = executor.submit(
jbig2enc.convert_group,
cwd=fspath(root),
infiles=(img_name(root, xref, ext) for xref, ext in xref_exts),
out_prefix=prefix
out_prefix=prefix,
)
yield future
def jbig2_single_futures(executor, root, groups):
for group, xref_exts in groups.items():
prefix = 'group{:08d}'.format(group)
prefix = f'group{group:08d}'
# Second loop is to ensure multiple images per page are unpacked
for n, xref_ext in enumerate(xref_exts):
xref, ext = xref_ext
@@ -246,7 +243,7 @@ def _produce_jbig2_images(jbig2_groups, root, log, options):
jbig2enc.convert_single,
cwd=fspath(root),
infile=img_name(root, xref, ext),
outfile=root / ('{}.{:04d}'.format(prefix, n))
outfile=root / f'{prefix}.{n:04d}',
)
yield future
@@ -255,8 +252,7 @@ def _produce_jbig2_images(jbig2_groups, root, log, options):
else:
jbig2_futures = jbig2_single_futures
with concurrent.futures.ThreadPoolExecutor(
max_workers=options.jobs) as executor:
with concurrent.futures.ThreadPoolExecutor(max_workers=options.jobs) as executor:
futures = jbig2_futures(executor, root, jbig2_groups)
for future in concurrent.futures.as_completed(futures):
proc = future.result()
@@ -280,14 +276,12 @@ def convert_to_jbig2(pike, jbig2_groups, root, log, options):
_produce_jbig2_images(jbig2_groups, root, log, options)
for group, xref_exts in jbig2_groups.items():
prefix = 'group{:08d}'.format(group)
prefix = f'group{group:08d}'
jbig2_symfile = root / (prefix + '.sym')
if jbig2_symfile.exists():
jbig2_globals_data = jbig2_symfile.read_bytes()
jbig2_globals = pikepdf.Stream(pike, jbig2_globals_data)
jbig2_globals_dict = pikepdf.Dictionary({
'/JBIG2Globals': jbig2_globals
})
jbig2_globals_dict = pikepdf.Dictionary({'/JBIG2Globals': jbig2_globals})
elif options.jbig2_page_group_size == 1:
jbig2_globals_dict = None
else:
@@ -295,13 +289,13 @@ def convert_to_jbig2(pike, jbig2_groups, root, log, options):
for n, xref_ext in enumerate(xref_exts):
xref, _ = xref_ext
jbig2_im_file = root / (prefix + '.{:04d}'.format(n))
jbig2_im_file = root / (prefix + f'.{n:04d}')
jbig2_im_data = jbig2_im_file.read_bytes()
im_obj = pike.get_object(xref, 0)
im_obj.write(
jbig2_im_data,
filter=pikepdf.Name('/JBIG2Decode'),
decode_parms=jbig2_globals_dict
decode_parms=jbig2_globals_dict,
)
@@ -315,9 +309,7 @@ def transcode_jpegs(pike, jpegs, root, log, options):
# 'close'. Seems to be mostly harmless
# https://github.com/python-pillow/Pillow/issues/1144
with Image.open(fspath(in_jpg)) as im:
im.save(fspath(opt_jpg),
optimize=True,
quality=options.jpeg_quality)
im.save(fspath(opt_jpg), optimize=True, quality=options.jpeg_quality)
# pylint: disable=no-member
if opt_jpg.stat().st_size > in_jpg.stat().st_size:
log.debug("xref %s, jpeg, made larger - skip", xref)
@@ -325,24 +317,26 @@ def transcode_jpegs(pike, jpegs, root, log, options):
compdata = leptonica.CompressedData.open(opt_jpg)
im_obj = pike.get_object(xref, 0)
im_obj.write(
compdata.read(), filter=pikepdf.Name('/DCTDecode')
)
im_obj.write(compdata.read(), filter=pikepdf.Name('/DCTDecode'))
def transcode_pngs(pike, pngs, root, log, options):
if options.optimize >= 2:
png_quality = (
max(10, options.png_quality - 10),
min(100, options.png_quality + 10)
min(100, options.png_quality + 10),
)
with concurrent.futures.ThreadPoolExecutor(
max_workers=options.jobs) as executor:
max_workers=options.jobs
) as executor:
for xref in pngs:
executor.submit(
pngquant.quantize,
png_name(root, xref), png_name(root, xref),
png_quality[0], png_quality[1])
png_name(root, xref),
png_name(root, xref),
png_quality[0],
png_quality[1],
)
for xref in pngs:
im_obj = pike.get_object(xref, 0)
@@ -352,9 +346,7 @@ def transcode_pngs(pike, pngs, root, log, options):
pix = leptonica.Pix.open(png_name(root, xref))
if pix.depth == 1:
pix = pix.invert() # PDF assumes 1 is black for monochrome
compdata = pix.generate_pdf_ci_data(
leptonica.lept.L_FLATE_ENCODE, 0
)
compdata = pix.generate_pdf_ci_data(leptonica.lept.L_FLATE_ENCODE, 0)
except leptonica.LeptonicaError as e:
log.error(e)
continue
@@ -362,7 +354,7 @@ def transcode_pngs(pike, pngs, root, log, options):
# This is what we should be doing: open the compressed data without
# transcoding. However this shifts each pixel row by one for some
# reason.
#compdata = leptonica.CompressedData.open(png_name(root, xref))
# compdata = leptonica.CompressedData.open(png_name(root, xref))
if len(compdata) > int(im_obj.stream_dict.Length):
continue # If we produced a larger image, don't use
@@ -378,8 +370,12 @@ def transcode_pngs(pike, pngs, root, log, options):
palette_pdf_string = compdata.get_palette_pdf_string()
palette_data = pikepdf.Object.parse(palette_pdf_string)
palette_stream = pikepdf.Stream(pike, bytes(palette_data))
palette = [pikepdf.Name('/Indexed'), pikepdf.Name('/DeviceRGB'),
compdata.ncolors - 1, palette_stream]
palette = [
pikepdf.Name('/Indexed'),
pikepdf.Name('/DeviceRGB'),
compdata.ncolors - 1,
palette_stream,
]
cs = palette
else:
if compdata.spp == 1:
@@ -390,16 +386,11 @@ def transcode_pngs(pike, pngs, root, log, options):
cs = pikepdf.Name('/DeviceCMYK')
im_obj.ColorSpace = cs
im_obj.write(
compdata.read(),
filter=pikepdf.Name('/FlateDecode'), decode_parms=predictor
compdata.read(), filter=pikepdf.Name('/FlateDecode'), decode_parms=predictor
)
def optimize(
input_file,
output_file,
log,
context):
def optimize(input_file, output_file, log, context):
options = context.get_options()
if options.optimize == 0:
@@ -407,14 +398,11 @@ def optimize(
return
if options.jpeg_quality == 0:
options.jpeg_quality = \
DEFAULT_JPEG_QUALITY if options.optimize < 3 else 40
options.jpeg_quality = DEFAULT_JPEG_QUALITY if options.optimize < 3 else 40
if options.png_quality == 0:
options.png_quality = \
DEFAULT_PNG_QUALITY if options.optimize < 3 else 30
options.png_quality = DEFAULT_PNG_QUALITY if options.optimize < 3 else 30
if options.jbig2_page_group_size == 0:
options.jbig2_page_group_size = \
10 if options.jbig2_lossy else 1
options.jbig2_page_group_size = 10 if options.jbig2_lossy else 1
pike = pikepdf.Pdf.open(input_file)
@@ -430,15 +418,17 @@ def optimize(
target_file = Path(output_file).with_suffix('.opt.pdf')
pike.remove_unreferenced_resources()
pike.save(target_file, preserve_pdfa=True,
object_stream_mode=pikepdf.ObjectStreamMode.generate)
pike.save(
target_file,
preserve_pdfa=True,
object_stream_mode=pikepdf.ObjectStreamMode.generate,
)
input_size = Path(input_file).stat().st_size
output_size = Path(target_file).stat().st_size
ratio = input_size / output_size
savings = 1 - output_size / input_size
log.info("Optimize ratio: {:.2f} savings: {:.1f}%".format(
ratio, 100 * savings))
log.info(f"Optimize ratio: {ratio:.2f} savings: {(100 * savings):.1f}%")
if savings < 0:
log.info("Optimize did not improve the file - discarded")
@@ -454,8 +444,7 @@ def main(infile, outfile, level, jobs=1):
class OptimizeOptions:
"""Emulate ocrmypdf's options"""
def __init__(
self, jobs, optimize, jpeg_quality, png_quality, jb2lossy):
def __init__(self, jobs, optimize, jpeg_quality, png_quality, jb2lossy):
self.jobs = jobs
self.optimize = optimize
self.jpeg_quality = jpeg_quality
@@ -472,7 +461,7 @@ def main(infile, outfile, level, jobs=1):
optimize=int(level),
jpeg_quality=0, # Use default
png_quality=0,
jb2lossy=False
jb2lossy=False,
)
ctx.set_options(options)
+25 -93
View File
@@ -31,26 +31,18 @@ Ghostscript's handling of pdfmark.
"""
import os
from binascii import hexlify
from pathlib import Path
from string import Template
import pkg_resources
import os
import pikepdf
from pikepdf.models.metadata import (
encode_pdf_date as _encode_date,
decode_pdf_date as _decode_date
)
from .helpers import deprecated
ICC_PROFILE_RELPATH = 'data/sRGB.icc'
SRGB_ICC_PROFILE = pkg_resources.resource_filename(
'ocrmypdf', ICC_PROFILE_RELPATH)
SRGB_ICC_PROFILE = pkg_resources.resource_filename('ocrmypdf', ICC_PROFILE_RELPATH)
# This is a template written in PostScript which is needed to create PDF/A
@@ -91,90 +83,29 @@ def
"""
@deprecated
def encode_text_string(s: str) -> str:
"""
Encode text string to hex string for use in a PDF
def generate_pdfa_ps(target_filename, icc='sRGB'):
"""Create a Postscript pdfmark file for Ghostscript PDF/A conversion
From PDF 32000-1:2008 a string object may be included in hexademical form
if it is enclosed in angle brackets. For general Unicode the string should
be UTF-16 (big endian) with byte order marks. Many strings including all
ASCII strings could be encoded as PdfDocEncoding literals provided
that certain Postscript sequences are escaped. But it's far simpler to
encode everything as UTF-16.
"""
A pdfmark file is a small Postscript program that provides some information
Ghostscript needs to perform PDF/A conversion. The only information we put
in specifies that we want the file to be a PDF/A, and we want to Ghostscript
to convert objects to the sRGB colorspace if it runs into any object that
it decides must be converted.
# Sometimes lazy C programmers leave their NULs at the end of strings they
# insert into PDFs
# tests/resources/aspect.pdf is one example (created by ImageMagick)
s = s.replace('\x00', '')
See the Adobe pdfmark Reference for details:
https://www.adobe.com/content/dam/acom/en/devnet/acrobat/pdfs/pdfmark_reference.pdf
if s == '':
return ''
utf16_bytes = s.encode('utf-16be')
ascii_hex_bytes = hexlify(b'\xfe\xff' + utf16_bytes)
ascii_hex_str = ascii_hex_bytes.decode('ascii').lower()
return ascii_hex_str
def _encode_ascii(s: str) -> str:
"""
Aggressively strip non-ASCII and PDF escape sequences
Ghostscript 9.24+ lost support for UTF-16BE in pdfmark files for reasons
given in GhostPDL commit e997c683. Our temporary workaround is use ASCII
and drop all non-ASCII characters. A slightly improved alternative would
be to implement PdfDocEncoding in pikepdf and encode to that, or handle
metadata there.
"""
trans = str.maketrans({
'(': '',
')': '',
'\\': '',
'\0': ''
})
return s.translate(trans).encode('ascii', errors='replace').decode()
@deprecated
def encode_pdf_date(*args, **kwargs):
return _encode_date(*args, **kwargs)
@deprecated
def decode_pdf_date(*args, **kwargs):
return _decode_date(*args, **kwargs)
def _get_pdfa_def(icc_profile, icc_identifier, pdfmark=None, ascii_docinfo=None):
"""
Create a Postscript pdfmark file for Ghostscript.
pdfmark contains the various objects as strings; these must be encoded in
ASCII, and dates have a special format.
:param icc_profile: filename of the ICC profile to include in pdfmark
:param icc_identifier: ICC identifier such as 'sRGB'
:param pdfmark: a dictionary containing keys to include the pdfmark
:param ascii_docinfo: parameter is no longer meaningful
:param target_filename: filename to save
:param icc: ICC identifier such as 'sRGB'
:returns: a string containing the entire pdfmark
"""
t = Template(pdfa_def_template)
result = t.substitute(icc_profile=icc_profile,
icc_identifier=icc_identifier)
return result
def generate_pdfa_ps(target_filename, pdfmark=None, icc='sRGB', ascii_docinfo=None):
if icc == 'sRGB':
icc_profile = SRGB_ICC_PROFILE
else:
raise NotImplementedError("Only supporting sRGB")
# pdfmark must contain the full path to the ICC profile, and pdfmark must
# pdfmark must contain the full path to the ICC profile, and pdfmark must be
# also encoded in ASCII. ocrmypdf can be installed anywhere, including to
# paths that have a non-ASCII character in the filename. Ghostscript
# accepts hex-encoded strings and converts them to byte strings, so
@@ -185,7 +116,8 @@ def generate_pdfa_ps(target_filename, pdfmark=None, icc='sRGB', ascii_docinfo=No
hex_icc_profile = hexlify(bytes_icc_profile)
icc_profile = '<' + hex_icc_profile.decode('ascii') + '>'
ps = _get_pdfa_def(icc_profile, icc, pdfmark)
t = Template(pdfa_def_template)
ps = t.substitute(icc_profile=icc_profile, icc_identifier=icc)
# We should have encoded everything to pure ASCII by this point, and
# to be safe, only allow ASCII in PostScript
@@ -195,20 +127,20 @@ def generate_pdfa_ps(target_filename, pdfmark=None, icc='sRGB', ascii_docinfo=No
def file_claims_pdfa(filename):
"""Determines if the file claims to be PDF/A compliant
Checking if a file is a truly compliant PDF/A is a massive undertaking
that no open source tool does properly. Some commercial tools are
generally reliable (Acrobat).
This checks if the XMP metadata contains a PDF/A marker.
This only checks if the XMP metadata contains a PDF/A marker. It does not
do full PDF/A validation.
"""
pdf = pikepdf.open(filename)
pdfmeta = pdf.open_metadata()
if not pdfmeta.pdfa_status:
return {'pass': False, 'output': 'pdf',
'conformance': 'No PDF/A metadata in XMP'}
return {
'pass': False,
'output': 'pdf',
'conformance': 'No PDF/A metadata in XMP',
}
valid_part_conforms = {'1A', '1B', '2A', '2B', '2U', '3A', '3B', '3U'}
conformance = 'PDF/A-{}'.format(pdfmeta.pdfa_status)
conformance = f'PDF/A-{pdfmeta.pdfa_status}'
pdfa_dict = {}
if pdfmeta.pdfa_status in valid_part_conforms:
pdfa_dict['pass'] = True
+96 -74
View File
@@ -20,6 +20,7 @@ from collections import namedtuple
from decimal import Decimal
from enum import Enum
from math import hypot, isclose
from os import fspath
from pathlib import Path
from unittest.mock import Mock
from warnings import warn
@@ -29,18 +30,15 @@ from pikepdf import PdfMatrix
import pikepdf
from . import ghosttext
from .layout import get_page_analysis, get_text_boxes
from ..exceptions import EncryptedPdfError
from ..helpers import fspath
from ..exceptions import EncryptedPdfError, MissingDependencyError
Colorspace = Enum('Colorspace',
'gray rgb cmyk lab icc index sep devn pattern jpeg2000')
Colorspace = Enum('Colorspace', 'gray rgb cmyk lab icc index sep devn pattern jpeg2000')
Encoding = Enum('Encoding',
'ccitt jpeg jpeg2000 jbig2 asciihex ascii85 lzw flate ' + \
'runlength')
Encoding = Enum(
'Encoding', 'ccitt jpeg jpeg2000 jbig2 asciihex ascii85 lzw flate ' + 'runlength'
)
FRIENDLY_COLORSPACE = {
'/DeviceGray': Colorspace.gray,
@@ -71,7 +69,7 @@ FRIENDLY_ENCODING = {
'/A85': Encoding.ascii85,
'/LZW': Encoding.lzw,
'/Fl': Encoding.flate,
'/RL': Encoding.runlength
'/RL': Encoding.runlength,
}
FRIENDLY_COMP = {
@@ -79,28 +77,28 @@ FRIENDLY_COMP = {
Colorspace.rgb: 3,
Colorspace.cmyk: 4,
Colorspace.lab: 3,
Colorspace.index: 1
Colorspace.index: 1,
}
UNIT_SQUARE = (1.0, 0.0, 0.0, 1.0, 0.0, 0.0)
def _is_unit_square(shorthand):
values = map(float, shorthand)
pairwise = zip(values, UNIT_SQUARE)
return all([isclose(a, b, rel_tol=1e-3) for a, b in pairwise])
XobjectSettings = namedtuple('XobjectSettings',
['name', 'shorthand', 'stack_depth'])
InlineSettings = namedtuple('InlineSettings',
['iimage', 'shorthand', 'stack_depth'])
XobjectSettings = namedtuple('XobjectSettings', ['name', 'shorthand', 'stack_depth'])
ContentsInfo = namedtuple('ContentsInfo',
['xobject_settings', 'inline_images', 'found_vector'])
InlineSettings = namedtuple('InlineSettings', ['iimage', 'shorthand', 'stack_depth'])
TextboxInfo = namedtuple('TextboxInfo',
['bbox', 'is_visible', 'is_corrupt'])
ContentsInfo = namedtuple(
'ContentsInfo', ['xobject_settings', 'inline_images', 'found_vector']
)
TextboxInfo = namedtuple('TextboxInfo', ['bbox', 'is_visible', 'is_corrupt'])
class VectorInfo:
@@ -112,9 +110,9 @@ def _normalize_stack(graphobjs):
"""Convert runs of qQ's in the stack into single graphobjs"""
for operands, operator in graphobjs:
operator = str(operator)
if re.match(r'Q*q+$', operator): # Zero or more Q, one or more q
for char in operator: # Split into individual
yield ([], char) # Yield individual
if re.match(r'Q*q+$', operator): # Zero or more Q, one or more q
for char in operator: # Split into individual
yield ([], char) # Yield individual
else:
yield (operands, operator)
@@ -155,15 +153,19 @@ def _interpret_contents(contentstream, initial_shorthand=UNIT_SQUARE):
image_ops = set('BI ID EI q Q Do cm'.split())
operator_whitelist = ' '.join(vector_ops | image_ops)
for n, graphobj in enumerate(_normalize_stack(
pikepdf.parse_content_stream(contentstream, operator_whitelist))):
for n, graphobj in enumerate(
_normalize_stack(
pikepdf.parse_content_stream(contentstream, operator_whitelist)
)
):
operands, operator = graphobj
if operator == 'q':
stack.append(ctm)
if len(stack) > 32: # See docstring
if len(stack) > 128:
raise RuntimeError(
"PDF graphics stack overflowed hard limit, operator %i" % n)
"PDF graphics stack overflowed hard limit, operator %i" % n
)
warn("PDF graphics stack overflowed spec limit")
elif operator == 'Q':
try:
@@ -177,14 +179,14 @@ def _interpret_contents(contentstream, initial_shorthand=UNIT_SQUARE):
elif operator == 'Do':
image_name = operands[0]
settings = XobjectSettings(
name=image_name, shorthand=ctm.shorthand,
stack_depth=len(stack))
name=image_name, shorthand=ctm.shorthand, stack_depth=len(stack)
)
xobject_settings.append(settings)
elif operator == 'INLINE IMAGE': # BI/ID/EI are grouped into this
elif operator == 'INLINE IMAGE': # BI/ID/EI are grouped into this
iimage = operands[0]
inline = InlineSettings(
iimage=iimage, shorthand=ctm.shorthand,
stack_depth=len(stack))
iimage=iimage, shorthand=ctm.shorthand, stack_depth=len(stack)
)
inline_images.append(inline)
elif operator in vector_ops:
found_vector = True
@@ -192,7 +194,8 @@ def _interpret_contents(contentstream, initial_shorthand=UNIT_SQUARE):
return ContentsInfo(
xobject_settings=xobject_settings,
inline_images=inline_images,
found_vector=found_vector)
found_vector=found_vector,
)
def _get_dpi(ctm_shorthand, image_size):
@@ -262,8 +265,7 @@ def _get_dpi(ctm_shorthand, image_size):
class ImageInfo:
DPI_PREC = Decimal('1.000')
def __init__(self, *, name='', pdfimage=None, inline=None,
shorthand=None):
def __init__(self, *, name='', pdfimage=None, inline=None, shorthand=None):
self._name = str(name)
self._shorthand = shorthand
@@ -348,19 +350,24 @@ class ImageInfo:
return _get_dpi(self._shorthand, (self._width, self._height))[1]
def __repr__(self):
class_locals = {attr: getattr(self, attr, None) for attr in dir(self)
if not attr.startswith('_')}
class_locals = {
attr: getattr(self, attr, None)
for attr in dir(self)
if not attr.startswith('_')
}
return (
"<ImageInfo '{name}' {type_} {width}x{height} {color} "
"{comp} {bpc} {enc} {xres}x{yres}>").format(**class_locals)
"{comp} {bpc} {enc} {xres}x{yres}>"
).format(**class_locals)
def _find_inline_images(contentsinfo):
"Find inline images in the contentstream"
for n, inline in enumerate(contentsinfo.inline_images):
yield ImageInfo(name='inline-%02d' % n, shorthand=inline.shorthand,
inline=inline)
yield ImageInfo(
name='inline-%02d' % n, shorthand=inline.shorthand, inline=inline
)
def _image_xobjects(container):
@@ -414,8 +421,7 @@ def _find_regular_images(container, contentsinfo):
# these from our DPI calculation for the page.
continue
yield ImageInfo(name=draw.name, pdfimage=pdfimage, shorthand=
draw.shorthand)
yield ImageInfo(name=draw.name, pdfimage=pdfimage, shorthand=draw.shorthand)
def _find_form_xobject_images(pdf, container, contentsinfo):
@@ -446,7 +452,8 @@ def _find_form_xobject_images(pdf, container, contentsinfo):
# same object are both very rare.
ctm_shorthand = settings.shorthand
yield from _process_content_streams(
pdf=pdf, container=form_xobject, shorthand=ctm_shorthand)
pdf=pdf, container=form_xobject, shorthand=ctm_shorthand
)
def _process_content_streams(*, pdf, container, shorthand=None):
@@ -470,8 +477,7 @@ def _process_content_streams(*, pdf, container, shorthand=None):
if container.get('/Type') == '/Page' and '/Contents' in container:
initial_shorthand = shorthand or UNIT_SQUARE
elif container.get('/Type') == '/XObject' and \
container['/Subtype'] == '/Form':
elif container.get('/Type') == '/XObject' and container['/Subtype'] == '/Form':
# Set the CTM to the state it was when the "Do" operator was
# encountered that is drawing this instance of the Form XObject
ctm = PdfMatrix(shorthand) if shorthand else PdfMatrix.identity()
@@ -505,9 +511,9 @@ def _page_has_text(text_blocks, page_width, page_height):
margin_ratio = 0.125
interior_bbox = (
margin_ratio * pw, # left
(1 - margin_ratio) * ph, # top
(1 - margin_ratio) * pw, # right
margin_ratio * ph # bottom (first quadrant: bottom < top)
(1 - margin_ratio) * ph, # top
(1 - margin_ratio) * pw, # right
margin_ratio * ph, # bottom (first quadrant: bottom < top)
)
def rects_intersect(a, b):
@@ -526,17 +532,17 @@ def _page_has_text(text_blocks, page_width, page_height):
return has_text
def simplify_textboxes(miner):
def simplify_textboxes(miner, textbox_getter):
"""Extract only limited content from text boxes
We do this to save memory and ensure that our objects are pickleable.
"""
for box in get_text_boxes(miner):
for box in textbox_getter(miner):
first_line = box._objs[0]
first_char = first_line._objs[0]
visible = (first_char.rendermode != 3)
corrupt = (first_char.get_text() == '\ufffd')
visible = first_char.rendermode != 3
corrupt = first_char.get_text() == '\ufffd'
yield TextboxInfo(box.bbox, visible, corrupt)
@@ -552,17 +558,24 @@ def _pdf_get_pageinfo(pdf, pageno: int, infile, xmltext):
if xmltext is not None:
bboxes = ghosttext.page_get_textblocks(
fspath(infile), pageno, xmltext=xmltext, height=height_pt)
fspath(infile), pageno, xmltext=xmltext, height=height_pt
)
pageinfo['bboxes'] = bboxes
else:
# pdfminer required for this section
try:
from .layout import get_page_analysis, get_text_boxes
except ImportError:
raise MissingDependencyError(
"pdfminer is required for this feature. Your distribution "
"may not have installed it."
)
pscript5_mode = str(pdf.docinfo.get('/Creator')).startswith('PScript5')
miner = get_page_analysis(infile, pageno, pscript5_mode)
pageinfo['textboxes'] = list(simplify_textboxes(miner))
pageinfo['textboxes'] = list(simplify_textboxes(miner, get_text_boxes))
bboxes = (box.bbox for box in pageinfo['textboxes'])
pageinfo['has_text'] = _page_has_text(
bboxes, width_pt, height_pt
)
pageinfo['has_text'] = _page_has_text(bboxes, width_pt, height_pt)
userunit = page.get('/UserUnit', Decimal(1.0))
if not isinstance(userunit, Decimal):
@@ -577,24 +590,24 @@ def _pdf_get_pageinfo(pdf, pageno: int, infile, xmltext):
pageinfo['rotate'] = 0
userunit_shorthand = (userunit, 0, 0, userunit, 0, 0)
contentsinfo = [ci for ci in
_process_content_streams(pdf=pdf, container=page,
shorthand=userunit_shorthand)]
contentsinfo = [
ci
for ci in _process_content_streams(
pdf=pdf, container=page, shorthand=userunit_shorthand
)
]
pageinfo['has_vector'] = False
if any(isinstance(ci, VectorInfo) for ci in contentsinfo):
pageinfo['has_vector'] = True
pageinfo['images'] = [im for im in contentsinfo
if isinstance(im, ImageInfo)]
pageinfo['images'] = [im for im in contentsinfo if isinstance(im, ImageInfo)]
if pageinfo['images']:
xres = Decimal(max(image.xres for image in pageinfo['images']))
yres = Decimal(max(image.yres for image in pageinfo['images']))
pageinfo['xres'], pageinfo['yres'] = xres, yres
pageinfo['width_pixels'] = \
int(round(xres * pageinfo['width_inches']))
pageinfo['height_pixels'] = \
int(round(yres * pageinfo['height_inches']))
pageinfo['width_pixels'] = int(round(xres * pageinfo['width_inches']))
pageinfo['height_pixels'] = int(round(yres * pageinfo['height_inches']))
return pageinfo
@@ -689,13 +702,14 @@ class PageInfo:
if 'textboxes' not in self._pageinfo:
if visible is not None and corrupt is not None:
raise NotImplementedError(
'Ghostscript textboxes cannot be classified')
raise NotImplementedError('Ghostscript textboxes cannot be classified')
return self._pageinfo['bboxes']
return (obj.bbox for obj in self._pageinfo['textboxes']
if predicate(obj, visible, corrupt))
return (
obj.bbox
for obj in self._pageinfo['textboxes']
if predicate(obj, visible, corrupt)
)
@property
def xres(self):
@@ -718,11 +732,15 @@ class PageInfo:
def __repr__(self):
return (
'<PageInfo '
'pageno={} {}"x{}" rotation={} res={}x{} has_text={}>').format(
self.pageno, self.width_inches, self.height_inches,
'<PageInfo ' 'pageno={} {}"x{}" rotation={} res={}x{} has_text={}>'
).format(
self.pageno,
self.width_inches,
self.height_inches,
self.rotation,
self.xres, self.yres, self.has_text
self.xres,
self.yres,
self.has_text,
)
@@ -732,7 +750,8 @@ class PdfInfo:
def __init__(self, infile, detailed_page_analysis=False, log=None):
self._infile = infile
self._pages, pdf = _pdf_get_all_pageinfo(
infile, detailed_page_analysis, log=log)
infile, detailed_page_analysis, log=log
)
self._needs_rendering = pdf.root.get('/NeedsRendering', False)
self._has_acroform = '/AcroForm' in pdf.root
@@ -770,15 +789,18 @@ class PdfInfo:
return len(self._pages)
def __repr__(self):
return "<PdfInfo('...'), page count={}>".format(len(self))
return f"<PdfInfo('...'), page count={len(self)}>"
def main():
import argparse
parser = argparse.ArgumentParser()
parser.add_argument('infile')
args = parser.parse_args()
info = _pdf_get_all_pageinfo(args.infile)
from pprint import pprint
pprint(info)
+8 -6
View File
@@ -23,13 +23,16 @@ from ..exec import ghostscript
# Forgive me for I have sinned
# I am using regular expressions to parse XML. However the XML in this case,
# generated by Ghostscript, is self-consistent enough to be parseable.
regex_remove_char_tags = re.compile(br"""
regex_remove_char_tags = re.compile(
br"""
<char\b
(?: [^>] # anything single character but >
| \">\" # special case: trap ">"
)*
/> # terminate with '/>'
""", re.VERBOSE)
""",
re.VERBOSE,
)
def page_get_textblocks(infile, pageno, xmltext, height):
@@ -76,15 +79,14 @@ def extract_text_xml(infile, pdf, pageno=None, log=None):
existing_text = regex_remove_char_tags.sub(b' ', existing_text)
try:
root = ET.fromstringlist([
b'<document>\n', existing_text, b'</document>\n'
])
root = ET.fromstringlist([b'<document>\n', existing_text, b'</document>\n'])
page_xml = root.findall('page')
except ET.ParseError as e:
log.error(
"An error occurred while attempting to retrieve existing text in "
"the input file. Will attempt to continue assuming that there is "
"no existing text in the file. The error was:")
"no existing text in the file. The error was:"
)
log.error(e)
page_xml = [None] * len(pdf.pages)
+87 -25
View File
@@ -25,13 +25,11 @@ import pdfminer.pdfdevice
import pdfminer.pdfinterp
from pdfminer.converter import PDFLayoutAnalyzer
from pdfminer.glyphlist import glyphname2unicode
from pdfminer.layout import (LAParams, LTChar, LTContainer, LTLayoutContainer,
LTPage, LTTextBox, LTTextLine)
from pdfminer.layout import LAParams, LTChar, LTPage, LTTextBox
from pdfminer.pdfdocument import PDFTextExtractionNotAllowed
from pdfminer.pdffont import (PDFCIDFont, PDFFont, PDFType3Font,
PDFUnicodeNotDefined, PDFSimpleFont)
from pdfminer.pdffont import PDFFont, PDFSimpleFont, PDFUnicodeNotDefined
from pdfminer.pdfpage import PDFPage
from pdfminer.utils import bbox2str, fsplit, matrix2str
from pdfminer.utils import bbox2str, matrix2str
from ..exceptions import EncryptedPdfError
@@ -41,6 +39,7 @@ STRIP_NAME = re.compile(r'[0-9]+')
# Unconditional pdfminer patches
#
def name2unicode(name):
"""Fix pdfminer's name2unicode function
@@ -62,9 +61,13 @@ def name2unicode(name):
if not m:
raise KeyError(name)
return chr(int(m.group(0)))
pdfminer.encodingdb.name2unicode = name2unicode
original_PDFFont_init = PDFFont.__init__
def PDFFont__init__(self, descriptor, widths, default_width=None):
original_PDFFont_init(self, descriptor, widths, default_width)
# PDF spec says descent should be negative
@@ -74,9 +77,13 @@ def PDFFont__init__(self, descriptor, widths, default_width=None):
# to misposition text.
if self.descent > 0:
self.descent = -self.descent
PDFFont.__init__ = PDFFont__init__
original_PDFSimpleFont_init = PDFSimpleFont.__init__
def PDFSimpleFont__init__(self, descriptor, widths, spec):
# Font encoding is specified either by a name of
# built-in encoding or a dictionary that describes
@@ -87,20 +94,25 @@ def PDFSimpleFont__init__(self, descriptor, widths, spec):
if not self.unicode_map and 'Encoding' not in spec:
self.cid2unicode = {}
return
PDFSimpleFont.__init__ = PDFSimpleFont__init__
#
# pdfminer patches when creator is PScript5.dll
#
def PDFType3Font__PScript5_get_height(self):
h = self.bbox[3]-self.bbox[1]
h = self.bbox[3] - self.bbox[1]
if h == 0:
h = self.ascent - self.descent
return h * copysign(1.0, self.vscale)
def PDFType3Font__PScript5_get_descent(self):
return self.descent * copysign(1.0, self.vscale)
def PDFType3Font__PScript5_get_ascent(self):
return self.ascent * copysign(1.0, self.vscale)
@@ -109,14 +121,48 @@ class LTStateAwareChar(LTChar):
"""A subclass of LTChar that tracks text render mode at time of drawing"""
__slots__ = (
'rendermode', '_text', 'matrix', 'fontname', 'adv', 'upright', 'size',
'width', 'height', 'bbox', 'x0', 'x1', 'y0', 'y1'
'rendermode',
'_text',
'matrix',
'fontname',
'adv',
'upright',
'size',
'width',
'height',
'bbox',
'x0',
'x1',
'y0',
'y1',
)
def __init__(self, matrix, font, fontsize, scaling, rise, text, textwidth,
textdisp, textstate, *args):
super().__init__(matrix, font, fontsize, scaling, rise, text, textwidth,
textdisp, *args)
def __init__(
self,
matrix,
font,
fontsize,
scaling,
rise,
text,
textwidth,
textdisp,
ncs,
graphicstate,
textstate,
):
super().__init__(
matrix,
font,
fontsize,
scaling,
rise,
text,
textwidth,
textdisp,
ncs,
graphicstate,
)
self.rendermode = textstate.render
def is_compatible(self, obj):
@@ -126,8 +172,7 @@ class LTStateAwareChar(LTChar):
- the Unicode mapping is known, and both have the same render mode
- the Unicode mapping is unknown but both are part of the same font
"""
both_unicode_mapped = (isinstance(self._text, str) and
isinstance(obj._text, str))
both_unicode_mapped = isinstance(self._text, str) and isinstance(obj._text, str)
try:
if both_unicode_mapped:
return self.rendermode == obj.rendermode
@@ -143,10 +188,15 @@ class LTStateAwareChar(LTChar):
return self._text
def __repr__(self):
return ('<%s %s matrix=%s rendermode=%r font=%r adv=%s text=%r>' %
(self.__class__.__name__, bbox2str(self.bbox),
matrix2str(self.matrix), self.rendermode, self.fontname, self.adv,
self.get_text()))
return '<%s %s matrix=%s rendermode=%r font=%r adv=%s text=%r>' % (
self.__class__.__name__,
bbox2str(self.bbox),
matrix2str(self.matrix),
self.rendermode,
self.fontname,
self.adv,
self.get_text(),
)
class TextPositionTracker(PDFLayoutAnalyzer):
@@ -169,11 +219,13 @@ class TextPositionTracker(PDFLayoutAnalyzer):
self.pageno += 1
self.receive_layout(self.cur_item)
def render_string(self, textstate, seq, *args):
def render_string(self, textstate, seq, ncs, graphicstate):
self.textstate = textstate.copy()
super().render_string(self.textstate, seq, *args)
super().render_string(self.textstate, seq, ncs, graphicstate)
def render_char(self, matrix, font, fontsize, scaling, rise, cid, *args):
def render_char(
self, matrix, font, fontsize, scaling, rise, cid, ncs, graphicstate
):
try:
text = font.to_unichr(cid)
assert isinstance(text, str), str(type(text))
@@ -182,13 +234,23 @@ class TextPositionTracker(PDFLayoutAnalyzer):
textwidth = font.char_width(cid)
textdisp = font.char_disp(cid)
item = LTStateAwareChar(
matrix, font, fontsize, scaling, rise, text,
textwidth, textdisp, self.textstate, *args)
matrix,
font,
fontsize,
scaling,
rise,
text,
textwidth,
textdisp,
ncs,
graphicstate,
self.textstate,
)
self.cur_item.add(item)
return item.adv
def handle_undefined_char(self, font, cid):
#log.info('undefined: %r, %r', font, cid)
# log.info('undefined: %r, %r', font, cid)
return (font.fontname, cid)
def receive_layout(self, ltpage):
@@ -209,7 +271,7 @@ def get_page_analysis(infile, pageno, pscript5_mode):
spec=True,
get_ascent=PDFType3Font__PScript5_get_ascent,
get_descent=PDFType3Font__PScript5_get_descent,
get_height=PDFType3Font__PScript5_get_height
get_height=PDFType3Font__PScript5_get_height,
)
patcher.start()
@@ -1 +1 @@
Tesseract Open Source OCR Engine v3.05.01 with Leptonica
Tesseract Open Source OCR Engine v4.0.0 with Leptonica
@@ -1,25 +1,25 @@
é la Waterman
a la Waterman
h ens linzen
4 ons linzen
3 liter water
3 mien
3 uien
bloem} hater
bloem, boter
2 kopjes melk
laurier, kruidnagel, kerrie, gout
Be linzen wassen en in¢l liter kokend wa-
ter 1 dag laten weken. 2 liter water bi'
de linzen voegen, gender hat water wagrin
ze geweekt zijn af te gieten. De helft Van
de mien bakken met laurier en kruiénagal.
Alla mien, kerrie en zout bij de linzen
voegen. A1135 aan de Rook brengem. Van de
bloem mat boter-en melk een papje maken en
verder afmaken met de soap. A13 de linzen
gaar zijn is de seep klaar.
laurier, kruidnagel, kerrie, zout
De linzgen wassen en in -l liter kokend wa-
ter 1 dag laten weken, 2 liter water bij
de linzen voegen, zonder het water waarin
ze geweekt zijn af te gieten, De helft van
de uien bakken met laurier en Kruicdnagel.
Alle uien, kerrie en gout bij de linzen
voegen, Alles aan de kook brengen,. Van de
bloem met boter en melk een papje maken en
verder afmaken met de soep, Als de linzen
gaar Zijn is de soep klaar.
@@ -1,3 +1 @@
Tesseract Open Source OCR Engine v3.05.01 with Leptonica
Too few characters. Skipping this page
OSD: Weak margin (0.00) for 24 blob text block, but using orientation anyway: 0
Tesseract Open Source OCR Engine v4.0.0 with Leptonica
@@ -1,4 +1,4 @@
This shnuld be a perfect circle-
This should be a perfect circle:
@@ -5,20 +5,27 @@
<head>
<title></title>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
<meta name='ocr-system' content='tesseract 3.05.01' />
<meta name='ocr-capabilities' content='ocr_page ocr_carea ocr_par ocr_line ocrx_word'/>
<meta name='ocr-system' content='tesseract 4.0.0' />
<meta name='ocr-capabilities' content='ocr_page ocr_carea ocr_par ocr_line ocrx_word ocrp_wconf'/>
</head>
<body>
<div class='ocr_page' id='page_1' title='image "/var/folders/37/78_114p552q16vv6vmgm5kr00000gn/T/com.github.ocrmypdf.7vjmeixk/000001.ocr.png"; bbox 0 0 1000 800; ppageno 0'>
<div class='ocr_page' id='page_1' title='image "/var/folders/37/78_114p552q16vv6vmgm5kr00000gn/T/com.github.ocrmypdf.jz4b2s0s/000001.ocr.png"; bbox 0 0 1000 800; ppageno 0'>
<div class='ocr_carea' id='block_1_1' title="bbox 296 96 704 504">
<p class='ocr_par' id='par_1_1' lang='eng' title="bbox 296 96 704 504">
<span class='ocr_line' id='line_1_1' title="bbox 296 96 704 504; baseline 0 296; x_size 169.33333; x_descenders 42.333332; x_ascenders 42.333336"><span class='ocrx_word' id='word_1_1' title='bbox 296 96 704 504; x_wconf 95'><strong> </strong></span>
<span class='ocr_line' id='line_1_1' title="bbox 296 96 704 504; baseline 0 296; x_size 169.33333; x_descenders 42.333332; x_ascenders 42.333336">
<span class='ocrx_word' id='word_1_1' title='bbox 296 96 704 504; x_wconf 95'><strong><em> </em></strong></span>
</span>
</p>
</div>
<div class='ocr_carea' id='block_1_2' title="bbox 150 592 841 622">
<p class='ocr_par' id='par_1_2' lang='eng' title="bbox 150 592 841 622">
<span class='ocr_line' id='line_1_2' title="bbox 150 592 841 622; baseline 0 -6; x_size 30; x_descenders 6; x_ascenders 8"><span class='ocrx_word' id='word_1_2' title='bbox 150 592 230 616; x_wconf 85'><strong>This</strong></span> <span class='ocrx_word' id='word_1_3' title='bbox 260 592 384 616; x_wconf 81'>shnuld</span> <span class='ocrx_word' id='word_1_4' title='bbox 413 592 449 616; x_wconf 81'><strong>be</strong></span> <span class='ocrx_word' id='word_1_5' title='bbox 479 600 493 616; x_wconf 85'><em>a</em></span> <span class='ocrx_word' id='word_1_6' title='bbox 523 592 668 622; x_wconf 76'>perfect</span> <span class='ocrx_word' id='word_1_7' title='bbox 698 592 841 616; x_wconf 76'><strong>circle-</strong></span>
<span class='ocr_line' id='line_1_2' title="bbox 150 592 841 622; baseline 0 -6; x_size 30; x_descenders 6; x_ascenders 8">
<span class='ocrx_word' id='word_1_2' title='bbox 150 592 230 616; x_wconf 96'><strong><em>This</em></strong></span>
<span class='ocrx_word' id='word_1_3' title='bbox 260 592 384 616; x_wconf 95'><strong><em>should</em></strong></span>
<span class='ocrx_word' id='word_1_4' title='bbox 413 592 449 616; x_wconf 95'><strong><em>be</em></strong></span>
<span class='ocrx_word' id='word_1_5' title='bbox 479 600 493 616; x_wconf 95'><strong><em>a</em></strong></span>
<span class='ocrx_word' id='word_1_6' title='bbox 523 592 668 622; x_wconf 95'><strong><em>perfect</em></strong></span>
<span class='ocrx_word' id='word_1_7' title='bbox 698 592 841 616; x_wconf 55'><strong><em>circle:</em></strong></span>
</span>
</p>
</div>
@@ -1,3 +1 @@
Tesseract Open Source OCR Engine v3.05.01 with Leptonica
Too few characters. Skipping this page
OSD: Weak margin (0.00) for 24 blob text block, but using orientation anyway: 0
Tesseract Open Source OCR Engine v4.0.0 with Leptonica
@@ -1,4 +1,4 @@
This shnuld be a perfect circle-
This should be a perfect circle:
@@ -1 +1 @@
Tesseract Open Source OCR Engine v3.05.01 with Leptonica
Tesseract Open Source OCR Engine v4.0.0 with Leptonica
@@ -1,51 +1,51 @@
The LinnSequencer
32 Track MIDI Sequence Recorder
The LinnSequencer is a stateofthe-art composition and performance tool for the professional musician. It is
The LinnSequencer is a state-of-the-art composition and performance tool for the professional musician. It is
extremely powerful, yet amazingly simple to learn and use. Its many remarkable features include:
0 Operation is similar to multitrack tape recorder with PLAY, STOP, RECORD, FAST
¢ Operation is similar to multi-track tape recorder with PLAY, STOP, RECORD, FAST
FORWARD, REWIND, and LOCATE controls.
0 Each of the 100 sequences contains 32 simultaneous, polyphonic tracks. Each track may
e Each of the 100 sequences contains 32 simultaneous, polyphonic tracks. Each track may
be assigned to one of 16 MIDI channels. Simultaneously plays up to 16 polyphonic
synthesizers !
synthesizers!
0 Ultrafast 3 1/2 ” disk drive stores complex songs in seconds and holds over 110,000 notes
¢ Ultra-fast 3%” disk drive stores complex songs in seconds and holds over 110,000 notes
per disk!
0 One or all tracks may be TRANSPOSED at the touch of a key.
0 Exclusive realtime ERASE function makes editing FAST.
0 Exclusive REPEAT function automatically repeats any held notes at a pre-selected
¢ One or all tracks may be TRANSPOSED at the touch of a key.
e Exclusive real-time ERASE function makes editing FAST.
* Exclusive REPEAT function automatically repeats any held notes at a pre-selected
rhythmic value.
0 TIMING CORRECTION works during playback and operates without chopping notes.
¢ TIMING CORRECTION works during playback and operates without chopping notes.
0 Optional SMPTE time code synchronization.
¢ Optional SMPTE time code synchronization.
0 Optional remote control.
© Optional remote control.
Recording 3 Sequence
Recording a Sequence
To record a sequence, simply press RECORD and PLAY,
then play your MIDI keyboard in time to the Sequencers
click track. When the sequence loops back around to bar 1,
youll hear what you played—only all timing errors will be
you ll hear what you played—only all timing errors will be
corrected! (Timing correction may be adjusted or defeated).
Any additional notes played will be added into the track
—existing notes are not erased while recording!
existing notes are not erased while recording!
FAST FORWARD, REWIND, and LOCATE controls
may be used at any time to quickly access any location in
your sequence for spotrecording. To overdub a new part,
select a different track and start recording~while you
record, the rsttrack will play in perfect sync (unless you
your sequence for spot-recording. To overdub a new part,
select a different track and start recordingwhile you
record, the first track will play in perfect sync (unless you
MUTE it, or SOLO another track). In this way, up to 32
tracks may be overdubbed! All MIDI effects are recorded
including pitch bend, modulation, velocity, aftertouch,
@@ -58,7 +58,7 @@ the note to be erased just before it plays in the sequence—
when played back, it will be gone. Notes may also be
added, erased, or changed using the SINGLE STEP func-
tion. To overdub notes at specic points within a sequence,
tion. To overdub notes at specific points within a sequence,
Additional Features
@@ -70,7 +70,7 @@ from one location to another—in the same sequence or a
different one. For example, you might insert a copy of the
first verse between the second chorus and the bridge.
DELETE BARS operates the same way to remove
unwanted sections.
unwanted sections,
Creating a Song
@@ -90,34 +90,34 @@ the LinnSequencer is designed to let you compose, record
and edit while devoting your undivided attention to your
music. See your Linn dealer today for a demonstration!
0 Simple, easy to learn operation—the 32 character LCD display clearly guides you through all operations. If needed, the
* Simple, easy to learn operation—the 32 character LCD display clearly guides you through all operations. If needed, the
HELP button displays additional explanations.
0 Non-destructive recording—existing notes are not erased while recording.
0 Two FOOTSWITCH INPUTS may be assigned to remotely control many of the commonly used functions, including
* Non-destructive recording—existing notes are not erased while recording.
¢ Two FOOTSWITCH INPUTS may be assigned to remotely control many of the commonly used functions, including
ERASE, REPEAT, PLAY/STOP, or LOCATE.
0 Two TRIGGER OUTPUTS may be programmed to output pulses at any selected note value.
¢ Iwo TRIGGER OUTPUTS may be programmed to output pulses at any selected note value.
0 Will sync to standard LinnDrum or Linn 9000 sync tone.
© Will sync to standard LinnDrum or Linn 9000 sync tone.
' Utilizes ultra highspeed, 8 MHz 80186 16 bit computer internally for FAST operation.
0 TEMPO may be specified in BEATS-PERMINUTE or FRAMES-PERBEAT at 24, 25, or 30 frames per second,
© Utilizes ultra high-speed, 8 MHz 80186 16 bit computer internally for FAST operation.
* TEMPO may be specified in BEATS-PER-MINUTE or FRAMES-PER-BEAT at 24, 25, or 30 frames per second,
(even drop frame!)
0 TEMPO may be entered numerically, adjustable in tenths of a Beat-Per-Minute increments, or by tapping quarter notes
¢ TEMPO may be entered numerically, adjustable in tenths of a Beat-Per-Minute increments, or by tapping quarter notes
on the TAP TEMPO button.
0 TEMPO CHANGES may be programmed into a sequence, with smooth transitions if desired.
° Any TIME SIGNATURE may be used, and may be changed within a song.
¢ TEMPO CHANGES may be programmed into a sequence, with smooth transitions if desired.
¢ Any TIME SIGNATURE may be used, and may be changed within a song.
E1111
linn
Linn Electronics, Inc.
18720 Oxnard Street, Tarzana, CA 91356
(818) 7088131 T ELEX #298949 LINN UR
(818) 708-8131 TELEX #298949 LINN UR
File diff suppressed because it is too large Load Diff
@@ -1 +1 @@
Tesseract Open Source OCR Engine v3.05.01 with Leptonica
Tesseract Open Source OCR Engine v4.0.0 with Leptonica
@@ -1,51 +1,51 @@
The LinnSequencer
32 Track MIDI Sequence Recorder
The LinnSequencer is a stateofthe-art composition and performance tool for the professional musician. It is
The LinnSequencer is a state-of-the-art composition and performance tool for the professional musician. It is
extremely powerful, yet amazingly simple to learn and use. Its many remarkable features include:
0 Operation is similar to multitrack tape recorder with PLAY, STOP, RECORD, FAST
¢ Operation is similar to multi-track tape recorder with PLAY, STOP, RECORD, FAST
FORWARD, REWIND, and LOCATE controls.
0 Each of the 100 sequences contains 32 simultaneous, polyphonic tracks. Each track may
e Each of the 100 sequences contains 32 simultaneous, polyphonic tracks. Each track may
be assigned to one of 16 MIDI channels. Simultaneously plays up to 16 polyphonic
synthesizers !
synthesizers!
0 Ultrafast 3 1/2 ” disk drive stores complex songs in seconds and holds over 110,000 notes
¢ Ultra-fast 3%” disk drive stores complex songs in seconds and holds over 110,000 notes
per disk!
0 One or all tracks may be TRANSPOSED at the touch of a key.
0 Exclusive realtime ERASE function makes editing FAST.
0 Exclusive REPEAT function automatically repeats any held notes at a pre-selected
¢ One or all tracks may be TRANSPOSED at the touch of a key.
e Exclusive real-time ERASE function makes editing FAST.
* Exclusive REPEAT function automatically repeats any held notes at a pre-selected
rhythmic value.
0 TIMING CORRECTION works during playback and operates without chopping notes.
¢ TIMING CORRECTION works during playback and operates without chopping notes.
0 Optional SMPTE time code synchronization.
¢ Optional SMPTE time code synchronization.
0 Optional remote control.
© Optional remote control.
Recording 3 Sequence
Recording a Sequence
To record a sequence, simply press RECORD and PLAY,
then play your MIDI keyboard in time to the Sequencers
click track. When the sequence loops back around to bar 1,
youll hear what you played—only all timing errors will be
you ll hear what you played—only all timing errors will be
corrected! (Timing correction may be adjusted or defeated).
Any additional notes played will be added into the track
—existing notes are not erased while recording!
existing notes are not erased while recording!
FAST FORWARD, REWIND, and LOCATE controls
may be used at any time to quickly access any location in
your sequence for spotrecording. To overdub a new part,
select a different track and start recording~while you
record, the rsttrack will play in perfect sync (unless you
your sequence for spot-recording. To overdub a new part,
select a different track and start recordingwhile you
record, the first track will play in perfect sync (unless you
MUTE it, or SOLO another track). In this way, up to 32
tracks may be overdubbed! All MIDI effects are recorded
including pitch bend, modulation, velocity, aftertouch,
@@ -58,7 +58,7 @@ the note to be erased just before it plays in the sequence—
when played back, it will be gone. Notes may also be
added, erased, or changed using the SINGLE STEP func-
tion. To overdub notes at specic points within a sequence,
tion. To overdub notes at specific points within a sequence,
Additional Features
@@ -70,7 +70,7 @@ from one location to another—in the same sequence or a
different one. For example, you might insert a copy of the
first verse between the second chorus and the bridge.
DELETE BARS operates the same way to remove
unwanted sections.
unwanted sections,
Creating a Song
@@ -90,34 +90,34 @@ the LinnSequencer is designed to let you compose, record
and edit while devoting your undivided attention to your
music. See your Linn dealer today for a demonstration!
0 Simple, easy to learn operation—the 32 character LCD display clearly guides you through all operations. If needed, the
* Simple, easy to learn operation—the 32 character LCD display clearly guides you through all operations. If needed, the
HELP button displays additional explanations.
0 Non-destructive recording—existing notes are not erased while recording.
0 Two FOOTSWITCH INPUTS may be assigned to remotely control many of the commonly used functions, including
* Non-destructive recording—existing notes are not erased while recording.
¢ Two FOOTSWITCH INPUTS may be assigned to remotely control many of the commonly used functions, including
ERASE, REPEAT, PLAY/STOP, or LOCATE.
0 Two TRIGGER OUTPUTS may be programmed to output pulses at any selected note value.
¢ Iwo TRIGGER OUTPUTS may be programmed to output pulses at any selected note value.
0 Will sync to standard LinnDrum or Linn 9000 sync tone.
© Will sync to standard LinnDrum or Linn 9000 sync tone.
' Utilizes ultra highspeed, 8 MHz 80186 16 bit computer internally for FAST operation.
0 TEMPO may be specified in BEATS-PERMINUTE or FRAMES-PERBEAT at 24, 25, or 30 frames per second,
© Utilizes ultra high-speed, 8 MHz 80186 16 bit computer internally for FAST operation.
* TEMPO may be specified in BEATS-PER-MINUTE or FRAMES-PER-BEAT at 24, 25, or 30 frames per second,
(even drop frame!)
0 TEMPO may be entered numerically, adjustable in tenths of a Beat-Per-Minute increments, or by tapping quarter notes
¢ TEMPO may be entered numerically, adjustable in tenths of a Beat-Per-Minute increments, or by tapping quarter notes
on the TAP TEMPO button.
0 TEMPO CHANGES may be programmed into a sequence, with smooth transitions if desired.
° Any TIME SIGNATURE may be used, and may be changed within a song.
¢ TEMPO CHANGES may be programmed into a sequence, with smooth transitions if desired.
¢ Any TIME SIGNATURE may be used, and may be changed within a song.
E1111
linn
Linn Electronics, Inc.
18720 Oxnard Street, Tarzana, CA 91356
(818) 7088131 T ELEX #298949 LINN UR
(818) 708-8131 TELEX #298949 LINN UR
@@ -1 +1 @@
Tesseract Open Source OCR Engine v3.05.01 with Leptonica
Tesseract Open Source OCR Engine v4.0.0 with Leptonica
@@ -1,51 +1,51 @@
The LinnSequencer
32 Track MIDI Sequence Recorder
The LinnSequencer is a stateofthe-art composition and performance tool for the professional musician. It is
The LinnSequencer is a state-of-the-art composition and performance tool for the professional musician. It is
extremely powerful, yet amazingly simple to learn and use. Its many remarkable features include:
0 Operation is similar to multitrack tape recorder with PLAY, STOP, RECORD, FAST
¢ Operation is similar to multi-track tape recorder with PLAY, STOP, RECORD, FAST
FORWARD, REWIND, and LOCATE controls.
0 Each of the 100 sequences contains 32 simultaneous, polyphonic tracks. Each track may
e Each of the 100 sequences contains 32 simultaneous, polyphonic tracks. Each track may
be assigned to one of 16 MIDI channels. Simultaneously plays up to 16 polyphonic
synthesizers !
synthesizers!
0 Ultrafast 3 1/2 ” disk drive stores complex songs in seconds and holds over 110,000 notes
¢ Ultra-fast 3%” disk drive stores complex songs in seconds and holds over 110,000 notes
per disk!
0 One or all tracks may be TRANSPOSED at the touch of a key.
0 Exclusive realtime ERASE function makes editing FAST.
0 Exclusive REPEAT function automatically repeats any held notes at a pre-selected
¢ One or all tracks may be TRANSPOSED at the touch of a key.
e Exclusive real-time ERASE function makes editing FAST.
* Exclusive REPEAT function automatically repeats any held notes at a pre-selected
rhythmic value.
0 TIMING CORRECTION works during playback and operates without chopping notes.
¢ TIMING CORRECTION works during playback and operates without chopping notes.
0 Optional SMPTE time code synchronization.
¢ Optional SMPTE time code synchronization.
0 Optional remote control.
© Optional remote control.
Recording 3 Sequence
Recording a Sequence
To record a sequence, simply press RECORD and PLAY,
then play your MIDI keyboard in time to the Sequencers
click track. When the sequence loops back around to bar 1,
youll hear what you played—only all timing errors will be
you ll hear what you played—only all timing errors will be
corrected! (Timing correction may be adjusted or defeated).
Any additional notes played will be added into the track
—existing notes are not erased while recording!
existing notes are not erased while recording!
FAST FORWARD, REWIND, and LOCATE controls
may be used at any time to quickly access any location in
your sequence for spotrecording. To overdub a new part,
select a different track and start recording~while you
record, the rsttrack will play in perfect sync (unless you
your sequence for spot-recording. To overdub a new part,
select a different track and start recordingwhile you
record, the first track will play in perfect sync (unless you
MUTE it, or SOLO another track). In this way, up to 32
tracks may be overdubbed! All MIDI effects are recorded
including pitch bend, modulation, velocity, aftertouch,
@@ -58,7 +58,7 @@ the note to be erased just before it plays in the sequence—
when played back, it will be gone. Notes may also be
added, erased, or changed using the SINGLE STEP func-
tion. To overdub notes at specic points within a sequence,
tion. To overdub notes at specific points within a sequence,
Additional Features
@@ -70,7 +70,7 @@ from one location to another—in the same sequence or a
different one. For example, you might insert a copy of the
first verse between the second chorus and the bridge.
DELETE BARS operates the same way to remove
unwanted sections.
unwanted sections,
Creating a Song
@@ -90,34 +90,34 @@ the LinnSequencer is designed to let you compose, record
and edit while devoting your undivided attention to your
music. See your Linn dealer today for a demonstration!
0 Simple, easy to learn operation—the 32 character LCD display clearly guides you through all operations. If needed, the
* Simple, easy to learn operation—the 32 character LCD display clearly guides you through all operations. If needed, the
HELP button displays additional explanations.
0 Non-destructive recording—existing notes are not erased while recording.
0 Two FOOTSWITCH INPUTS may be assigned to remotely control many of the commonly used functions, including
* Non-destructive recording—existing notes are not erased while recording.
¢ Two FOOTSWITCH INPUTS may be assigned to remotely control many of the commonly used functions, including
ERASE, REPEAT, PLAY/STOP, or LOCATE.
0 Two TRIGGER OUTPUTS may be programmed to output pulses at any selected note value.
¢ Iwo TRIGGER OUTPUTS may be programmed to output pulses at any selected note value.
0 Will sync to standard LinnDrum or Linn 9000 sync tone.
© Will sync to standard LinnDrum or Linn 9000 sync tone.
' Utilizes ultra highspeed, 8 MHz 80186 16 bit computer internally for FAST operation.
0 TEMPO may be specified in BEATS-PERMINUTE or FRAMES-PERBEAT at 24, 25, or 30 frames per second,
© Utilizes ultra high-speed, 8 MHz 80186 16 bit computer internally for FAST operation.
* TEMPO may be specified in BEATS-PER-MINUTE or FRAMES-PER-BEAT at 24, 25, or 30 frames per second,
(even drop frame!)
0 TEMPO may be entered numerically, adjustable in tenths of a Beat-Per-Minute increments, or by tapping quarter notes
¢ TEMPO may be entered numerically, adjustable in tenths of a Beat-Per-Minute increments, or by tapping quarter notes
on the TAP TEMPO button.
0 TEMPO CHANGES may be programmed into a sequence, with smooth transitions if desired.
° Any TIME SIGNATURE may be used, and may be changed within a song.
¢ TEMPO CHANGES may be programmed into a sequence, with smooth transitions if desired.
¢ Any TIME SIGNATURE may be used, and may be changed within a song.
E1111
linn
Linn Electronics, Inc.
18720 Oxnard Street, Tarzana, CA 91356
(818) 7088131 T ELEX #298949 LINN UR
(818) 708-8131 TELEX #298949 LINN UR
File diff suppressed because it is too large Load Diff
@@ -1 +1 @@
Tesseract Open Source OCR Engine v3.05.01 with Leptonica
Tesseract Open Source OCR Engine v4.0.0 with Leptonica
@@ -1,51 +1,51 @@
The LinnSequencer
32 Track MIDI Sequence Recorder
The LinnSequencer is a stateofthe-art composition and performance tool for the professional musician. It is
The LinnSequencer is a state-of-the-art composition and performance tool for the professional musician. It is
extremely powerful, yet amazingly simple to learn and use. Its many remarkable features include:
0 Operation is similar to multitrack tape recorder with PLAY, STOP, RECORD, FAST
¢ Operation is similar to multi-track tape recorder with PLAY, STOP, RECORD, FAST
FORWARD, REWIND, and LOCATE controls.
0 Each of the 100 sequences contains 32 simultaneous, polyphonic tracks. Each track may
e Each of the 100 sequences contains 32 simultaneous, polyphonic tracks. Each track may
be assigned to one of 16 MIDI channels. Simultaneously plays up to 16 polyphonic
synthesizers !
synthesizers!
0 Ultrafast 3 1/2 ” disk drive stores complex songs in seconds and holds over 110,000 notes
¢ Ultra-fast 3%” disk drive stores complex songs in seconds and holds over 110,000 notes
per disk!
0 One or all tracks may be TRANSPOSED at the touch of a key.
0 Exclusive realtime ERASE function makes editing FAST.
0 Exclusive REPEAT function automatically repeats any held notes at a pre-selected
¢ One or all tracks may be TRANSPOSED at the touch of a key.
e Exclusive real-time ERASE function makes editing FAST.
* Exclusive REPEAT function automatically repeats any held notes at a pre-selected
rhythmic value.
0 TIMING CORRECTION works during playback and operates without chopping notes.
¢ TIMING CORRECTION works during playback and operates without chopping notes.
0 Optional SMPTE time code synchronization.
¢ Optional SMPTE time code synchronization.
0 Optional remote control.
© Optional remote control.
Recording 3 Sequence
Recording a Sequence
To record a sequence, simply press RECORD and PLAY,
then play your MIDI keyboard in time to the Sequencers
click track. When the sequence loops back around to bar 1,
youll hear what you played—only all timing errors will be
you ll hear what you played—only all timing errors will be
corrected! (Timing correction may be adjusted or defeated).
Any additional notes played will be added into the track
—existing notes are not erased while recording!
existing notes are not erased while recording!
FAST FORWARD, REWIND, and LOCATE controls
may be used at any time to quickly access any location in
your sequence for spotrecording. To overdub a new part,
select a different track and start recording~while you
record, the rsttrack will play in perfect sync (unless you
your sequence for spot-recording. To overdub a new part,
select a different track and start recordingwhile you
record, the first track will play in perfect sync (unless you
MUTE it, or SOLO another track). In this way, up to 32
tracks may be overdubbed! All MIDI effects are recorded
including pitch bend, modulation, velocity, aftertouch,
@@ -58,7 +58,7 @@ the note to be erased just before it plays in the sequence—
when played back, it will be gone. Notes may also be
added, erased, or changed using the SINGLE STEP func-
tion. To overdub notes at specic points within a sequence,
tion. To overdub notes at specific points within a sequence,
Additional Features
@@ -70,7 +70,7 @@ from one location to another—in the same sequence or a
different one. For example, you might insert a copy of the
first verse between the second chorus and the bridge.
DELETE BARS operates the same way to remove
unwanted sections.
unwanted sections,
Creating a Song
@@ -90,34 +90,34 @@ the LinnSequencer is designed to let you compose, record
and edit while devoting your undivided attention to your
music. See your Linn dealer today for a demonstration!
0 Simple, easy to learn operation—the 32 character LCD display clearly guides you through all operations. If needed, the
* Simple, easy to learn operation—the 32 character LCD display clearly guides you through all operations. If needed, the
HELP button displays additional explanations.
0 Non-destructive recording—existing notes are not erased while recording.
0 Two FOOTSWITCH INPUTS may be assigned to remotely control many of the commonly used functions, including
* Non-destructive recording—existing notes are not erased while recording.
¢ Two FOOTSWITCH INPUTS may be assigned to remotely control many of the commonly used functions, including
ERASE, REPEAT, PLAY/STOP, or LOCATE.
0 Two TRIGGER OUTPUTS may be programmed to output pulses at any selected note value.
¢ Iwo TRIGGER OUTPUTS may be programmed to output pulses at any selected note value.
0 Will sync to standard LinnDrum or Linn 9000 sync tone.
© Will sync to standard LinnDrum or Linn 9000 sync tone.
' Utilizes ultra highspeed, 8 MHz 80186 16 bit computer internally for FAST operation.
0 TEMPO may be specified in BEATS-PERMINUTE or FRAMES-PERBEAT at 24, 25, or 30 frames per second,
© Utilizes ultra high-speed, 8 MHz 80186 16 bit computer internally for FAST operation.
* TEMPO may be specified in BEATS-PER-MINUTE or FRAMES-PER-BEAT at 24, 25, or 30 frames per second,
(even drop frame!)
0 TEMPO may be entered numerically, adjustable in tenths of a Beat-Per-Minute increments, or by tapping quarter notes
¢ TEMPO may be entered numerically, adjustable in tenths of a Beat-Per-Minute increments, or by tapping quarter notes
on the TAP TEMPO button.
0 TEMPO CHANGES may be programmed into a sequence, with smooth transitions if desired.
° Any TIME SIGNATURE may be used, and may be changed within a song.
¢ TEMPO CHANGES may be programmed into a sequence, with smooth transitions if desired.
¢ Any TIME SIGNATURE may be used, and may be changed within a song.
E1111
linn
Linn Electronics, Inc.
18720 Oxnard Street, Tarzana, CA 91356
(818) 7088131 T ELEX #298949 LINN UR
(818) 708-8131 TELEX #298949 LINN UR
@@ -1 +1 @@
Tesseract Open Source OCR Engine v3.05.01 with Leptonica
Tesseract Open Source OCR Engine v4.0.0 with Leptonica
@@ -1,51 +1,51 @@
The LinnSequencer
32 Track MIDI Sequence Recorder
The LinnSequencer is a stateofthe-art composition and performance tool for the professional musician. It is
The LinnSequencer is a state-of-the-art composition and performance tool for the professional musician. It is
extremely powerful, yet amazingly simple to learn and use. Its many remarkable features include:
0 Operation is similar to multitrack tape recorder with PLAY, STOP, RECORD, FAST
¢ Operation is similar to multi-track tape recorder with PLAY, STOP, RECORD, FAST
FORWARD, REWIND, and LOCATE controls.
0 Each of the 100 sequences contains 32 simultaneous, polyphonic tracks. Each track may
e Each of the 100 sequences contains 32 simultaneous, polyphonic tracks. Each track may
be assigned to one of 16 MIDI channels. Simultaneously plays up to 16 polyphonic
synthesizers !
synthesizers!
0 Ultrafast 3 1/2 ” disk drive stores complex songs in seconds and holds over 110,000 notes
¢ Ultra-fast 3%” disk drive stores complex songs in seconds and holds over 110,000 notes
per disk!
0 One or all tracks may be TRANSPOSED at the touch of a key.
0 Exclusive realtime ERASE function makes editing FAST.
0 Exclusive REPEAT function automatically repeats any held notes at a pre-selected
¢ One or all tracks may be TRANSPOSED at the touch of a key.
e Exclusive real-time ERASE function makes editing FAST.
* Exclusive REPEAT function automatically repeats any held notes at a pre-selected
rhythmic value.
0 TIMING CORRECTION works during playback and operates without chopping notes.
¢ TIMING CORRECTION works during playback and operates without chopping notes.
0 Optional SMPTE time code synchronization.
¢ Optional SMPTE time code synchronization.
0 Optional remote control.
© Optional remote control.
Recording 3 Sequence
Recording a Sequence
To record a sequence, simply press RECORD and PLAY,
then play your MIDI keyboard in time to the Sequencers
click track. When the sequence loops back around to bar 1,
youll hear what you played—only all timing errors will be
you ll hear what you played—only all timing errors will be
corrected! (Timing correction may be adjusted or defeated).
Any additional notes played will be added into the track
—existing notes are not erased while recording!
existing notes are not erased while recording!
FAST FORWARD, REWIND, and LOCATE controls
may be used at any time to quickly access any location in
your sequence for spotrecording. To overdub a new part,
select a different track and start recording~while you
record, the rsttrack will play in perfect sync (unless you
your sequence for spot-recording. To overdub a new part,
select a different track and start recordingwhile you
record, the first track will play in perfect sync (unless you
MUTE it, or SOLO another track). In this way, up to 32
tracks may be overdubbed! All MIDI effects are recorded
including pitch bend, modulation, velocity, aftertouch,
@@ -58,7 +58,7 @@ the note to be erased just before it plays in the sequence—
when played back, it will be gone. Notes may also be
added, erased, or changed using the SINGLE STEP func-
tion. To overdub notes at specic points within a sequence,
tion. To overdub notes at specific points within a sequence,
Additional Features
@@ -70,7 +70,7 @@ from one location to another—in the same sequence or a
different one. For example, you might insert a copy of the
first verse between the second chorus and the bridge.
DELETE BARS operates the same way to remove
unwanted sections.
unwanted sections,
Creating a Song
@@ -90,34 +90,34 @@ the LinnSequencer is designed to let you compose, record
and edit while devoting your undivided attention to your
music. See your Linn dealer today for a demonstration!
0 Simple, easy to learn operation—the 32 character LCD display clearly guides you through all operations. If needed, the
* Simple, easy to learn operation—the 32 character LCD display clearly guides you through all operations. If needed, the
HELP button displays additional explanations.
0 Non-destructive recording—existing notes are not erased while recording.
0 Two FOOTSWITCH INPUTS may be assigned to remotely control many of the commonly used functions, including
* Non-destructive recording—existing notes are not erased while recording.
¢ Two FOOTSWITCH INPUTS may be assigned to remotely control many of the commonly used functions, including
ERASE, REPEAT, PLAY/STOP, or LOCATE.
0 Two TRIGGER OUTPUTS may be programmed to output pulses at any selected note value.
¢ Iwo TRIGGER OUTPUTS may be programmed to output pulses at any selected note value.
0 Will sync to standard LinnDrum or Linn 9000 sync tone.
© Will sync to standard LinnDrum or Linn 9000 sync tone.
' Utilizes ultra highspeed, 8 MHz 80186 16 bit computer internally for FAST operation.
0 TEMPO may be specified in BEATS-PERMINUTE or FRAMES-PERBEAT at 24, 25, or 30 frames per second,
© Utilizes ultra high-speed, 8 MHz 80186 16 bit computer internally for FAST operation.
* TEMPO may be specified in BEATS-PER-MINUTE or FRAMES-PER-BEAT at 24, 25, or 30 frames per second,
(even drop frame!)
0 TEMPO may be entered numerically, adjustable in tenths of a Beat-Per-Minute increments, or by tapping quarter notes
¢ TEMPO may be entered numerically, adjustable in tenths of a Beat-Per-Minute increments, or by tapping quarter notes
on the TAP TEMPO button.
0 TEMPO CHANGES may be programmed into a sequence, with smooth transitions if desired.
° Any TIME SIGNATURE may be used, and may be changed within a song.
¢ TEMPO CHANGES may be programmed into a sequence, with smooth transitions if desired.
¢ Any TIME SIGNATURE may be used, and may be changed within a song.
E1111
linn
Linn Electronics, Inc.
18720 Oxnard Street, Tarzana, CA 91356
(818) 7088131 T ELEX #298949 LINN UR
(818) 708-8131 TELEX #298949 LINN UR
File diff suppressed because it is too large Load Diff
@@ -1 +1 @@
Tesseract Open Source OCR Engine v3.05.01 with Leptonica
Tesseract Open Source OCR Engine v4.0.0 with Leptonica
@@ -1,51 +1,51 @@
The LinnSequencer
32 Track MIDI Sequence Recorder
The LinnSequencer is a stateofthe-art composition and performance tool for the professional musician. It is
The LinnSequencer is a state-of-the-art composition and performance tool for the professional musician. It is
extremely powerful, yet amazingly simple to learn and use. Its many remarkable features include:
0 Operation is similar to multitrack tape recorder with PLAY, STOP, RECORD, FAST
¢ Operation is similar to multi-track tape recorder with PLAY, STOP, RECORD, FAST
FORWARD, REWIND, and LOCATE controls.
0 Each of the 100 sequences contains 32 simultaneous, polyphonic tracks. Each track may
e Each of the 100 sequences contains 32 simultaneous, polyphonic tracks. Each track may
be assigned to one of 16 MIDI channels. Simultaneously plays up to 16 polyphonic
synthesizers !
synthesizers!
0 Ultrafast 3 1/2 ” disk drive stores complex songs in seconds and holds over 110,000 notes
¢ Ultra-fast 3%” disk drive stores complex songs in seconds and holds over 110,000 notes
per disk!
0 One or all tracks may be TRANSPOSED at the touch of a key.
0 Exclusive realtime ERASE function makes editing FAST.
0 Exclusive REPEAT function automatically repeats any held notes at a pre-selected
¢ One or all tracks may be TRANSPOSED at the touch of a key.
e Exclusive real-time ERASE function makes editing FAST.
* Exclusive REPEAT function automatically repeats any held notes at a pre-selected
rhythmic value.
0 TIMING CORRECTION works during playback and operates without chopping notes.
¢ TIMING CORRECTION works during playback and operates without chopping notes.
0 Optional SMPTE time code synchronization.
¢ Optional SMPTE time code synchronization.
0 Optional remote control.
© Optional remote control.
Recording 3 Sequence
Recording a Sequence
To record a sequence, simply press RECORD and PLAY,
then play your MIDI keyboard in time to the Sequencers
click track. When the sequence loops back around to bar 1,
youll hear what you played—only all timing errors will be
you ll hear what you played—only all timing errors will be
corrected! (Timing correction may be adjusted or defeated).
Any additional notes played will be added into the track
—existing notes are not erased while recording!
existing notes are not erased while recording!
FAST FORWARD, REWIND, and LOCATE controls
may be used at any time to quickly access any location in
your sequence for spotrecording. To overdub a new part,
select a different track and start recording~while you
record, the rsttrack will play in perfect sync (unless you
your sequence for spot-recording. To overdub a new part,
select a different track and start recordingwhile you
record, the first track will play in perfect sync (unless you
MUTE it, or SOLO another track). In this way, up to 32
tracks may be overdubbed! All MIDI effects are recorded
including pitch bend, modulation, velocity, aftertouch,
@@ -58,7 +58,7 @@ the note to be erased just before it plays in the sequence—
when played back, it will be gone. Notes may also be
added, erased, or changed using the SINGLE STEP func-
tion. To overdub notes at specic points within a sequence,
tion. To overdub notes at specific points within a sequence,
Additional Features
@@ -70,7 +70,7 @@ from one location to another—in the same sequence or a
different one. For example, you might insert a copy of the
first verse between the second chorus and the bridge.
DELETE BARS operates the same way to remove
unwanted sections.
unwanted sections,
Creating a Song
@@ -90,34 +90,34 @@ the LinnSequencer is designed to let you compose, record
and edit while devoting your undivided attention to your
music. See your Linn dealer today for a demonstration!
0 Simple, easy to learn operation—the 32 character LCD display clearly guides you through all operations. If needed, the
* Simple, easy to learn operation—the 32 character LCD display clearly guides you through all operations. If needed, the
HELP button displays additional explanations.
0 Non-destructive recording—existing notes are not erased while recording.
0 Two FOOTSWITCH INPUTS may be assigned to remotely control many of the commonly used functions, including
* Non-destructive recording—existing notes are not erased while recording.
¢ Two FOOTSWITCH INPUTS may be assigned to remotely control many of the commonly used functions, including
ERASE, REPEAT, PLAY/STOP, or LOCATE.
0 Two TRIGGER OUTPUTS may be programmed to output pulses at any selected note value.
¢ Iwo TRIGGER OUTPUTS may be programmed to output pulses at any selected note value.
0 Will sync to standard LinnDrum or Linn 9000 sync tone.
© Will sync to standard LinnDrum or Linn 9000 sync tone.
' Utilizes ultra highspeed, 8 MHz 80186 16 bit computer internally for FAST operation.
0 TEMPO may be specified in BEATS-PERMINUTE or FRAMES-PERBEAT at 24, 25, or 30 frames per second,
© Utilizes ultra high-speed, 8 MHz 80186 16 bit computer internally for FAST operation.
* TEMPO may be specified in BEATS-PER-MINUTE or FRAMES-PER-BEAT at 24, 25, or 30 frames per second,
(even drop frame!)
0 TEMPO may be entered numerically, adjustable in tenths of a Beat-Per-Minute increments, or by tapping quarter notes
¢ TEMPO may be entered numerically, adjustable in tenths of a Beat-Per-Minute increments, or by tapping quarter notes
on the TAP TEMPO button.
0 TEMPO CHANGES may be programmed into a sequence, with smooth transitions if desired.
° Any TIME SIGNATURE may be used, and may be changed within a song.
¢ TEMPO CHANGES may be programmed into a sequence, with smooth transitions if desired.
¢ Any TIME SIGNATURE may be used, and may be changed within a song.
E1111
linn
Linn Electronics, Inc.
18720 Oxnard Street, Tarzana, CA 91356
(818) 7088131 T ELEX #298949 LINN UR
(818) 708-8131 TELEX #298949 LINN UR
@@ -1 +1 @@
Tesseract Open Source OCR Engine v3.05.01 with Leptonica
Tesseract Open Source OCR Engine v4.0.0 with Leptonica
@@ -1,51 +1,51 @@
The LinnSequencer
32 Track MIDI Sequence Recorder
The LinnSequencer is a stateofthe-art composition and performance tool for the professional musician. It is
The LinnSequencer is a state-of-the-art composition and performance tool for the professional musician. It is
extremely powerful, yet amazingly simple to learn and use. Its many remarkable features include:
0 Operation is similar to multitrack tape recorder with PLAY, STOP, RECORD, FAST
¢ Operation is similar to multi-track tape recorder with PLAY, STOP, RECORD, FAST
FORWARD, REWIND, and LOCATE controls.
0 Each of the 100 sequences contains 32 simultaneous, polyphonic tracks. Each track may
e Each of the 100 sequences contains 32 simultaneous, polyphonic tracks. Each track may
be assigned to one of 16 MIDI channels. Simultaneously plays up to 16 polyphonic
synthesizers !
synthesizers!
0 Ultrafast 3 1/2 ” disk drive stores complex songs in seconds and holds over 110,000 notes
¢ Ultra-fast 3%” disk drive stores complex songs in seconds and holds over 110,000 notes
per disk!
0 One or all tracks may be TRANSPOSED at the touch of a key.
0 Exclusive realtime ERASE function makes editing FAST.
0 Exclusive REPEAT function automatically repeats any held notes at a pre-selected
¢ One or all tracks may be TRANSPOSED at the touch of a key.
e Exclusive real-time ERASE function makes editing FAST.
* Exclusive REPEAT function automatically repeats any held notes at a pre-selected
rhythmic value.
0 TIMING CORRECTION works during playback and operates without chopping notes.
¢ TIMING CORRECTION works during playback and operates without chopping notes.
0 Optional SMPTE time code synchronization.
¢ Optional SMPTE time code synchronization.
0 Optional remote control.
© Optional remote control.
Recording 3 Sequence
Recording a Sequence
To record a sequence, simply press RECORD and PLAY,
then play your MIDI keyboard in time to the Sequencers
click track. When the sequence loops back around to bar 1,
youll hear what you played—only all timing errors will be
you ll hear what you played—only all timing errors will be
corrected! (Timing correction may be adjusted or defeated).
Any additional notes played will be added into the track
—existing notes are not erased while recording!
existing notes are not erased while recording!
FAST FORWARD, REWIND, and LOCATE controls
may be used at any time to quickly access any location in
your sequence for spotrecording. To overdub a new part,
select a different track and start recording~while you
record, the rsttrack will play in perfect sync (unless you
your sequence for spot-recording. To overdub a new part,
select a different track and start recordingwhile you
record, the first track will play in perfect sync (unless you
MUTE it, or SOLO another track). In this way, up to 32
tracks may be overdubbed! All MIDI effects are recorded
including pitch bend, modulation, velocity, aftertouch,
@@ -58,7 +58,7 @@ the note to be erased just before it plays in the sequence—
when played back, it will be gone. Notes may also be
added, erased, or changed using the SINGLE STEP func-
tion. To overdub notes at specic points within a sequence,
tion. To overdub notes at specific points within a sequence,
Additional Features
@@ -70,7 +70,7 @@ from one location to another—in the same sequence or a
different one. For example, you might insert a copy of the
first verse between the second chorus and the bridge.
DELETE BARS operates the same way to remove
unwanted sections.
unwanted sections,
Creating a Song
@@ -90,34 +90,34 @@ the LinnSequencer is designed to let you compose, record
and edit while devoting your undivided attention to your
music. See your Linn dealer today for a demonstration!
0 Simple, easy to learn operation—the 32 character LCD display clearly guides you through all operations. If needed, the
* Simple, easy to learn operation—the 32 character LCD display clearly guides you through all operations. If needed, the
HELP button displays additional explanations.
0 Non-destructive recording—existing notes are not erased while recording.
0 Two FOOTSWITCH INPUTS may be assigned to remotely control many of the commonly used functions, including
* Non-destructive recording—existing notes are not erased while recording.
¢ Two FOOTSWITCH INPUTS may be assigned to remotely control many of the commonly used functions, including
ERASE, REPEAT, PLAY/STOP, or LOCATE.
0 Two TRIGGER OUTPUTS may be programmed to output pulses at any selected note value.
¢ Iwo TRIGGER OUTPUTS may be programmed to output pulses at any selected note value.
0 Will sync to standard LinnDrum or Linn 9000 sync tone.
© Will sync to standard LinnDrum or Linn 9000 sync tone.
' Utilizes ultra highspeed, 8 MHz 80186 16 bit computer internally for FAST operation.
0 TEMPO may be specified in BEATS-PERMINUTE or FRAMES-PERBEAT at 24, 25, or 30 frames per second,
© Utilizes ultra high-speed, 8 MHz 80186 16 bit computer internally for FAST operation.
* TEMPO may be specified in BEATS-PER-MINUTE or FRAMES-PER-BEAT at 24, 25, or 30 frames per second,
(even drop frame!)
0 TEMPO may be entered numerically, adjustable in tenths of a Beat-Per-Minute increments, or by tapping quarter notes
¢ TEMPO may be entered numerically, adjustable in tenths of a Beat-Per-Minute increments, or by tapping quarter notes
on the TAP TEMPO button.
0 TEMPO CHANGES may be programmed into a sequence, with smooth transitions if desired.
° Any TIME SIGNATURE may be used, and may be changed within a song.
¢ TEMPO CHANGES may be programmed into a sequence, with smooth transitions if desired.
¢ Any TIME SIGNATURE may be used, and may be changed within a song.
E1111
linn
Linn Electronics, Inc.
18720 Oxnard Street, Tarzana, CA 91356
(818) 7088131 T ELEX #298949 LINN UR
(818) 708-8131 TELEX #298949 LINN UR
File diff suppressed because it is too large Load Diff
@@ -1 +1 @@
Tesseract Open Source OCR Engine v3.05.01 with Leptonica
Tesseract Open Source OCR Engine v4.0.0 with Leptonica
@@ -1,51 +1,51 @@
The LinnSequencer
32 Track MIDI Sequence Recorder
The LinnSequencer is a stateofthe-art composition and performance tool for the professional musician. It is
The LinnSequencer is a state-of-the-art composition and performance tool for the professional musician. It is
extremely powerful, yet amazingly simple to learn and use. Its many remarkable features include:
0 Operation is similar to multitrack tape recorder with PLAY, STOP, RECORD, FAST
¢ Operation is similar to multi-track tape recorder with PLAY, STOP, RECORD, FAST
FORWARD, REWIND, and LOCATE controls.
0 Each of the 100 sequences contains 32 simultaneous, polyphonic tracks. Each track may
e Each of the 100 sequences contains 32 simultaneous, polyphonic tracks. Each track may
be assigned to one of 16 MIDI channels. Simultaneously plays up to 16 polyphonic
synthesizers !
synthesizers!
0 Ultrafast 3 1/2 ” disk drive stores complex songs in seconds and holds over 110,000 notes
¢ Ultra-fast 3%” disk drive stores complex songs in seconds and holds over 110,000 notes
per disk!
0 One or all tracks may be TRANSPOSED at the touch of a key.
0 Exclusive realtime ERASE function makes editing FAST.
0 Exclusive REPEAT function automatically repeats any held notes at a pre-selected
¢ One or all tracks may be TRANSPOSED at the touch of a key.
e Exclusive real-time ERASE function makes editing FAST.
* Exclusive REPEAT function automatically repeats any held notes at a pre-selected
rhythmic value.
0 TIMING CORRECTION works during playback and operates without chopping notes.
¢ TIMING CORRECTION works during playback and operates without chopping notes.
0 Optional SMPTE time code synchronization.
¢ Optional SMPTE time code synchronization.
0 Optional remote control.
© Optional remote control.
Recording 3 Sequence
Recording a Sequence
To record a sequence, simply press RECORD and PLAY,
then play your MIDI keyboard in time to the Sequencers
click track. When the sequence loops back around to bar 1,
youll hear what you played—only all timing errors will be
you ll hear what you played—only all timing errors will be
corrected! (Timing correction may be adjusted or defeated).
Any additional notes played will be added into the track
—existing notes are not erased while recording!
existing notes are not erased while recording!
FAST FORWARD, REWIND, and LOCATE controls
may be used at any time to quickly access any location in
your sequence for spotrecording. To overdub a new part,
select a different track and start recording~while you
record, the rsttrack will play in perfect sync (unless you
your sequence for spot-recording. To overdub a new part,
select a different track and start recordingwhile you
record, the first track will play in perfect sync (unless you
MUTE it, or SOLO another track). In this way, up to 32
tracks may be overdubbed! All MIDI effects are recorded
including pitch bend, modulation, velocity, aftertouch,
@@ -58,7 +58,7 @@ the note to be erased just before it plays in the sequence—
when played back, it will be gone. Notes may also be
added, erased, or changed using the SINGLE STEP func-
tion. To overdub notes at specic points within a sequence,
tion. To overdub notes at specific points within a sequence,
Additional Features
@@ -70,7 +70,7 @@ from one location to another—in the same sequence or a
different one. For example, you might insert a copy of the
first verse between the second chorus and the bridge.
DELETE BARS operates the same way to remove
unwanted sections.
unwanted sections,
Creating a Song
@@ -90,34 +90,34 @@ the LinnSequencer is designed to let you compose, record
and edit while devoting your undivided attention to your
music. See your Linn dealer today for a demonstration!
0 Simple, easy to learn operation—the 32 character LCD display clearly guides you through all operations. If needed, the
* Simple, easy to learn operation—the 32 character LCD display clearly guides you through all operations. If needed, the
HELP button displays additional explanations.
0 Non-destructive recording—existing notes are not erased while recording.
0 Two FOOTSWITCH INPUTS may be assigned to remotely control many of the commonly used functions, including
* Non-destructive recording—existing notes are not erased while recording.
¢ Two FOOTSWITCH INPUTS may be assigned to remotely control many of the commonly used functions, including
ERASE, REPEAT, PLAY/STOP, or LOCATE.
0 Two TRIGGER OUTPUTS may be programmed to output pulses at any selected note value.
¢ Iwo TRIGGER OUTPUTS may be programmed to output pulses at any selected note value.
0 Will sync to standard LinnDrum or Linn 9000 sync tone.
© Will sync to standard LinnDrum or Linn 9000 sync tone.
' Utilizes ultra highspeed, 8 MHz 80186 16 bit computer internally for FAST operation.
0 TEMPO may be specified in BEATS-PERMINUTE or FRAMES-PERBEAT at 24, 25, or 30 frames per second,
© Utilizes ultra high-speed, 8 MHz 80186 16 bit computer internally for FAST operation.
* TEMPO may be specified in BEATS-PER-MINUTE or FRAMES-PER-BEAT at 24, 25, or 30 frames per second,
(even drop frame!)
0 TEMPO may be entered numerically, adjustable in tenths of a Beat-Per-Minute increments, or by tapping quarter notes
¢ TEMPO may be entered numerically, adjustable in tenths of a Beat-Per-Minute increments, or by tapping quarter notes
on the TAP TEMPO button.
0 TEMPO CHANGES may be programmed into a sequence, with smooth transitions if desired.
° Any TIME SIGNATURE may be used, and may be changed within a song.
¢ TEMPO CHANGES may be programmed into a sequence, with smooth transitions if desired.
¢ Any TIME SIGNATURE may be used, and may be changed within a song.
E1111
linn
Linn Electronics, Inc.
18720 Oxnard Street, Tarzana, CA 91356
(818) 7088131 T ELEX #298949 LINN UR
(818) 708-8131 TELEX #298949 LINN UR
@@ -1,6 +1,6 @@
Page number: 0
Orientation in degrees: 0
Rotate: 0
Orientation confidence: 18.91
Orientation confidence: 34.40
Script: Latin
Script confidence: 0.97
Script confidence: 2.90
@@ -1,6 +1,6 @@
Page number: 0
Orientation in degrees: 90
Rotate: 270
Orientation confidence: 17.21
Orientation confidence: 34.53
Script: Latin
Script confidence: 1.06
Script confidence: 3.83
@@ -1,6 +1,6 @@
Page number: 0
Orientation in degrees: 180
Rotate: 180
Orientation confidence: 14.79
Orientation confidence: 31.79
Script: Latin
Script confidence: 2.87
Script confidence: 3.18
@@ -1,6 +1,6 @@
Page number: 0
Orientation in degrees: 270
Rotate: 90
Orientation confidence: 19.19
Orientation confidence: 32.59
Script: Latin
Script confidence: 0.58
Script confidence: 2.85
@@ -1 +1 @@
Tesseract Open Source OCR Engine v3.05.01 with Leptonica
Tesseract Open Source OCR Engine v4.0.0 with Leptonica
@@ -1,51 +1,51 @@
The LinnSequencer
32 Track MIDI Sequence Recorder
The LinnSequencer is a stateofthe-art composition and performance tool for the professional musician. It is
The LinnSequencer is a state-of-the-art composition and performance tool for the professional musician. It is
extremely powerful, yet amazingly simple to learn and use. Its many remarkable features include:
0 Operation is similar to multitrack tape recorder with PLAY, STOP, RECORD, FAST
¢ Operation is similar to multi-track tape recorder with PLAY, STOP, RECORD, FAST
FORWARD, REWIND, and LOCATE controls.
0 Each of the 100 sequences contains 32 simultaneous, polyphonic tracks. Each track may
e Each of the 100 sequences contains 32 simultaneous, polyphonic tracks. Each track may
be assigned to one of 16 MIDI channels. Simultaneously plays up to 16 polyphonic
synthesizers !
synthesizers!
0 Ultrafast 3 1/2 ” disk drive stores complex songs in seconds and holds over 110,000 notes
¢ Ultra-fast 3%” disk drive stores complex songs in seconds and holds over 110,000 notes
per disk!
0 One or all tracks may be TRANSPOSED at the touch of a key.
0 Exclusive realtime ERASE function makes editing FAST.
0 Exclusive REPEAT function automatically repeats any held notes at a pre-selected
¢ One or all tracks may be TRANSPOSED at the touch of a key.
e Exclusive real-time ERASE function makes editing FAST.
* Exclusive REPEAT function automatically repeats any held notes at a pre-selected
rhythmic value.
0 TIMING CORRECTION works during playback and operates without chopping notes.
¢ TIMING CORRECTION works during playback and operates without chopping notes.
0 Optional SMPTE time code synchronization.
¢ Optional SMPTE time code synchronization.
0 Optional remote control.
© Optional remote control.
Recording 3 Sequence
Recording a Sequence
To record a sequence, simply press RECORD and PLAY,
then play your MIDI keyboard in time to the Sequencers
click track. When the sequence loops back around to bar 1,
youll hear what you played—only all timing errors will be
you ll hear what you played—only all timing errors will be
corrected! (Timing correction may be adjusted or defeated).
Any additional notes played will be added into the track
—existing notes are not erased while recording!
existing notes are not erased while recording!
FAST FORWARD, REWIND, and LOCATE controls
may be used at any time to quickly access any location in
your sequence for spotrecording. To overdub a new part,
select a different track and start recording~while you
record, the rst track will play in perfect sync (unless you
your sequence for spot-recording. To overdub a new part,
select a different track and start recordingwhile you
record, the first track will play in perfect sync (unless you
MUTE it, or SOLO another track). In this way, up to 32
tracks may be overdubbed! All MIDI effects are recorded
including pitch bend, modulation, velocity, aftertouch,
@@ -58,7 +58,7 @@ the note to be erased just before it plays in the sequence—
when played back, it will be gone. Notes may also be
added, erased, or changed using the SINGLE STEP func-
tion. To overdub notes at specic points within a sequence,
tion. To overdub notes at specific points within a sequence,
Additional Features
@@ -70,7 +70,7 @@ from one location to another—in the same sequence or a
different one. For example, you might insert a copy of the
first verse between the second chorus and the bridge.
DELETE BARS operates the same way to remove
unwanted sections.
unwanted sections,
Creating a Song
@@ -90,34 +90,34 @@ the LinnSequencer is designed to let you compose, record
and edit while devoting your undivided attention to your
music. See your Linn dealer today for a demonstration!
0 Simple, easy to learn operation—the 32 character LCD display clearly guides you through all operations. If needed, the
* Simple, easy to learn operation—the 32 character LCD display clearly guides you through all operations. If needed, the
HELP button displays additional explanations.
0 Non-destructive recording—existing notes are not erased while recording.
0 Two FOOTSWITCH INPUTS may be assigned to remotely control many of the commonly used functions, including
* Non-destructive recording—existing notes are not erased while recording.
¢ Two FOOTSWITCH INPUTS may be assigned to remotely control many of the commonly used functions, including
ERASE, REPEAT, PLAY/STOP, or LOCATE.
0 Two TRIGGER OUTPUTS may be programmed to output pulses at any selected note value.
¢ Iwo TRIGGER OUTPUTS may be programmed to output pulses at any selected note value.
0 Will sync to standard LinnDrum or Linn 9000 sync tone.
© Will sync to standard LinnDrum or Linn 9000 sync tone.
' Utilizes ultra highspeed, 8 MHZ 80186 16 bit computer internally for FAST operation.
0 TEMPO may be specified in BEATS-PERMINUTE or FRAMES-PERBEAT at 24, 25, or 30 frames per second,
© Utilizes ultra high-speed, 8 MHz 80186 16 bit computer internally for FAST operation.
* TEMPO may be specified in BEATS-PER-MINUTE or FRAMES-PER-BEAT at 24, 25, or 30 frames per second,
(even drop frame!)
0 TEMPO may be entered numerically, adjustable in tenths of a Beat-Per-Minute increments, or by tapping quarter notes
¢ TEMPO may be entered numerically, adjustable in tenths of a Beat-Per-Minute increments, or by tapping quarter notes
on the TAP TEMPO button.
0 TEMPO CHANGES may be programmed into a sequence, with smooth transitions if desired.
° Any TIME SIGNATURE may be used, and may be changed within a song.
¢ TEMPO CHANGES may be programmed into a sequence, with smooth transitions if desired.
¢ Any TIME SIGNATURE may be used, and may be changed within a song.
E1111
linn
Linn Electronics, Inc.
18720 Oxnard Street, Tarzana, CA 91356
(818) 7088131 T ELEX #298949 LINN UR
(818) 708-8131 TELEX #298949 LINN UR
File diff suppressed because it is too large Load Diff
@@ -1 +1 @@
Tesseract Open Source OCR Engine v3.05.01 with Leptonica
Tesseract Open Source OCR Engine v4.0.0 with Leptonica
@@ -1,51 +1,51 @@
The LinnSequencer
32 Track MIDI Sequence Recorder
The LinnSequencer is a stateofthe-art composition and performance tool for the professional musician. It is
The LinnSequencer is a state-of-the-art composition and performance tool for the professional musician. It is
extremely powerful, yet amazingly simple to learn and use. Its many remarkable features include:
0 Operation is similar to multitrack tape recorder with PLAY, STOP, RECORD, FAST
¢ Operation is similar to multi-track tape recorder with PLAY, STOP, RECORD, FAST
FORWARD, REWIND, and LOCATE controls.
0 Each of the 100 sequences contains 32 simultaneous, polyphonic tracks. Each track may
e Each of the 100 sequences contains 32 simultaneous, polyphonic tracks. Each track may
be assigned to one of 16 MIDI channels. Simultaneously plays up to 16 polyphonic
synthesizers !
synthesizers!
0 Ultrafast 3 1/2 ” disk drive stores complex songs in seconds and holds over 110,000 notes
¢ Ultra-fast 3%” disk drive stores complex songs in seconds and holds over 110,000 notes
per disk!
0 One or all tracks may be TRANSPOSED at the touch of a key.
0 Exclusive realtime ERASE function makes editing FAST.
0 Exclusive REPEAT function automatically repeats any held notes at a pre-selected
¢ One or all tracks may be TRANSPOSED at the touch of a key.
e Exclusive real-time ERASE function makes editing FAST.
* Exclusive REPEAT function automatically repeats any held notes at a pre-selected
rhythmic value.
0 TIMING CORRECTION works during playback and operates without chopping notes.
¢ TIMING CORRECTION works during playback and operates without chopping notes.
0 Optional SMPTE time code synchronization.
¢ Optional SMPTE time code synchronization.
0 Optional remote control.
© Optional remote control.
Recording 3 Sequence
Recording a Sequence
To record a sequence, simply press RECORD and PLAY,
then play your MIDI keyboard in time to the Sequencers
click track. When the sequence loops back around to bar 1,
youll hear what you played—only all timing errors will be
you ll hear what you played—only all timing errors will be
corrected! (Timing correction may be adjusted or defeated).
Any additional notes played will be added into the track
—existing notes are not erased while recording!
existing notes are not erased while recording!
FAST FORWARD, REWIND, and LOCATE controls
may be used at any time to quickly access any location in
your sequence for spotrecording. To overdub a new part,
select a different track and start recording~while you
record, the rst track will play in perfect sync (unless you
your sequence for spot-recording. To overdub a new part,
select a different track and start recordingwhile you
record, the first track will play in perfect sync (unless you
MUTE it, or SOLO another track). In this way, up to 32
tracks may be overdubbed! All MIDI effects are recorded
including pitch bend, modulation, velocity, aftertouch,
@@ -58,7 +58,7 @@ the note to be erased just before it plays in the sequence—
when played back, it will be gone. Notes may also be
added, erased, or changed using the SINGLE STEP func-
tion. To overdub notes at specic points within a sequence,
tion. To overdub notes at specific points within a sequence,
Additional Features
@@ -70,7 +70,7 @@ from one location to another—in the same sequence or a
different one. For example, you might insert a copy of the
first verse between the second chorus and the bridge.
DELETE BARS operates the same way to remove
unwanted sections.
unwanted sections,
Creating a Song
@@ -90,34 +90,34 @@ the LinnSequencer is designed to let you compose, record
and edit while devoting your undivided attention to your
music. See your Linn dealer today for a demonstration!
0 Simple, easy to learn operation—the 32 character LCD display clearly guides you through all operations. If needed, the
* Simple, easy to learn operation—the 32 character LCD display clearly guides you through all operations. If needed, the
HELP button displays additional explanations.
0 Non-destructive recording—existing notes are not erased while recording.
0 Two FOOTSWITCH INPUTS may be assigned to remotely control many of the commonly used functions, including
* Non-destructive recording—existing notes are not erased while recording.
¢ Two FOOTSWITCH INPUTS may be assigned to remotely control many of the commonly used functions, including
ERASE, REPEAT, PLAY/STOP, or LOCATE.
0 Two TRIGGER OUTPUTS may be programmed to output pulses at any selected note value.
¢ Iwo TRIGGER OUTPUTS may be programmed to output pulses at any selected note value.
0 Will sync to standard LinnDrum or Linn 9000 sync tone.
© Will sync to standard LinnDrum or Linn 9000 sync tone.
' Utilizes ultra highspeed, 8 MHZ 80186 16 bit computer internally for FAST operation.
0 TEMPO may be specified in BEATS-PERMINUTE or FRAMES-PERBEAT at 24, 25, or 30 frames per second,
© Utilizes ultra high-speed, 8 MHz 80186 16 bit computer internally for FAST operation.
* TEMPO may be specified in BEATS-PER-MINUTE or FRAMES-PER-BEAT at 24, 25, or 30 frames per second,
(even drop frame!)
0 TEMPO may be entered numerically, adjustable in tenths of a Beat-Per-Minute increments, or by tapping quarter notes
¢ TEMPO may be entered numerically, adjustable in tenths of a Beat-Per-Minute increments, or by tapping quarter notes
on the TAP TEMPO button.
0 TEMPO CHANGES may be programmed into a sequence, with smooth transitions if desired.
° Any TIME SIGNATURE may be used, and may be changed within a song.
¢ TEMPO CHANGES may be programmed into a sequence, with smooth transitions if desired.
¢ Any TIME SIGNATURE may be used, and may be changed within a song.
E1111
linn
Linn Electronics, Inc.
18720 Oxnard Street, Tarzana, CA 91356
(818) 7088131 T ELEX #298949 LINN UR
(818) 708-8131 TELEX #298949 LINN UR
@@ -1,2 +1 @@
Tesseract Open Source OCR Engine v3.05.01 with Leptonica
OSD: Weak margin (6.83) for 47 blob text block, but using orientation anyway: 0
Tesseract Open Source OCR Engine v4.0.0 with Leptonica
@@ -1,9 +1,9 @@
Multicolor Black
Pure Block (K = 100)
Pure Black (K = 100}
Pure Magenta
Pu re Cya n
Pure Cyan
Pure Yellow
@@ -5,34 +5,47 @@
<head>
<title></title>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
<meta name='ocr-system' content='tesseract 3.05.01' />
<meta name='ocr-capabilities' content='ocr_page ocr_carea ocr_par ocr_line ocrx_word'/>
<meta name='ocr-system' content='tesseract 4.0.0' />
<meta name='ocr-capabilities' content='ocr_page ocr_carea ocr_par ocr_line ocrx_word ocrp_wconf'/>
</head>
<body>
<div class='ocr_page' id='page_1' title='image "/var/folders/37/78_114p552q16vv6vmgm5kr00000gn/T/com.github.ocrmypdf.lfruqc8g/000001.ocr.png"; bbox 0 0 900 900; ppageno 0'>
<div class='ocr_page' id='page_1' title='image "/var/folders/37/78_114p552q16vv6vmgm5kr00000gn/T/com.github.ocrmypdf.wy7q83pl/000001.ocr.png"; bbox 0 0 900 900; ppageno 0'>
<div class='ocr_carea' id='block_1_1' title="bbox 97 87 502 204">
<p class='ocr_par' id='par_1_1' lang='eng' title="bbox 97 87 502 204">
<span class='ocr_line' id='line_1_1' title="bbox 97 87 399 122; baseline 0 0; x_size 40.714287; x_descenders 5.7142859; x_ascenders 15"><span class='ocrx_word' id='word_1_1' title='bbox 97 87 285 122; x_wconf 75'>Multicolor</span> <span class='ocrx_word' id='word_1_2' title='bbox 302 87 399 122; x_wconf 83'>Black</span>
<span class='ocr_line' id='line_1_1' title="bbox 97 87 399 122; baseline 0 0; x_size 40.714287; x_descenders 5.7142859; x_ascenders 15">
<span class='ocrx_word' id='word_1_1' title='bbox 97 87 285 122; x_wconf 95'><strong><em>Multicolor</em></strong></span>
<span class='ocrx_word' id='word_1_2' title='bbox 302 87 399 122; x_wconf 96'><strong><em>Black</em></strong></span>
</span>
<span class='ocr_line' id='line_1_2' title="bbox 114 160 502 204; baseline 0 -9; x_size 44; x_descenders 9; x_ascenders 15"><span class='ocrx_word' id='word_1_3' title='bbox 114 163 191 195; x_wconf 91'>Pure</span> <span class='ocrx_word' id='word_1_4' title='bbox 210 160 308 195; x_wconf 81'>Block</span> <span class='ocrx_word' id='word_1_5' title='bbox 325 160 363 204; x_wconf 88'>(K</span> <span class='ocrx_word' id='word_1_6' title='bbox 378 174 400 183; x_wconf 96'><strong>=</strong></span> <span class='ocrx_word' id='word_1_7' title='bbox 421 160 502 204; x_wconf 77'>100)</span>
<span class='ocr_line' id='line_1_2' title="bbox 114 160 502 204; baseline 0 -9; x_size 44; x_descenders 9; x_ascenders 15">
<span class='ocrx_word' id='word_1_3' title='bbox 114 163 191 195; x_wconf 96'><strong><em>Pure</em></strong></span>
<span class='ocrx_word' id='word_1_4' title='bbox 210 160 308 195; x_wconf 93'><strong><em>Black</em></strong></span>
<span class='ocrx_word' id='word_1_5' title='bbox 325 160 363 204; x_wconf 93'><strong><em>(K</em></strong></span>
<span class='ocrx_word' id='word_1_6' title='bbox 378 174 400 183; x_wconf 96'><strong><em>=</em></strong></span>
<span class='ocrx_word' id='word_1_7' title='bbox 421 160 502 204; x_wconf 70'><strong><em>100}</em></strong></span>
</span>
</p>
</div>
<div class='ocr_carea' id='block_1_2' title="bbox 121 282 383 326">
<p class='ocr_par' id='par_1_2' lang='eng' title="bbox 121 282 383 326">
<span class='ocr_line' id='line_1_3' title="bbox 121 282 383 326; baseline 0 -11; x_size 44; x_descenders 11; x_ascenders 13"><span class='ocrx_word' id='word_1_8' title='bbox 121 283 199 315; x_wconf 91'>Pure</span> <span class='ocrx_word' id='word_1_9' title='bbox 216 282 383 326; x_wconf 75'>Magenta</span>
<span class='ocr_line' id='line_1_3' title="bbox 121 282 383 326; baseline 0 -11; x_size 44; x_descenders 11; x_ascenders 13">
<span class='ocrx_word' id='word_1_8' title='bbox 121 283 199 315; x_wconf 96'><strong><em>Pure</em></strong></span>
<span class='ocrx_word' id='word_1_9' title='bbox 216 282 383 326; x_wconf 96'><strong><em>Magenta</em></strong></span>
</span>
</p>
</div>
<div class='ocr_carea' id='block_1_3' title="bbox 140 375 329 418">
<p class='ocr_par' id='par_1_3' lang='eng' title="bbox 140 375 329 418">
<span class='ocr_line' id='line_1_4' title="bbox 140 375 329 418; baseline 0 -11; x_size 43; x_descenders 11; x_ascenders 12"><span class='ocrx_word' id='word_1_10' title='bbox 140 375 178 407; x_wconf 94'>Pu</span> <span class='ocrx_word' id='word_1_11' title='bbox 184 387 218 407; x_wconf 90'>re</span> <span class='ocrx_word' id='word_1_12' title='bbox 234 375 306 418; x_wconf 85'>Cya</span> <span class='ocrx_word' id='word_1_13' title='bbox 312 387 329 407; x_wconf 94'>n</span>
<span class='ocr_line' id='line_1_4' title="bbox 140 375 329 418; baseline 0 -11; x_size 43; x_descenders 11; x_ascenders 12">
<span class='ocrx_word' id='word_1_10' title='bbox 140 375 218 407; x_wconf 96'><strong><em>Pure</em></strong></span>
<span class='ocrx_word' id='word_1_11' title='bbox 234 375 329 418; x_wconf 96'><strong><em>Cyan</em></strong></span>
</span>
</p>
</div>
<div class='ocr_carea' id='block_1_4' title="bbox 207 570 422 605">
<p class='ocr_par' id='par_1_4' lang='eng' title="bbox 207 570 422 605">
<span class='ocr_line' id='line_1_5' title="bbox 207 570 422 605; baseline 0 0; x_size 40.365852; x_descenders 5.3658538; x_ascenders 15"><span class='ocrx_word' id='word_1_14' title='bbox 207 573 285 605; x_wconf 91'><strong>Pure</strong></span> <span class='ocrx_word' id='word_1_15' title='bbox 299 570 422 605; x_wconf 88'>Yellow</span>
<span class='ocr_line' id='line_1_5' title="bbox 207 570 422 605; baseline 0 0; x_size 40.365852; x_descenders 5.3658538; x_ascenders 15">
<span class='ocrx_word' id='word_1_12' title='bbox 207 573 285 605; x_wconf 96'><strong><em>Pure</em></strong></span>
<span class='ocrx_word' id='word_1_13' title='bbox 299 570 422 605; x_wconf 95'><strong><em>Yellow</em></strong></span>
</span>
</p>
</div>
@@ -1,2 +1 @@
Tesseract Open Source OCR Engine v3.05.01 with Leptonica
OSD: Weak margin (6.83) for 47 blob text block, but using orientation anyway: 0
Tesseract Open Source OCR Engine v4.0.0 with Leptonica
@@ -1,9 +1,9 @@
Multicolor Black
Pure Block (K = 100)
Pure Black (K = 100}
Pure Magenta
Pu re Cya n
Pure Cyan
Pure Yellow
@@ -1 +1 @@
Tesseract Open Source OCR Engine v3.05.01 with Leptonica
Tesseract Open Source OCR Engine v4.0.0 with Leptonica
@@ -1,13 +1,13 @@
Portez ce vieux whisky au juge
blond qui fume sur son île
intérieure, à côté de l'alcôve
ovoïde, où les bûches se
consument dans l'être, ce qui
ovoide, où les bûches se
consument dans l'âtre, ce qui
lui permet de penser à la
cænogénèse de l'être dont il
est question dans la cause
ambiguë entendue à Moÿ, dans
un capharnaüm qui, pense—t—il,
diminue çà et là la qualité de son
oeuvre.
un capharnaüm qui, pense-t-il,
diminue cà et là la qualité de son
œuvre.
@@ -1,2 +1 @@
Tesseract Open Source OCR Engine v3.05.01 with Leptonica
OSD: Weak margin (4.74) for 181 blob text block, but using orientation anyway: 0
Tesseract Open Source OCR Engine v4.0.0 with Leptonica
@@ -4,8 +4,8 @@ Replacement of "creationism" with "intelligent design"
+ "Creation" and "creationist"
+ "Intelligent design"
—@— "Creation" and "creationist"
—®@-— "Intelligent design"
and "design proponent"
Word count
@@ -17,4 +17,4 @@ Word count
@@ -1 +1 @@
Tesseract Open Source OCR Engine v3.05.01 with Leptonica
Tesseract Open Source OCR Engine v4.0.0 with Leptonica
@@ -1,62 +1,62 @@
415T CONGRESS, } SENATE. { Ex. Doc.
4ist ConGREss, } SENATE. { Ex. Doc,
3d Session. No. 25.
MESSAGE
OF THE
PRESIDENT OF THE UNITED STATES.
PRESIDENT OF THE UNITED STATES,
commcnme
COMMUNICATING
A copy of regulation for the comqu courta of the Um'tmi States in Japan,
decreed and iesued by the minister of the United States in that country.
A copy of regulations for the consular courts of the United States in Japan,
decreed and issued by the minister of the United States in that country.
anunr 91, 1571.——Read,refened to me pfimittee on Commerce, and ordered to be
pun .
JANUARY 27, 1871,—Read, referred to the Committee on Commerce, and ordered to be
printed.
1'» the Senate and House of Reprcommtires :
To the Senate and House of Representatives :
I transmit herewith, for the consideration of Congress, a report from
the Secretary of State, and the papers which accompanied it, concern-
ing regulations for the consular courts of the United States in J epan.
ing regulations for the consular courts of the United States in Japan.
U. S. GRAN 1.
U. 8. GRANT.
WASHINGTON, January 27, 1871.
WASHINGTON, January 27, 1871.
DEPARTMENT OF STATE,
Waahinyton, Ja/nuary 26, 1870.
Washington, January 26, 1870,
The Secretary of State has the honor 1:0 submit herewith for revision
by Congress, in conformity with the provisions of section (5 of the act.
approved 22d of June, 1860, a. copy of “regulations for the consular
courts of the United States in Japan,” decreed and issued by C. E.
The Secretary of State has the honor to submit herewith, for revision
by Congress, in conformity with the provisions of section 6 of the act
approved 22d of June, 1860, a copy of “regulations for the consular
courts of the United States in Japan,” decreed and issued by C. BE.
De Long, the minister of the United States in that country, in Septem-
ber, 1870; and also the papers mentioned in the subjoiued list, which.
ber, 1870; and also the papers mentioned in the subjoined list, which,
contain suggestions on the subject thereof.
A copy of Article XXVI of the consular regulations is also submitted,
and the Secretary of State respectfully suggests, fur the consideration
of Congress, the propriety of limiting the power of ministers tomake
deerees and regulation, in the sense, in which it is limited by paragraph
431 of the article before named—that is, “ to acts neeessaryto organize
and give efciency to the courts created by the act.”
and the Secretary of State respectfully suggests, for the consideration
of Congress, the propriety of limiting the power of ministers to make
decrees and regulation, in the sense in which it is limited by paragraph
431 of the article before named—that is, “to acts necessary to organize
and give efficiency to the courts created by the act.”
Respectfully submitted.
HAMILTON FISH.
The PRESIDENT.
The PRESIDENT,
List of accompanying papers.
1. Regulations for the consular courts of the United States in Japan.
2. Mr. Fish to Mr. De Long, September 10, 1870.
1, Regulations for the consular courts of the United States in Japan.
2, Mr. Fish to Mr. De Long, September 10, 1870,
@@ -5,169 +5,471 @@
<head>
<title></title>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
<meta name='ocr-system' content='tesseract 3.05.01' />
<meta name='ocr-capabilities' content='ocr_page ocr_carea ocr_par ocr_line ocrx_word'/>
<meta name='ocr-system' content='tesseract 4.0.0' />
<meta name='ocr-capabilities' content='ocr_page ocr_carea ocr_par ocr_line ocrx_word ocrp_wconf'/>
</head>
<body>
<div class='ocr_page' id='page_1' title='image "/var/folders/37/78_114p552q16vv6vmgm5kr00000gn/T/com.github.ocrmypdf.xd964naf/000001.ocr.png"; bbox 0 0 1000 1520; ppageno 0'>
<div class='ocr_page' id='page_1' title='image "/var/folders/37/78_114p552q16vv6vmgm5kr00000gn/T/com.github.ocrmypdf.doxmgxvs/000001.ocr.png"; bbox 0 0 1000 1520; ppageno 0'>
<div class='ocr_carea' id='block_1_1' title="bbox 122 103 848 146">
<p class='ocr_par' id='par_1_1' lang='eng' title="bbox 122 103 848 146">
<span class='ocr_line' id='line_1_1' title="bbox 122 103 848 146; baseline 0 -26; x_size 22; x_descenders 5; x_ascenders 4"><span class='ocrx_word' id='word_1_1' title='bbox 122 104 169 121; x_wconf 71'><strong>415T</strong></span> <span class='ocrx_word' id='word_1_2' title='bbox 177 103 291 125; x_wconf 63'><strong>CONGRESS,</strong></span> <span class='ocrx_word' id='word_1_3' title='bbox 300 105 308 146; x_wconf 60'>}</span> <span class='ocrx_word' id='word_1_4' title='bbox 439 103 543 120; x_wconf 79'><strong>SENATE.</strong></span> <span class='ocrx_word' id='word_1_5' title='bbox 736 105 745 146; x_wconf 66'>{</span> <span class='ocrx_word' id='word_1_6' title='bbox 753 103 788 120; x_wconf 85'><strong>Ex.</strong></span> <span class='ocrx_word' id='word_1_7' title='bbox 798 103 848 121; x_wconf 80'>Doc.</span>
<span class='ocr_line' id='line_1_1' title="bbox 122 103 848 146; baseline 0 -26; x_size 22; x_descenders 5; x_ascenders 4">
<span class='ocrx_word' id='word_1_1' title='bbox 122 104 169 121; x_wconf 29'><strong><em>4ist</em></strong></span>
<span class='ocrx_word' id='word_1_2' title='bbox 177 103 291 125; x_wconf 54'><strong><em>ConGREss,</em></strong></span>
<span class='ocrx_word' id='word_1_3' title='bbox 300 105 308 146; x_wconf 46'><strong><em>}</em></strong></span>
<span class='ocrx_word' id='word_1_4' title='bbox 439 103 543 120; x_wconf 94'><strong><em>SENATE.</em></strong></span>
<span class='ocrx_word' id='word_1_5' title='bbox 736 105 745 146; x_wconf 90'><strong><em>{</em></strong></span>
<span class='ocrx_word' id='word_1_6' title='bbox 753 103 788 120; x_wconf 94'><strong><em>Ex.</em></strong></span>
<span class='ocrx_word' id='word_1_7' title='bbox 798 103 848 121; x_wconf 95'><strong><em>Doc,</em></strong></span>
</span>
<span class='ocr_line' id='line_1_2' title="bbox 152 125 838 143; baseline -0.001 0; x_size 21.943821; x_descenders 4.94382; x_ascenders 5"><span class='ocrx_word' id='word_1_8' title='bbox 152 126 176 142; x_wconf 84'><strong>3d</strong></span> <span class='ocrx_word' id='word_1_9' title='bbox 185 126 260 143; x_wconf 64'><strong>Session.</strong></span> <span class='ocrx_word' id='word_1_10' title='bbox 767 125 802 142; x_wconf 71'><strong>No.</strong></span> <span class='ocrx_word' id='word_1_11' title='bbox 810 126 838 142; x_wconf 80'><strong>25.</strong></span>
<span class='ocr_line' id='line_1_2' title="bbox 152 125 838 143; baseline -0.001 0; x_size 21.943821; x_descenders 4.94382; x_ascenders 5">
<span class='ocrx_word' id='word_1_8' title='bbox 152 126 176 142; x_wconf 93'><strong><em>3d</em></strong></span>
<span class='ocrx_word' id='word_1_9' title='bbox 185 126 260 143; x_wconf 88'><strong><em>Session.</em></strong></span>
<span class='ocrx_word' id='word_1_10' title='bbox 767 125 802 142; x_wconf 86'><strong><em>No.</em></strong></span>
<span class='ocrx_word' id='word_1_11' title='bbox 810 126 838 142; x_wconf 76'><strong><em>25.</em></strong></span>
</span>
</p>
</div>
<div class='ocr_carea' id='block_1_2' title="bbox 384 245 594 269">
<p class='ocr_par' id='par_1_2' lang='eng' title="bbox 384 245 594 269">
<span class='ocr_line' id='line_1_3' title="bbox 384 245 594 269; baseline 0 0; x_size 32.666668; x_descenders 8.166667; x_ascenders 8.166667"><span class='ocrx_word' id='word_1_12' title='bbox 384 245 594 269; x_wconf 81'><strong>MESSAGE</strong></span>
<span class='ocr_line' id='line_1_3' title="bbox 384 245 594 269; baseline 0 0; x_size 32.666668; x_descenders 8.166667; x_ascenders 8.166667">
<span class='ocrx_word' id='word_1_12' title='bbox 384 245 594 269; x_wconf 94'><strong><em>MESSAGE</em></strong></span>
</span>
</p>
</div>
<div class='ocr_carea' id='block_1_3' title="bbox 459 302 523 313">
<p class='ocr_par' id='par_1_3' lang='eng' title="bbox 459 302 523 313">
<span class='ocr_line' id='line_1_4' title="bbox 459 302 523 313; baseline 0 0; x_size 20; x_descenders 5; x_ascenders 5"><span class='ocrx_word' id='word_1_13' title='bbox 459 302 481 313; x_wconf 74'><strong>OF</strong></span> <span class='ocrx_word' id='word_1_14' title='bbox 490 302 523 313; x_wconf 75'><strong>THE</strong></span>
<span class='ocr_line' id='line_1_4' title="bbox 459 302 523 313; baseline 0 0; x_size 20; x_descenders 5; x_ascenders 5">
<span class='ocrx_word' id='word_1_13' title='bbox 459 302 481 313; x_wconf 87'><strong><em>OF</em></strong></span>
<span class='ocrx_word' id='word_1_14' title='bbox 490 302 523 313; x_wconf 96'><strong><em>THE</em></strong></span>
</span>
</p>
</div>
<div class='ocr_carea' id='block_1_4' title="bbox 148 338 839 375">
<p class='ocr_par' id='par_1_4' lang='eng' title="bbox 148 338 839 375">
<span class='ocr_line' id='line_1_5' title="bbox 148 338 839 375; baseline 0.003 -3; x_size 43.490196; x_descenders 10.872549; x_ascenders 10.872549"><span class='ocrx_word' id='word_1_15' title='bbox 148 339 358 372; x_wconf 80'><strong>PRESIDENT</strong></span> <span class='ocrx_word' id='word_1_16' title='bbox 379 339 422 371; x_wconf 81'><strong>OF</strong></span> <span class='ocrx_word' id='word_1_17' title='bbox 444 338 518 371; x_wconf 88'><strong>THE</strong></span> <span class='ocrx_word' id='word_1_18' title='bbox 539 338 673 371; x_wconf 86'><strong>UNITED</strong></span> <span class='ocrx_word' id='word_1_19' title='bbox 694 338 839 375; x_wconf 83'>STATES.</span>
<span class='ocr_line' id='line_1_5' title="bbox 148 338 839 375; baseline 0.003 -3; x_size 43.490196; x_descenders 10.872549; x_ascenders 10.872549">
<span class='ocrx_word' id='word_1_15' title='bbox 148 339 358 372; x_wconf 96'><strong><em>PRESIDENT</em></strong></span>
<span class='ocrx_word' id='word_1_16' title='bbox 379 339 422 371; x_wconf 95'><strong><em>OF</em></strong></span>
<span class='ocrx_word' id='word_1_17' title='bbox 444 338 518 371; x_wconf 96'><strong><em>THE</em></strong></span>
<span class='ocrx_word' id='word_1_18' title='bbox 539 338 673 371; x_wconf 96'><strong><em>UNITED</em></strong></span>
<span class='ocrx_word' id='word_1_19' title='bbox 694 338 839 375; x_wconf 96'><strong><em>STATES,</em></strong></span>
</span>
</p>
</div>
<div class='ocr_carea' id='block_1_5' title="bbox 423 406 563 417">
<p class='ocr_par' id='par_1_5' lang='eng' title="bbox 423 406 563 417">
<span class='ocr_line' id='line_1_6' title="bbox 423 406 563 417; baseline 0 -1; x_size 20; x_descenders 5; x_ascenders 5"><span class='ocrx_word' id='word_1_20' title='bbox 423 406 563 417; x_wconf 68'><strong>commcnme</strong></span>
<span class='ocr_line' id='line_1_6' title="bbox 423 406 563 417; baseline 0 -1; x_size 20; x_descenders 5; x_ascenders 5">
<span class='ocrx_word' id='word_1_20' title='bbox 423 406 563 417; x_wconf 95'><strong><em>COMMUNICATING</em></strong></span>
</span>
</p>
</div>
<div class='ocr_carea' id='block_1_6' title="bbox 123 447 859 492">
<p class='ocr_par' id='par_1_6' lang='eng' title="bbox 123 447 859 492">
<span class='ocr_line' id='line_1_7' title="bbox 123 447 859 470; baseline 0.001 -6; x_size 22; x_descenders 5; x_ascenders 5"><span class='ocrx_word' id='word_1_21' title='bbox 123 447 141 465; x_wconf 79'><strong><em>A</em></strong></span> <span class='ocrx_word' id='word_1_22' title='bbox 147 452 189 469; x_wconf 74'><strong>copy</strong></span> <span class='ocrx_word' id='word_1_23' title='bbox 193 447 215 469; x_wconf 78'><strong>of</strong></span> <span class='ocrx_word' id='word_1_24' title='bbox 220 447 329 469; x_wconf 62'><strong>regulation</strong></span> <span class='ocrx_word' id='word_1_25' title='bbox 335 447 369 468; x_wconf 78'><strong>for</strong></span> <span class='ocrx_word' id='word_1_26' title='bbox 374 447 401 464; x_wconf 75'><strong>the</strong></span> <span class='ocrx_word' id='word_1_27' title='bbox 410 447 492 464; x_wconf 75'><em>comqu</em></span> <span class='ocrx_word' id='word_1_28' title='bbox 497 449 555 464; x_wconf 71'><strong>courta</strong></span> <span class='ocrx_word' id='word_1_29' title='bbox 563 447 585 469; x_wconf 84'><strong>of</strong></span> <span class='ocrx_word' id='word_1_30' title='bbox 590 447 617 464; x_wconf 77'><strong>the</strong></span> <span class='ocrx_word' id='word_1_31' title='bbox 628 447 692 465; x_wconf 68'><strong>Um&#39;tmi</strong></span> <span class='ocrx_word' id='word_1_32' title='bbox 700 447 758 465; x_wconf 71'><strong>States</strong></span> <span class='ocrx_word' id='word_1_33' title='bbox 766 448 785 464; x_wconf 72'><strong>in</strong></span> <span class='ocrx_word' id='word_1_34' title='bbox 793 447 859 470; x_wconf 71'><strong><em>Japan,</em></strong></span>
<span class='ocr_line' id='line_1_7' title="bbox 123 447 859 470; baseline 0.001 -6; x_size 22; x_descenders 5; x_ascenders 5">
<span class='ocrx_word' id='word_1_21' title='bbox 123 447 141 465; x_wconf 95'><strong><em>A</em></strong></span>
<span class='ocrx_word' id='word_1_22' title='bbox 147 452 189 469; x_wconf 95'><strong><em>copy</em></strong></span>
<span class='ocrx_word' id='word_1_23' title='bbox 193 447 215 469; x_wconf 96'><strong><em>of</em></strong></span>
<span class='ocrx_word' id='word_1_24' title='bbox 220 447 329 469; x_wconf 96'><strong><em>regulations</em></strong></span>
<span class='ocrx_word' id='word_1_25' title='bbox 335 447 369 468; x_wconf 95'><strong><em>for</em></strong></span>
<span class='ocrx_word' id='word_1_26' title='bbox 374 447 401 464; x_wconf 96'><strong><em>the</em></strong></span>
<span class='ocrx_word' id='word_1_27' title='bbox 410 447 492 464; x_wconf 96'><strong><em>consular</em></strong></span>
<span class='ocrx_word' id='word_1_28' title='bbox 497 449 555 464; x_wconf 79'><strong><em>courts</em></strong></span>
<span class='ocrx_word' id='word_1_29' title='bbox 563 447 585 469; x_wconf 96'><strong><em>of</em></strong></span>
<span class='ocrx_word' id='word_1_30' title='bbox 590 447 617 464; x_wconf 96'><strong><em>the</em></strong></span>
<span class='ocrx_word' id='word_1_31' title='bbox 628 447 692 465; x_wconf 96'><strong><em>United</em></strong></span>
<span class='ocrx_word' id='word_1_32' title='bbox 700 447 758 465; x_wconf 93'><strong><em>States</em></strong></span>
<span class='ocrx_word' id='word_1_33' title='bbox 766 448 785 464; x_wconf 93'><strong><em>in</em></strong></span>
<span class='ocrx_word' id='word_1_34' title='bbox 793 447 859 470; x_wconf 96'><strong><em>Japan,</em></strong></span>
</span>
<span class='ocr_line' id='line_1_8' title="bbox 145 468 832 492; baseline 0 -6; x_size 23; x_descenders 5; x_ascenders 6"><span class='ocrx_word' id='word_1_35' title='bbox 145 470 213 486; x_wconf 73'><strong>decreed</strong></span> <span class='ocrx_word' id='word_1_36' title='bbox 220 470 256 487; x_wconf 74'><strong>and</strong></span> <span class='ocrx_word' id='word_1_37' title='bbox 263 469 321 487; x_wconf 65'><strong>iesued</strong></span> <span class='ocrx_word' id='word_1_38' title='bbox 329 469 351 490; x_wconf 74'><strong>by</strong></span> <span class='ocrx_word' id='word_1_39' title='bbox 359 469 386 486; x_wconf 80'><strong>the</strong></span> <span class='ocrx_word' id='word_1_40' title='bbox 393 468 474 486; x_wconf 73'><strong>minister</strong></span> <span class='ocrx_word' id='word_1_41' title='bbox 480 469 502 491; x_wconf 79'><strong>of</strong></span> <span class='ocrx_word' id='word_1_42' title='bbox 507 470 533 487; x_wconf 77'><strong>the</strong></span> <span class='ocrx_word' id='word_1_43' title='bbox 544 469 608 487; x_wconf 67'><strong>United</strong></span> <span class='ocrx_word' id='word_1_44' title='bbox 616 470 674 487; x_wconf 69'><strong>States</strong></span> <span class='ocrx_word' id='word_1_45' title='bbox 680 470 700 487; x_wconf 76'><strong>in</strong></span> <span class='ocrx_word' id='word_1_46' title='bbox 708 470 746 487; x_wconf 77'><strong>that</strong></span> <span class='ocrx_word' id='word_1_47' title='bbox 753 472 832 492; x_wconf 72'><strong>country.</strong></span>
<span class='ocr_line' id='line_1_8' title="bbox 145 468 832 492; baseline 0 -6; x_size 23; x_descenders 5; x_ascenders 6">
<span class='ocrx_word' id='word_1_35' title='bbox 145 470 213 486; x_wconf 96'><strong><em>decreed</em></strong></span>
<span class='ocrx_word' id='word_1_36' title='bbox 220 470 256 487; x_wconf 95'><strong><em>and</em></strong></span>
<span class='ocrx_word' id='word_1_37' title='bbox 263 469 321 487; x_wconf 95'><strong><em>issued</em></strong></span>
<span class='ocrx_word' id='word_1_38' title='bbox 329 469 351 490; x_wconf 96'><strong><em>by</em></strong></span>
<span class='ocrx_word' id='word_1_39' title='bbox 359 469 386 486; x_wconf 96'><strong><em>the</em></strong></span>
<span class='ocrx_word' id='word_1_40' title='bbox 393 468 474 486; x_wconf 96'><strong><em>minister</em></strong></span>
<span class='ocrx_word' id='word_1_41' title='bbox 480 469 502 491; x_wconf 96'><strong><em>of</em></strong></span>
<span class='ocrx_word' id='word_1_42' title='bbox 507 470 533 487; x_wconf 96'><strong><em>the</em></strong></span>
<span class='ocrx_word' id='word_1_43' title='bbox 544 469 608 487; x_wconf 96'><strong><em>United</em></strong></span>
<span class='ocrx_word' id='word_1_44' title='bbox 616 470 674 487; x_wconf 96'><strong><em>States</em></strong></span>
<span class='ocrx_word' id='word_1_45' title='bbox 680 470 700 487; x_wconf 96'><strong><em>in</em></strong></span>
<span class='ocrx_word' id='word_1_46' title='bbox 708 470 746 487; x_wconf 96'><strong><em>that</em></strong></span>
<span class='ocrx_word' id='word_1_47' title='bbox 753 472 832 492; x_wconf 83'><strong><em>country.</em></strong></span>
</span>
</p>
</div>
<div class='ocr_carea' id='block_1_7' title="bbox 121 543 860 579">
<p class='ocr_par' id='par_1_7' lang='eng' title="bbox 121 543 860 579">
<span class='ocr_line' id='line_1_9' title="bbox 121 543 860 575; baseline 0 -17; x_size 19; x_descenders 4; x_ascenders 4"><span class='ocrx_word' id='word_1_48' title='bbox 121 544 200 559; x_wconf 66'><strong>anunr</strong></span> <span class='ocrx_word' id='word_1_49' title='bbox 206 544 229 562; x_wconf 66'><strong>91,</strong></span> <span class='ocrx_word' id='word_1_50' title='bbox 236 543 413 561; x_wconf 75'><strong>1571.——Read,refened</strong></span> <span class='ocrx_word' id='word_1_51' title='bbox 419 545 435 558; x_wconf 72'><strong>to</strong></span> <span class='ocrx_word' id='word_1_52' title='bbox 441 543 469 557; x_wconf 68'><strong>me</strong></span> <span class='ocrx_word' id='word_1_53' title='bbox 478 543 570 575; x_wconf 43'><strong>pfimittee</strong></span> <span class='ocrx_word' id='word_1_54' title='bbox 581 547 601 557; x_wconf 83'><strong>on</strong></span> <span class='ocrx_word' id='word_1_55' title='bbox 612 543 703 562; x_wconf 73'><strong>Commerce,</strong></span> <span class='ocrx_word' id='word_1_56' title='bbox 710 543 741 558; x_wconf 71'><strong>and</strong></span> <span class='ocrx_word' id='word_1_57' title='bbox 748 544 812 558; x_wconf 77'><strong>ordered</strong></span> <span class='ocrx_word' id='word_1_58' title='bbox 817 545 834 558; x_wconf 69'><strong>to</strong></span> <span class='ocrx_word' id='word_1_59' title='bbox 840 544 860 558; x_wconf 81'><strong>be</strong></span>
<span class='ocr_line' id='line_1_9' title="bbox 121 543 860 575; baseline 0 -17; x_size 19; x_descenders 4; x_ascenders 4">
<span class='ocrx_word' id='word_1_48' title='bbox 121 544 200 559; x_wconf 95'><strong><em>JANUARY</em></strong></span>
<span class='ocrx_word' id='word_1_49' title='bbox 206 544 229 562; x_wconf 85'><strong><em>27,</em></strong></span>
<span class='ocrx_word' id='word_1_50' title='bbox 236 543 342 561; x_wconf 58'><strong><em>1871,—Read,</em></strong></span>
<span class='ocrx_word' id='word_1_51' title='bbox 346 543 413 558; x_wconf 95'><strong><em>referred</em></strong></span>
<span class='ocrx_word' id='word_1_52' title='bbox 419 545 435 558; x_wconf 96'><strong><em>to</em></strong></span>
<span class='ocrx_word' id='word_1_53' title='bbox 441 543 469 557; x_wconf 96'><strong><em>the</em></strong></span>
<span class='ocrx_word' id='word_1_54' title='bbox 478 543 570 575; x_wconf 66'><strong><em>Committee</em></strong></span>
<span class='ocrx_word' id='word_1_55' title='bbox 581 547 601 557; x_wconf 96'><strong><em>on</em></strong></span>
<span class='ocrx_word' id='word_1_56' title='bbox 612 543 703 562; x_wconf 96'><strong><em>Commerce,</em></strong></span>
<span class='ocrx_word' id='word_1_57' title='bbox 710 543 741 558; x_wconf 96'><strong><em>and</em></strong></span>
<span class='ocrx_word' id='word_1_58' title='bbox 748 544 812 558; x_wconf 96'><strong><em>ordered</em></strong></span>
<span class='ocrx_word' id='word_1_59' title='bbox 817 545 834 558; x_wconf 96'><strong><em>to</em></strong></span>
<span class='ocrx_word' id='word_1_60' title='bbox 840 544 860 558; x_wconf 96'><strong><em>be</em></strong></span>
</span>
<span class='ocr_line' id='line_1_10' title="bbox 458 565 524 579; baseline 0 -4; x_size 18.782608; x_descenders 4; x_ascenders 4.782609"><span class='ocrx_word' id='word_1_60' title='bbox 458 565 492 579; x_wconf 73'><strong>pun</strong></span> <span class='ocrx_word' id='word_1_61' title='bbox 521 572 524 575; x_wconf 98'>.</span>
<span class='ocr_line' id='line_1_10' title="bbox 458 565 524 579; baseline 0 -4; x_size 18.782608; x_descenders 4; x_ascenders 4.782609">
<span class='ocrx_word' id='word_1_61' title='bbox 458 565 524 579; x_wconf 93'><strong><em>printed.</em></strong></span>
</span>
</p>
</div>
<div class='ocr_carea' id='block_1_8' title="bbox 121 631 858 770">
<p class='ocr_par' id='par_1_8' lang='eng' title="bbox 123 631 565 653">
<span class='ocr_line' id='line_1_11' title="bbox 123 631 565 653; baseline 0 -5; x_size 22; x_descenders 5; x_ascenders 5"><span class='ocrx_word' id='word_1_62' title='bbox 123 631 149 649; x_wconf 72'><strong>1&#39;»</strong></span> <span class='ocrx_word' id='word_1_63' title='bbox 157 631 185 648; x_wconf 75'><strong>the</strong></span> <span class='ocrx_word' id='word_1_64' title='bbox 193 631 255 648; x_wconf 67'><strong>Senate</strong></span> <span class='ocrx_word' id='word_1_65' title='bbox 263 631 300 649; x_wconf 73'><strong>and</strong></span> <span class='ocrx_word' id='word_1_66' title='bbox 306 631 367 648; x_wconf 66'><strong>House</strong></span> <span class='ocrx_word' id='word_1_67' title='bbox 375 631 397 653; x_wconf 84'><strong>of</strong></span> <span class='ocrx_word' id='word_1_68' title='bbox 404 631 554 652; x_wconf 64'><strong>Reprcommtires</strong></span> <span class='ocrx_word' id='word_1_69' title='bbox 559 638 565 648; x_wconf 91'><strong><em>:</em></strong></span>
<span class='ocr_line' id='line_1_11' title="bbox 123 631 565 653; baseline 0 -5; x_size 22; x_descenders 5; x_ascenders 5">
<span class='ocrx_word' id='word_1_62' title='bbox 123 631 149 649; x_wconf 96'><strong><em>To</em></strong></span>
<span class='ocrx_word' id='word_1_63' title='bbox 157 631 185 648; x_wconf 95'><strong><em>the</em></strong></span>
<span class='ocrx_word' id='word_1_64' title='bbox 193 631 255 648; x_wconf 95'><strong><em>Senate</em></strong></span>
<span class='ocrx_word' id='word_1_65' title='bbox 263 631 300 649; x_wconf 95'><strong><em>and</em></strong></span>
<span class='ocrx_word' id='word_1_66' title='bbox 306 631 367 648; x_wconf 95'><strong><em>House</em></strong></span>
<span class='ocrx_word' id='word_1_67' title='bbox 375 631 397 653; x_wconf 96'><strong><em>of</em></strong></span>
<span class='ocrx_word' id='word_1_68' title='bbox 404 631 554 652; x_wconf 74'><strong><em>Representatives</em></strong></span>
<span class='ocrx_word' id='word_1_69' title='bbox 559 638 565 648; x_wconf 86'><strong><em>:</em></strong></span>
</span>
</p>
<p class='ocr_par' id='par_1_9' lang='eng' title="bbox 121 658 858 724">
<span class='ocr_line' id='line_1_12' title="bbox 145 658 857 681; baseline 0.003 -7; x_size 22; x_descenders 5; x_ascenders 5"><span class='ocrx_word' id='word_1_70' title='bbox 145 658 155 674; x_wconf 91'>I</span> <span class='ocrx_word' id='word_1_71' title='bbox 162 659 250 675; x_wconf 72'><strong>transmit</strong></span> <span class='ocrx_word' id='word_1_72' title='bbox 261 658 357 681; x_wconf 75'><strong>herewith,</strong></span> <span class='ocrx_word' id='word_1_73' title='bbox 365 658 394 675; x_wconf 80'><strong>for</strong></span> <span class='ocrx_word' id='word_1_74' title='bbox 401 659 434 675; x_wconf 82'><strong>the</strong></span> <span class='ocrx_word' id='word_1_75' title='bbox 441 658 577 675; x_wconf 78'><strong>consideration</strong></span> <span class='ocrx_word' id='word_1_76' title='bbox 586 658 607 675; x_wconf 85'><strong>of</strong></span> <span class='ocrx_word' id='word_1_77' title='bbox 616 658 714 680; x_wconf 77'><strong>Congress,</strong></span> <span class='ocrx_word' id='word_1_78' title='bbox 723 663 734 675; x_wconf 72'><strong>a</strong></span> <span class='ocrx_word' id='word_1_79' title='bbox 742 659 805 679; x_wconf 74'><strong>report</strong></span> <span class='ocrx_word' id='word_1_80' title='bbox 810 658 857 676; x_wconf 81'><strong>from</strong></span>
<span class='ocr_line' id='line_1_12' title="bbox 145 658 857 681; baseline 0.003 -7; x_size 22; x_descenders 5; x_ascenders 5">
<span class='ocrx_word' id='word_1_70' title='bbox 145 658 155 674; x_wconf 92'><strong><em>I</em></strong></span>
<span class='ocrx_word' id='word_1_71' title='bbox 162 659 250 675; x_wconf 92'><strong><em>transmit</em></strong></span>
<span class='ocrx_word' id='word_1_72' title='bbox 261 658 357 681; x_wconf 94'><strong><em>herewith,</em></strong></span>
<span class='ocrx_word' id='word_1_73' title='bbox 365 658 394 675; x_wconf 96'><strong><em>for</em></strong></span>
<span class='ocrx_word' id='word_1_74' title='bbox 401 659 434 675; x_wconf 96'><strong><em>the</em></strong></span>
<span class='ocrx_word' id='word_1_75' title='bbox 441 658 577 675; x_wconf 96'><strong><em>consideration</em></strong></span>
<span class='ocrx_word' id='word_1_76' title='bbox 586 658 607 675; x_wconf 96'><strong><em>of</em></strong></span>
<span class='ocrx_word' id='word_1_77' title='bbox 616 658 714 680; x_wconf 95'><strong><em>Congress,</em></strong></span>
<span class='ocrx_word' id='word_1_78' title='bbox 723 663 734 675; x_wconf 94'><strong><em>a</em></strong></span>
<span class='ocrx_word' id='word_1_79' title='bbox 742 659 805 679; x_wconf 96'><strong><em>report</em></strong></span>
<span class='ocrx_word' id='word_1_80' title='bbox 810 658 857 676; x_wconf 96'><strong><em>from</em></strong></span>
</span>
<span class='ocr_line' id='line_1_13' title="bbox 121 680 858 703; baseline 0 -6; x_size 22; x_descenders 5; x_ascenders 5"><span class='ocrx_word' id='word_1_81' title='bbox 121 680 155 697; x_wconf 75'><strong>the</strong></span> <span class='ocrx_word' id='word_1_82' title='bbox 163 680 259 702; x_wconf 68'><strong>Secretary</strong></span> <span class='ocrx_word' id='word_1_83' title='bbox 268 680 288 697; x_wconf 75'><strong>of</strong></span> <span class='ocrx_word' id='word_1_84' title='bbox 299 680 357 703; x_wconf 75'><strong>State,</strong></span> <span class='ocrx_word' id='word_1_85' title='bbox 366 681 403 697; x_wconf 66'><strong>and</strong></span> <span class='ocrx_word' id='word_1_86' title='bbox 410 681 444 698; x_wconf 82'><strong>the</strong></span> <span class='ocrx_word' id='word_1_87' title='bbox 456 681 524 701; x_wconf 67'><strong>papers</strong></span> <span class='ocrx_word' id='word_1_88' title='bbox 531 680 592 697; x_wconf 79'><strong>which</strong></span> <span class='ocrx_word' id='word_1_89' title='bbox 605 680 736 702; x_wconf 69'><strong>accompanied</strong></span> <span class='ocrx_word' id='word_1_90' title='bbox 744 680 765 702; x_wconf 75'><strong>it,</strong></span> <span class='ocrx_word' id='word_1_91' title='bbox 774 685 858 698; x_wconf 80'><strong>concern-</strong></span>
<span class='ocr_line' id='line_1_13' title="bbox 121 680 858 703; baseline 0 -6; x_size 22; x_descenders 5; x_ascenders 5">
<span class='ocrx_word' id='word_1_81' title='bbox 121 680 155 697; x_wconf 96'><strong><em>the</em></strong></span>
<span class='ocrx_word' id='word_1_82' title='bbox 163 680 259 702; x_wconf 94'><strong><em>Secretary</em></strong></span>
<span class='ocrx_word' id='word_1_83' title='bbox 268 680 288 697; x_wconf 96'><strong><em>of</em></strong></span>
<span class='ocrx_word' id='word_1_84' title='bbox 299 680 357 703; x_wconf 96'><strong><em>State,</em></strong></span>
<span class='ocrx_word' id='word_1_85' title='bbox 366 681 403 697; x_wconf 96'><strong><em>and</em></strong></span>
<span class='ocrx_word' id='word_1_86' title='bbox 410 681 444 698; x_wconf 95'><strong><em>the</em></strong></span>
<span class='ocrx_word' id='word_1_87' title='bbox 456 681 524 701; x_wconf 95'><strong><em>papers</em></strong></span>
<span class='ocrx_word' id='word_1_88' title='bbox 531 680 592 697; x_wconf 94'><strong><em>which</em></strong></span>
<span class='ocrx_word' id='word_1_89' title='bbox 605 680 736 702; x_wconf 94'><strong><em>accompanied</em></strong></span>
<span class='ocrx_word' id='word_1_90' title='bbox 744 680 765 702; x_wconf 93'><strong><em>it,</em></strong></span>
<span class='ocrx_word' id='word_1_91' title='bbox 774 685 858 698; x_wconf 92'><strong><em>concern-</em></strong></span>
</span>
<span class='ocr_line' id='line_1_14' title="bbox 122 702 835 724; baseline 0.001 -5; x_size 21; x_descenders 4; x_ascenders 5"><span class='ocrx_word' id='word_1_92' title='bbox 122 703 155 723; x_wconf 80'><strong>ing</strong></span> <span class='ocrx_word' id='word_1_93' title='bbox 163 702 277 723; x_wconf 74'><strong>regulations</strong></span> <span class='ocrx_word' id='word_1_94' title='bbox 285 702 314 719; x_wconf 86'><strong>for</strong></span> <span class='ocrx_word' id='word_1_95' title='bbox 321 703 354 720; x_wconf 81'><strong>the</strong></span> <span class='ocrx_word' id='word_1_96' title='bbox 361 703 446 720; x_wconf 81'><strong>consular</strong></span> <span class='ocrx_word' id='word_1_97' title='bbox 453 703 516 720; x_wconf 77'><strong>courts</strong></span> <span class='ocrx_word' id='word_1_98' title='bbox 524 703 546 720; x_wconf 76'><strong>of</strong></span> <span class='ocrx_word' id='word_1_99' title='bbox 552 704 583 720; x_wconf 70'><strong>the</strong></span> <span class='ocrx_word' id='word_1_100' title='bbox 591 703 661 720; x_wconf 77'><strong>United</strong></span> <span class='ocrx_word' id='word_1_101' title='bbox 669 703 732 720; x_wconf 67'><strong>States</strong></span> <span class='ocrx_word' id='word_1_102' title='bbox 740 702 759 719; x_wconf 82'><strong>in</strong></span> <span class='ocrx_word' id='word_1_103' title='bbox 768 703 781 719; x_wconf 88'><strong>J</strong></span> <span class='ocrx_word' id='word_1_104' title='bbox 782 707 835 724; x_wconf 69'><strong>epan.</strong></span>
<span class='ocr_line' id='line_1_14' title="bbox 122 702 835 724; baseline 0.001 -5; x_size 21; x_descenders 4; x_ascenders 5">
<span class='ocrx_word' id='word_1_92' title='bbox 122 703 155 723; x_wconf 96'><strong><em>ing</em></strong></span>
<span class='ocrx_word' id='word_1_93' title='bbox 163 702 277 723; x_wconf 96'><strong><em>regulations</em></strong></span>
<span class='ocrx_word' id='word_1_94' title='bbox 285 702 314 719; x_wconf 96'><strong><em>for</em></strong></span>
<span class='ocrx_word' id='word_1_95' title='bbox 321 703 354 720; x_wconf 96'><strong><em>the</em></strong></span>
<span class='ocrx_word' id='word_1_96' title='bbox 361 703 446 720; x_wconf 96'><strong><em>consular</em></strong></span>
<span class='ocrx_word' id='word_1_97' title='bbox 453 703 516 720; x_wconf 95'><strong><em>courts</em></strong></span>
<span class='ocrx_word' id='word_1_98' title='bbox 524 703 546 720; x_wconf 96'><strong><em>of</em></strong></span>
<span class='ocrx_word' id='word_1_99' title='bbox 552 704 583 720; x_wconf 96'><strong><em>the</em></strong></span>
<span class='ocrx_word' id='word_1_100' title='bbox 591 703 661 720; x_wconf 96'><strong><em>United</em></strong></span>
<span class='ocrx_word' id='word_1_101' title='bbox 669 703 732 720; x_wconf 96'><strong><em>States</em></strong></span>
<span class='ocrx_word' id='word_1_102' title='bbox 740 702 759 719; x_wconf 96'><strong><em>in</em></strong></span>
<span class='ocrx_word' id='word_1_103' title='bbox 768 703 835 724; x_wconf 90'><strong><em>Japan.</em></strong></span>
</span>
</p>
<p class='ocr_par' id='par_1_10' lang='eng' title="bbox 682 724 835 743">
<span class='ocr_line' id='line_1_15' title="bbox 682 724 835 743; baseline 0 -1; x_size 23.573172; x_descenders 5.5365853; x_ascenders 5.5"><span class='ocrx_word' id='word_1_105' title='bbox 682 725 705 743; x_wconf 87'><strong>U.</strong></span> <span class='ocrx_word' id='word_1_106' title='bbox 715 724 734 743; x_wconf 84'><strong>S.</strong></span> <span class='ocrx_word' id='word_1_107' title='bbox 743 725 814 742; x_wconf 67'><strong>GRAN</strong></span> <span class='ocrx_word' id='word_1_108' title='bbox 815 725 835 743; x_wconf 84'><strong>1.</strong></span>
<span class='ocr_line' id='line_1_15' title="bbox 682 724 835 743; baseline 0 -1; x_size 23.573172; x_descenders 5.5365853; x_ascenders 5.5">
<span class='ocrx_word' id='word_1_104' title='bbox 682 725 705 743; x_wconf 85'><strong><em>U.</em></strong></span>
<span class='ocrx_word' id='word_1_105' title='bbox 715 724 734 743; x_wconf 89'><strong><em>8.</em></strong></span>
<span class='ocrx_word' id='word_1_106' title='bbox 743 725 835 743; x_wconf 83'><strong><em>GRANT.</em></strong></span>
</span>
</p>
<p class='ocr_par' id='par_1_11' lang='eng' title="bbox 144 746 482 770">
<span class='ocr_line' id='line_1_16' title="bbox 144 746 482 770; baseline 0 -6; x_size 24; x_descenders 6; x_ascenders 5"><span class='ocrx_word' id='word_1_109' title='bbox 144 746 293 769; x_wconf 68'><strong>WASHINGTON,</strong></span> <span class='ocrx_word' id='word_1_110' title='bbox 302 746 385 768; x_wconf 76'><strong><em>January</em></strong></span> <span class='ocrx_word' id='word_1_111' title='bbox 393 748 422 770; x_wconf 85'><strong>27,</strong></span> <span class='ocrx_word' id='word_1_112' title='bbox 431 747 482 764; x_wconf 86'>1871.</span>
<span class='ocr_line' id='line_1_16' title="bbox 144 746 482 770; baseline 0 -6; x_size 24; x_descenders 6; x_ascenders 5">
<span class='ocrx_word' id='word_1_107' title='bbox 144 746 293 769; x_wconf 78'><strong><em>WASHINGTON,</em></strong></span>
<span class='ocrx_word' id='word_1_108' title='bbox 302 746 385 768; x_wconf 96'><strong><em>January</em></strong></span>
<span class='ocrx_word' id='word_1_109' title='bbox 393 748 422 770; x_wconf 92'><strong><em>27,</em></strong></span>
<span class='ocrx_word' id='word_1_110' title='bbox 431 747 482 764; x_wconf 92'><strong><em>1871.</em></strong></span>
</span>
</p>
</div>
<div class='ocr_carea' id='block_1_9' title="bbox 120 846 865 1225">
<p class='ocr_par' id='par_1_12' lang='eng' title="bbox 443 846 834 891">
<span class='ocr_line' id='line_1_17' title="bbox 443 846 710 869; baseline 0.004 -7; x_size 23; x_descenders 6; x_ascenders 4"><span class='ocrx_word' id='word_1_113' title='bbox 443 846 586 863; x_wconf 75'><strong>DEPARTMENT</strong></span> <span class='ocrx_word' id='word_1_114' title='bbox 599 849 624 863; x_wconf 79'><strong>OF</strong></span> <span class='ocrx_word' id='word_1_115' title='bbox 636 846 710 869; x_wconf 74'><strong>STATE,</strong></span>
<span class='ocr_line' id='line_1_17' title="bbox 443 846 710 869; baseline 0.004 -7; x_size 23; x_descenders 6; x_ascenders 4">
<span class='ocrx_word' id='word_1_111' title='bbox 443 846 586 863; x_wconf 95'><strong><em>DEPARTMENT</em></strong></span>
<span class='ocrx_word' id='word_1_112' title='bbox 599 849 624 863; x_wconf 96'><strong><em>OF</em></strong></span>
<span class='ocrx_word' id='word_1_113' title='bbox 636 846 710 869; x_wconf 95'><strong><em>STATE,</em></strong></span>
</span>
<span class='ocr_line' id='line_1_18' title="bbox 529 868 834 891; baseline 0 -5; x_size 23.255997; x_descenders 5.2559972; x_ascenders 6"><span class='ocrx_word' id='word_1_116' title='bbox 529 868 649 891; x_wconf 62'><strong>Waahinyton,</strong></span> <span class='ocrx_word' id='word_1_117' title='bbox 657 868 740 889; x_wconf 74'><strong><em>Ja/nuary</em></strong></span> <span class='ocrx_word' id='word_1_118' title='bbox 748 868 775 891; x_wconf 79'><strong>26,</strong></span> <span class='ocrx_word' id='word_1_119' title='bbox 784 868 834 886; x_wconf 87'><strong>1870.</strong></span>
<span class='ocr_line' id='line_1_18' title="bbox 529 868 834 891; baseline 0 -5; x_size 23.255997; x_descenders 5.2559972; x_ascenders 6">
<span class='ocrx_word' id='word_1_114' title='bbox 529 868 649 891; x_wconf 95'><strong><em>Washington,</em></strong></span>
<span class='ocrx_word' id='word_1_115' title='bbox 657 868 740 889; x_wconf 96'><strong><em>January</em></strong></span>
<span class='ocrx_word' id='word_1_116' title='bbox 748 868 775 891; x_wconf 94'><strong><em>26,</em></strong></span>
<span class='ocrx_word' id='word_1_117' title='bbox 784 868 834 886; x_wconf 85'><strong><em>1870,</em></strong></span>
</span>
</p>
<p class='ocr_par' id='par_1_13' lang='eng' title="bbox 121 894 865 1051">
<span class='ocr_line' id='line_1_19' title="bbox 146 894 857 917; baseline 0 -5; x_size 22; x_descenders 5; x_ascenders 5"><span class='ocrx_word' id='word_1_120' title='bbox 146 895 184 912; x_wconf 79'><strong>The</strong></span> <span class='ocrx_word' id='word_1_121' title='bbox 193 895 290 917; x_wconf 69'><strong>Secretary</strong></span> <span class='ocrx_word' id='word_1_122' title='bbox 297 895 319 912; x_wconf 79'><strong>of</strong></span> <span class='ocrx_word' id='word_1_123' title='bbox 328 895 381 913; x_wconf 77'><strong>State</strong></span> <span class='ocrx_word' id='word_1_124' title='bbox 389 896 422 913; x_wconf 69'><strong>has</strong></span> <span class='ocrx_word' id='word_1_125' title='bbox 430 894 462 912; x_wconf 79'><strong>the</strong></span> <span class='ocrx_word' id='word_1_126' title='bbox 469 895 528 912; x_wconf 78'><strong>honor</strong></span> <span class='ocrx_word' id='word_1_127' title='bbox 535 897 555 912; x_wconf 80'><strong>1:0</strong></span> <span class='ocrx_word' id='word_1_128' title='bbox 564 895 633 912; x_wconf 77'><strong>submit</strong></span> <span class='ocrx_word' id='word_1_129' title='bbox 640 895 730 913; x_wconf 75'><strong>herewith</strong></span> <span class='ocrx_word' id='word_1_130' title='bbox 739 895 768 912; x_wconf 78'><strong>for</strong></span> <span class='ocrx_word' id='word_1_131' title='bbox 776 895 857 912; x_wconf 76'><strong>revision</strong></span>
<span class='ocr_line' id='line_1_19' title="bbox 146 894 857 917; baseline 0 -5; x_size 22; x_descenders 5; x_ascenders 5">
<span class='ocrx_word' id='word_1_118' title='bbox 146 895 184 912; x_wconf 96'><strong><em>The</em></strong></span>
<span class='ocrx_word' id='word_1_119' title='bbox 193 895 290 917; x_wconf 96'><strong><em>Secretary</em></strong></span>
<span class='ocrx_word' id='word_1_120' title='bbox 297 895 319 912; x_wconf 96'><strong><em>of</em></strong></span>
<span class='ocrx_word' id='word_1_121' title='bbox 328 895 381 913; x_wconf 96'><strong><em>State</em></strong></span>
<span class='ocrx_word' id='word_1_122' title='bbox 389 896 422 913; x_wconf 96'><strong><em>has</em></strong></span>
<span class='ocrx_word' id='word_1_123' title='bbox 430 894 462 912; x_wconf 96'><strong><em>the</em></strong></span>
<span class='ocrx_word' id='word_1_124' title='bbox 469 895 528 912; x_wconf 96'><strong><em>honor</em></strong></span>
<span class='ocrx_word' id='word_1_125' title='bbox 535 897 555 912; x_wconf 96'><strong><em>to</em></strong></span>
<span class='ocrx_word' id='word_1_126' title='bbox 564 895 633 912; x_wconf 96'><strong><em>submit</em></strong></span>
<span class='ocrx_word' id='word_1_127' title='bbox 640 895 730 913; x_wconf 90'><strong><em>herewith,</em></strong></span>
<span class='ocrx_word' id='word_1_128' title='bbox 739 895 768 912; x_wconf 90'><strong><em>for</em></strong></span>
<span class='ocrx_word' id='word_1_129' title='bbox 776 895 857 912; x_wconf 95'><strong><em>revision</em></strong></span>
</span>
<span class='ocr_line' id='line_1_20' title="bbox 122 907 857 940; baseline 0 -5; x_size 23; x_descenders 5; x_ascenders 6"><span class='ocrx_word' id='word_1_132' title='bbox 122 918 148 939; x_wconf 83'><strong>by</strong></span> <span class='ocrx_word' id='word_1_133' title='bbox 160 917 258 940; x_wconf 74'><strong>Congress,</strong></span> <span class='ocrx_word' id='word_1_134' title='bbox 266 918 285 935; x_wconf 85'><strong>in</strong></span> <span class='ocrx_word' id='word_1_135' title='bbox 294 918 403 939; x_wconf 76'><strong>conformity</strong></span> <span class='ocrx_word' id='word_1_136' title='bbox 412 917 456 935; x_wconf 74'><strong>with</strong></span> <span class='ocrx_word' id='word_1_137' title='bbox 464 917 496 934; x_wconf 79'><strong>the</strong></span> <span class='ocrx_word' id='word_1_138' title='bbox 505 918 607 939; x_wconf 77'>provisions</span> <span class='ocrx_word' id='word_1_139' title='bbox 615 917 636 934; x_wconf 79'><strong>of</strong></span> <span class='ocrx_word' id='word_1_140' title='bbox 646 918 715 935; x_wconf 81'><strong>section</strong></span> <span class='ocrx_word' id='word_1_141' title='bbox 724 907 736 934; x_wconf 47'><strong>(5</strong></span> <span class='ocrx_word' id='word_1_142' title='bbox 749 917 770 934; x_wconf 81'><strong>of</strong></span> <span class='ocrx_word' id='word_1_143' title='bbox 779 918 812 935; x_wconf 69'><strong>the</strong></span> <span class='ocrx_word' id='word_1_144' title='bbox 826 919 857 935; x_wconf 68'><strong>act.</strong></span>
<span class='ocr_line' id='line_1_20' title="bbox 122 907 857 940; baseline 0 -5; x_size 23; x_descenders 5; x_ascenders 6">
<span class='ocrx_word' id='word_1_130' title='bbox 122 918 148 939; x_wconf 95'><strong><em>by</em></strong></span>
<span class='ocrx_word' id='word_1_131' title='bbox 160 917 258 940; x_wconf 96'><strong><em>Congress,</em></strong></span>
<span class='ocrx_word' id='word_1_132' title='bbox 266 918 285 935; x_wconf 96'><strong><em>in</em></strong></span>
<span class='ocrx_word' id='word_1_133' title='bbox 294 918 403 939; x_wconf 96'><strong><em>conformity</em></strong></span>
<span class='ocrx_word' id='word_1_134' title='bbox 412 917 456 935; x_wconf 96'><strong><em>with</em></strong></span>
<span class='ocrx_word' id='word_1_135' title='bbox 464 917 496 934; x_wconf 97'><strong><em>the</em></strong></span>
<span class='ocrx_word' id='word_1_136' title='bbox 505 918 607 939; x_wconf 96'><strong><em>provisions</em></strong></span>
<span class='ocrx_word' id='word_1_137' title='bbox 615 917 636 934; x_wconf 96'><strong><em>of</em></strong></span>
<span class='ocrx_word' id='word_1_138' title='bbox 646 918 715 935; x_wconf 97'><strong><em>section</em></strong></span>
<span class='ocrx_word' id='word_1_139' title='bbox 724 907 736 934; x_wconf 92'><strong><em>6</em></strong></span>
<span class='ocrx_word' id='word_1_140' title='bbox 749 917 770 934; x_wconf 94'><strong><em>of</em></strong></span>
<span class='ocrx_word' id='word_1_141' title='bbox 779 918 812 935; x_wconf 94'><strong><em>the</em></strong></span>
<span class='ocrx_word' id='word_1_142' title='bbox 826 919 857 935; x_wconf 96'><strong><em>act</em></strong></span>
</span>
<span class='ocr_line' id='line_1_21' title="bbox 121 939 857 962; baseline -0.001 -5; x_size 21; x_descenders 4; x_ascenders 5"><span class='ocrx_word' id='word_1_145' title='bbox 121 940 217 961; x_wconf 79'><strong>approved</strong></span> <span class='ocrx_word' id='word_1_146' title='bbox 229 940 265 957; x_wconf 85'><strong>22d</strong></span> <span class='ocrx_word' id='word_1_147' title='bbox 278 939 299 957; x_wconf 82'><strong>of</strong></span> <span class='ocrx_word' id='word_1_148' title='bbox 313 940 368 962; x_wconf 83'><strong>June,</strong></span> <span class='ocrx_word' id='word_1_149' title='bbox 383 940 432 962; x_wconf 81'><strong>1860,</strong></span> <span class='ocrx_word' id='word_1_150' title='bbox 441 944 453 956; x_wconf 78'><strong>a.</strong></span> <span class='ocrx_word' id='word_1_151' title='bbox 466 944 513 961; x_wconf 78'><strong>copy</strong></span> <span class='ocrx_word' id='word_1_152' title='bbox 525 940 546 957; x_wconf 82'><strong>of</strong></span> <span class='ocrx_word' id='word_1_153' title='bbox 555 940 686 961; x_wconf 74'><strong>“regulations</strong></span> <span class='ocrx_word' id='word_1_154' title='bbox 693 940 722 957; x_wconf 77'><strong>for</strong></span> <span class='ocrx_word' id='word_1_155' title='bbox 730 940 762 956; x_wconf 75'><strong>the</strong></span> <span class='ocrx_word' id='word_1_156' title='bbox 770 940 857 957; x_wconf 75'><strong>consular</strong></span>
<span class='ocr_line' id='line_1_21' title="bbox 121 939 857 962; baseline -0.001 -5; x_size 21; x_descenders 4; x_ascenders 5">
<span class='ocrx_word' id='word_1_143' title='bbox 121 940 217 961; x_wconf 96'><strong><em>approved</em></strong></span>
<span class='ocrx_word' id='word_1_144' title='bbox 229 940 265 957; x_wconf 95'><strong><em>22d</em></strong></span>
<span class='ocrx_word' id='word_1_145' title='bbox 278 939 299 957; x_wconf 96'><strong><em>of</em></strong></span>
<span class='ocrx_word' id='word_1_146' title='bbox 313 940 368 962; x_wconf 96'><strong><em>June,</em></strong></span>
<span class='ocrx_word' id='word_1_147' title='bbox 383 940 432 962; x_wconf 57'><strong><em>1860,</em></strong></span>
<span class='ocrx_word' id='word_1_148' title='bbox 441 944 453 956; x_wconf 57'><strong><em>a</em></strong></span>
<span class='ocrx_word' id='word_1_149' title='bbox 466 944 513 961; x_wconf 96'><strong><em>copy</em></strong></span>
<span class='ocrx_word' id='word_1_150' title='bbox 525 940 546 957; x_wconf 96'><strong><em>of</em></strong></span>
<span class='ocrx_word' id='word_1_151' title='bbox 555 940 686 961; x_wconf 82'><strong><em>“regulations</em></strong></span>
<span class='ocrx_word' id='word_1_152' title='bbox 693 940 722 957; x_wconf 95'><strong><em>for</em></strong></span>
<span class='ocrx_word' id='word_1_153' title='bbox 730 940 762 956; x_wconf 97'><strong><em>the</em></strong></span>
<span class='ocrx_word' id='word_1_154' title='bbox 770 940 857 957; x_wconf 95'><strong><em>consular</em></strong></span>
</span>
<span class='ocr_line' id='line_1_22' title="bbox 121 962 857 983; baseline -0.001 -3; x_size 21; x_descenders 4; x_ascenders 5"><span class='ocrx_word' id='word_1_157' title='bbox 121 963 184 980; x_wconf 77'><strong>courts</strong></span> <span class='ocrx_word' id='word_1_158' title='bbox 198 962 219 979; x_wconf 86'><strong>of</strong></span> <span class='ocrx_word' id='word_1_159' title='bbox 228 963 261 979; x_wconf 82'><strong>the</strong></span> <span class='ocrx_word' id='word_1_160' title='bbox 272 962 342 980; x_wconf 80'><strong>United</strong></span> <span class='ocrx_word' id='word_1_161' title='bbox 356 962 419 980; x_wconf 69'><strong>States</strong></span> <span class='ocrx_word' id='word_1_162' title='bbox 430 962 450 979; x_wconf 82'><strong>in</strong></span> <span class='ocrx_word' id='word_1_163' title='bbox 465 962 544 983; x_wconf 74'><strong>Japan,”</strong></span> <span class='ocrx_word' id='word_1_164' title='bbox 556 962 633 979; x_wconf 77'><strong>decreed</strong></span> <span class='ocrx_word' id='word_1_165' title='bbox 645 963 683 979; x_wconf 79'><strong>and</strong></span> <span class='ocrx_word' id='word_1_166' title='bbox 695 962 759 980; x_wconf 76'><strong>issued</strong></span> <span class='ocrx_word' id='word_1_167' title='bbox 772 962 797 983; x_wconf 77'><strong>by</strong></span> <span class='ocrx_word' id='word_1_168' title='bbox 806 962 826 979; x_wconf 83'><strong>C.</strong></span> <span class='ocrx_word' id='word_1_169' title='bbox 835 962 857 979; x_wconf 76'><strong>E.</strong></span>
<span class='ocr_line' id='line_1_22' title="bbox 121 962 857 983; baseline -0.001 -3; x_size 21; x_descenders 4; x_ascenders 5">
<span class='ocrx_word' id='word_1_155' title='bbox 121 963 184 980; x_wconf 96'><strong><em>courts</em></strong></span>
<span class='ocrx_word' id='word_1_156' title='bbox 198 962 219 979; x_wconf 96'><strong><em>of</em></strong></span>
<span class='ocrx_word' id='word_1_157' title='bbox 228 963 261 979; x_wconf 96'><strong><em>the</em></strong></span>
<span class='ocrx_word' id='word_1_158' title='bbox 272 962 342 980; x_wconf 96'><strong><em>United</em></strong></span>
<span class='ocrx_word' id='word_1_159' title='bbox 356 962 419 980; x_wconf 96'><strong><em>States</em></strong></span>
<span class='ocrx_word' id='word_1_160' title='bbox 430 962 450 979; x_wconf 95'><strong><em>in</em></strong></span>
<span class='ocrx_word' id='word_1_161' title='bbox 465 962 544 983; x_wconf 95'><strong><em>Japan,”</em></strong></span>
<span class='ocrx_word' id='word_1_162' title='bbox 556 962 633 979; x_wconf 96'><strong><em>decreed</em></strong></span>
<span class='ocrx_word' id='word_1_163' title='bbox 645 963 683 979; x_wconf 96'><strong><em>and</em></strong></span>
<span class='ocrx_word' id='word_1_164' title='bbox 695 962 759 980; x_wconf 93'><strong><em>issued</em></strong></span>
<span class='ocrx_word' id='word_1_165' title='bbox 772 962 797 983; x_wconf 92'><strong><em>by</em></strong></span>
<span class='ocrx_word' id='word_1_166' title='bbox 806 962 826 979; x_wconf 81'><strong><em>C.</em></strong></span>
<span class='ocrx_word' id='word_1_167' title='bbox 835 962 857 979; x_wconf 47'><strong><em>BE.</em></strong></span>
</span>
<span class='ocr_line' id='line_1_23' title="bbox 122 984 858 1007; baseline 0 -6; x_size 22; x_descenders 5; x_ascenders 5"><span class='ocrx_word' id='word_1_170' title='bbox 122 985 152 1001; x_wconf 84'><strong>De</strong></span> <span class='ocrx_word' id='word_1_171' title='bbox 158 984 217 1007; x_wconf 77'><strong>Long,</strong></span> <span class='ocrx_word' id='word_1_172' title='bbox 226 985 258 1002; x_wconf 74'><strong>the</strong></span> <span class='ocrx_word' id='word_1_173' title='bbox 266 985 350 1002; x_wconf 75'><strong>minister</strong></span> <span class='ocrx_word' id='word_1_174' title='bbox 361 985 383 1002; x_wconf 84'><strong>of</strong></span> <span class='ocrx_word' id='word_1_175' title='bbox 391 985 423 1002; x_wconf 80'><strong>the</strong></span> <span class='ocrx_word' id='word_1_176' title='bbox 431 984 501 1001; x_wconf 78'><strong>United</strong></span> <span class='ocrx_word' id='word_1_177' title='bbox 509 985 572 1002; x_wconf 71'><strong>States</strong></span> <span class='ocrx_word' id='word_1_178' title='bbox 579 984 597 1001; x_wconf 88'><strong>in</strong></span> <span class='ocrx_word' id='word_1_179' title='bbox 606 984 648 1002; x_wconf 71'><strong>that</strong></span> <span class='ocrx_word' id='word_1_180' title='bbox 656 986 740 1006; x_wconf 80'><strong>country,</strong></span> <span class='ocrx_word' id='word_1_181' title='bbox 749 984 768 1001; x_wconf 81'><strong>in</strong></span> <span class='ocrx_word' id='word_1_182' title='bbox 777 984 858 1005; x_wconf 81'><strong>Septem-</strong></span>
<span class='ocr_line' id='line_1_23' title="bbox 122 984 858 1007; baseline 0 -6; x_size 22; x_descenders 5; x_ascenders 5">
<span class='ocrx_word' id='word_1_168' title='bbox 122 985 152 1001; x_wconf 96'><strong><em>De</em></strong></span>
<span class='ocrx_word' id='word_1_169' title='bbox 158 984 217 1007; x_wconf 96'><strong><em>Long,</em></strong></span>
<span class='ocrx_word' id='word_1_170' title='bbox 226 985 258 1002; x_wconf 96'><strong><em>the</em></strong></span>
<span class='ocrx_word' id='word_1_171' title='bbox 266 985 350 1002; x_wconf 96'><strong><em>minister</em></strong></span>
<span class='ocrx_word' id='word_1_172' title='bbox 361 985 383 1002; x_wconf 96'><strong><em>of</em></strong></span>
<span class='ocrx_word' id='word_1_173' title='bbox 391 985 423 1002; x_wconf 96'><strong><em>the</em></strong></span>
<span class='ocrx_word' id='word_1_174' title='bbox 431 984 501 1001; x_wconf 97'><strong><em>United</em></strong></span>
<span class='ocrx_word' id='word_1_175' title='bbox 509 985 572 1002; x_wconf 96'><strong><em>States</em></strong></span>
<span class='ocrx_word' id='word_1_176' title='bbox 579 984 597 1001; x_wconf 96'><strong><em>in</em></strong></span>
<span class='ocrx_word' id='word_1_177' title='bbox 606 984 648 1002; x_wconf 96'><strong><em>that</em></strong></span>
<span class='ocrx_word' id='word_1_178' title='bbox 656 986 740 1006; x_wconf 96'><strong><em>country,</em></strong></span>
<span class='ocrx_word' id='word_1_179' title='bbox 749 984 768 1001; x_wconf 92'><strong><em>in</em></strong></span>
<span class='ocrx_word' id='word_1_180' title='bbox 777 984 858 1005; x_wconf 91'><strong><em>Septem-</em></strong></span>
</span>
<span class='ocr_line' id='line_1_24' title="bbox 121 1006 865 1034; baseline 0 -11; x_size 22; x_descenders 5; x_ascenders 5"><span class='ocrx_word' id='word_1_183' title='bbox 121 1007 160 1028; x_wconf 80'><strong>ber,</strong></span> <span class='ocrx_word' id='word_1_184' title='bbox 169 1007 223 1029; x_wconf 76'><strong>1870;</strong></span> <span class='ocrx_word' id='word_1_185' title='bbox 236 1008 273 1024; x_wconf 71'><strong>and</strong></span> <span class='ocrx_word' id='word_1_186' title='bbox 287 1007 326 1024; x_wconf 70'><strong>also</strong></span> <span class='ocrx_word' id='word_1_187' title='bbox 339 1007 371 1024; x_wconf 78'><strong>the</strong></span> <span class='ocrx_word' id='word_1_188' title='bbox 383 1011 450 1029; x_wconf 79'><strong>papers</strong></span> <span class='ocrx_word' id='word_1_189' title='bbox 461 1007 568 1024; x_wconf 77'><strong>mentioned</strong></span> <span class='ocrx_word' id='word_1_190' title='bbox 576 1006 595 1023; x_wconf 83'><strong>in</strong></span> <span class='ocrx_word' id='word_1_191' title='bbox 604 1007 635 1024; x_wconf 77'><strong>the</strong></span> <span class='ocrx_word' id='word_1_192' title='bbox 643 1007 741 1029; x_wconf 74'><strong>subjoiued</strong></span> <span class='ocrx_word' id='word_1_193' title='bbox 748 1006 786 1028; x_wconf 79'><strong>list,</strong></span> <span class='ocrx_word' id='word_1_194' title='bbox 794 1007 865 1034; x_wconf 52'><strong>which.</strong></span>
<span class='ocr_line' id='line_1_24' title="bbox 121 1006 865 1034; baseline 0 -11; x_size 22; x_descenders 5; x_ascenders 5">
<span class='ocrx_word' id='word_1_181' title='bbox 121 1007 160 1028; x_wconf 91'><strong><em>ber,</em></strong></span>
<span class='ocrx_word' id='word_1_182' title='bbox 169 1007 223 1029; x_wconf 95'><strong><em>1870;</em></strong></span>
<span class='ocrx_word' id='word_1_183' title='bbox 236 1008 273 1024; x_wconf 84'><strong><em>and</em></strong></span>
<span class='ocrx_word' id='word_1_184' title='bbox 287 1007 326 1024; x_wconf 95'><strong><em>also</em></strong></span>
<span class='ocrx_word' id='word_1_185' title='bbox 339 1007 371 1024; x_wconf 96'><strong><em>the</em></strong></span>
<span class='ocrx_word' id='word_1_186' title='bbox 383 1011 450 1029; x_wconf 96'><strong><em>papers</em></strong></span>
<span class='ocrx_word' id='word_1_187' title='bbox 461 1007 568 1024; x_wconf 96'><strong><em>mentioned</em></strong></span>
<span class='ocrx_word' id='word_1_188' title='bbox 576 1006 595 1023; x_wconf 96'><strong><em>in</em></strong></span>
<span class='ocrx_word' id='word_1_189' title='bbox 604 1007 635 1024; x_wconf 93'><strong><em>the</em></strong></span>
<span class='ocrx_word' id='word_1_190' title='bbox 643 1007 727 1029; x_wconf 92'><strong><em>subjoined</em></strong></span>
<span class='ocrx_word' id='word_1_191' title='bbox 728 1006 786 1028; x_wconf 96'><strong><em>list,</em></strong></span>
<span class='ocrx_word' id='word_1_192' title='bbox 794 1007 865 1034; x_wconf 86'><strong><em>which,</em></strong></span>
</span>
<span class='ocr_line' id='line_1_25' title="bbox 122 1029 557 1051; baseline 0 -5; x_size 22; x_descenders 5; x_ascenders 5"><span class='ocrx_word' id='word_1_195' title='bbox 122 1029 197 1046; x_wconf 74'><strong>contain</strong></span> <span class='ocrx_word' id='word_1_196' title='bbox 205 1029 324 1051; x_wconf 72'><strong>suggestions</strong></span> <span class='ocrx_word' id='word_1_197' title='bbox 332 1034 355 1046; x_wconf 87'><strong>on</strong></span> <span class='ocrx_word' id='word_1_198' title='bbox 363 1029 394 1046; x_wconf 72'><strong>the</strong></span> <span class='ocrx_word' id='word_1_199' title='bbox 402 1029 473 1050; x_wconf 75'><strong>subject</strong></span> <span class='ocrx_word' id='word_1_200' title='bbox 480 1029 557 1046; x_wconf 79'><strong>thereof.</strong></span>
<span class='ocr_line' id='line_1_25' title="bbox 122 1029 557 1051; baseline 0 -5; x_size 22; x_descenders 5; x_ascenders 5">
<span class='ocrx_word' id='word_1_193' title='bbox 122 1029 197 1046; x_wconf 96'><strong><em>contain</em></strong></span>
<span class='ocrx_word' id='word_1_194' title='bbox 205 1029 324 1051; x_wconf 96'><strong><em>suggestions</em></strong></span>
<span class='ocrx_word' id='word_1_195' title='bbox 332 1034 355 1046; x_wconf 96'><strong><em>on</em></strong></span>
<span class='ocrx_word' id='word_1_196' title='bbox 363 1029 394 1046; x_wconf 96'><strong><em>the</em></strong></span>
<span class='ocrx_word' id='word_1_197' title='bbox 402 1029 473 1050; x_wconf 93'><strong><em>subject</em></strong></span>
<span class='ocrx_word' id='word_1_198' title='bbox 480 1029 557 1046; x_wconf 85'><strong><em>thereof.</em></strong></span>
</span>
</p>
<p class='ocr_par' id='par_1_14' lang='eng' title="bbox 120 1051 857 1185">
<span class='ocr_line' id='line_1_26' title="bbox 144 1051 855 1074; baseline -0.001 -6; x_size 21; x_descenders 4; x_ascenders 5"><span class='ocrx_word' id='word_1_201' title='bbox 144 1052 164 1067; x_wconf 74'><strong>A</strong></span> <span class='ocrx_word' id='word_1_202' title='bbox 171 1056 218 1073; x_wconf 84'><strong>copy</strong></span> <span class='ocrx_word' id='word_1_203' title='bbox 226 1052 247 1068; x_wconf 80'><strong>of</strong></span> <span class='ocrx_word' id='word_1_204' title='bbox 253 1051 325 1068; x_wconf 73'><strong>Article</strong></span> <span class='ocrx_word' id='word_1_205' title='bbox 332 1051 399 1068; x_wconf 78'><strong>XXVI</strong></span> <span class='ocrx_word' id='word_1_206' title='bbox 407 1052 427 1069; x_wconf 84'><strong>of</strong></span> <span class='ocrx_word' id='word_1_207' title='bbox 433 1051 464 1068; x_wconf 85'><strong>the</strong></span> <span class='ocrx_word' id='word_1_208' title='bbox 472 1052 558 1068; x_wconf 79'><strong>consular</strong></span> <span class='ocrx_word' id='word_1_209' title='bbox 562 1051 676 1072; x_wconf 78'><strong>regulations</strong></span> <span class='ocrx_word' id='word_1_210' title='bbox 682 1052 698 1068; x_wconf 79'><strong>is</strong></span> <span class='ocrx_word' id='word_1_211' title='bbox 703 1052 742 1068; x_wconf 75'><strong>also</strong></span> <span class='ocrx_word' id='word_1_212' title='bbox 749 1051 855 1074; x_wconf 73'><strong>submitted,</strong></span>
<span class='ocr_line' id='line_1_26' title="bbox 144 1051 855 1074; baseline -0.001 -6; x_size 21; x_descenders 4; x_ascenders 5">
<span class='ocrx_word' id='word_1_199' title='bbox 144 1052 164 1067; x_wconf 95'><strong><em>A</em></strong></span>
<span class='ocrx_word' id='word_1_200' title='bbox 171 1056 218 1073; x_wconf 95'><strong><em>copy</em></strong></span>
<span class='ocrx_word' id='word_1_201' title='bbox 226 1052 247 1068; x_wconf 96'><strong><em>of</em></strong></span>
<span class='ocrx_word' id='word_1_202' title='bbox 253 1051 325 1068; x_wconf 93'><strong><em>Article</em></strong></span>
<span class='ocrx_word' id='word_1_203' title='bbox 332 1051 389 1068; x_wconf 86'><strong><em>XXVI</em></strong></span>
<span class='ocrx_word' id='word_1_204' title='bbox 389 1052 427 1069; x_wconf 96'><strong><em>of</em></strong></span>
<span class='ocrx_word' id='word_1_205' title='bbox 433 1051 464 1068; x_wconf 95'><strong><em>the</em></strong></span>
<span class='ocrx_word' id='word_1_206' title='bbox 472 1052 558 1068; x_wconf 95'><strong><em>consular</em></strong></span>
<span class='ocrx_word' id='word_1_207' title='bbox 562 1051 676 1072; x_wconf 95'><strong><em>regulations</em></strong></span>
<span class='ocrx_word' id='word_1_208' title='bbox 682 1052 698 1068; x_wconf 96'><strong><em>is</em></strong></span>
<span class='ocrx_word' id='word_1_209' title='bbox 703 1052 742 1068; x_wconf 94'><strong><em>also</em></strong></span>
<span class='ocrx_word' id='word_1_210' title='bbox 749 1051 855 1074; x_wconf 95'><strong><em>submitted,</em></strong></span>
</span>
<span class='ocr_line' id='line_1_27' title="bbox 121 1072 856 1096; baseline 0 -5; x_size 22; x_descenders 5; x_ascenders 5"><span class='ocrx_word' id='word_1_213' title='bbox 121 1073 158 1091; x_wconf 64'><strong>and</strong></span> <span class='ocrx_word' id='word_1_214' title='bbox 171 1073 204 1090; x_wconf 72'><strong>the</strong></span> <span class='ocrx_word' id='word_1_215' title='bbox 218 1074 315 1095; x_wconf 76'><strong>Secretary</strong></span> <span class='ocrx_word' id='word_1_216' title='bbox 321 1074 342 1090; x_wconf 77'><strong>of</strong></span> <span class='ocrx_word' id='word_1_217' title='bbox 351 1074 404 1091; x_wconf 77'><strong>State</strong></span> <span class='ocrx_word' id='word_1_218' title='bbox 415 1073 534 1095; x_wconf 77'><strong>respectfully</strong></span> <span class='ocrx_word' id='word_1_219' title='bbox 542 1074 634 1096; x_wconf 75'><strong>suggests,</strong></span> <span class='ocrx_word' id='word_1_220' title='bbox 643 1074 672 1090; x_wconf 84'><strong>fur</strong></span> <span class='ocrx_word' id='word_1_221' title='bbox 679 1074 712 1091; x_wconf 87'><strong>the</strong></span> <span class='ocrx_word' id='word_1_222' title='bbox 720 1072 856 1091; x_wconf 71'><strong>consideration</strong></span>
<span class='ocr_line' id='line_1_27' title="bbox 121 1072 856 1096; baseline 0 -5; x_size 22; x_descenders 5; x_ascenders 5">
<span class='ocrx_word' id='word_1_211' title='bbox 121 1073 158 1091; x_wconf 95'><strong><em>and</em></strong></span>
<span class='ocrx_word' id='word_1_212' title='bbox 171 1073 204 1090; x_wconf 95'><strong><em>the</em></strong></span>
<span class='ocrx_word' id='word_1_213' title='bbox 218 1074 315 1095; x_wconf 96'><strong><em>Secretary</em></strong></span>
<span class='ocrx_word' id='word_1_214' title='bbox 321 1074 342 1090; x_wconf 96'><strong><em>of</em></strong></span>
<span class='ocrx_word' id='word_1_215' title='bbox 351 1074 404 1091; x_wconf 96'><strong><em>State</em></strong></span>
<span class='ocrx_word' id='word_1_216' title='bbox 415 1073 534 1095; x_wconf 96'><strong><em>respectfully</em></strong></span>
<span class='ocrx_word' id='word_1_217' title='bbox 542 1074 634 1096; x_wconf 96'><strong><em>suggests,</em></strong></span>
<span class='ocrx_word' id='word_1_218' title='bbox 643 1074 672 1090; x_wconf 96'><strong><em>for</em></strong></span>
<span class='ocrx_word' id='word_1_219' title='bbox 679 1074 712 1091; x_wconf 96'><strong><em>the</em></strong></span>
<span class='ocrx_word' id='word_1_220' title='bbox 720 1072 856 1091; x_wconf 96'><strong><em>consideration</em></strong></span>
</span>
<span class='ocr_line' id='line_1_28' title="bbox 120 1095 854 1118; baseline -0.001 -5; x_size 23; x_descenders 5; x_ascenders 6"><span class='ocrx_word' id='word_1_223' title='bbox 120 1095 142 1113; x_wconf 83'><strong>of</strong></span> <span class='ocrx_word' id='word_1_224' title='bbox 151 1095 248 1118; x_wconf 75'><strong>Congress,</strong></span> <span class='ocrx_word' id='word_1_225' title='bbox 257 1097 289 1113; x_wconf 78'><strong>the</strong></span> <span class='ocrx_word' id='word_1_226' title='bbox 302 1096 397 1118; x_wconf 74'><strong>propriety</strong></span> <span class='ocrx_word' id='word_1_227' title='bbox 408 1096 429 1113; x_wconf 82'><strong>of</strong></span> <span class='ocrx_word' id='word_1_228' title='bbox 437 1096 518 1117; x_wconf 75'><strong>limiting</strong></span> <span class='ocrx_word' id='word_1_229' title='bbox 530 1095 562 1113; x_wconf 83'><strong>the</strong></span> <span class='ocrx_word' id='word_1_230' title='bbox 573 1100 635 1117; x_wconf 70'><strong>power</strong></span> <span class='ocrx_word' id='word_1_231' title='bbox 643 1096 664 1113; x_wconf 83'><strong>of</strong></span> <span class='ocrx_word' id='word_1_232' title='bbox 673 1096 766 1113; x_wconf 80'><strong>ministers</strong></span> <span class='ocrx_word' id='word_1_233' title='bbox 774 1095 854 1113; x_wconf 77'><strong>tomake</strong></span>
<span class='ocr_line' id='line_1_28' title="bbox 120 1095 854 1118; baseline -0.001 -5; x_size 23; x_descenders 5; x_ascenders 6">
<span class='ocrx_word' id='word_1_221' title='bbox 120 1095 142 1113; x_wconf 96'><strong><em>of</em></strong></span>
<span class='ocrx_word' id='word_1_222' title='bbox 151 1095 248 1118; x_wconf 96'><strong><em>Congress,</em></strong></span>
<span class='ocrx_word' id='word_1_223' title='bbox 257 1097 289 1113; x_wconf 96'><strong><em>the</em></strong></span>
<span class='ocrx_word' id='word_1_224' title='bbox 302 1096 397 1118; x_wconf 96'><strong><em>propriety</em></strong></span>
<span class='ocrx_word' id='word_1_225' title='bbox 408 1096 429 1113; x_wconf 96'><strong><em>of</em></strong></span>
<span class='ocrx_word' id='word_1_226' title='bbox 437 1096 518 1117; x_wconf 96'><strong><em>limiting</em></strong></span>
<span class='ocrx_word' id='word_1_227' title='bbox 530 1095 562 1113; x_wconf 96'><strong><em>the</em></strong></span>
<span class='ocrx_word' id='word_1_228' title='bbox 573 1100 635 1117; x_wconf 96'><strong><em>power</em></strong></span>
<span class='ocrx_word' id='word_1_229' title='bbox 643 1096 664 1113; x_wconf 96'><strong><em>of</em></strong></span>
<span class='ocrx_word' id='word_1_230' title='bbox 673 1096 766 1113; x_wconf 96'><strong><em>ministers</em></strong></span>
<span class='ocrx_word' id='word_1_231' title='bbox 774 1096 793 1112; x_wconf 96'><strong><em>to</em></strong></span>
<span class='ocrx_word' id='word_1_232' title='bbox 799 1095 854 1113; x_wconf 96'><strong><em>make</em></strong></span>
</span>
<span class='ocr_line' id='line_1_29' title="bbox 121 1117 856 1140; baseline 0 -6; x_size 22; x_descenders 4; x_ascenders 5"><span class='ocrx_word' id='word_1_234' title='bbox 121 1118 197 1135; x_wconf 60'><strong>deerees</strong></span> <span class='ocrx_word' id='word_1_235' title='bbox 208 1118 246 1135; x_wconf 66'><strong>and</strong></span> <span class='ocrx_word' id='word_1_236' title='bbox 250 1117 361 1140; x_wconf 68'><strong>regulation,</strong></span> <span class='ocrx_word' id='word_1_237' title='bbox 369 1118 388 1135; x_wconf 75'><strong>in</strong></span> <span class='ocrx_word' id='word_1_238' title='bbox 395 1119 428 1136; x_wconf 73'><strong>the</strong></span> <span class='ocrx_word' id='word_1_239' title='bbox 435 1122 489 1135; x_wconf 62'><strong>sense,</strong></span> <span class='ocrx_word' id='word_1_240' title='bbox 495 1118 516 1135; x_wconf 74'><strong>in</strong></span> <span class='ocrx_word' id='word_1_241' title='bbox 523 1118 584 1136; x_wconf 68'><strong>which</strong></span> <span class='ocrx_word' id='word_1_242' title='bbox 591 1118 608 1135; x_wconf 73'><strong>it</strong></span> <span class='ocrx_word' id='word_1_243' title='bbox 614 1118 632 1135; x_wconf 80'><strong>is</strong></span> <span class='ocrx_word' id='word_1_244' title='bbox 638 1117 711 1135; x_wconf 67'><strong>limited</strong></span> <span class='ocrx_word' id='word_1_245' title='bbox 718 1118 743 1139; x_wconf 79'><strong>by</strong></span> <span class='ocrx_word' id='word_1_246' title='bbox 750 1118 856 1139; x_wconf 65'><strong>paragraph</strong></span>
<span class='ocr_line' id='line_1_29' title="bbox 121 1117 856 1140; baseline 0 -6; x_size 22; x_descenders 4; x_ascenders 5">
<span class='ocrx_word' id='word_1_233' title='bbox 121 1118 197 1135; x_wconf 95'><strong><em>decrees</em></strong></span>
<span class='ocrx_word' id='word_1_234' title='bbox 208 1118 246 1135; x_wconf 94'><strong><em>and</em></strong></span>
<span class='ocrx_word' id='word_1_235' title='bbox 250 1117 361 1140; x_wconf 94'><strong><em>regulation,</em></strong></span>
<span class='ocrx_word' id='word_1_236' title='bbox 369 1118 388 1135; x_wconf 96'><strong><em>in</em></strong></span>
<span class='ocrx_word' id='word_1_237' title='bbox 395 1119 428 1136; x_wconf 96'><strong><em>the</em></strong></span>
<span class='ocrx_word' id='word_1_238' title='bbox 435 1122 489 1135; x_wconf 96'><strong><em>sense</em></strong></span>
<span class='ocrx_word' id='word_1_239' title='bbox 495 1118 516 1135; x_wconf 96'><strong><em>in</em></strong></span>
<span class='ocrx_word' id='word_1_240' title='bbox 523 1118 584 1136; x_wconf 96'><strong><em>which</em></strong></span>
<span class='ocrx_word' id='word_1_241' title='bbox 591 1118 608 1135; x_wconf 96'><strong><em>it</em></strong></span>
<span class='ocrx_word' id='word_1_242' title='bbox 614 1118 632 1135; x_wconf 96'><strong><em>is</em></strong></span>
<span class='ocrx_word' id='word_1_243' title='bbox 638 1117 711 1135; x_wconf 95'><strong><em>limited</em></strong></span>
<span class='ocrx_word' id='word_1_244' title='bbox 718 1118 743 1139; x_wconf 96'><strong><em>by</em></strong></span>
<span class='ocrx_word' id='word_1_245' title='bbox 750 1118 856 1139; x_wconf 96'><strong><em>paragraph</em></strong></span>
</span>
<span class='ocr_line' id='line_1_30' title="bbox 122 1140 857 1162; baseline 0 -5; x_size 22; x_descenders 5; x_ascenders 5"><span class='ocrx_word' id='word_1_247' title='bbox 122 1140 156 1157; x_wconf 74'><strong>431</strong></span> <span class='ocrx_word' id='word_1_248' title='bbox 164 1140 186 1157; x_wconf 84'><strong>of</strong></span> <span class='ocrx_word' id='word_1_249' title='bbox 195 1141 227 1157; x_wconf 77'><strong>the</strong></span> <span class='ocrx_word' id='word_1_250' title='bbox 235 1140 300 1158; x_wconf 66'><strong>article</strong></span> <span class='ocrx_word' id='word_1_251' title='bbox 307 1140 369 1158; x_wconf 78'><strong>before</strong></span> <span class='ocrx_word' id='word_1_252' title='bbox 377 1140 508 1158; x_wconf 75'><strong>named—that</strong></span> <span class='ocrx_word' id='word_1_253' title='bbox 516 1141 537 1161; x_wconf 78'><strong>is,</strong></span> <span class='ocrx_word' id='word_1_254' title='bbox 547 1141 557 1151; x_wconf 81'><strong>“</strong></span> <span class='ocrx_word' id='word_1_255' title='bbox 563 1142 582 1158; x_wconf 80'><strong>to</strong></span> <span class='ocrx_word' id='word_1_256' title='bbox 591 1141 631 1157; x_wconf 76'><strong>acts</strong></span> <span class='ocrx_word' id='word_1_257' title='bbox 638 1141 760 1162; x_wconf 75'><strong>neeessaryto</strong></span> <span class='ocrx_word' id='word_1_258' title='bbox 770 1140 857 1162; x_wconf 70'><strong>organize</strong></span>
<span class='ocr_line' id='line_1_30' title="bbox 122 1140 857 1162; baseline 0 -5; x_size 22; x_descenders 5; x_ascenders 5">
<span class='ocrx_word' id='word_1_246' title='bbox 122 1140 156 1157; x_wconf 96'><strong><em>431</em></strong></span>
<span class='ocrx_word' id='word_1_247' title='bbox 164 1140 186 1157; x_wconf 97'><strong><em>of</em></strong></span>
<span class='ocrx_word' id='word_1_248' title='bbox 195 1141 227 1157; x_wconf 95'><strong><em>the</em></strong></span>
<span class='ocrx_word' id='word_1_249' title='bbox 235 1140 300 1158; x_wconf 95'><strong><em>article</em></strong></span>
<span class='ocrx_word' id='word_1_250' title='bbox 307 1140 369 1158; x_wconf 93'><strong><em>before</em></strong></span>
<span class='ocrx_word' id='word_1_251' title='bbox 377 1140 499 1158; x_wconf 92'><strong><em>named—that</em></strong></span>
<span class='ocrx_word' id='word_1_252' title='bbox 499 1141 537 1161; x_wconf 96'><strong><em>is,</em></strong></span>
<span class='ocrx_word' id='word_1_253' title='bbox 547 1141 582 1158; x_wconf 85'><strong><em>“to</em></strong></span>
<span class='ocrx_word' id='word_1_254' title='bbox 591 1141 631 1157; x_wconf 96'><strong><em>acts</em></strong></span>
<span class='ocrx_word' id='word_1_255' title='bbox 638 1144 736 1162; x_wconf 95'><strong><em>necessary</em></strong></span>
<span class='ocrx_word' id='word_1_256' title='bbox 741 1141 760 1157; x_wconf 96'><strong><em>to</em></strong></span>
<span class='ocrx_word' id='word_1_257' title='bbox 770 1140 857 1162; x_wconf 96'><strong><em>organize</em></strong></span>
</span>
<span class='ocr_line' id='line_1_31' title="bbox 121 1162 662 1185; baseline 0.002 -6; x_size 22; x_descenders 4; x_ascenders 5"><span class='ocrx_word' id='word_1_259' title='bbox 121 1162 159 1180; x_wconf 70'><strong>and</strong></span> <span class='ocrx_word' id='word_1_260' title='bbox 168 1162 210 1184; x_wconf 77'><strong>give</strong></span> <span class='ocrx_word' id='word_1_261' title='bbox 218 1163 312 1184; x_wconf 79'><strong>efficiency</strong></span> <span class='ocrx_word' id='word_1_262' title='bbox 320 1164 340 1180; x_wconf 76'><strong>to</strong></span> <span class='ocrx_word' id='word_1_263' title='bbox 348 1163 380 1180; x_wconf 77'><strong>the</strong></span> <span class='ocrx_word' id='word_1_264' title='bbox 388 1164 449 1181; x_wconf 79'><strong>courts</strong></span> <span class='ocrx_word' id='word_1_265' title='bbox 458 1163 533 1180; x_wconf 74'><strong>created</strong></span> <span class='ocrx_word' id='word_1_266' title='bbox 539 1163 564 1185; x_wconf 83'><strong>by</strong></span> <span class='ocrx_word' id='word_1_267' title='bbox 574 1162 607 1180; x_wconf 74'><strong>the</strong></span> <span class='ocrx_word' id='word_1_268' title='bbox 615 1163 662 1180; x_wconf 71'><strong>act.”</strong></span>
<span class='ocr_line' id='line_1_31' title="bbox 121 1162 662 1185; baseline 0.002 -6; x_size 22; x_descenders 4; x_ascenders 5">
<span class='ocrx_word' id='word_1_258' title='bbox 121 1162 159 1180; x_wconf 96'><strong><em>and</em></strong></span>
<span class='ocrx_word' id='word_1_259' title='bbox 168 1162 210 1184; x_wconf 97'><strong><em>give</em></strong></span>
<span class='ocrx_word' id='word_1_260' title='bbox 218 1163 312 1184; x_wconf 96'><strong><em>efficiency</em></strong></span>
<span class='ocrx_word' id='word_1_261' title='bbox 320 1164 340 1180; x_wconf 96'><strong><em>to</em></strong></span>
<span class='ocrx_word' id='word_1_262' title='bbox 348 1163 380 1180; x_wconf 96'><strong><em>the</em></strong></span>
<span class='ocrx_word' id='word_1_263' title='bbox 388 1164 449 1181; x_wconf 96'><strong><em>courts</em></strong></span>
<span class='ocrx_word' id='word_1_264' title='bbox 458 1163 533 1180; x_wconf 96'><strong><em>created</em></strong></span>
<span class='ocrx_word' id='word_1_265' title='bbox 539 1163 564 1185; x_wconf 96'><strong><em>by</em></strong></span>
<span class='ocrx_word' id='word_1_266' title='bbox 574 1162 607 1180; x_wconf 96'><strong><em>the</em></strong></span>
<span class='ocrx_word' id='word_1_267' title='bbox 615 1163 662 1180; x_wconf 96'><strong><em>act.”</em></strong></span>
</span>
</p>
<p class='ocr_par' id='par_1_15' lang='eng' title="bbox 144 1184 386 1207">
<span class='ocr_line' id='line_1_32' title="bbox 144 1184 386 1207; baseline 0 -5; x_size 23; x_descenders 5; x_ascenders 5"><span class='ocrx_word' id='word_1_269' title='bbox 144 1185 271 1207; x_wconf 77'><strong>Respectfully</strong></span> <span class='ocrx_word' id='word_1_270' title='bbox 279 1184 386 1202; x_wconf 76'><strong>submitted.</strong></span>
<span class='ocr_line' id='line_1_32' title="bbox 144 1184 386 1207; baseline 0 -5; x_size 23; x_descenders 5; x_ascenders 5">
<span class='ocrx_word' id='word_1_268' title='bbox 144 1185 271 1207; x_wconf 86'><strong><em>Respectfully</em></strong></span>
<span class='ocrx_word' id='word_1_269' title='bbox 279 1184 386 1202; x_wconf 93'><strong><em>submitted.</em></strong></span>
</span>
</p>
<p class='ocr_par' id='par_1_16' lang='eng' title="bbox 625 1206 834 1225">
<span class='ocr_line' id='line_1_33' title="bbox 625 1206 834 1225; baseline -0.005 0; x_size 23.69949; x_descenders 5.5158105; x_ascenders 5.590498"><span class='ocrx_word' id='word_1_271' title='bbox 625 1206 760 1225; x_wconf 80'><strong>HAMILTON</strong></span> <span class='ocrx_word' id='word_1_272' title='bbox 768 1207 834 1224; x_wconf 77'>FISH.</span>
<span class='ocr_line' id='line_1_33' title="bbox 625 1206 834 1225; baseline -0.005 0; x_size 23.69949; x_descenders 5.5158105; x_ascenders 5.590498">
<span class='ocrx_word' id='word_1_270' title='bbox 625 1206 760 1225; x_wconf 96'><strong><em>HAMILTON</em></strong></span>
<span class='ocrx_word' id='word_1_271' title='bbox 768 1207 834 1224; x_wconf 95'><strong><em>FISH.</em></strong></span>
</span>
</p>
</div>
<div class='ocr_carea' id='block_1_10' title="bbox 143 1229 317 1247">
<p class='ocr_par' id='par_1_17' lang='eng' title="bbox 143 1229 317 1247">
<span class='ocr_line' id='line_1_34' title="bbox 143 1229 317 1247; baseline 0.006 -1; x_size 22.296295; x_descenders 5.2962961; x_ascenders 4"><span class='ocrx_word' id='word_1_273' title='bbox 143 1229 183 1246; x_wconf 83'><strong>The</strong></span> <span class='ocrx_word' id='word_1_274' title='bbox 191 1230 317 1247; x_wconf 74'><strong>PRESIDENT.</strong></span>
<span class='ocr_line' id='line_1_34' title="bbox 143 1229 317 1247; baseline 0.006 -1; x_size 22.296295; x_descenders 5.2962961; x_ascenders 4">
<span class='ocrx_word' id='word_1_272' title='bbox 143 1229 183 1246; x_wconf 96'><strong><em>The</em></strong></span>
<span class='ocrx_word' id='word_1_273' title='bbox 191 1230 317 1247; x_wconf 74'><strong><em>PRESIDENT,</em></strong></span>
</span>
</p>
</div>
<div class='ocr_carea' id='block_1_11' title="bbox 345 1308 632 1331">
<p class='ocr_par' id='par_1_18' lang='eng' title="bbox 345 1308 632 1331">
<span class='ocr_line' id='line_1_35' title="bbox 345 1308 632 1331; baseline 0 -6; x_size 22; x_descenders 5; x_ascenders 4"><span class='ocrx_word' id='word_1_275' title='bbox 345 1308 387 1325; x_wconf 73'><strong>List</strong></span> <span class='ocrx_word' id='word_1_276' title='bbox 393 1308 415 1331; x_wconf 77'><strong>of</strong></span> <span class='ocrx_word' id='word_1_277' title='bbox 423 1308 557 1330; x_wconf 67'><strong>accompanying</strong></span> <span class='ocrx_word' id='word_1_278' title='bbox 561 1312 632 1331; x_wconf 70'><strong>papers.</strong></span>
<span class='ocr_line' id='line_1_35' title="bbox 345 1308 632 1331; baseline 0 -6; x_size 22; x_descenders 5; x_ascenders 4">
<span class='ocrx_word' id='word_1_274' title='bbox 345 1308 387 1325; x_wconf 91'><strong><em>List</em></strong></span>
<span class='ocrx_word' id='word_1_275' title='bbox 393 1308 415 1331; x_wconf 96'><strong><em>of</em></strong></span>
<span class='ocrx_word' id='word_1_276' title='bbox 423 1308 557 1330; x_wconf 96'><strong><em>accompanying</em></strong></span>
<span class='ocrx_word' id='word_1_277' title='bbox 561 1312 632 1331; x_wconf 87'><strong><em>papers.</em></strong></span>
</span>
</p>
</div>
<div class='ocr_carea' id='block_1_12' title="bbox 142 1340 857 1393">
<p class='ocr_par' id='par_1_19' lang='eng' title="bbox 142 1340 857 1393">
<span class='ocr_line' id='line_1_36' title="bbox 142 1340 857 1370; baseline 0 -5; x_size 23; x_descenders 5; x_ascenders 6"><span class='ocrx_word' id='word_1_279' title='bbox 142 1348 159 1365; x_wconf 88'><strong>1.</strong></span> <span class='ocrx_word' id='word_1_280' title='bbox 170 1348 293 1370; x_wconf 66'><strong>Regulations</strong></span> <span class='ocrx_word' id='word_1_281' title='bbox 300 1348 329 1365; x_wconf 79'><strong>for</strong></span> <span class='ocrx_word' id='word_1_282' title='bbox 338 1340 370 1366; x_wconf 49'><strong>the</strong></span> <span class='ocrx_word' id='word_1_283' title='bbox 378 1348 463 1366; x_wconf 63'><strong>consular</strong></span> <span class='ocrx_word' id='word_1_284' title='bbox 470 1350 533 1366; x_wconf 75'><strong>courts</strong></span> <span class='ocrx_word' id='word_1_285' title='bbox 541 1349 562 1366; x_wconf 81'><strong>of</strong></span> <span class='ocrx_word' id='word_1_286' title='bbox 570 1348 603 1365; x_wconf 80'><strong>the</strong></span> <span class='ocrx_word' id='word_1_287' title='bbox 611 1348 682 1366; x_wconf 76'><strong>United</strong></span> <span class='ocrx_word' id='word_1_288' title='bbox 690 1348 753 1366; x_wconf 74'><strong>States</strong></span> <span class='ocrx_word' id='word_1_289' title='bbox 761 1347 781 1365; x_wconf 82'><strong>in</strong></span> <span class='ocrx_word' id='word_1_290' title='bbox 788 1348 857 1370; x_wconf 63'>Japan.</span>
<span class='ocr_line' id='line_1_36' title="bbox 142 1340 857 1370; baseline 0 -5; x_size 23; x_descenders 5; x_ascenders 6">
<span class='ocrx_word' id='word_1_278' title='bbox 142 1348 159 1365; x_wconf 96'><strong><em>1,</em></strong></span>
<span class='ocrx_word' id='word_1_279' title='bbox 170 1348 293 1370; x_wconf 96'><strong><em>Regulations</em></strong></span>
<span class='ocrx_word' id='word_1_280' title='bbox 300 1348 329 1365; x_wconf 96'><strong><em>for</em></strong></span>
<span class='ocrx_word' id='word_1_281' title='bbox 338 1340 370 1366; x_wconf 96'><strong><em>the</em></strong></span>
<span class='ocrx_word' id='word_1_282' title='bbox 378 1348 463 1366; x_wconf 96'><strong><em>consular</em></strong></span>
<span class='ocrx_word' id='word_1_283' title='bbox 470 1350 533 1366; x_wconf 96'><strong><em>courts</em></strong></span>
<span class='ocrx_word' id='word_1_284' title='bbox 541 1349 562 1366; x_wconf 96'><strong><em>of</em></strong></span>
<span class='ocrx_word' id='word_1_285' title='bbox 570 1348 603 1365; x_wconf 96'><strong><em>the</em></strong></span>
<span class='ocrx_word' id='word_1_286' title='bbox 611 1348 682 1366; x_wconf 95'><strong><em>United</em></strong></span>
<span class='ocrx_word' id='word_1_287' title='bbox 690 1348 753 1366; x_wconf 96'><strong><em>States</em></strong></span>
<span class='ocrx_word' id='word_1_288' title='bbox 761 1347 781 1365; x_wconf 95'><strong><em>in</em></strong></span>
<span class='ocrx_word' id='word_1_289' title='bbox 788 1348 857 1370; x_wconf 93'><strong><em>Japan.</em></strong></span>
</span>
<span class='ocr_line' id='line_1_37' title="bbox 142 1371 644 1393; baseline 0.004 -7; x_size 30.84; x_descenders 5; x_ascenders 8.8400002"><span class='ocrx_word' id='word_1_291' title='bbox 142 1371 159 1387; x_wconf 88'><strong>2.</strong></span> <span class='ocrx_word' id='word_1_292' title='bbox 170 1371 205 1387; x_wconf 82'><strong>Mr.</strong></span> <span class='ocrx_word' id='word_1_293' title='bbox 214 1371 260 1388; x_wconf 78'><strong>Fish</strong></span> <span class='ocrx_word' id='word_1_294' title='bbox 268 1372 288 1389; x_wconf 79'><strong>to</strong></span> <span class='ocrx_word' id='word_1_295' title='bbox 295 1371 330 1388; x_wconf 74'><strong>Mr.</strong></span> <span class='ocrx_word' id='word_1_296' title='bbox 338 1371 368 1388; x_wconf 83'><strong>De</strong></span> <span class='ocrx_word' id='word_1_297' title='bbox 375 1371 433 1393; x_wconf 81'><strong>Long,</strong></span> <span class='ocrx_word' id='word_1_298' title='bbox 442 1371 550 1392; x_wconf 79'><strong>September</strong></span> <span class='ocrx_word' id='word_1_299' title='bbox 557 1371 585 1393; x_wconf 87'><strong>10,</strong></span> <span class='ocrx_word' id='word_1_300' title='bbox 594 1371 644 1388; x_wconf 84'><strong>1870.</strong></span>
<span class='ocr_line' id='line_1_37' title="bbox 142 1371 644 1393; baseline 0.004 -7; x_size 30.84; x_descenders 5; x_ascenders 8.8400002">
<span class='ocrx_word' id='word_1_290' title='bbox 142 1371 159 1387; x_wconf 90'><strong><em>2,</em></strong></span>
<span class='ocrx_word' id='word_1_291' title='bbox 170 1371 205 1387; x_wconf 96'><strong><em>Mr.</em></strong></span>
<span class='ocrx_word' id='word_1_292' title='bbox 214 1371 260 1388; x_wconf 95'><strong><em>Fish</em></strong></span>
<span class='ocrx_word' id='word_1_293' title='bbox 268 1372 288 1389; x_wconf 95'><strong><em>to</em></strong></span>
<span class='ocrx_word' id='word_1_294' title='bbox 295 1371 330 1388; x_wconf 95'><strong><em>Mr.</em></strong></span>
<span class='ocrx_word' id='word_1_295' title='bbox 338 1371 368 1388; x_wconf 96'><strong><em>De</em></strong></span>
<span class='ocrx_word' id='word_1_296' title='bbox 375 1371 433 1393; x_wconf 96'><strong><em>Long,</em></strong></span>
<span class='ocrx_word' id='word_1_297' title='bbox 442 1371 550 1392; x_wconf 95'><strong><em>September</em></strong></span>
<span class='ocrx_word' id='word_1_298' title='bbox 557 1371 585 1393; x_wconf 95'><strong><em>10,</em></strong></span>
<span class='ocrx_word' id='word_1_299' title='bbox 594 1371 644 1388; x_wconf 79'><strong><em>1870,</em></strong></span>
</span>
</p>
</div>
<div class='ocr_carea' id='block_1_13' title="bbox 0 0 1000 1520">
<p class='ocr_par' id='par_1_20' lang='eng' title="bbox 0 0 1000 1520">
<span class='ocr_line' id='line_1_38' title="bbox 0 0 1000 1520; baseline 0 2; x_size 763; x_descenders -381.5; x_ascenders 381.5"><span class='ocrx_word' id='word_1_301' title='bbox 0 0 1000 1520; x_wconf 95'><strong> </strong></span>
<span class='ocr_line' id='line_1_38' title="bbox 0 0 1000 1520; baseline 0 2; x_size 763; x_descenders -381.5; x_ascenders 381.5">
<span class='ocrx_word' id='word_1_300' title='bbox 0 0 1000 1520; x_wconf 95'><strong><em> </em></strong></span>
</span>
</p>
</div>
<div class='ocr_carea' id='block_1_14' title="bbox 24 1504 845 1520">
<p class='ocr_par' id='par_1_21' lang='eng' title="bbox 24 1504 845 1520">
<span class='ocr_line' id='line_1_39' title="bbox 24 1504 845 1520; baseline 0 0; x_size 8; x_descenders -4; x_ascenders 4"><span class='ocrx_word' id='word_1_302' title='bbox 24 1504 845 1520; x_wconf 95'><strong> </strong></span>
<span class='ocr_line' id='line_1_39' title="bbox 24 1504 845 1520; baseline 0 0; x_size 8; x_descenders -4; x_ascenders 4">
<span class='ocrx_word' id='word_1_301' title='bbox 24 1504 845 1520; x_wconf 95'><strong><em> </em></strong></span>
</span>
</p>
</div>
<div class='ocr_carea' id='block_1_15' title="bbox 982 987 1000 1500">
<p class='ocr_par' id='par_1_22' lang='eng' title="bbox 982 987 1000 1500">
<span class='ocr_line' id='line_1_40' title="bbox 982 987 1000 1500; baseline 0 0; x_size 256.5; x_descenders -128.25; x_ascenders 128.25"><span class='ocrx_word' id='word_1_303' title='bbox 982 987 1000 1500; x_wconf 95'><strong> </strong></span>
<span class='ocr_line' id='line_1_40' title="bbox 982 987 1000 1500; baseline 0 0; x_size 256.5; x_descenders -128.25; x_ascenders 128.25">
<span class='ocrx_word' id='word_1_302' title='bbox 982 987 1000 1500; x_wconf 95'><strong><em> </em></strong></span>
</span>
</p>
</div>
@@ -1 +1 @@
Tesseract Open Source OCR Engine v3.05.01 with Leptonica
Tesseract Open Source OCR Engine v4.0.0 with Leptonica

Some files were not shown because too many files have changed in this diff Show More