Compare commits

...
9 Commits
8 changed files with 54 additions and 33 deletions
+2 -1
View File
@@ -190,7 +190,8 @@ of ocrmypdf, and install the following dependencies:
python3-reportlab \ python3-reportlab \
qpdf \ qpdf \
tesseract-ocr \ tesseract-ocr \
zlib1g zlib1g \
unpaper
We will need a newer version of ``pip`` then was available for Ubuntu 18.04: We will need a newer version of ``pip`` then was available for Ubuntu 18.04:
+17 -1
View File
@@ -12,12 +12,28 @@ may be unreliable. Use the API to depend on precise behavior.
The public API may be useful in scripts that launch OCRmyPDF processes or that The public API may be useful in scripts that launch OCRmyPDF processes or that
wish to use some of its features for working with PDFs. wish to use some of its features for working with PDFs.
v11.1.2
=======
- Fix hOCR renderer writing the text in roughly reverse order. This should not
affect reasonably smart PDF readers that properly locate the position of all
text, but may confuse those that rely on the order of objects in the content
stream. (#642)
v11.1.1
=======
- We now avoid using named temporary files when using pngquant allowing containerized
pngquant installs to be used.
- Clarified an error message.
- Highest number of 1's in a release ever!
v11.1.0 v11.1.0
======= =======
- Fixed page rotation issues: #634, #589. - Fixed page rotation issues: #634, #589.
- Fixed some cases where optimization created an invalid image such as a - Fixed some cases where optimization created an invalid image such as a
1-bit "RGB" iamge: #629, #620. 1-bit "RGB" image: #629, #620.
- Page numbers are now displayed in debug logs when pages are being grafted. - Page numbers are now displayed in debug logs when pages are being grafted.
- ocrmypdf.optimize.rewrite_png and ocrmypdf.optimize.rewrite_png_as_g4 were - ocrmypdf.optimize.rewrite_png and ocrmypdf.optimize.rewrite_png_as_g4 were
marked deprecated. Strictly speaking these should have been internal APIs, marked deprecated. Strictly speaking these should have been internal APIs,
+25 -23
View File
@@ -7,7 +7,11 @@
"""Interface to pngquant executable""" """Interface to pngquant executable"""
from contextlib import contextmanager
from io import BytesIO
from os import fspath from os import fspath
from pathlib import Path
from subprocess import PIPE
from tempfile import NamedTemporaryFile from tempfile import NamedTemporaryFile
from PIL import Image from PIL import Image
@@ -28,34 +32,32 @@ def available():
return True return True
def quantize(input_file, output_file, quality_min, quality_max): @contextmanager
input_file = fspath(input_file) def input_as_png(input_file: Path):
output_file = fspath(output_file) if not input_file.name.endswith('.png'):
if input_file.endswith('.jpg'): with Image.open(input_file) as im:
with Image.open(input_file) as im, NamedTemporaryFile(suffix='.png') as tmp: bio = BytesIO()
im.save(tmp) im.save(bio, format='png')
args = [ bio.seek(0)
'pngquant', yield bio
'--force',
'--skip-if-larger',
'--output',
output_file,
'--quality',
f'{quality_min}-{quality_max}',
'--',
tmp.name,
]
run(args)
else: else:
with open(input_file, 'rb') as f:
yield f
def quantize(input_file: Path, output_file: Path, quality_min: int, quality_max: int):
with input_as_png(input_file) as input_stream:
args = [ args = [
'pngquant', 'pngquant',
'--force', '--force',
'--skip-if-larger', '--skip-if-larger',
'--output',
output_file,
'--quality', '--quality',
f'{quality_min}-{quality_max}', f'{quality_min}-{quality_max}',
'--', '--', # pngquant: stop processing arguments
input_file, '-', # pngquant: stream input and output
] ]
run(args) result = run(args, stdin=input_stream, stdout=PIPE, stderr=PIPE, check=False)
if result.returncode == 0:
# input_file could be the same as output_file, so we defer the write
output_file.write_bytes(result.stdout)
+1 -1
View File
@@ -107,7 +107,7 @@ def run(input_file, output_file, dpi, mode_args):
def validate_custom_args(args: str): def validate_custom_args(args: str):
unpaper_args = shlex.split(args) unpaper_args = shlex.split(args)
if any('/' in arg for arg in unpaper_args): if any(('/' in arg or arg == '.' or arg == '..') for arg in unpaper_args):
raise ValueError('No filenames allowed in --unpaper-args') raise ValueError('No filenames allowed in --unpaper-args')
return unpaper_args return unpaper_args
+3 -5
View File
@@ -39,13 +39,11 @@ def check_options(options):
if gs_version < '9.20' and options.output_type != 'pdf' and not is_latin: if gs_version < '9.20' and options.output_type != 'pdf' and not is_latin:
# https://bugs.ghostscript.com/show_bug.cgi?id=696874 # https://bugs.ghostscript.com/show_bug.cgi?id=696874
# Ghostscript < 9.20 fails to encode multibyte characters properly # Ghostscript < 9.20 fails to encode multibyte characters properly
msg = ( log.warning(
"The installed version of Ghostscript does not work correctly " f"The installed version of Ghostscript ({gs_version}) does not work "
"with the OCR languages you specified. Use --output-type pdf or " "correctly with the OCR languages you specified. Use --output-type pdf or "
"upgrade to Ghostscript 9.20 or later to avoid this issue." "upgrade to Ghostscript 9.20 or later to avoid this issue."
) )
msg += f"Found Ghostscript {gs_version}"
log.warning(msg)
if options.output_type == 'pdfa': if options.output_type == 'pdfa':
options.output_type = 'pdfa-2' options.output_type = 'pdfa-2'
+4 -1
View File
@@ -167,7 +167,10 @@ class HocrTransform:
def topdown_position(self, element): def topdown_position(self, element):
pxl_line_coords = self.element_coordinates(element) pxl_line_coords = self.element_coordinates(element)
line_box = self.pt_from_pixel(pxl_line_coords) line_box = self.pt_from_pixel(pxl_line_coords)
return -line_box.y2 # Coordinates here are still in the hocr coordinate system, so 0 on the y axis
# is the top of the page and increasing values of y will move towards the
# bottom of the page.
return line_box.y2
def to_pdf( def to_pdf(
self, self,
+1
View File
@@ -417,6 +417,7 @@ def _transcode_png(pike: Pdf, filename: Path, xref: Xref) -> bool:
im_obj[key] = local_image[key] im_obj[key] = local_image[key]
for key in del_keys: for key in del_keys:
del im_obj[key] del im_obj[key]
return True
def transcode_pngs( def transcode_pngs(
+1 -1
View File
@@ -55,7 +55,7 @@ def test_old_ghostscript(caplog):
vd._check_options( vd._check_options(
*make_opts_pm(language='chi_sim', output_type='pdfa'), {'chi_sim'} *make_opts_pm(language='chi_sim', output_type='pdfa'), {'chi_sim'}
) )
assert 'Ghostscript does not work correctly' in caplog.text assert 'does not work correctly' in caplog.text
with patch('ocrmypdf._exec.ghostscript.version', return_value='9.18'), patch( with patch('ocrmypdf._exec.ghostscript.version', return_value='9.18'), patch(
'ocrmypdf._exec.tesseract.has_textonly_pdf', return_value=True 'ocrmypdf._exec.tesseract.has_textonly_pdf', return_value=True