From 9a4493f211125e0b9d101059c2a255a89af3c791 Mon Sep 17 00:00:00 2001 From: "James R. Barlow" Date: Fri, 18 Jan 2019 05:33:28 -0800 Subject: [PATCH] Add --unpaper-args Needs test code and stricter validation --- src/ocrmypdf/__main__.py | 18 ++++++++++++++++ src/ocrmypdf/_pipeline.py | 2 +- src/ocrmypdf/exec/unpaper.py | 41 ++++++++++++++++++++---------------- 3 files changed, 42 insertions(+), 19 deletions(-) diff --git a/src/ocrmypdf/__main__.py b/src/ocrmypdf/__main__.py index c2cb06bb..f7a9047f 100755 --- a/src/ocrmypdf/__main__.py +++ b/src/ocrmypdf/__main__.py @@ -278,6 +278,13 @@ preprocessing.add_argument( help="Clean page as above, and incorporate the cleaned image in the final " "PDF. Might remove desired content.", ) +preprocessing.add_argument( + '--unpaper-args', + type=str, + default=None, + help="A quoted string of arguments to pass to unpaper. Requires --clean. " + "Example: --unpaper-args '--layout double'.", +) preprocessing.add_argument( '--oversample', metavar='DPI', @@ -623,12 +630,23 @@ def _optional_program_recommended(name, version_fn, min_version, for_argument): def check_options_preprocessing(options, log): + if options.unpaper_args and not options.clean: + raise argparse.ArgumentError( + None, "--clean is required for --unpaper-args" + ) if any((options.clean, options.clean_final)): from .exec import unpaper _optional_program_required( 'unpaper', unpaper.version, '6.1', '--clean, --clean-final' ) + try: + if options.unpaper_args: + options.unpaper_args = unpaper.validate_custom_args( + options.unpaper_args + ) + except Exception as e: + raise argparse.ArgumentError(None, str(e)) def check_options_ocr_behavior(options, log): diff --git a/src/ocrmypdf/_pipeline.py b/src/ocrmypdf/_pipeline.py index 4fe52970..abe90f9c 100644 --- a/src/ocrmypdf/_pipeline.py +++ b/src/ocrmypdf/_pipeline.py @@ -566,7 +566,7 @@ def preprocess_clean(input_file, output_file, log, context): pageinfo = get_pageinfo(input_file, context) dpi = get_page_square_dpi(pageinfo, options) - unpaper.clean(input_file, output_file, dpi, log) + unpaper.clean(input_file, output_file, dpi, log, options.unpaper_args) def select_ocr_image(infiles, output_file, log, context): diff --git a/src/ocrmypdf/exec/unpaper.py b/src/ocrmypdf/exec/unpaper.py index 87104f99..cf53fd8a 100644 --- a/src/ocrmypdf/exec/unpaper.py +++ b/src/ocrmypdf/exec/unpaper.py @@ -19,6 +19,7 @@ # https://github.com/Flameeyes/unpaper/blob/master/doc/basic-concepts.md import os +import shlex import sys from functools import lru_cache from subprocess import STDOUT, CalledProcessError, check_output @@ -86,21 +87,25 @@ def run(input_file, output_file, dpi, log, mode_args): Image.open(output_pnm.name).save(output_file, dpi=(dpi, dpi)) -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 - ], - ) +def validate_custom_args(args: str): + unpaper_args = shlex.split(args) + if any('/' in arg for arg in unpaper_args): + raise ValueError('No filenames allowed in --unpaper-args') + return unpaper_args + + +def clean(input_file, output_file, dpi, log, unpaper_args=None): + default_args = [ + '--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 + ] + if not unpaper_args: + unpaper_args = default_args + run(input_file, output_file, dpi, log, unpaper_args)