Added support for changing color conversion strategy

This commit is contained in:
James R. Barlow
2023-09-20 01:08:15 -07:00
parent 35a1eaf62a
commit e3c813fc67
11 changed files with 123 additions and 50 deletions
+66 -46
View File
@@ -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
+10
View File
@@ -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)"
+15 -3
View File
@@ -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",
"-",
+1
View File
@@ -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,
+3
View File
@@ -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.
+1
View File
@@ -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,
+1
View File
@@ -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,
+1
View File
@@ -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,
+1
View File
@@ -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,
+4 -1
View File
@@ -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([])