69 lines
4.6 KiB
Python
69 lines
4.6 KiB
Python
#!/usr/bin/env python3
|
|
"""Rebuild shared templates, or check their decoded-pixel repeatability."""
|
|
from pathlib import Path
|
|
import argparse, json, subprocess, tempfile
|
|
import numpy as np
|
|
from PIL import Image
|
|
from library import ROOT, digest, load_tier
|
|
|
|
NAMES=['frame-normal','frame-textless','backing-normal','backing-borderless','overlay-normal']
|
|
|
|
def rebuild(tier,version,refresh=False):
|
|
directory=ROOT/tier/version
|
|
layout=json.loads((directory/'layout.json').read_text())
|
|
if not refresh: load_tier(tier,version)
|
|
with tempfile.TemporaryDirectory(prefix='sanctification-tier-') as tmp:
|
|
temporary=Path(tmp)
|
|
for name in NAMES[:-1]:
|
|
target=temporary/f'{name}-2000.png'
|
|
if version=='v1':
|
|
Image.open(directory/'exports'/target.name).save(target)
|
|
else:
|
|
source=directory/'source'/f'{name}.svg'
|
|
subprocess.run(['inkscape',str(source),'--export-type=png',f'--export-filename={target}','--export-width=2000','--export-height=2800'],check=True,stdout=subprocess.DEVNULL)
|
|
if version=='v1':
|
|
Image.open(directory/'exports/overlay-normal-2000.png').save(temporary/'overlay-normal-2000.png')
|
|
else:
|
|
back=Image.open(temporary/'backing-normal-2000.png').convert('RGBA')
|
|
Image.alpha_composite(back,Image.open(temporary/'frame-normal-2000.png').convert('RGBA')).save(temporary/'overlay-normal-2000.png')
|
|
for name in NAMES:
|
|
master=Image.open(temporary/f'{name}-2000.png').convert('RGBA')
|
|
for width in [1000,500]:
|
|
master.resize((width,width*7//5),Image.Resampling.LANCZOS).save(temporary/f'{name}-{width}.png')
|
|
for width in [2000,1000,500]:
|
|
p=temporary/f'{name}-{width}.png'
|
|
if refresh: (directory/'exports'/p.name).write_bytes(p.read_bytes())
|
|
else:
|
|
expected=Image.open(directory/'exports'/p.name).convert('RGBA')
|
|
assert np.array_equal(np.asarray(expected),np.asarray(Image.open(p).convert('RGBA'))),f'Non-repeatable {tier}/{version}/{p.name}'
|
|
assets={name:f'exports/{name}-2000.png' for name in NAMES}
|
|
if refresh:
|
|
files={str(p.relative_to(directory)):{'sha256':digest(p)} for p in sorted(directory.rglob('*')) if p.is_file() and p.name!='manifest.json'}
|
|
(directory/'manifest.json').write_text(json.dumps({'schemaVersion':1,'tier':tier,'version':version,'canvas':[2000,2800],'reviewStatus':layout['reviewStatus'],'assets':assets,'files':files},indent=2)+'\n')
|
|
checks=[]
|
|
for width in [2000,1000,500]:
|
|
for name in ['frame-normal','frame-textless','overlay-normal']:
|
|
a=np.asarray(Image.open(directory/'exports'/f'{name}-{width}.png').convert('RGBA'))[:,:,3]
|
|
assert all(a[y,x]==255 for x,y in [(0,0),(width-1,0),(0,len(a)-1),(width-1,len(a)-1)])
|
|
checks.append({'width':width,'opaqueCorners':True})
|
|
a=np.asarray(Image.open(directory/'exports/overlay-normal-2000.png').convert('RGBA'))[:,:,3]
|
|
for x,y,w,h in layout['normalBacking']:
|
|
assert np.all(a[y+10:y+h-10,x+10:x+w-10]==255),f'Panel holes in {tier}'
|
|
assert not np.any(a[430:2100,160:1840]),f'Art window obstruction in {tier}'
|
|
if layout['normalRelationship']=='floating':
|
|
band=layout['perimeterWidth']; x=layout['normalBacking'][0][0]
|
|
assert not np.any(a[220:280,band+3:x-3]),f'Lost intentional reveal in {tier}'
|
|
result={'tier':tier,'version':version,'status':'passed','repeatability':'decoded pixels checked' if not refresh else 'initial exports created','checks':checks,'geometry':{'opaquePanels':True,'clearFocalWindow':True,'relationship':layout['normalRelationship']}}
|
|
print(json.dumps(result))
|
|
return result
|
|
|
|
if __name__=='__main__':
|
|
parser=argparse.ArgumentParser(description=__doc__)
|
|
parser.add_argument('--refresh',action='store_true',help='Write exports/manifests for an explicitly revised template; use a new version directory after approval.')
|
|
parser.add_argument('--tier',choices=['common','uncommon','rare','extraordinary'])
|
|
parser.add_argument('--version',default='v2')
|
|
args=parser.parse_args()
|
|
results=[rebuild(tier,args.version,args.refresh) for tier in ([args.tier] if args.tier else ['common','uncommon','rare','extraordinary'])]
|
|
if not args.refresh: (ROOT/'repeatability.json').write_text(json.dumps({'status':'passed','templates':results},indent=2)+'\n')
|
|
if args.refresh: (ROOT/'validation.json').write_text(json.dumps({'status':'passed','templates':results,'visualReview':'pending-user-review','movingLight':'not performed'},indent=2)+'\n')
|