diff --git a/src/ocrmypdf/__main__.py b/src/ocrmypdf/__main__.py index c154e888..3e69effd 100755 --- a/src/ocrmypdf/__main__.py +++ b/src/ocrmypdf/__main__.py @@ -294,6 +294,12 @@ optimizing.add_argument( "Values have same meaning as with --jpeg-quality" ) ) +optimizing.add_argument( + '--jbig2-lossy', action='store_true', + help=("Enable JBIG2 lossy mode (better compression, not suitable for some " + "use cases - see documentation)." + ) +) optimizing.add_argument( '--jbig2-page-group-size', type=numeric(int, 1, 10000), default=0, metavar='N', @@ -517,10 +523,26 @@ def check_options_optimizing(options, log): _optional_program_required( 'pngquant', pngquant.version, '2.0.1', '--optimize {2,3}' ) + + if options.jbig2_lossy: + _optional_program_required( + 'jbig2', jbig2enc.version, '0.28', '--jbig2-lossy' + ) + elif options.optimize >= 2: + # Although we use JBIG2 for optimize=1, don't nag about it unless the + # user is asking for more optimization _optional_program_recommended( 'jbig2', jbig2enc.version, '0.28', '--optimize {2,3}' ) + if options.optimize == 0 and any([ + options.jbig2_lossy, options.png_quality, options.jpeg_quality + ]): + log.warning( + "The arguments --jbig2-lossy, --png-quality, and --jpeg-quality " + "will be ignored because --optimize=0." + ) + def check_options_advanced(options, log): if options.tesseract_oem and not tesseract.v4(): diff --git a/src/ocrmypdf/optimize.py b/src/ocrmypdf/optimize.py index cb940dc3..862bac6a 100644 --- a/src/ocrmypdf/optimize.py +++ b/src/ocrmypdf/optimize.py @@ -30,7 +30,6 @@ from . import leptonica from .helpers import re_symlink, fspath from .exec import pngquant, jbig2enc -DEFAULT_PAGE_GROUP_SIZE = 1 DEFAULT_JPEG_QUALITY = 75 DEFAULT_PNG_QUALITY = 70 @@ -363,7 +362,7 @@ def optimize( DEFAULT_PNG_QUALITY if options.optimize < 3 else 30 if options.jbig2_page_group_size == 0: options.jbig2_page_group_size = \ - DEFAULT_PAGE_GROUP_SIZE if options.optimize < 3 else 10 + 10 if options.jbig2_lossy else 1 pike = pikepdf.Pdf.open(input_file) @@ -401,12 +400,14 @@ def main(infile, outfile, level, jobs=1): class OptimizeOptions: """Emulate ocrmypdf's options""" - def __init__(self, jobs, optimize, jpeg_quality, png_quality): + def __init__( + self, jobs, optimize, jpeg_quality, png_quality, jb2lossy): self.jobs = jobs self.optimize = optimize self.jpeg_quality = jpeg_quality self.png_quality = png_quality self.jbig2_page_group_size = 0 + self.jbig2_lossy = jb2lossy logging.basicConfig(level=logging.DEBUG) log = logging.getLogger() @@ -416,7 +417,8 @@ def main(infile, outfile, level, jobs=1): jobs=jobs, optimize=int(level), jpeg_quality=0, # Use default - png_quality=0 + png_quality=0, + jb2lossy=False ) ctx.set_options(options) diff --git a/tests/test_optimize.py b/tests/test_optimize.py index a232f5a7..fa1072cf 100644 --- a/tests/test_optimize.py +++ b/tests/test_optimize.py @@ -64,19 +64,22 @@ def test_jpg_png_params(resources, outpdf, spoof_tesseract_noop): @pytest.mark.skipif(not jbig2enc.available(), reason='need jbig2enc') -@pytest.mark.parametrize('optimize', ['2', '3']) -def test_jbig2(optimize, resources, outpdf, spoof_tesseract_noop): - check_ocrmypdf( +@pytest.mark.parametrize('lossy', [False, True]) +def test_jbig2_lossy(lossy, resources, outpdf, spoof_tesseract_noop): + args = [ resources / 'ccitt.pdf', outpdf, '--image-dpi', '200', - '--optimize', optimize, '--jpg-quality', '50', '--png-quality', '20', - env=spoof_tesseract_noop - ) + '--optimize', 3, '--jpg-quality', '50', '--png-quality', '20' + ] + if lossy: + args.append('--jbig2-lossy') + + check_ocrmypdf(*args, env=spoof_tesseract_noop) pdf = pikepdf.open(outpdf) pim = pikepdf.PdfImage(next(iter(pdf.pages[0].images.values()))) assert pim.filters[0] == '/JBIG2Decode' - if optimize == '3': + if lossy: assert '/JBIG2Globals' in pim.decode_parms[0] else: assert len(pim.decode_parms) == 0