Files
Wallenc/Report/scripts/compress_screenshots.py

133 lines
3.7 KiB
Python
Executable File
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env python3
"""Сжатие только скриншотов в Report/images/ (не PlantUML PNG).
JPEG: quality=28 (ImageMagick).
PNG-скриншоты (Gradle, ручная схема): pngquant quality 2540.
"""
from __future__ import annotations
import re
import shutil
import subprocess
import sys
from pathlib import Path
# Имена из IMAGES_REGISTRY: Скриншот UI, Gradle, Ручная схема
SCREENSHOT_STEMS = {
"fig_05_local_vaults",
"fig_06_encrypt_dialog",
"fig_07_open_close_dialog",
"fig_08_rename_delete_dialog",
"fig_09_remote_vaults",
"fig_10_yandex_oauth",
"fig_12_tasks_screen",
"fig_13_tasks_notification",
"fig_33_storage_secrets_2fa",
"fig_34_2fa_single_token",
"fig_24_domain_class_manual",
"fig_27_gradle_domain_test",
"fig_28_gradle_usecases_test",
"fig_29_gradle_ui_test",
"fig_30_gradle_test_summary",
"fig_31_gradle_connected_test",
}
JPEG_QUALITY = "28"
PNGQUANT_QUALITY = "25-40"
def stem(path: Path) -> str:
return path.stem
def is_screenshot(path: Path) -> bool:
if path.suffix.lower() == ".jpg":
return stem(path) in SCREENSHOT_STEMS or path.name.startswith("fig_")
if path.suffix.lower() == ".png":
return stem(path) in SCREENSHOT_STEMS
return False
def size_kb(path: Path) -> float:
return path.stat().st_size / 1024
def compress_jpeg(path: Path, magick: str) -> None:
tmp = path.with_suffix(path.suffix + ".tmp")
subprocess.run(
[magick, str(path), "-strip", "-quality", JPEG_QUALITY, str(tmp)],
check=True,
capture_output=True,
)
tmp.replace(path)
def compress_png(path: Path, pngquant: str) -> bool:
tmp = path.with_suffix(".pngquant.tmp.png")
for quality in (PNGQUANT_QUALITY, "15-55", "10-80"):
try:
subprocess.run(
[
pngquant,
f"--quality={quality}",
"--force",
"--output",
str(tmp),
str(path),
],
check=True,
capture_output=True,
)
tmp.replace(path)
return True
except subprocess.CalledProcessError:
if tmp.exists():
tmp.unlink()
print(f" WARN: pngquant skip {path.name}", file=sys.stderr)
return False
def main() -> int:
report = Path(__file__).resolve().parents[1]
images = report / "images"
magick = shutil.which("magick") or shutil.which("convert")
pngquant = shutil.which("pngquant")
if not magick:
print("ERROR: ImageMagick (magick/convert) not found", file=sys.stderr)
return 1
if not pngquant:
print("ERROR: pngquant not found", file=sys.stderr)
return 1
targets = sorted(
p for p in images.iterdir() if p.is_file() and is_screenshot(p)
)
if not targets:
print("No screenshots to compress", file=sys.stderr)
return 1
total_before = 0.0
total_after = 0.0
for path in targets:
before = size_kb(path)
total_before += before
if path.suffix.lower() in {".jpg", ".jpeg"}:
compress_jpeg(path, magick)
else:
compress_png(path, pngquant)
after = size_kb(path)
total_after += after
pct = (1 - after / before) * 100 if before else 0
print(f" {path.name}: {before:.0f} KiB → {after:.0f} KiB ({pct:.0f}%)")
saved = (1 - total_after / total_before) * 100 if total_before else 0
print(
f"OK: {len(targets)} screenshots, "
f"{total_before:.0f} KiB → {total_after:.0f} KiB ({saved:.0f}%)"
)
return 0
if __name__ == "__main__":
sys.exit(main())