Preserve full opaque HD backgrounds and source-supported small cues

This commit is contained in:
raptorreplica committed 2026-10-12 08:40:14 +11:00
1 parent a02c9b0679
commit e95d060b0c
13 files changed
+1022 -33

No files matched your search

+76
View File
@@ -0,0 +1,76 @@
import sys
sys.dont_write_bytecode=True
from pathlib import Path
import hashlib,importlib.util,json,tempfile,unittest
from PIL import Image
OUT=Path(__file__).resolve().parent
sys.path.insert(0,str(Path(__file__).resolve().parents[1]/"tools"))
import hd_art_audit as audit
class PythonRoundingMirror(unittest.TestCase):
def setUp(self):
self.temp=tempfile.TemporaryDirectory(prefix='python-fixture-',dir=OUT)
self.addCleanup(self.temp.cleanup)
self.root=Path(self.temp.name)
self.payload=b'synthetic original payload'
self.picture=Image.new('RGBA',(8,5),(80,100,120,255))
self.frame={'source_sha256':hashlib.sha256(self.payload).hexdigest(),'logical_width':8,'logical_height':5,'origin':[0,0],'file':'fixture.png'}
def artwork(self,size,alpha=255):
Image.new('RGBA',size,(80,100,120,alpha)).save(self.root/'fixture.png')
def check(self):
return audit.validate_hd_frame(self.root,self.frame,self.payload,self.picture)
def test_full_opaque_landscape_has_only_integer_aspect_rounding(self):
self.picture=Image.new('RGBA',(320,200),(80,100,120,255))
self.frame.update(logical_width=320,logical_height=200,crop=[0,0,1586,992])
self.artwork((1586,992))
self.assertEqual(self.check(),1280*800*4)
def test_full_image_none_and_explicit_crop_accept_rounding(self):
self.artwork((17,11))
self.assertEqual(self.check(),17*11*4)
self.frame['crop']=[0,0,17,11]
self.assertEqual(self.check(),17*11*4)
def test_portrait_rounding_accepts_and_arbitrary_aspect_rejects(self):
self.picture=Image.new('RGBA',(5,8),(0,0,0,255))
self.frame.update(logical_width=5,logical_height=8)
self.artwork((11,17));self.assertEqual(self.check(),11*17*4)
self.artwork((12,17))
with self.assertRaisesRegex(ValueError,'aspect differs'):self.check()
def test_nonopaque_raw_rejected_before_resampling(self):
for alpha in (0,128,254):
with self.subTest(alpha=alpha):
raw=Image.new('RGBA',(161,101),(0,0,0,255));raw.putpixel((160,100),(0,0,0,alpha))
raw.save(self.root/'fixture.png')
with self.assertRaisesRegex(ValueError,'fully opaque'):self.check()
def test_transparent_original_cannot_use_rounding(self):
self.picture.putpixel((0,0),(0,0,0,0));self.artwork((17,11))
with self.assertRaisesRegex(ValueError,'aspect differs'):self.check()
def test_partial_crop_never_gets_exception(self):
self.artwork((18,12))
for crop in ([0,0,17,11],[1,1,17,11]):
with self.subTest(crop=crop):
self.frame['crop']=crop
with self.assertRaisesRegex(ValueError,'aspect differs'):self.check()
def test_exact_aspect_transparent_source_and_cropped_atlas_are_unchanged(self):
self.picture.putpixel((0,0),(0,0,0,0));self.artwork((20,12))
raw=Image.open(self.root/'fixture.png').convert('RGBA');raw.putpixel((2,2),(0,0,0,0));raw.save(self.root/'fixture.png')
self.frame['crop']=[2,2,16,10]
self.assertEqual(self.check(),16*10*4)
def test_half_tie_wrong_aspect_low_resolution_hash_and_origin_stay_rejected(self):
self.assertFalse(audit.integer_rounded_aspect(5,6,2,2))
self.artwork((15,10))
with self.assertRaisesRegex(ValueError,'twice'):self.check()
self.artwork((17,11));self.frame['source_sha256']='wrong'
with self.assertRaisesRegex(ValueError,'hash'):self.check()
self.frame['source_sha256']=hashlib.sha256(self.payload).hexdigest();self.frame['origin']=[1,0]
with self.assertRaisesRegex(ValueError,'anchor'):self.check()
def test_common_scale_nearest_integer_fixtures(self):
checked=0
for w in range(1,17):
for h in range(1,17):
for numerator in range(128,1025):
self.assertTrue(audit.integer_rounded_aspect((w*numerator+32)//64,(h*numerator+32)//64,w,h))
checked+=1
self.assertEqual(checked,229632)
if __name__=='__main__':unittest.main(verbosity=2)
+66
View File
@@ -0,0 +1,66 @@
import sys
from pathlib import Path
sys.path.insert(0,str(Path(__file__).resolve().parents[1]/"tools"))
import copy, struct, unittest, tempfile,hashlib
from pathlib import Path
from PIL import Image
from hd_frame_policy import validate_frame_policy, _indices
class FramePolicyTests(unittest.TestCase):
def setUp(self):
self.frame={"logical_width":2,"logical_height":2}
self.raw=struct.pack("<iiiii",1,0,0,2,2)+bytes([5,239,0,30])
def test_absent_or_explicit_default_metadata_is_valid(self):
validate_frame_policy(self.frame,self.raw)
self.frame.update(preserve_reserved_coverage=False,native_nearest_cues=[])
validate_frame_policy(self.frame,self.raw)
def test_valid_explicit_flags_and_sorted_ordinary_cells(self):
self.frame.update(preserve_reserved_coverage=True,native_nearest_cues=[[0,0],[1,0]])
validate_frame_policy(self.frame,self.raw)
def test_coverage_type_is_strict(self):
for value in [0,1,"yes",None,[],{}]:
with self.subTest(value=value),self.assertRaises(ValueError):
validate_frame_policy(dict(self.frame,preserve_reserved_coverage=value))
def test_coordinate_structure_bounds_types_order_duplicates_limit(self):
for value in [None,"yes",{},[[0]],[[0,0,0]],[[True,0]],[[0.0,0]],[[-1,0]],[[2,0]],[[0,2]],[[0,0],[0,0]],[[1,0],[0,0]],[[0,0]]*65]:
with self.subTest(value=value),self.assertRaises(ValueError):
validate_frame_policy(dict(self.frame,native_nearest_cues=value),self.raw)
def test_ordinary_cues_never_use_reserved_source_indices(self):
self.frame['native_nearest_cues']=[[0,0]]
for label in [240,244,245,249,250,255]:
with self.subTest(label=label),self.assertRaises(ValueError):
validate_frame_policy(self.frame,self.raw[:20]+bytes([label,5,5,5]))
def test_sparse_source_requires_actual_complete_coverage(self):
header=struct.pack('<iiiii',0,0,0,2,2)
end=struct.pack('<iiii',0,0,-1,0)
sparse=header+struct.pack('<iiii',0,0,0,2)+bytes([5,5])+end
self.frame['native_nearest_cues']=[[0,0]]
with self.assertRaises(ValueError):validate_frame_policy(self.frame,sparse)
complete=header+struct.pack('<iiii',0,0,0,2)+bytes([5,5])+struct.pack('<iiii',0,1,0,2)+bytes([5,5])+end
validate_frame_policy(self.frame,complete)
def test_checked_source_rejects_invalid_or_truncated_original(self):
self.frame['native_nearest_cues']=[[0,0]]
for payload in [b'',self.raw[:22],struct.pack('<iiiii',1,0,0,4096,4096),struct.pack('<iiiii',3,0,0,2,2)]:
with self.subTest(payload=payload),self.assertRaises(ValueError):validate_frame_policy(self.frame,payload)
def test_matched_candidate_tool_checks_flags_and_exact_target_bindings(self):
from hd_candidate_review import proposal_frames
f=dict(self.frame,frame=0,file='a.png',origin=[0,0],source_sha256='00',native_nearest_cues=[[0,0]])
pack={'sequences':[{'name':'a','base_asset':1,'frame_count':1,'frames':[f]}]}
self.assertEqual(set(proposal_frames(pack)),{'00001'})
bad=copy.deepcopy(pack);bad['sequences'][0]['frames'][0]['preserve_reserved_coverage']=1
with self.assertRaises(ValueError):proposal_frames(bad)
bad=copy.deepcopy(pack);bad['targets']=[dict(f,asset='00001',native_nearest_cues=[])]
with self.assertRaises(ValueError):proposal_frames(bad)
def test_matched_art_audit_checks_original_index_and_transparency(self):
from hd_art_audit import validate_hd_frame
with tempfile.TemporaryDirectory() as temp:
root=Path(temp);Image.new('RGBA',(8,8),(10,20,30,255)).save(root/'a.png')
f=dict(self.frame,frame=0,file='a.png',origin=[0,0],source_sha256=hashlib.sha256(self.raw).hexdigest(),native_nearest_cues=[[0,0]])
picture=Image.new('RGBA',(2,2),(10,20,30,255))
self.assertEqual(validate_hd_frame(root,f,self.raw,picture),8*8*4)
reserved=self.raw[:20]+bytes([253,5,5,5]);f['source_sha256']=hashlib.sha256(reserved).hexdigest()
with self.assertRaisesRegex(ValueError,'ordinary'):validate_hd_frame(root,f,reserved,picture)
def test_unknown_frame_policy_is_rejected(self):
with self.assertRaisesRegex(ValueError,'unknown'):validate_frame_policy(dict(self.frame,imaginary_cue_rule=True))
if __name__=='__main__':unittest.main()