Пережаты картинки

This commit is contained in:
2026-05-31 22:34:26 +03:00
parent 3e4a6e8112
commit 7d3b213144
38 changed files with 16821 additions and 27485 deletions

View File

@@ -70,7 +70,10 @@
## Команды ## Команды
```bash ```bash
cd Report && bash scripts/render_puml.sh cd Report && bash scripts/render_puml.sh # PlantUML → PNG (dpi 72 + pngquant 2845)
cd Report && python scripts/check_images.py cd Report && python3 scripts/compress_screenshots.py # скриншоты: JPEG q28, pngquant 2540
cd Report && python3 scripts/check_images.py
typst compile --root .. ояснительная_записка_ПытковРЕ.typ" typst compile --root .. ояснительная_записка_ПытковРЕ.typ"
``` ```
Сначала `render_puml.sh`, затем `compress_screenshots.py` — диаграммы не пережимаются повторно.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 121 KiB

After

Width:  |  Height:  |  Size: 51 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 127 KiB

After

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 66 KiB

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 354 KiB

After

Width:  |  Height:  |  Size: 140 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 221 KiB

After

Width:  |  Height:  |  Size: 60 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 222 KiB

After

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 237 KiB

After

Width:  |  Height:  |  Size: 57 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 294 KiB

After

Width:  |  Height:  |  Size: 75 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 118 KiB

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 158 KiB

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 54 KiB

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 399 KiB

After

Width:  |  Height:  |  Size: 104 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 MiB

After

Width:  |  Height:  |  Size: 62 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 45 KiB

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 38 KiB

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 23 KiB

After

Width:  |  Height:  |  Size: 8.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 65 KiB

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

After

Width:  |  Height:  |  Size: 9.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 41 KiB

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 51 KiB

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 49 KiB

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 38 KiB

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 199 KiB

After

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 278 KiB

After

Width:  |  Height:  |  Size: 64 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 424 KiB

After

Width:  |  Height:  |  Size: 96 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 407 KiB

After

Width:  |  Height:  |  Size: 90 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 427 KiB

After

Width:  |  Height:  |  Size: 106 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 127 KiB

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 7.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 254 KiB

After

Width:  |  Height:  |  Size: 67 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 171 KiB

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 76 KiB

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 68 KiB

After

Width:  |  Height:  |  Size: 26 KiB

View File

@@ -3,8 +3,9 @@
skinparam monochrome true skinparam monochrome true
skinparam shadowing false skinparam shadowing false
skinparam roundcorner 0 skinparam roundcorner 0
skinparam dpi 72
skinparam defaultFontName "Liberation Serif" skinparam defaultFontName "Liberation Serif"
skinparam defaultFontSize 12 skinparam defaultFontSize 11
skinparam defaultFontColor black skinparam defaultFontColor black
skinparam backgroundColor white skinparam backgroundColor white
skinparam ArrowColor black skinparam ArrowColor black

View File

@@ -0,0 +1,132 @@
#!/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())

View File

@@ -48,4 +48,22 @@ export PLANTUML_LIMIT_SIZE="${PLANTUML_LIMIT_SIZE:-16384}"
${GOST_CFG:+-config "$GOST_CFG"} \ ${GOST_CFG:+-config "$GOST_CFG"} \
-o "$IMG_DIR" "${PUML_FILES[@]}" -o "$IMG_DIR" "${PUML_FILES[@]}"
echo "Done. $(ls -1 "$IMG_DIR"/fig_*.png 2>/dev/null | wc -l) PNG in images/" # Лёгкое сжатие только свежесгенерированных PNG из .puml (скриншоты не трогаем).
PNGQUANT="${PNGQUANT:-pngquant}"
PUML_PNG_QUALITY="${PUML_PNG_QUALITY:-28-45}"
if command -v "$PNGQUANT" >/dev/null 2>&1; then
for puml in "${PUML_FILES[@]}"; do
base="$(basename "$puml" .puml)"
png="$IMG_DIR/${base}.png"
if [[ -f "$png" ]]; then
tmp="${png}.pquant.tmp"
"$PNGQUANT" --quality="$PUML_PNG_QUALITY" --force --output "$tmp" "$png"
mv -f "$tmp" "$png"
fi
done
echo "PNGquant ($PUML_PNG_QUALITY) applied to PlantUML outputs."
else
echo "WARN: pngquant not found, PlantUML PNG left uncompressed" >&2
fi
echo "Done. $(ls -1 "$IMG_DIR"/fig_*.png 2>/dev/null | wc -l) PNG in images/ (dpi 72, see plantuml-gost.cfg)."

File diff suppressed because one or more lines are too long