generate.py
4.2 kB · python · 124 lines
1import math2import mrlypy.gen3from automator.core.api import logger4from automator.core.errors import TaskAborted5from automator.core.models import Mockup, Task6from automator.core.s3 import cdn_key, put_png, s3_url, save_task7from automator.core.steps import Step8from io import BytesIO9from mrlypy.core.state import seed10from PIL import Image, ImageCms1112FORMAT = "PNG"13UNIT_SCALE = 114TILE_SCALE = 1015UNIT_IN = 0.2516DPI = 30017TILES = [1, 3, 5, 7, 9]18TILE_NAME = "tile"19OG_TILE = 320OG_NAME = "og"21OG_SIZE = 120022MAX_RENDERS = 32324PROFILE = ImageCms.createProfile("sRGB")25SRGB = ImageCms.ImageCmsProfile(PROFILE).tobytes()2627Image.MAX_IMAGE_PIXELS = None2829def crop(image: Image.Image, width: int, height: int) -> Image.Image:30 if image.width == width and image.height == height:31 return image32 w, h = image.size33 left = (w - width) // 234 top = (h - height) // 235 return image.crop(box=(left, top, left + width, top + height))3637def guard_renders(task: Task) -> Task:38 count = task.metadata.get("render_count", 0) + 139 task.metadata["render_count"] = count40 if count >= MAX_RENDERS:41 raise TaskAborted(f"render_count {count} for task {task.key}")42 save_task(task)43 return task4445def prepare_printfiles(task: Task, gen: mrlypy.gen.Gen) -> mrlypy.gen.Gen:46 tile_width, tile_height = gen.tile.unit_width, gen.tile.unit_height47 for pf in task.printfiles:48 grid_width = math.ceil(pf.width / (tile_width * UNIT_IN))49 grid_height = math.ceil(pf.height / (tile_height * UNIT_IN))50 gen.files.append(mrlypy.gen.File(width=grid_width, height=grid_height))51 return gen5253def prepare_tiles(task: Task, gen: mrlypy.gen.Gen) -> mrlypy.gen.Gen:54 for size in TILES:55 gen.files.append(mrlypy.gen.File(width=size, height=size))56 return gen5758def save_png(key: str, image: Image.Image, dpi: int = None) -> str:59 with BytesIO() as data:60 options = {"format": FORMAT, "optimize": True, "icc_profile": SRGB}61 if dpi:62 options["dpi"] = (dpi, dpi)63 image.save(data, **options)64 data.seek(0)65 put_png(key, data)66 return s3_url(key)6768def process_printfiles(task: Task, gen: mrlypy.gen.Gen, start: int) -> Task:69 for i, pf in enumerate(task.printfiles):70 pf.dpi = DPI71 image = gen.files[start + i].data72 full_width = round(image.width * UNIT_IN * pf.dpi)73 full_height = round(image.height * UNIT_IN * pf.dpi)74 image = image.resize(75 size=(full_width, full_height),76 resample=Image.Resampling.NEAREST,77 )78 image = crop(image, round(pf.width * pf.dpi), round(pf.height * pf.dpi))79 pf.url = save_png(cdn_key(task.key, pf.name), image, pf.dpi)80 logger.info(f"{task.desc} uploaded_printfile {pf.url}")81 return task8283def process_og(task: Task, image: Image.Image) -> None:84 og = image.resize(size=(OG_SIZE, OG_SIZE), resample=Image.Resampling.NEAREST)85 url = save_png(cdn_key(task.key, OG_NAME), og)86 logger.info(f"{task.desc} uploaded_og {url}")8788def process_tiles(task: Task, gen: mrlypy.gen.Gen, start: int) -> Task:89 for i, size in enumerate(TILES):90 raw = gen.files[start + i].data91 image = raw.resize(92 size=(raw.width * TILE_SCALE, raw.height * TILE_SCALE),93 resample=Image.Resampling.NEAREST,94 )95 name = f"{task.key}-{size}"96 url = save_png(cdn_key(task.key, f"{TILE_NAME}-{size}"), image)97 logger.info(f"{task.desc} uploaded_tile {url}")98 task.mockups.append(99 Mockup(100 id=size,101 key=task.key,102 name=name,103 category="Tile",104 title=f"{size}x{size}",105 url=url,106 )107 )108 if size == OG_TILE:109 process_og(task, raw)110 return task111112def mrly_generate(task: Task) -> Task:113 gen = mrlypy.gen.Gen.from_dict(task.variation)114 seed(gen.seed)115 gen = prepare_printfiles(task, gen)116 gen = prepare_tiles(task, gen)117 task = guard_renders(task)118 gen = mrlypy.gen.generate(gen)119 gen = mrlypy.gen.render(gen, scale=UNIT_SCALE)120 task = process_printfiles(task, gen, 0)121 task = process_tiles(task, gen, len(task.printfiles))122 task.variation = gen.to_dict()123 task.place(Step.MOCKUP)124 return task