- numpy
- Pillow
- paths:
- ./canvas.py
from pyodide import to_js, create_proxy
from PIL import Image
import io
import time
import base64
import numpy as np
from js import (
console,
document,
parent,
devicePixelRatio,
ImageData,
Uint8ClampedArray,
CanvasRenderingContext2D as Context2d,
requestAnimationFrame,
window
)
from canvas import InfCanvas
base_lst = [None]
async def draw_canvas() -> None:
width=1500
height=600
canvas=InfCanvas(1500,600)
document.querySelector("#container").style.width = f"{width}px"
canvas.setup_mouse()
canvas.clear_background()
canvas.draw_buffer()
canvas.draw_selection_box()
base_lst[0]=canvas
async def draw_canvas_func(event):
try:
width=parent.document.querySelector("gradio-app").shadowRoot.querySelector("#canvas_width input").value
height=parent.document.querySelector("gradio-app").shadowRoot.querySelector("#canvas_height input").value
selection_size=parent.document.querySelector("gradio-app").shadowRoot.querySelector("#selection_size input").value
except:
width=1024
height=768
selection_size=384
document.querySelector("#container").style.width = f"{width}px"
canvas=InfCanvas(int(width),int(height),selection_size=int(selection_size))
canvas.setup_mouse()
canvas.clear_background()
canvas.draw_buffer()
canvas.draw_selection_box()
base_lst[0]=canvas
async def export_func(event):
base=base_lst[0]
arr=base.export()
base64_str = base.numpy_to_base64(arr)
time_str = time.strftime("%Y%m%d_%H%M%S")
console.log(f"Canvas saved to outpaint_{time_str}.png")
link = document.createElement("a")
link.download = f"outpaint_{time_str}.png"
link.href = "data:image/png;base64,"+base64_str
link.click()
async def outpaint_func(event):
base=base_lst[0]
base64_str=event.data[1]
arr=base.base64_to_numpy(base64_str)
base.fill_selection(arr)
base.draw_selection_box()
async def undo_func(event):
base=base_lst[0]
if base.sel_dirty:
base.canvas[2].clear()
base.sel_buffer = base.sel_buffer_bak.copy()
base.sel_dirty = False
async def commit_func(event):
base=base_lst[0]
if base.sel_dirty:
base.write_selection_to_buffer()
async def transfer_func(event):
base=base_lst[0]
base.read_selection_from_buffer()
sel_buffer=base.sel_buffer
sel_buffer_str=base.numpy_to_base64(sel_buffer)
parent.postMessage(to_js(["transfer",str(sel_buffer_str)]),"*")
async def upload_func(event):
base=base_lst[0]
base64_str=event.data[1]
arr=base.base64_to_numpy(base64_str)
h,w,_=arr.shape
yo=(base.height-h)//2
xo=(base.width-w)//2
base.buffer_dirty=True
base.buffer*=0
base.buffer[yo:yo+h,xo:xo+w,0:3]=arr[:,:,0:3]
base.buffer[yo:yo+h,xo:xo+w,-1]=arr[:,:,-1]
base.draw_buffer()
document.querySelector("#export").addEventListener("click",create_proxy(export_func))
document.querySelector("#undo").addEventListener("click",create_proxy(undo_func))
document.querySelector("#commit").addEventListener("click",create_proxy(commit_func))
document.querySelector("#outpaint").addEventListener("click",create_proxy(outpaint_func))
document.querySelector("#upload").addEventListener("click",create_proxy(upload_func))
document.querySelector("#transfer").addEventListener("click",create_proxy(transfer_func))
document.querySelector("#draw").addEventListener("click",create_proxy(draw_canvas_func))
async def setup_func():
document.querySelector("#setup").value="1"
async def message_func(event):
if event.data[0]=="click":
if event.data[1]=="export":
await export_func(event)
elif event.data[1]=="commit":
await commit_func(event)
elif event.data[1]=="undo":
await undo_func(event)
elif event.data[0]=="upload":
await upload_func(event)
elif event.data[0]=="outpaint":
await outpaint_func(event)
elif event.data[0]=="mode":
document.querySelector("#mode").value=event.data[1]
elif event.data[0]=="transfer":
await transfer_func(event)
window.addEventListener("message",create_proxy(message_func))
import asyncio
_ = await asyncio.gather(
setup_func(),draw_canvas()
)