Add SVG compression via npx svgo

Add vector extension support for .svg and route SVG files through npx svgo before raster compression.

Keep behavior fail-safe: missing npx/svgo or non-zero svgo exit returns None and preserves existing flow.

Extend tests for SVG discovery, SVG routing priority, and missing npx handling.

Co-Authored-By: Abacus.AI CLI <agent@abacus.ai>
This commit is contained in:
2026-06-08 13:40:45 +02:00
parent 89d0bb399c
commit 75059f829a
2 changed files with 84 additions and 2 deletions
+39 -1
View File
@@ -2,6 +2,7 @@ import tempfile
import unittest
import zipfile
from pathlib import Path
from unittest import mock
import pptx_image_compress as pic
@@ -14,8 +15,9 @@ class TestPptxImageCompress(unittest.TestCase):
(media_dir / "b.png").write_bytes(b"1")
(media_dir / "c.txt").write_bytes(b"1")
(media_dir / "d.GIF").write_bytes(b"1")
(media_dir / "e.svg").write_bytes(b"<svg/>")
images = pic.discover_images(media_dir)
self.assertEqual([p.name for p in images], ["a.jpg", "b.png", "d.GIF"])
self.assertEqual([p.name for p in images], ["a.jpg", "b.png", "d.GIF", "e.svg"])
def test_image_result_to_log_line(self):
image_result = pic.ImageProcessResult(
@@ -271,6 +273,42 @@ class TestPptxImageCompress(unittest.TestCase):
self.fail("Output should not be None")
self.assertEqual(out.name, "image1.png")
self.assertEqual(out.stat().st_size, 80)
def test_compress_svg_with_svgo_returns_none_when_npx_missing(self):
with tempfile.TemporaryDirectory() as td:
root = Path(td)
svg = root / "vector.svg"
svg.write_text("<svg></svg>", encoding="utf-8")
out_dir = root / "out"
with mock.patch("pptx_image_compress.which", return_value=None):
out = pic.compress_svg_with_svgo(svg, out_dir)
self.assertEqual(out, None)
def test_compress_image_with_routing_uses_svg_backend(self):
with tempfile.TemporaryDirectory() as td:
root = Path(td)
original = root / "vector.svg"
original.write_text("<svg></svg>", encoding="utf-8")
out_dir = root / "out"
out_dir.mkdir(parents=True, exist_ok=True)
vector_out = out_dir / "vector.svg"
vector_out.write_text("<svg/>", encoding="utf-8")
def fake_compressor(original_path: Path, out_subdir: Path, caesium_threads: int | None, quality: int, min_savings: str):
raise AssertionError("Raster compressor should not be called for svg")
with mock.patch("pptx_image_compress.compress_vector_image", return_value=vector_out):
out = pic.compress_image_with_routing(
compressor=fake_compressor,
original=original,
out_dir=out_dir,
caesium_threads=1,
quality=90,
min_savings="2%",
)
self.assertEqual(out, vector_out)
if __name__ == "__main__":