app
AI Flow: Video
Public Made by Adomby adom
Turn a board build into a narrated walkthrough video on your wiki page and YouTube.
main
"""Compose a 1280 x 720 thumbnail: the narrator (cut out) pointing at the product picture, and a two-line headline.
python3 compose.py --person pose-cut.png --product product.jpg --line1 "AI built this" --line2 "for my daughter." \
--tip 1230,555 --out thumb.jpg [--font /path/Bold.ttf] [--scale 0.54]
--tip is the fingertip in the person photo (pixels). The person is placed so the fingertip lands on the product
picture's edge. No logo is added: the film is the user's own."""
import argparse, numpy as np
from PIL import Image, ImageDraw, ImageFont, ImageFilter
a=argparse.ArgumentParser(); [a.add_argument(x,**k) for x,k in [('--person',{}),('--product',{}),('--line1',{}),('--line2',{}),('--tip',{}),('--out',{}),('--font',{'default':''}),('--scale',{'type':float,'default':0.54})]]
o=a.parse_args(); W,H=1280,720
def glow(img,c,cx,cy,r,s):
y,x=np.mgrid[0:H,0:W]; al=np.clip(1-np.sqrt((x-cx)**2+(y-cy)**2)/r,0,1)**2*s; arr=np.asarray(img,dtype=np.float32); return Image.fromarray((arr*(1-al[...,None])+np.array(c,dtype=np.float32)*al[...,None]).astype(np.uint8))
im=glow(glow(Image.new('RGB',(W,H),(13,17,23)),(0,150,170),-60,800,700,.5),(110,90,210),1340,820,640,.45).convert('RGBA')
tw,th,tx,ty=590,474,660,196
t=Image.open(o.product).convert('RGB'); r=max(tw/t.width,th/t.height); t=t.resize((int(t.width*r)+1,int(t.height*r)+1),Image.LANCZOS); t=t.crop(((t.width-tw)//2,(t.height-th)//2,(t.width-tw)//2+tw,(t.height-th)//2+th))
m=Image.new('L',(tw,th),0); ImageDraw.Draw(m).rounded_rectangle([0,0,tw-1,th-1],radius=20,fill=255)
g=Image.new('RGBA',(W,H),(0,0,0,0)); ImageDraw.Draw(g).rounded_rectangle([tx-4,ty-4,tx+tw+4,ty+th+4],radius=24,fill=(255,255,255,90)); im.alpha_composite(g.filter(ImageFilter.GaussianBlur(14))); im.paste(t,(tx,ty),m)
p=Image.open(o.person).convert('RGBA'); k=o.scale; p=p.resize((int(p.width*k),int(p.height*k)),Image.LANCZOS); tipx,tipy=[float(v) for v in o.tip.split(',')]
ox,oy=int(tx+12-tipx*k),H-p.height
sh=Image.new('RGBA',(W,H),(0,0,0,0)); b=Image.new('RGBA',p.size,(0,0,0,255)); b.putalpha(p.split()[3].point(lambda v:int(v*.55))); sh.paste(b,(ox,oy+10),b); im.alpha_composite(sh.filter(ImageFilter.GaussianBlur(18))); im.paste(p,(ox,oy),p)
def font(sz):
for f in [o.font,'/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf','DejaVuSans-Bold.ttf']:
try: return ImageFont.truetype(f,sz)
except Exception: pass
return ImageFont.load_default()
d=ImageDraw.Draw(im); f=font(84); d.text((44,30),o.line1,font=f,fill=(255,255,255,255)); d.text((44,30+82),o.line2,font=f,fill=(47,208,195,255))
im.convert('RGB').save(o.out,quality=92); print('OK:',o.out)