Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0b10db91be | ||
|
|
1a516b2af9 | ||
|
|
076363d78e | ||
|
|
5fde214290 | ||
|
|
a620724d6a | ||
|
|
7368399f8b | ||
|
|
34c78a892a | ||
|
|
9d28879505 | ||
|
|
2482296e2b |
@@ -287,7 +287,7 @@ If you prefer to not modify your system in this matter, consider using a Docker
|
|||||||
sudo apt-get update
|
sudo apt-get update
|
||||||
|
|
||||||
sudo apt-get install \
|
sudo apt-get install \
|
||||||
python3.6 \
|
python3.6-dev \
|
||||||
ghostscript \
|
ghostscript \
|
||||||
tesseract-ocr \
|
tesseract-ocr \
|
||||||
tesseract-ocr-eng \
|
tesseract-ocr-eng \
|
||||||
@@ -298,7 +298,7 @@ Now we need to install ``pip`` and let it install ocrmypdf:
|
|||||||
|
|
||||||
.. code-block:: bash
|
.. code-block:: bash
|
||||||
|
|
||||||
wget -O - -o /dev/null https://bootstrap.pypa.io/get-pip.py | python3.6
|
curl https://bootstrap.pypa.io/ez_setup.py -o - | python3.6 && python3.6 -m easy_install pip
|
||||||
pip3.6 install ocrmypdf[fitz]
|
pip3.6 install ocrmypdf[fitz]
|
||||||
|
|
||||||
The ``wget`` command will download a program and run it.
|
The ``wget`` command will download a program and run it.
|
||||||
|
|||||||
@@ -9,10 +9,18 @@ The OCRmyPDF package itself does not contain a public API, although it is fairly
|
|||||||
find: [^`]\#([0-9]{1,3})[^0-9]
|
find: [^`]\#([0-9]{1,3})[^0-9]
|
||||||
replace: `#$1 <https://github.com/jbarlow83/OCRmyPDF/issues/$1>`_
|
replace: `#$1 <https://github.com/jbarlow83/OCRmyPDF/issues/$1>`_
|
||||||
|
|
||||||
|
v6.1.5
|
||||||
|
------
|
||||||
|
|
||||||
|
- Fix issue `#253 <https://github.com/jbarlow83/OCRmyPDF/issues/248>`_, a possible division by zero when using the ``hocr`` renderer.
|
||||||
|
|
||||||
|
- Fix incorrectly formatted ``<xmp:ModifyDate>`` field inside XMP metadata for PDF/As. veraPDF flags this as a PDF/A validation failure. The error is caused the timezone and final digit of the seconds of modified time to be omitted, so at worst the modification time stamp is rounded to the nearest 10 seconds.
|
||||||
|
|
||||||
|
|
||||||
v6.1.4
|
v6.1.4
|
||||||
------
|
------
|
||||||
|
|
||||||
- Fix issue #248, ``--clean`` argument may remove OCR from left column of text on certain documents. We now set ``--layout none`` to suppress this.
|
- Fix issue `#248 <https://github.com/jbarlow83/OCRmyPDF/issues/248>`_ ``--clean`` argument may remove OCR from left column of text on certain documents. We now set ``--layout none`` to suppress this.
|
||||||
|
|
||||||
- The test cache was updated to reflect the change above.
|
- The test cache was updated to reflect the change above.
|
||||||
|
|
||||||
|
|||||||
@@ -32,6 +32,18 @@ def version():
|
|||||||
return get_version('gs')
|
return get_version('gs')
|
||||||
|
|
||||||
|
|
||||||
|
def jpeg_passthrough_available():
|
||||||
|
"""
|
||||||
|
Ghostscript 9.23 introduced JPEG passthrough but it seems to corrupt the
|
||||||
|
last two bytes of certain images, for now we disable it for 9.23 and
|
||||||
|
do not mention it for < 9.23.
|
||||||
|
|
||||||
|
https://bugs.ghostscript.com/show_bug.cgi?id=699216
|
||||||
|
|
||||||
|
"""
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
def _gs_error_reported(stream):
|
def _gs_error_reported(stream):
|
||||||
return re.search(r'error', stream, flags=re.IGNORECASE)
|
return re.search(r'error', stream, flags=re.IGNORECASE)
|
||||||
|
|
||||||
@@ -132,6 +144,12 @@ def generate_pdfa(pdf_pages, output_file, compression, log,
|
|||||||
# git commit fe1c025d.
|
# git commit fe1c025d.
|
||||||
strategy = 'RGB' if version() >= '9.19' else '/RGB'
|
strategy = 'RGB' if version() >= '9.19' else '/RGB'
|
||||||
|
|
||||||
|
if version() == '9.23':
|
||||||
|
# 9.23: new feature JPEG passthrough is broken in some cases, best to
|
||||||
|
# disable it always
|
||||||
|
# https://bugs.ghostscript.com/show_bug.cgi?id=699216
|
||||||
|
compression_args.append('-dPassThroughJPEGImages=false')
|
||||||
|
|
||||||
with NamedTemporaryFile(delete=True) as gs_pdf:
|
with NamedTemporaryFile(delete=True) as gs_pdf:
|
||||||
args_gs = [
|
args_gs = [
|
||||||
"gs",
|
"gs",
|
||||||
|
|||||||
@@ -322,8 +322,11 @@ class HocrTransform():
|
|||||||
dy = baseline_y2 - cursor[1]
|
dy = baseline_y2 - cursor[1]
|
||||||
text.moveCursor(dx, dy)
|
text.moveCursor(dx, dy)
|
||||||
|
|
||||||
text.setHorizScale(100 * box_width / font_width)
|
# If reportlab tells us this word is 0 units wide, our best seems
|
||||||
text.textOut(elemtxt)
|
# to be to suppress this text
|
||||||
|
if font_width > 0:
|
||||||
|
text.setHorizScale(100 * box_width / font_width)
|
||||||
|
text.textOut(elemtxt)
|
||||||
pdf.drawText(text)
|
pdf.drawText(text)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -129,7 +129,9 @@ def encode_pdf_date(d: datetime) -> str:
|
|||||||
s += "+00'00'"
|
s += "+00'00'"
|
||||||
elif tz != '':
|
elif tz != '':
|
||||||
sign, tz_hours, tz_mins = tz[0], tz[1:3], tz[3:5]
|
sign, tz_hours, tz_mins = tz[0], tz[1:3], tz[3:5]
|
||||||
s += "{}{}'{tz}'".format(sign, tz_hours, tz_mins)
|
s += "{}{}'{}'".format(sign, tz_hours, tz_mins)
|
||||||
|
else:
|
||||||
|
raise ValueError("Naive timezone not supported")
|
||||||
return s
|
return s
|
||||||
|
|
||||||
|
|
||||||
@@ -141,6 +143,7 @@ def decode_pdf_date(s: str) -> datetime:
|
|||||||
|
|
||||||
if s.startswith('D:'):
|
if s.startswith('D:'):
|
||||||
s = s[2:]
|
s = s[2:]
|
||||||
|
s = s.replace("'", "") # Remove apos from PDF time strings
|
||||||
for fmt in pdfmark_date_fmts:
|
for fmt in pdfmark_date_fmts:
|
||||||
try:
|
try:
|
||||||
return datetime.strptime(s, fmt)
|
return datetime.strptime(s, fmt)
|
||||||
|
|||||||
@@ -18,7 +18,7 @@
|
|||||||
from contextlib import suppress
|
from contextlib import suppress
|
||||||
from shutil import copyfileobj
|
from shutil import copyfileobj
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from datetime import datetime
|
from datetime import datetime, timezone
|
||||||
import sys
|
import sys
|
||||||
import os
|
import os
|
||||||
import shutil
|
import shutil
|
||||||
@@ -900,7 +900,7 @@ def get_pdfmark(base_pdf, options):
|
|||||||
PROGRAM_NAME, VERSION,
|
PROGRAM_NAME, VERSION,
|
||||||
renderer_tag,
|
renderer_tag,
|
||||||
tesseract.version())
|
tesseract.version())
|
||||||
pdfmark['/ModDate'] = encode_pdf_date(datetime.utcnow())
|
pdfmark['/ModDate'] = encode_pdf_date(datetime.now(timezone.utc))
|
||||||
return pdfmark
|
return pdfmark
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -110,6 +110,7 @@ licensed under the specified license.
|
|||||||
- Wikipedia authors
|
- Wikipedia authors
|
||||||
- CC-BY-SA 3.0
|
- CC-BY-SA 3.0
|
||||||
* - missing_docinfo.pdf
|
* - missing_docinfo.pdf
|
||||||
|
- @jbarlow83
|
||||||
- @jbarlow83
|
- @jbarlow83
|
||||||
- PDF file with no /DocumentInfo section
|
- PDF file with no /DocumentInfo section
|
||||||
- CC-BY-SA 4.0
|
- CC-BY-SA 4.0
|
||||||
@@ -117,7 +118,7 @@ licensed under the specified license.
|
|||||||
- PDF file generated by PDFPen pro that triggered content stream parse errors
|
- PDF file generated by PDFPen pro that triggered content stream parse errors
|
||||||
- @maxandersen
|
- @maxandersen
|
||||||
- @maxandersen
|
- @maxandersen
|
||||||
- MIT
|
- CC-BY-SA 4.0
|
||||||
* - negzero.pdf
|
* - negzero.pdf
|
||||||
- copy of formxobject.pdf with token that qpdf doesn't like
|
- copy of formxobject.pdf with token that qpdf doesn't like
|
||||||
- @jbarlow83
|
- @jbarlow83
|
||||||
@@ -137,7 +138,7 @@ licensed under the specified license.
|
|||||||
- a PDF with vector art and text rendered as curves with no fonts
|
- a PDF with vector art and text rendered as curves with no fonts
|
||||||
- @Catscratch
|
- @Catscratch
|
||||||
- @Catscratch
|
- @Catscratch
|
||||||
- MIT
|
- CC-BY-SA 4.0
|
||||||
|
|
||||||
|
|
||||||
Assemblies
|
Assemblies
|
||||||
|
|||||||
+1
-5
@@ -610,10 +610,6 @@ def test_masks(spoof_tesseract_noop, resources, outpdf):
|
|||||||
p, out, err = run_ocrmypdf(
|
p, out, err = run_ocrmypdf(
|
||||||
resources / 'masks.pdf', outpdf, env=spoof_tesseract_noop)
|
resources / 'masks.pdf', outpdf, env=spoof_tesseract_noop)
|
||||||
|
|
||||||
if ghostscript.version() == '9.23' and \
|
|
||||||
p.returncode == ExitCode.invalid_output_pdf:
|
|
||||||
pytest.xfail('https://bugs.ghostscript.com/show_bug.cgi?id=699216')
|
|
||||||
|
|
||||||
assert p.returncode == ExitCode.ok
|
assert p.returncode == ExitCode.ok
|
||||||
|
|
||||||
|
|
||||||
@@ -906,7 +902,7 @@ def test_compression_changed(spoof_tesseract_noop, ocrmypdf_exec,
|
|||||||
if compression == "jpeg":
|
if compression == "jpeg":
|
||||||
assert pdfimage.enc == Encoding.jpeg
|
assert pdfimage.enc == Encoding.jpeg
|
||||||
else:
|
else:
|
||||||
if ghostscript.version() >= '9.23':
|
if ghostscript.jpeg_passthrough_available():
|
||||||
# Ghostscript 9.23 adds JPEG passthrough, which allows a JPEG to be
|
# Ghostscript 9.23 adds JPEG passthrough, which allows a JPEG to be
|
||||||
# copied without transcoding - so report
|
# copied without transcoding - so report
|
||||||
if image.endswith('jpg'):
|
if image.endswith('jpg'):
|
||||||
|
|||||||
@@ -19,6 +19,7 @@
|
|||||||
import pytest
|
import pytest
|
||||||
import PyPDF2 as pypdf
|
import PyPDF2 as pypdf
|
||||||
import datetime
|
import datetime
|
||||||
|
from datetime import timezone
|
||||||
|
|
||||||
from ocrmypdf.pdfa import file_claims_pdfa, encode_pdf_date, decode_pdf_date
|
from ocrmypdf.pdfa import file_claims_pdfa, encode_pdf_date, decode_pdf_date
|
||||||
from ocrmypdf.exceptions import ExitCode
|
from ocrmypdf.exceptions import ExitCode
|
||||||
@@ -150,6 +151,6 @@ def test_creation_date_preserved(spoof_tesseract_noop, output_type, resources,
|
|||||||
# We expect that the modified date is quite recent
|
# We expect that the modified date is quite recent
|
||||||
date_after = decode_pdf_date(after['/ModDate'])
|
date_after = decode_pdf_date(after['/ModDate'])
|
||||||
assert seconds_between_dates(
|
assert seconds_between_dates(
|
||||||
date_after, datetime.datetime.utcnow()) < 1000
|
date_after, datetime.datetime.now(timezone.utc)) < 1000
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user