from PIL import Image,ImageDraw,ImageFilter
import numpy as np
from pathlib import Path
from collections import deque
A=Path(__file__).parent/'deliverables/assets';A.mkdir(parents=True,exist_ok=True)
source=A/'scale410.png'
im=Image.open(source).convert('RGBA');ar=np.array(im);white=(ar[:,:,:3].min(axis=2)>247).astype('uint8')*255
mask=Image.fromarray(white).copy();ImageDraw.floodfill(mask,(0,0),128);bg=np.array(mask)==128;ar[:,:,3]=np.where(bg,0,255);device=Image.fromarray(ar);device=device.crop(device.getbbox());device.save(A/'410-original-cutout.png')
background=Image.open(A/'scene-clean-background.png').convert('RGBA');background.save(A/'scene-clean-background.png')
food=Image.open(A/'food-pan-flat-sheet.png').convert('RGBA');fw,fh=food.size
pans=[]
for j in range(8):
 cell=food.crop((j%4*fw//4,j//4*fh//2,(j%4+1)*fw//4,(j//4+1)*fh//2))
 ar=np.array(cell);wh=(ar[:,:,:3].min(axis=2)>235).astype('uint8')*255
 m=Image.fromarray(wh).copy()
 for corner in [(0,0),(cell.width-1,0),(0,cell.height-1),(cell.width-1,cell.height-1)]:ImageDraw.floodfill(m,corner,128)
 ar[:,:,3]=np.where(np.array(m)==128,0,255);cell=Image.fromarray(ar);cell=cell.crop(cell.getbbox());cell.save(A/f'food-pan-{j+1}.png');pans.append(cell)
scale=2;can=background.resize((background.width*scale,background.height*scale),Image.Resampling.LANCZOS)
placements=[(707,323,148),(827,348,148),(947,374,148),(1068,401,148),(561,526,162),(690,557,162),(821,591,162),(953,627,162)]
# Align every front edge with the restaurant counter's vanishing direction.
shear=0.23
for j,(cx,base,h) in enumerate(placements):
 w=int(h*device.width/device.height)
 dev=device.resize((w*scale,h*scale),Image.Resampling.LANCZOS)
 dh=int((h+shear*w)*scale)
 dev=dev.transform((w*scale,dh),Image.Transform.AFFINE,(1,0,0,-shear,1,0),Image.Resampling.BICUBIC)
 x=int(cx-w/2);y=int(base-h-shear*w/2)
 can.alpha_composite(dev,(x*scale,y*scale))
 pw=int(w*.78);ph=int(pw*.30)
 pan=pans[j].resize((pw*scale,ph*scale),Image.Resampling.LANCZOS)
 pan=pan.transform((pw*scale,int((ph+shear*pw)*scale)),Image.Transform.AFFINE,(1,0,0,-shear,1,0),Image.Resampling.BICUBIC)
 can.alpha_composite(pan,(int(cx-pw/2)*scale,int(base-ph-shear*pw/2-4)*scale))
# Restore foreground people from the unchanged scene plate for correct occlusion.
for poly in [[(472,430),(512,434),(536,460),(548,502),(549,544),(532,570),(527,675),(504,705),(472,694),(456,625),(452,513)],[(867,499),(900,496),(919,518),(925,548),(940,560),(939,595),(932,629),(925,740),(904,784),(872,778),(864,714),(850,630),(838,577),(842,535)]]:
 m=Image.new('L',background.size);ImageDraw.Draw(m).polygon(poly,fill=255);fg=background.copy();fg.putalpha(m);can.alpha_composite(fg.resize(can.size,Image.Resampling.LANCZOS))
can.convert('RGB').save(A/'scene-original-410-composite.jpg',quality=96)
# Insert the exact single-floor dashboard screenshot into the front-hall display.
board=Image.open(A/'nutrition-display.png').convert('RGBA')
dst=[(1296*scale,65*scale),(1361*scale,36*scale),(1358*scale,178*scale),(1293*scale,211*scale)]
src=[(0,0),(board.width,0),(board.width,board.height),(0,board.height)]
mat=[];rhs=[]
for (x,y),(u,v) in zip(dst,src):
 mat.extend([[x,y,1,0,0,0,-u*x,-u*y],[0,0,0,x,y,1,-v*x,-v*y]]);rhs.extend([u,v])
coef=np.linalg.solve(np.array(mat,float),np.array(rhs,float));warp=board.transform(can.size,Image.Transform.PERSPECTIVE,tuple(coef),Image.Resampling.BICUBIC)
mm=Image.new('L',can.size);ImageDraw.Draw(mm).polygon(dst,fill=255);warp.putalpha(mm);can.alpha_composite(warp);can.convert('RGB').save(A/'scene-original-410-composite.jpg',quality=96)
