Files
jiapuapp/design-pipeline/tests/test_build_scroll_skins.py
T
2026-07-22 17:31:38 +08:00

116 lines
4.4 KiB
Python

import hashlib
import json
import sys
import tempfile
import unittest
from pathlib import Path
from PIL import Image
SCRIPTS = Path(__file__).resolve().parents[1] / "scripts"
sys.path.insert(0, str(SCRIPTS))
from asset_quality import analyze_asset
from build_scroll_skins import (
build_asset,
remove_chroma_background,
sanitize_output_edges,
stretch_safe_center,
)
class BuildScrollSkinsTests(unittest.TestCase):
def setUp(self):
self.directory = tempfile.TemporaryDirectory()
self.addCleanup(self.directory.cleanup)
self.root = Path(self.directory.name)
def test_chroma_background_becomes_transparent_black(self):
image = Image.new("RGB", (4, 2), (0, 255, 0))
image.putpixel((1, 0), (180, 30, 20))
cleaned = remove_chroma_background(image, (0, 255, 0), tolerance=80)
self.assertEqual((0, 0, 0, 0), cleaned.getpixel((0, 0)))
self.assertEqual((180, 30, 20, 255), cleaned.getpixel((1, 0)))
def test_safe_center_stretch_preserves_caps_and_exact_size(self):
image = Image.new("RGBA", (30, 10), (150, 20, 10, 255))
for y in range(10):
for x in range(5):
image.putpixel((x, y), (220, 170, 40, 255))
image.putpixel((29 - x, y), (220, 170, 40, 255))
output = stretch_safe_center(image, output_size=(60, 20), cap_width=5, padding=2)
self.assertEqual((60, 20), output.size)
self.assertEqual((0, 0, 0, 0), output.getpixel((0, 0)))
self.assertEqual((220, 170, 40, 255), output.getpixel((3, 10)))
self.assertEqual((150, 20, 10, 255), output.getpixel((30, 10)))
self.assertEqual((220, 170, 40, 255), output.getpixel((56, 10)))
def test_sanitizes_only_forbidden_edge_artifacts(self):
image = Image.new("RGBA", (3, 1), (248, 240, 220, 255))
image.putpixel((0, 0), (0, 255, 0, 128))
image.putpixel((1, 0), (250, 250, 250, 96))
cleaned = sanitize_output_edges(image)
self.assertEqual((0, 0, 0, 0), cleaned.getpixel((0, 0)))
self.assertEqual((0, 0, 0, 0), cleaned.getpixel((1, 0)))
self.assertEqual((248, 240, 220, 255), cleaned.getpixel((2, 0)))
def asset(self, asset_id):
"""返回与现行判别式 schema 一致的最小透明卷轴测试资产。"""
return {
"id": asset_id,
"source": "source.png",
"output": "output.png",
"sourcePixels": {"width": 32, "height": 16},
"outputPixels": {"width": 60, "height": 30},
"alpha": {"required": True, "transparentOuterPadding": 1, "cornerMaxAlpha": 0},
"edge": {
"forbidChromaResidue": True,
"forbidLightFringe": True,
"premultipliedAlphaCheck": True,
},
"quality": {"maxBytes": 10000, "colorSpace": "sRGB"},
"processing": {
"mode": "chroma-stretch",
"capWidth": 4,
"keyColor": "#00FF00",
"keyTolerance": 80,
"paletteColors": 8,
},
}
def save_test_source(self):
source = Image.new("RGB", (32, 16), (0, 255, 0))
for y in range(1, 15):
for x in range(1, 31):
source.putpixel((x, y), (120 + (x % 30) * 4, 20 + y, 10))
source.save(self.root / "source.png")
def test_build_asset_honors_declared_palette_size(self):
self.save_test_source()
build_asset(self.asset("palette-test"), self.root)
with Image.open(self.root / "output.png") as output:
visible_colors = {
pixel[:3] for pixel in output.convert("RGBA").get_flattened_data() if pixel[3] > 0
}
self.assertLessEqual(len(visible_colors), 8)
def test_same_input_produces_identical_bytes_and_report_twice(self):
self.save_test_source()
asset = self.asset("deterministic-test")
snapshots = []
for _ in range(2):
build_asset(asset, self.root)
output = self.root / "output.png"
snapshots.append(
(
hashlib.sha256(output.read_bytes()).hexdigest(),
json.dumps(analyze_asset(output, asset, self.root), ensure_ascii=False, sort_keys=True),
)
)
self.assertEqual(snapshots[0], snapshots[1])
if __name__ == "__main__":
unittest.main()