diff --git a/src/ocrmypdf/_sync.py b/src/ocrmypdf/_sync.py index 1d256c92..f15dbbaf 100644 --- a/src/ocrmypdf/_sync.py +++ b/src/ocrmypdf/_sync.py @@ -165,6 +165,12 @@ def exec_page_sync(page_context): visible_image_out = create_visible_page_jpg( visible_image_out, page_context ) + visible_image_out = ( + page_context.plugin_manager.hook.filter_page_image( + page=page_context, image_filename=Path(visible_image_out) + ) + or visible_image_out + ) pdf_page_from_image_out = create_pdf_page_from_image( visible_image_out, page_context ) diff --git a/src/ocrmypdf/example.py b/src/ocrmypdf/example.py index 73b1b544..926831c3 100644 --- a/src/ocrmypdf/example.py +++ b/src/ocrmypdf/example.py @@ -1,13 +1,15 @@ import logging +from PIL import Image + from ocrmypdf import hookimpl log = logging.getLogger(__name__) @hookimpl -def install_cli(parser): - parser.add_argument('--invert', action='store_true') +def add_options(parser): + parser.add_argument('--grayscale-ocr', action='store_true') @hookimpl @@ -22,7 +24,15 @@ def validate(pdfinfo, options): @hookimpl def filter_ocr_image(page, image): - if page.options.invert: - log.info("inverting") - return image.invert() + if page.options.grayscale_ocr: + log.info("graying") + return image.convert('L') return image + + +@hookimpl +def filter_page_image(page, image_filename): + output = image_filename.with_suffix('.jpg') + with Image.open(image_filename) as im: + im.save(output) + return output diff --git a/src/ocrmypdf/pluginspec.py b/src/ocrmypdf/pluginspec.py index 76eed1cc..3a9620c4 100644 --- a/src/ocrmypdf/pluginspec.py +++ b/src/ocrmypdf/pluginspec.py @@ -16,6 +16,8 @@ # along with OCRmyPDF. If not, see . from argparse import ArgumentParser, Namespace +from pathlib import Path +from typing import Optional import pluggy from PIL import Image @@ -49,11 +51,15 @@ def validate(pdfinfo: 'PdfInfo', options: Namespace) -> None: options contains the "work order" to process a particular file. pdfinfo contains information about the input file obtained after loading and - parsing. + parsing. The plugin may modify the options. For example, you could decide + that a certain type of file should be treated with ``options.force_ocr = True`` + based on information in its pdfinfo. The plugin may raise InputFileError or any ExitCodeException to request - normal termination. If the plugin raises another exception type, ocrmypdf - will abort with an error and hold the plugin responsible. + normal termination. ocrmypdf will hold the plugin responsible for raising + exceptions of any other type. + + The return value is ignored. To abort processing, raise an ExitCodeException. """ @@ -64,3 +70,19 @@ def filter_ocr_image(page: 'PageContext', image: Image) -> Image: This is the image that OCR sees, not what the user sees when they view the PDF. """ + + +@hookspec(firstresult=True) +def filter_page_image(page: 'PageContext', image_filename: Path) -> Path: + """Called to filter the whole page before it is inserted into the PDF. + + A whole page image is only produced when preprocessing command line arguments + are issued or when ``--force-ocr`` is issued. If no whole page is image is + produced for a given page, this function will not be called. This is not + the image that will be shown to OCR. + + ocrmypdf will create the PDF page based on the image format used. If you + convert the image to a JPEG, the output page will be created as a JPEG, etc. + Note that the ocrmypdf image optimization stage may ultimately chose a + different format. + """