#!/usr/bin/env python3 """Desktop pixel-diff for the header lang-toggle move (spec acceptance 7). Compares two screenshot dirs (intro/results, EN+FR) and proves the ONLY change is inside the header strip: the diff bbox must sit entirely above `hdr_bottom` (masked), and everything below the header must be bit-identical. Prints a self-jitter baseline DIR_A vs DIR_A2 (same version captured twice) for the jitter-controlled comparison. Usage: python3 audit/lang_right_pixdiff.py BEFORE AFTER HDR_BOTTOM python3 audit/lang_right_pixdiff.py SELFJITTER DIR DIR2 HDR_BOTTOM """ import os, sys from PIL import Image, ImageChops # Usage: pixdiff.py BEFORE AFTER HDR_BOTTOM [PREFIX] # pixdiff.py SELFJITTER DIR DIR2 HDR_BOTTOM [PREFIX] if sys.argv[1] == 'SELFJITTER': cross = False A, B, HB = sys.argv[2], sys.argv[3], int(sys.argv[4]) PREFIX = sys.argv[5] if len(sys.argv) > 5 else None else: cross = True A, B, HB = sys.argv[1], sys.argv[2], int(sys.argv[3]) PREFIX = sys.argv[4] if len(sys.argv) > 4 else None fa = sorted(f for f in os.listdir(A) if f.endswith('.png') and (PREFIX is None or f.startswith(PREFIX))) zero, all_in_hdr = True, True for f in fa: p = os.path.join(A, f) q = os.path.join(B, f) if not os.path.exists(q): if cross: print(f'{f}: MISSING in {B}'); zero = False; all_in_hdr = False else: print(f'{f}: (no self-jitter pair, skipping)') continue ia, ib = Image.open(p).convert('RGB'), Image.open(q).convert('RGB') if ia.size != ib.size: print(f'{f}: SIZE DIFF {ia.size} vs {ib.size}'); zero = False; all_in_hdr = False; continue W, H = ia.size d = ImageChops.difference(ia, ib) bbox = d.getbbox() if bbox is None: print(f'{f}: 0 px (identical)'); continue x0, y0, x1, y1 = bbox # mask the header strip: crop everything below HB and diff that below = ImageChops.difference(ia.crop((0, HB, W, H)), ib.crop((0, HB, W, H))) below_bbox = below.getbbox() hist = d.convert('L').histogram() ndiff = sum(hist[1:]) below_hist = below.convert('L').histogram() ndiff_below = sum(below_hist[1:]) if ndiff_below > 0: print(f'{f}: {ndiff} px total, {ndiff_below} px BELOW header (bbox {bbox}) <-- LEAK') zero = False; all_in_hdr = False else: tag = 'header-only' if cross else 'identical' print(f'{f}: {ndiff} px total, 0 px below y={HB}, bbox_top={y0} bbox_bot={y1} [{tag}]') if not cross: zero = zero and (ndiff == 0) print('---') if cross: print('PIXDIFF-HEADER-ONLY' if all_in_hdr else 'PIXDIFF-LEAK-BELOW-HEADER') sys.exit(0 if all_in_hdr else 1) else: print('SELFJITTER-ZERO' if zero else 'SELFJITTER-NONZERO') sys.exit(0 if zero else 1)