Added support for changing color conversion strategy
This commit is contained in:
@@ -6,53 +6,55 @@ set -o errexit
|
||||
|
||||
__ocrmypdf_arguments()
|
||||
{
|
||||
local arguments="--help (show help message)
|
||||
--language (language(s) of the file to be OCRed)
|
||||
--image-dpi (assume this DPI if input image DPI is unknown)
|
||||
--output-type (select PDF output options)
|
||||
--sidecar (write OCR to text file)
|
||||
--version (print program version and exit)
|
||||
--jobs (how many worker processes to use)
|
||||
--quiet (suppress INFO messages)
|
||||
--verbose (set verbosity level)
|
||||
--title (set metadata)
|
||||
--author (set metadata)
|
||||
--subject (set metadata)
|
||||
--keywords (set metadata)
|
||||
--rotate-pages (rotate pages to correct orientation)
|
||||
--remove-background (attempt to remove background from pages)
|
||||
--deskew (fix small horizontal alignment skew)
|
||||
--clean (clean document images before OCR)
|
||||
--clean-final (clean document images and keep result)
|
||||
--unpaper-args (a quoted string of arguments to pass to unpaper)
|
||||
--oversample (oversample images to this DPI)
|
||||
--remove-vectors (don\'t send vector objects to OCR)
|
||||
--threshold (threshold images before OCR)
|
||||
--force-ocr (OCR documents that already have printable text)
|
||||
--skip-text (skip OCR on any pages that already contain text)
|
||||
--redo-ocr (redo OCR on any pages that seem to have OCR already)
|
||||
local arguments="\
|
||||
--help (show help message)
|
||||
--language (language(s) of the file to be OCRed)
|
||||
--image-dpi (assume this DPI if input image DPI is unknown)
|
||||
--output-type (select PDF output options)
|
||||
--sidecar (write OCR to text file)
|
||||
--version (print program version and exit)
|
||||
--jobs (how many worker processes to use)
|
||||
--quiet (suppress INFO messages)
|
||||
--verbose (set verbosity level)
|
||||
--title (set metadata)
|
||||
--author (set metadata)
|
||||
--subject (set metadata)
|
||||
--keywords (set metadata)
|
||||
--rotate-pages (rotate pages to correct orientation)
|
||||
--remove-background (attempt to remove background from pages)
|
||||
--deskew (fix small horizontal alignment skew)
|
||||
--clean (clean document images before OCR)
|
||||
--clean-final (clean document images and keep result)
|
||||
--unpaper-args (a quoted string of arguments to pass to unpaper)
|
||||
--oversample (oversample images to this DPI)
|
||||
--remove-vectors (don\'t send vector objects to OCR)
|
||||
--threshold (threshold images before OCR)
|
||||
--force-ocr (OCR documents that already have printable text)
|
||||
--skip-text (skip OCR on any pages that already contain text)
|
||||
--redo-ocr (redo OCR on any pages that seem to have OCR already)
|
||||
--invalidate-digital-signatures (remove digital signatures from PDF)
|
||||
--skip-big (skip OCR on pages larger than this many MPixels)
|
||||
--optimize (select optimization level)
|
||||
--jpeg-quality (JPEG quality [0..100])
|
||||
--png-quality (PNG quality [0..100])
|
||||
--jbig2-lossy (enable lossy JBIG2 (see docs))
|
||||
--pages (apply OCR to only the specified pages)
|
||||
--max-image-mpixels (image decompression bomb threshold)
|
||||
--pdf-renderer (select PDF renderer options)
|
||||
--rotate-pages-threshold (page rotation confidence)
|
||||
--pdfa-image-compression (set PDF/A image compression options)
|
||||
--fast-web-view (if file size if above this amount in MB linearize PDF)
|
||||
--plugin (name of plugin to import)
|
||||
--keep-temporary-files (keep temporary files (debug)
|
||||
--tesseract-config (set custom tesseract config file)
|
||||
--tesseract-pagesegmode (set tesseract --psm)
|
||||
--tesseract-oem (set tesseract --oem)
|
||||
--tesseract-thresholding (set tesseract image thresholding)
|
||||
--tesseract-timeout (maximum number of seconds to wait for OCR)
|
||||
--user-words (specify location of user words file)
|
||||
--user-patterns (specify location of user patterns file)
|
||||
--no-progress-bar (disable the progress bar)
|
||||
--skip-big (skip OCR on pages larger than this many MPixels)
|
||||
--optimize (select optimization level)
|
||||
--jpeg-quality (JPEG quality [0..100])
|
||||
--png-quality (PNG quality [0..100])
|
||||
--jbig2-lossy (enable lossy JBIG2 (see docs))
|
||||
--pages (apply OCR to only the specified pages)
|
||||
--max-image-mpixels (image decompression bomb threshold)
|
||||
--pdf-renderer (select PDF renderer options)
|
||||
--rotate-pages-threshold (page rotation confidence)
|
||||
--pdfa-image-compression (set PDF/A image compression options)
|
||||
--fast-web-view (if file size if above this amount in MB linearize PDF)
|
||||
--plugin (name of plugin to import)
|
||||
--keep-temporary-files (keep temporary files (debug)
|
||||
--tesseract-config (set custom tesseract config file)
|
||||
--tesseract-pagesegmode (set tesseract --psm)
|
||||
--tesseract-oem (set tesseract --oem)
|
||||
--tesseract-thresholding (set tesseract image thresholding)
|
||||
--tesseract-timeout (maximum number of seconds to wait for OCR)
|
||||
--user-words (specify location of user words file)
|
||||
--user-patterns (specify location of user patterns file)
|
||||
--no-progress-bar (disable the progress bar)
|
||||
--color-conversion-strategy (select color conversion strategy)
|
||||
"
|
||||
|
||||
COMPREPLY=( $( compgen -W "$arguments" -- "$cur") )
|
||||
@@ -192,6 +194,20 @@ sauvola (use Sauvola thresholding)"
|
||||
fi
|
||||
}
|
||||
|
||||
__ocrmypdf_color-conversion-strategy()
|
||||
{
|
||||
local choices="LeaveColorUnchanged (default)
|
||||
CMYK (convert to CMYK)
|
||||
Gray (convert to grayscale)
|
||||
RGB (convert to RGB)
|
||||
UseDeviceIndependentColor (convert with device independent color)"
|
||||
|
||||
COMPREPLY=( $( compgen -W "$choices" -- "$cur") )
|
||||
# Remove description if only one completion exists
|
||||
if [[ ${#COMPREPLY[*]} -eq 1 ]]; then
|
||||
COMPREPLY=( ${COMPREPLY[0]%% *} )
|
||||
fi
|
||||
}
|
||||
|
||||
__ocrmypdf_check_previous()
|
||||
{
|
||||
@@ -251,6 +267,10 @@ __ocrmypdf_check_previous()
|
||||
_filedir
|
||||
return 0
|
||||
;;
|
||||
--color-conversion-strategy)
|
||||
__ocrmypdf_color-conversion-strategy
|
||||
return 0
|
||||
;;
|
||||
esac
|
||||
|
||||
return 1
|
||||
|
||||
@@ -129,4 +129,14 @@ complete -c ocrmypdf -r -l user-words -d "specify location of user words file"
|
||||
complete -c ocrmypdf -r -l user-patterns -d "specify location of user patterns file"
|
||||
complete -c ocrmypdf -x -l fast-web-view -d "if file size if above this amount in MB, linearize PDF"
|
||||
|
||||
function __fish_ocrmypdf_color_conversion_strategy
|
||||
echo -e "LeaveColorUnchanged\t"(_ "do not convert color spaces (default)")
|
||||
echo -e "CMYK\t"(_ "convert all color spaces to CMYK")
|
||||
echo -e "Gray\t"(_ "convert all color spaces to grayscale")
|
||||
echo -e "RGB\t"(_ "convert all color spaces to RGB")
|
||||
echo -e "UseDeviceIndependentColor\t"(_ "convert all color spaces to ICC-based color spaces")
|
||||
end
|
||||
|
||||
complete -c ocrmypdf -x -l color-conversion-strategy -a '(__fish_ocrmypdf_color_conversion_strategy)' -d "set color conversion strategy"
|
||||
|
||||
complete -c ocrmypdf -x -a "(__fish_complete_suffix .pdf; __fish_complete_suffix .PDF; __fish_complete_suffix .jpg; __fish_complete_suffix .png)"
|
||||
|
||||
@@ -28,6 +28,17 @@ except AttributeError:
|
||||
# Pillow 9 shim
|
||||
Transpose = Image # type: ignore
|
||||
|
||||
|
||||
COLOR_CONVERSION_STRATEGIES = frozenset(
|
||||
[
|
||||
'CMYK',
|
||||
'Gray',
|
||||
'LeaveColorUnchanged',
|
||||
'RGB',
|
||||
'UseDeviceIndependentColor',
|
||||
]
|
||||
)
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
# Most reliable way to get the bitness of Python interpreter, according to Python docs
|
||||
@@ -160,6 +171,7 @@ def generate_pdfa(
|
||||
output_file: os.PathLike,
|
||||
*,
|
||||
compression: str,
|
||||
color_conversion_strategy: str,
|
||||
pdf_version: str = '1.5',
|
||||
pdfa_part: str = '2',
|
||||
progressbar_class=None,
|
||||
@@ -209,16 +221,16 @@ def generate_pdfa(
|
||||
"-dBATCH",
|
||||
"-dNOPAUSE",
|
||||
"-dSAFER",
|
||||
"-dCompatibilityLevel=" + str(pdf_version),
|
||||
f"-dCompatibilityLevel={str(pdf_version)}",
|
||||
"-sDEVICE=pdfwrite",
|
||||
"-dAutoRotatePages=/None",
|
||||
"-sColorConversionStrategy=" + strategy,
|
||||
f"-sColorConversionStrategy={color_conversion_strategy}",
|
||||
]
|
||||
+ (['-dPDFSTOPONERROR'] if stop_on_error else [])
|
||||
+ compression_args
|
||||
+ [
|
||||
"-dJPEGQ=95",
|
||||
"-dPDFA=" + pdfa_part,
|
||||
f"-dPDFA={pdfa_part}",
|
||||
"-dPDFACompatibilityPolicy=1",
|
||||
"-o",
|
||||
"-",
|
||||
|
||||
@@ -793,6 +793,7 @@ def convert_to_pdfa(input_pdf: Path, input_ps_stub: Path, context: PdfContext) -
|
||||
pdfmark=input_ps_stub,
|
||||
output_file=output_file,
|
||||
compression=options.pdfa_image_compression,
|
||||
color_conversion_strategy=options.color_conversion_strategy,
|
||||
pdfa_part=options.output_type[-1], # is pdfa-1, pdfa-2, or pdfa-3
|
||||
progressbar_class=(
|
||||
context.plugin_manager.hook.get_progressbar_class()
|
||||
|
||||
@@ -14,6 +14,20 @@ from ocrmypdf.subprocess import check_external_program
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@hookimpl
|
||||
def add_options(parser):
|
||||
gs = parser.add_argument_group("Ghostscript", "Advanced control of Ghostscript")
|
||||
gs.add_argument(
|
||||
'--color-conversion-strategy',
|
||||
action='store',
|
||||
type=str,
|
||||
metavar='STRATEGY',
|
||||
choices=ghostscript.COLOR_CONVERSION_STRATEGIES,
|
||||
default='LeaveColorUnchanged',
|
||||
help="Set Ghostscript color conversion strategy",
|
||||
)
|
||||
|
||||
|
||||
@hookimpl
|
||||
def check_options(options):
|
||||
"""Check that the options are valid for this plugin."""
|
||||
@@ -33,6 +47,10 @@ def check_options(options):
|
||||
|
||||
if options.output_type == 'pdfa':
|
||||
options.output_type = 'pdfa-2'
|
||||
if options.color_conversion_strategy not in ghostscript.COLOR_CONVERSION_STRATEGIES:
|
||||
raise ValueError(
|
||||
f"Invalid color conversion strategy: {options.color_conversion_strategy}"
|
||||
)
|
||||
|
||||
|
||||
@hookimpl
|
||||
@@ -68,6 +86,7 @@ def generate_pdfa(
|
||||
pdfmark,
|
||||
output_file,
|
||||
compression,
|
||||
color_conversion_strategy,
|
||||
pdf_version,
|
||||
pdfa_part,
|
||||
progressbar_class,
|
||||
@@ -78,6 +97,7 @@ def generate_pdfa(
|
||||
pdf_pages=[*pdf_pages, pdfmark],
|
||||
output_file=output_file,
|
||||
compression=compression,
|
||||
color_conversion_strategy=color_conversion_strategy,
|
||||
pdf_version=pdf_version,
|
||||
pdfa_part=pdfa_part,
|
||||
progressbar_class=progressbar_class,
|
||||
|
||||
@@ -467,6 +467,7 @@ def generate_pdfa(
|
||||
pdfmark: Path,
|
||||
output_file: Path,
|
||||
compression: str,
|
||||
color_conversion_strategy: str,
|
||||
pdf_version: str,
|
||||
pdfa_part: str,
|
||||
progressbar_class,
|
||||
@@ -489,6 +490,8 @@ def generate_pdfa(
|
||||
possible. For lossless, all images should be converted to FlateEncode
|
||||
(lossless PNG). If an empty string, the PDF generator should make its
|
||||
own decisions about how to encode images.
|
||||
color_conversion_strategy: A valid Ghostscript color conversion strategy
|
||||
name.
|
||||
pdf_version: The minimum PDF version that the output file should be.
|
||||
At its own discretion, the PDF/A generator may raise the version,
|
||||
but should not lower it.
|
||||
|
||||
@@ -28,6 +28,7 @@ def generate_pdfa(pdf_pages, pdfmark, output_file, compression, pdf_version, pdf
|
||||
pdfmark=pdfmark,
|
||||
output_file=output_file,
|
||||
compression=compression,
|
||||
color_conversion_strategy='LeaveColorUnchanged',
|
||||
pdf_version=pdf_version,
|
||||
pdfa_part=pdfa_part,
|
||||
progressbar_class=None,
|
||||
|
||||
@@ -30,6 +30,7 @@ def generate_pdfa(pdf_pages, pdfmark, output_file, compression, pdf_version, pdf
|
||||
pdfmark=pdfmark,
|
||||
output_file=output_file,
|
||||
compression=compression,
|
||||
color_conversion_strategy='LeaveColorUnchanged',
|
||||
pdf_version=pdf_version,
|
||||
pdfa_part=pdfa_part,
|
||||
progressbar_class=None,
|
||||
|
||||
@@ -25,6 +25,7 @@ def generate_pdfa(pdf_pages, pdfmark, output_file, compression, pdf_version, pdf
|
||||
pdfmark=pdfmark,
|
||||
output_file=output_file,
|
||||
compression=compression,
|
||||
color_conversion_strategy='LeaveColorUnchanged',
|
||||
pdf_version=pdf_version,
|
||||
pdfa_part=pdfa_part,
|
||||
progressbar_class=None,
|
||||
|
||||
@@ -35,6 +35,7 @@ def generate_pdfa(
|
||||
pdfmark=pdfmark,
|
||||
output_file=output_file,
|
||||
compression=compression,
|
||||
color_conversion_strategy='LeaveColorUnchanged',
|
||||
pdf_version=pdf_version,
|
||||
pdfa_part=pdfa_part,
|
||||
progressbar_class=None,
|
||||
|
||||
@@ -86,7 +86,8 @@ def test_unset_metadata(output_type, field, resources, outpdf):
|
||||
'title': b'NFY5f7Ft2DWMkxLhXwxvFf7eWR2KeK3vEDcd',
|
||||
'author': b'yXaryipxyRk9dVjWjSSaVaNCKeLRgEVzPRMp',
|
||||
'subject': b't49vimctvnuH7ZeAjAkv52ACvWFjcnm5MPJr',
|
||||
'keywords': b's9EeALwUg7urA7fnnhm5EtUyC54sW2WPUzqh'}
|
||||
'keywords': b's9EeALwUg7urA7fnnhm5EtUyC54sW2WPUzqh',
|
||||
}
|
||||
|
||||
p = run_ocrmypdf(
|
||||
input_file,
|
||||
@@ -364,6 +365,7 @@ def test_prevent_gs_invalid_xml(resources, outdir):
|
||||
options = get_parser().parse_args(
|
||||
args=['-j', '1', '--output-type', 'pdfa-2', 'a.pdf', 'b.pdf']
|
||||
)
|
||||
options.color_conversion_strategy = 'LeaveColorUnchanged'
|
||||
pdfinfo = PdfInfo(outdir / 'layers.rendered.pdf')
|
||||
context = PdfContext(
|
||||
options, outdir, outdir / 'layers.rendered.pdf', pdfinfo, get_plugin_manager([])
|
||||
@@ -404,6 +406,7 @@ def test_malformed_docinfo(caplog, resources, outdir):
|
||||
'b.pdf',
|
||||
]
|
||||
)
|
||||
options.color_conversion_strategy = 'LeaveColorUnchanged'
|
||||
pdfinfo = PdfInfo(outdir / 'layers.rendered.pdf')
|
||||
context = PdfContext(
|
||||
options, outdir, outdir / 'layers.rendered.pdf', pdfinfo, get_plugin_manager([])
|
||||
|
||||
Reference in New Issue
Block a user