repomatic.images module

Image optimization using external CLI tools.

Replaces the Docker-based calibreapp/image-actions GitHub Action with direct invocations of lightweight CLI tools, removing the Docker dependency.

Tools used per format:

  • PNG: oxipng (lossless, multithreaded Rust optimizer).

  • JPEG/JPG: jpegoptim (lossless Huffman optimization + metadata stripping).

Note

Both tools are strictly lossless: oxipng finds optimal PNG encoding parameters without altering pixel data, and jpegoptim (without -m) rewrites Huffman tables only. This means optimization is idempotent — a second run produces no further changes, so the workflow never creates noisy PRs for negligible savings.

Warning

WebP and AVIF are intentionally not optimized. The only available tools (cwebp, avifenc) work by lossy re-encoding: decode → re-compress at a target quality. This is not idempotent — each pass re-compresses the previous output, producing progressively smaller (and worse) files. The earlier calibreapp/image-actions suffered from this: it required multiple workflow runs to stabilize below the savings threshold, generating repeated PRs with diminishing returns and cumulative quality loss. Lossless WebP/AVIF modes exist but typically increase file size when applied to already lossy-encoded images, making them counterproductive. Since WebP and AVIF are modern formats chosen specifically for their compression efficiency, files in these formats are almost always already well-optimized at creation time.

class repomatic.images.OptimizationResult(path, before_bytes, after_bytes)[source]

Bases: object

Result of optimizing a single image file.

path: Path
before_bytes: int
after_bytes: int
property saved_bytes: int

Bytes saved by optimization.

property saved_pct: float

Percentage saved, as a float 0–100.

repomatic.images.optimize_image(path, min_savings_pct, min_savings_bytes=1024)[source]

Optimize a single image file in-place.

Parameters:
  • path (Path) – Path to the image file.

  • min_savings_pct (float) – Minimum percentage savings to keep the result. If savings are below this threshold, the original file is restored.

  • min_savings_bytes (int) – Minimum absolute byte savings to keep the result. Prevents noisy diffs for tiny files where even a high percentage represents negligible absolute savings.

Return type:

OptimizationResult | None

Returns:

An OptimizationResult if the file was optimized, or None if the format is unsupported, the required tool is missing, or savings were below the threshold.

repomatic.images.optimize_images(image_files, min_savings_pct=5, min_savings_bytes=1024)[source]

Optimize a list of image files.

Parameters:
  • image_files (Sequence[Path]) – Paths to image files.

  • min_savings_pct (float) – Minimum percentage savings to keep an optimization.

  • min_savings_bytes (int) – Minimum absolute byte savings to keep an optimization.

Return type:

list[OptimizationResult]

Returns:

List of results for files that were successfully optimized.

repomatic.images.generate_markdown_summary(results)[source]

Generate a markdown summary table of optimization results.

Produces a table similar to calibreapp/image-actions output, showing before/after sizes and percentage improvement for each optimized file.

Return type:

str