gallery.py
At 1ae6528Copy the commit ID
Preview
Code · 3.9 KiB#!/usr/bin/env python3
"""Render a labeled silhouette library and four curated glass compositions."""
from pathlib import Path
import argparse
from PIL import Image, ImageDraw, ImageFont
from shapes import SHAPES,shape
from geometry import curve_points
from renderer import render
ROOT=Path(__file__).parent
def glass(role='middle',warmth=0.,hue=0.,opacity=.93):
return dict(role=role,warmth=warmth,hue=hue,opacity=opacity)
def piece(name,center,radius,rotation,role):
return dict(shape=name,center=center,radius=radius,rotation=rotation,material=glass(role))
STUDIES={
'heart':[piece('heart',(486,600),400,0,'middle')],
'soft-forms':[
piece('cloud',(300,350),240,0,'outer'),
piece('bubbles',(588,580),305,.24,'middle'),
piece('pebble',(365,864),240,-.45,'front')],
'cutouts':[
piece('seaweed',(305,365),252,-.3,'outer'),
piece('coral',(604,554),325,.3,'middle'),
piece('bow',(350,835),294,-.7,'front')],
'celestial':[
piece('crescent',(322,350),260,-.22,'outer'),
piece('star',(594,559),326,.21,'middle'),
piece('sparkle',(377,845),282,-.19,'front')],
'orchard':[
piece('apple',(337,395),223,-.18,'outer'),
piece('strawberry',(614,563),316,.20,'middle'),
piece('lemon',(355,826),277,-.48,'front')]
}
def font(size):
# Pillow's bundled font keeps the sheet portable across operating systems.
return ImageFont.load_default(size=size)
def sampler(outlines=False,names=None):
cellw,cellh=360,420
catalog=SHAPES if names is None else {name:SHAPES[name] for name in names}
columns=4 if names is None else 2
height=180+cellh*((len(catalog)+columns-1)//columns)
sheet=Image.new('RGB',(cellw*columns,height),(241,235,232));draw=ImageDraw.Draw(sheet)
draw.text((48,36),'GLASS / REFINED SHAPES' if names else ('CONTOUR / SHAPE LIBRARY' if outlines else 'GLASS / SHAPE LIBRARY'),font=font(30),fill=(46,42,55))
draw.text((48,83),'New heart silhouette · butterfly · rounded bow · strawberry' if names else ('16 continuous contours · no shading or texture' if outlines else '16 silhouettes · one iridescent material · generated from curves'),font=font(17),fill=(104,97,110))
for i,(name,label) in enumerate(catalog.items()):
if outlines:
tile=Image.new('RGB',(round(972*.34)*4,round(1202*.34)*4),(241,235,232))
ImageDraw.Draw(tile).polygon([tuple(p*.34*4) for p in curve_points(shape(name,(486,565),370))],fill=(42,37,50))
tile=tile.resize((round(972*.34),round(1202*.34)),Image.Resampling.LANCZOS)
else:
tile=render(scale=.34,specs=[piece(name,(486,565),370,0,'middle')])
tile=tile.crop((0,10,tile.width,355))
x=(i%columns)*cellw; y=142+(i//columns)*cellh
sheet.paste(tile,(x+(cellw-tile.width)//2,y))
draw.text((x+28,y+357),label,font=font(20),fill=(46,42,55))
draw.text((x+28,y+385),name,font=font(14),fill=(112,103,117))
return sheet
def main():
ap=argparse.ArgumentParser(description=__doc__)
ap.add_argument('--output-dir',type=Path,default=ROOT/'renders')
ap.add_argument('--only',choices=['sampler','outlines','refinements',*STUDIES],help='Render only one asset')
args=ap.parse_args();args.output_dir.mkdir(parents=True,exist_ok=True)
if args.only in (None,'sampler'):
path=args.output_dir/'shape-library.png';sampler().save(path);print(path)
if args.only in (None,'outlines'):
path=args.output_dir/'shape-outlines.png';sampler(outlines=True).save(path);print(path)
if args.only in (None,'refinements'):
path=args.output_dir/'shape-refinements.png'
sampler(names=['heart','butterfly','bow','strawberry']).save(path);print(path)
for name,specs in STUDIES.items():
if args.only in (None,name):
path=args.output_dir/f'shape-study-{name}.png'
render(specs=specs).save(path);print(path)
if __name__=='__main__':main()