Files
Sanctification/spikes/rejected-compositions/calling-disciples-layer-proof-SOL-fonts/build.py

78 lines
5.3 KiB
Python

#!/usr/bin/env python3
"""Four controlled font proofs using retained SOL v2 assembly and validation."""
from pathlib import Path
import hashlib, json, subprocess, sys
import numpy as np
from PIL import Image
ROOT = Path(__file__).resolve().parent
OUT = ROOT/'output'
(OUT/'review').mkdir(parents=True, exist_ok=True)
choices = json.loads((ROOT/'font-choices.json').read_text())
def run(*args):
subprocess.run([str(x) for x in args], check=True)
def pixels(path):
return np.asarray(Image.open(path).convert('RGBA'))
def pixel_sha(path):
return hashlib.sha256(pixels(path).tobytes()).hexdigest()
reports = {}
for item in choices:
folder = ROOT/'variants'/item['slug']
if '--review-only' not in sys.argv:
run(sys.executable, folder/'build.py')
reports[item['slug']] = json.loads((folder/'output'/f"{item['prefix']}-validation.json").read_text())
# A controlled experiment: exactly the same source inputs and material layers.
preserved = {}
provenance = json.loads((ROOT/'source/provenance.json').read_text())
for relative in ['source/calling-disciples-SOL-art.png', 'source/calling-disciples-SOL-frame-runtime.png']:
hashes = [hashlib.sha256((ROOT/'variants'/i['slug']/relative).read_bytes()).hexdigest() for i in choices]
assert len(set(hashes)) == 1
preserved[relative] = {'byteIdenticalAcrossVariants': True, 'sha256': hashes[0]}
for suffix in ['art-master', 'frame-runtime', 'backing-normal', 'backing-borderless', 'normal-runtime-overlay']:
hashes = [pixel_sha(ROOT/'variants'/i['slug']/'output/layers'/f"{i['prefix']}-{suffix}.png") for i in choices]
assert len(set(hashes)) == 1, suffix
assert hashes[0] == provenance['preservedLayerDecodedRGBA_SHA256'][suffix], suffix
preserved[suffix] = {'pixelIdenticalAcrossVariants': True, 'pixelIdenticalToSOLv2': True, 'decodedRGBA_SHA256': hashes[0]}
for item in choices:
layout = json.loads((ROOT/'variants'/item['slug']/'layout.json').read_text())
assert layout['fontSizes'] == {'title':112, 'verse':80, 'reference':57}
assert layout['backingTreatment']['baseColor'] == '#f4ead4'
assert layout['backingTreatment']['palette']['type'] == '#263f50'
assert reports[item['slug']]['status'] == 'passed'
label_font = ROOT/'variants/noto-sans/fonts/NotoSans-Regular.ttf'
for size in [500,1000]:
tiles = []
for item in choices:
source = ROOT/'variants'/item['slug']/'output/cards'/f"{item['prefix']}-normal-{size}.png"
tile = OUT/'review'/f"{item['slug']}-{size}-tile.png"
label = 'Helvetica* / Nimbus Sans' if item['slug']=='helvetica' else item['renderedFamily']
run('magick',source,'-background','#ede9df','-gravity','north','-splice',f'0x{size//7}','-font',label_font,'-fill','#263f50','-pointsize',str(size//20),'-gravity','north','-annotate',f'+0+{size//35}',label,tile)
tiles.append(tile)
run('magick','montage',*tiles,'-tile','4x1','-geometry',f'{size}x{size*7//5+size//7}+18+18','-background','#ede9df',OUT/'review'/f'calling-disciples-SOL-font-comparison-{size}.png')
# Real 320px-wide digital view, separately labeled so it is clear what is shown.
tiles=[]
for item in choices:
source=ROOT/'variants'/item['slug']/'output/cards'/f"{item['prefix']}-normal-2000.png"
tile=OUT/'review'/f"{item['slug']}-320-tile.png"
label='Helvetica* / Nimbus Sans' if item['slug']=='helvetica' else item['renderedFamily']
run('magick',source,'-filter','Lanczos','-resize','320x448','-background','#ede9df','-gravity','north','-splice','0x48','-font',label_font,'-fill','#263f50','-pointsize','16','-gravity','north','-annotate','+0+12',label,tile)
tiles.append(tile)
run('magick','montage',*tiles,'-tile','4x1','-geometry','320x496+14+14','-background','#ede9df',OUT/'review/calling-disciples-SOL-font-comparison-320.png')
# Header and verse crops preserve native size, simplifying stroke/glyph inspection.
for section,geometry in [('headers','2000x300+0+60'),('verses','2000x560+0+2180')]:
tiles=[]
for item in choices:
source=ROOT/'variants'/item['slug']/'output/cards'/f"{item['prefix']}-normal-2000.png"
tile=OUT/'review'/f"{item['slug']}-{section}.png"
run('magick',source,'-crop',geometry,'+repage','-background','#ede9df','-gravity','north','-splice','0x70','-font',label_font,'-fill','#263f50','-pointsize','36','-annotate','+0+16',item['label'],tile)
tiles.append(tile)
run('magick','montage',*tiles,'-tile','1x4','-geometry','+10+10','-background','#ede9df',OUT/'review'/f'calling-disciples-SOL-font-comparison-{section}.png')
report = {'status':'passed','proof':'Controlled font comparison; only font family varies','fontChoices':choices,'palette':{'text':'#263f50','backingBase':'#f4ead4'},'preserved':preserved,'variantValidation':reports,'checks':{'sameFontSizesBaselinesAndLineBreaks':True,'samePaletteAndBackingAcrossVariants':True,'exactReference':'Matthew 4:19 • NKJV','noVisibleCategoryOrSubtitle':True},'limitations':['Helvetica is not installed; its proof explicitly uses pinned Nimbus Sans rather than genuine Helvetica glyphs.','Visual preference and readability require user review; automated glyph fit does not establish optical quality.','No human or moving-light harness approval is claimed.']}
(OUT/'validation.json').write_text(json.dumps(report,indent=2)+'\n')
print(f'Four-font comparison built and validated: {ROOT}')