diff --git a/src/ocrmypdf/_options.py b/src/ocrmypdf/_options.py index 499fea1e..7364aeb5 100644 --- a/src/ocrmypdf/_options.py +++ b/src/ocrmypdf/_options.py @@ -161,8 +161,6 @@ class OCROptions(BaseModel): tesseract_non_ocr_timeout: float | None = None tesseract_downsample_above: int = 32767 tesseract_downsample_large_images: bool | None = None - user_words: str | None = None - user_patterns: str | None = None # Legacy ghostscript options (for backward compatibility) pdfa_image_compression: str | None = None diff --git a/src/ocrmypdf/_validation_coordinator.py b/src/ocrmypdf/_validation_coordinator.py index 8ac640df..9f734e16 100644 --- a/src/ocrmypdf/_validation_coordinator.py +++ b/src/ocrmypdf/_validation_coordinator.py @@ -42,54 +42,47 @@ class ValidationCoordinator: def _validate_plugin_contexts(self, options: OCROptions) -> None: """Validate plugin options that require external context.""" - if not self.registry: - return - - registered_models = self.registry.get_registered_models() + # For now, we'll run the plugin validation directly since the models + # are still being integrated. This ensures the validation warnings + # and checks still work as expected. - # Validate Tesseract options with language context - if 'tesseract' in registered_models: - from ocrmypdf.builtin_plugins.tesseract_ocr import TesseractOptions - - # Create TesseractOptions from legacy fields for validation - tesseract_data = { - 'config': options.tesseract_config, - 'pagesegmode': options.tesseract_pagesegmode, - 'oem': options.tesseract_oem, - 'thresholding': options.tesseract_thresholding, - 'timeout': options.tesseract_timeout, - 'non_ocr_timeout': options.tesseract_non_ocr_timeout or 180.0, - 'downsample_large_images': options.tesseract_downsample_large_images, - 'downsample_above': options.tesseract_downsample_above, - 'user_words': options.user_words, - 'user_patterns': options.user_patterns, - } - # Remove None values - tesseract_data = {k: v for k, v in tesseract_data.items() if v is not None} - - tesseract_options = TesseractOptions(**tesseract_data) - tesseract_options.validate_with_context(options.languages) + # Run Tesseract validation + self._validate_tesseract_options(options) - # Validate Optimize options with external program context - if 'optimize' in registered_models: - from ocrmypdf.builtin_plugins.optimize import OptimizeOptions - from ocrmypdf._exec import jbig2enc, pngquant - - optimize_data = { - 'level': options.optimize, - 'jpeg_quality': options.jpeg_quality or 0, - 'png_quality': options.png_quality or 0, - 'jbig2_lossy': options.jbig2_lossy or False, - 'jbig2_page_group_size': options.jbig2_page_group_size or 0, - 'jbig2_threshold': options.jbig2_threshold, - } - - optimize_options = OptimizeOptions(**optimize_data) - external_programs = { - 'pngquant': pngquant.available(), - 'jbig2enc': jbig2enc.available(), - } - optimize_options.validate_with_context(external_programs) + # Run Optimize validation + self._validate_optimize_options(options) + + def _validate_tesseract_options(self, options: OCROptions) -> None: + """Validate Tesseract options.""" + # Check pagesegmode warning + if options.tesseract_pagesegmode in (0, 2): + log.warning( + "The tesseract-pagesegmode you selected will disable OCR. " + "This may cause processing to fail." + ) + + # Check downsample consistency + if ( + options.tesseract_downsample_above != 32767 + and not options.tesseract_downsample_large_images + ): + log.warning( + "The --tesseract-downsample-above argument will have no effect unless " + "--tesseract-downsample-large-images is also given." + ) + + def _validate_optimize_options(self, options: OCROptions) -> None: + """Validate optimization options.""" + # Check optimization consistency + if options.optimize == 0 and any([ + options.jbig2_lossy, + options.png_quality and options.png_quality > 0, + options.jpeg_quality and options.jpeg_quality > 0 + ]): + log.warning( + "The arguments --jbig2-lossy, --png-quality, and --jpeg-quality " + "will be ignored because --optimize=0." + ) def _validate_cross_cutting_concerns(self, options: OCROptions) -> None: """Validate cross-cutting concerns that span multiple plugins.""" @@ -98,14 +91,12 @@ class ValidationCoordinator: 1 for opt in [options.force_ocr, options.skip_text, options.redo_ocr] if opt ) if exclusive_options >= 2: - from ocrmypdf.exceptions import BadArgsError - raise BadArgsError("Choose only one of --force-ocr, --skip-text, --redo-ocr.") + raise ValueError("Choose only one of --force-ocr, --skip-text, --redo-ocr.") # Validate redo_ocr compatibility if options.redo_ocr: if options.deskew or options.clean_final or options.remove_background: - from ocrmypdf.exceptions import BadArgsError - raise BadArgsError( + raise ValueError( "--redo-ocr is not currently compatible with --deskew, " "--clean-final, and --remove-background" ) @@ -114,8 +105,7 @@ class ValidationCoordinator: if options.output_type == 'none' and str(options.output_file) not in ( os.devnull, '-' ): - from ocrmypdf.exceptions import BadArgsError - raise BadArgsError( + raise ValueError( "Since you specified `--output-type none`, the output file " f"{options.output_file} cannot be produced. Set the output file to " "`-` to suppress this message."