Split ocrmypdf.subprocess/__init__.py into three private submodules by concern (_run, _version, _check) and reduce __init__ to re-exports. Introduce ocrmypdf._exec._probe.ToolProbe to centralize the version()/ available() pattern each tool module was reimplementing, so the "is this tool installed and suitable?" question is cleanly distinct from the pure, picklable functions that do the work. Also replace the ghostscript module-import log.addFilter() side effect with an idempotent _ensure_log_filter_installed() called at the top of each work function, so the DuplicateFilter is present in subprocess workers without relying on import-time ordering. Public API of ocrmypdf.subprocess is unchanged.
43 lines
1.3 KiB
Python
43 lines
1.3 KiB
Python
# SPDX-FileCopyrightText: 2022 James R. Barlow
|
|
# SPDX-License-Identifier: MPL-2.0
|
|
|
|
"""Interface to pngquant executable."""
|
|
|
|
from __future__ import annotations
|
|
|
|
from pathlib import Path
|
|
from subprocess import PIPE
|
|
|
|
from ocrmypdf._exec._probe import ToolProbe
|
|
from ocrmypdf.subprocess import run
|
|
|
|
PROBE = ToolProbe(program='pngquant', version_regex=r'(\d+(\.\d+)*).*')
|
|
version = PROBE.version
|
|
available = PROBE.available
|
|
|
|
|
|
def quantize(input_file: Path, output_file: Path, quality_min: int, quality_max: int):
|
|
"""Quantize a PNG image using pngquant.
|
|
|
|
Args:
|
|
input_file: Input PNG image
|
|
output_file: Output PNG image
|
|
quality_min: Minimum quality to use
|
|
quality_max: Maximum quality to use
|
|
"""
|
|
with open(input_file, 'rb') as input_stream:
|
|
args = [
|
|
'pngquant',
|
|
'--force',
|
|
'--skip-if-larger',
|
|
'--quality',
|
|
f'{quality_min}-{quality_max}',
|
|
'--', # pngquant: stop processing arguments
|
|
'-', # pngquant: stream input and output
|
|
]
|
|
result = run(args, stdin=input_stream, stdout=PIPE, stderr=PIPE, check=False)
|
|
|
|
if result.returncode == 0:
|
|
# input_file could be the same as output_file, so we defer the write
|
|
output_file.write_bytes(result.stdout)
|