Introduce pdf_to_hocr API

This commit is contained in:
James R. Barlow
2023-10-24 00:52:31 -07:00
parent b3de5833d3
commit 0443e87345
4 changed files with 96 additions and 5 deletions
+1 -1
View File
@@ -11,7 +11,7 @@ from ocrmypdf import helpers, hocrtransform, pdfa, pdfinfo
from ocrmypdf._concurrent import Executor
from ocrmypdf._jobcontext import PageContext, PdfContext
from ocrmypdf._version import PROGRAM_NAME, __version__
from ocrmypdf.api import Verbosity, configure_logging, ocr
from ocrmypdf.api import Verbosity, configure_logging, ocr, pdf_to_hocr
from ocrmypdf.exceptions import (
BadArgsError,
DpiError,
+3 -1
View File
@@ -57,6 +57,7 @@ from ocrmypdf._validation import (
check_requested_output_file,
create_input_file,
report_output_file_size,
set_lossless_reconstruction,
)
from ocrmypdf.exceptions import ExitCode, ExitCodeException
from ocrmypdf.helpers import (
@@ -580,7 +581,7 @@ def run_hocr_pipeline(
options=options,
plugin_manager=plugin_manager,
api=True,
work_folder=options.output_file,
work_folder=options.output_folder,
)
# Gather pdfinfo and create context
pdfinfo = get_pdfinfo(
@@ -595,5 +596,6 @@ def run_hocr_pipeline(
options, work_folder, options.input_file, pdfinfo, plugin_manager
)
# Validate options are okay for this pdf
set_lossless_reconstruction(options)
validate_pdfinfo_options(context)
exec_hocr(context, executor)
+79
View File
@@ -374,6 +374,84 @@ def ocr( # noqa: D417
return run_pipeline(options=options, plugin_manager=plugin_manager, api=True)
def pdf_to_hocr(
input_pdf: Path,
output_folder: Path,
*,
language: Iterable[str] | None = None,
image_dpi: int | None = None,
jobs: int | None = None,
use_threads: bool | None = None,
title: str | None = None,
author: str | None = None,
subject: str | None = None,
keywords: str | None = None,
rotate_pages: bool | None = None,
remove_background: bool | None = None,
deskew: bool | None = None,
clean: bool | None = None,
clean_final: bool | None = None,
unpaper_args: str | None = None,
oversample: int | None = None,
remove_vectors: bool | None = None,
force_ocr: bool | None = None,
skip_text: bool | None = None,
redo_ocr: bool | None = None,
skip_big: float | None = None,
pages: str | None = None,
max_image_mpixels: float | None = None,
tesseract_config: Iterable[str] | None = None,
tesseract_pagesegmode: int | None = None,
tesseract_oem: int | None = None,
tesseract_thresholding: int | None = None,
tesseract_timeout: float | None = None,
tesseract_non_ocr_timeout: float | None = None,
tesseract_downsample_above: int | None = None,
tesseract_downsample_large_images: bool | None = None,
rotate_pages_threshold: float | None = None,
user_words: os.PathLike | None = None,
user_patterns: os.PathLike | None = None,
continue_on_soft_render_error: bool | None = None,
invalidate_digital_signatures: bool | None = None,
plugin_manager=None,
keep_temporary_files: bool | None = None,
**kwargs,
):
"""Run OCRmyPDF and produces an output folder containing hOCR files."""
# No new variable names should be assigned until these two steps are run
create_options_kwargs = {
k: v
for k, v in locals().items()
if k not in {'input_pdf', 'output_folder', 'kwargs'}
}
create_options_kwargs.update(kwargs)
parser = get_parser()
with _api_lock:
# We can't allow multiple ocrmypdf.ocr() threads to run in parallel, because
# they might install different plugins, and generally speaking we have areas
# of code that use global state.
if not plugin_manager:
plugin_manager = get_plugin_manager()
plugin_manager.hook.add_options(parser=parser) # pylint: disable=no-member
cmdline, deferred = _kwargs_to_cmdline(
defer_kwargs={'input_pdf', 'output_folder'}, **create_options_kwargs
)
cmdline.append(str(input_pdf))
cmdline.append(str(output_folder))
parser.enable_api_mode()
options = parser.parse_args(cmdline)
for keyword, val in deferred:
setattr(options, keyword, val)
delattr(options, 'output_file')
setattr(options, 'output_folder', output_folder)
return run_hocr_pipeline(options=options, plugin_manager=plugin_manager)
__all__ = [
'PageNumberFilter',
'Verbosity',
@@ -383,5 +461,6 @@ __all__ = [
'get_parser',
'get_plugin_manager',
'ocr',
'pdf_to_hocr',
'run_pipeline',
]
+13 -3
View File
@@ -3,8 +3,8 @@
from __future__ import annotations
import logging
from io import BytesIO, StringIO
from io import BytesIO
from pathlib import Path
import pytest
@@ -18,10 +18,20 @@ def test_language_list():
ocrmypdf.ocr('doesnotexist.pdf', '_.pdf', language=['eng', 'deu'])
def test_stream_api(resources):
def test_stream_api(resources: Path):
in_ = (resources / 'graph.pdf').open('rb')
out = BytesIO()
ocrmypdf.ocr(in_, out, tesseract_timeout=0.0)
out.seek(0)
assert b'%PDF' in out.read(1024)
def test_hocr_api(outdir):
ocrmypdf.pdf_to_hocr(
'tests/resources/multipage.pdf', outdir, language='eng', skip_text=True
)
assert (outdir / '000001_ocr_hocr.hocr').exists()
assert (outdir / '000006_ocr_hocr.hocr').exists()
assert not (outdir / '000004_ocr_hocr.hocr').exists()