Spaces:
Running
Running
import spaces | |
import gradio as gr | |
import subprocess | |
import re | |
from PIL import Image,ImageSequence | |
import webp | |
import io | |
import hashlib | |
import os | |
import time | |
import shutil | |
css=""" | |
#col-left { | |
margin: 0 auto; | |
max-width: 640px; | |
} | |
#col-right { | |
margin: 0 auto; | |
max-width: 640px; | |
} | |
.grid-container { | |
display: flex; | |
align-items: center; | |
justify-content: center; | |
gap:10px | |
} | |
.image { | |
width: 128px; | |
height: 128px; | |
object-fit: cover; | |
} | |
.text { | |
font-size: 16px; | |
} | |
""" | |
output_dir = "outputs" | |
passed_time = 60 * 20 | |
def load_text(text_path: str) -> str: | |
with open(text_path, 'r', encoding='utf-8') as f: | |
text = f.read() | |
return text | |
def clear_old_files(dir,passed_time): | |
try: | |
files = os.listdir(dir) | |
current_time = time.time() | |
for file in files: | |
file_path = os.path.join(dir,file) | |
ctime = os.stat(file_path).st_ctime | |
diff = current_time - ctime | |
#print(f"ctime={ctime},current_time={current_time},passed_time={passed_time},diff={diff}") | |
if diff > passed_time: | |
os.remove(file_path) | |
except: | |
print("maybe still gallery using error") | |
def process_images(normal_image,mouth_open_image,eye_close_image,duration=100,pattern = "nnnmmmnenmmmnnnmmmnnnmmmnnnmmm",looping = True): | |
# validating images | |
# cache control | |
if not os.path.exists(output_dir): | |
os.mkdir(output_dir) | |
clear_old_files(output_dir,passed_time) | |
if normal_image is None or mouth_open_image is None or eye_close_image is None: | |
raise gr.Error("Need Normal Mouth Eyes 3 images") | |
#validate check | |
normal_width, normal_height = normal_image.size | |
mouth_width, mouth_height = mouth_open_image.size | |
eye_width, eye_height = eye_close_image.size | |
if normal_width!=mouth_width or normal_height!=mouth_height: | |
raise gr.Error("Mouth Image Size must be same as normal") | |
if normal_width!=eye_width or normal_height!=eye_height: | |
raise gr.Error("Eyes Image Size must be same as normal") | |
if duration<1: | |
raise gr.Error("min duration is 1") | |
pattern = pattern[:32] | |
if pattern == "": | |
pattern = "nme" | |
else: | |
valids =["n","m","e"] | |
for ch in pattern: | |
if ch not in valids: | |
raise gr.Error("invalid pattern contain.pattern must be n or e or m") | |
frames = [] | |
for ch in pattern: | |
if ch == "m": | |
frames.append(mouth_open_image) | |
elif ch == "e": | |
frames.append(eye_close_image) | |
else: | |
frames.append(normal_image) | |
loop = 0 if looping else 1 #MUST BE ZERO,NOT TRUE | |
output_buffer = io.BytesIO() | |
frames[0].save(output_buffer, | |
save_all=True, | |
append_images=frames[1:], | |
duration=duration, | |
loop=loop, | |
format='WebP') | |
hash_object = hashlib.sha256(output_buffer.getvalue()) | |
hex_dig = hash_object.hexdigest() | |
unique_id = hex_dig[:32] | |
output_path = f"{output_dir}/{unique_id}.webp" | |
with open(output_path,"wb") as f: | |
f.write(output_buffer.getvalue()) | |
return output_path | |
with gr.Blocks(css=css, elem_id="demo-container") as demo: | |
with gr.Column(): | |
gr.HTML(load_text("demo_header.html")) | |
gr.HTML(load_text("demo_tools.html")) | |
with gr.Row(): | |
with gr.Column(): | |
image_normal = gr.Image(sources=['upload','clipboard'], elem_id="image_normal", type="pil", label="Normal Image",height=400, value=None) | |
with gr.Row(elem_id="prompt-container", equal_height=False): | |
with gr.Row(): | |
btn = gr.Button("Make WebP Animation", elem_id="run_button") | |
image_mouth = gr.Image(sources=['upload','clipboard'], elem_id="image_mouth", type="pil", label="Mouth Opened",height=400, value=None) | |
image_eyes = gr.Image(sources=['upload','clipboard'], elem_id="image_eyes", type="pil", label="Eyes Closed",height=400, value=None) | |
id_input=gr.Text(label="Name", visible=False) | |
with gr.Accordion(label="Advanced Settings", open=False): | |
with gr.Row(equal_height=True): | |
animation_time = gr.Number(value=100, minimum=1, maximum=1000, step=10, label="Animation Time") | |
looping = gr.Checkbox(label="Loop",value=True) | |
with gr.Row( equal_height=True): | |
timing_seat = gr.Text(value="nnnmmmnenmmmnnnmmmnnnmmm", max_length=32,label="Timing Seat") | |
with gr.Column(): | |
image_out = gr.Image(sources=[],label="Output", elem_id="output-img",type="filepath", format="webp") | |
btn.click(fn=process_images, inputs=[image_normal, image_mouth,image_eyes,animation_time,timing_seat,looping], outputs =image_out, api_name='infer') | |
gr.Examples( | |
examples=[ | |
["examples/00003245_normal.jpg","examples/00003245_mouth.jpg","examples/00003245_eyes.jpg","examples/00003245.webp"], | |
["examples/00207245_normal.png","examples/00207245_mouth.png","examples/00207245_eyes.png","examples/00207245.webp"], | |
["examples/00350245_normal.jpg","examples/00350245_mouth.jpg","examples/00350245_eyes.jpg","examples/00350245.webp"], | |
["examples/00538245_normal.jpg","examples/00538245_mouth.jpg","examples/00538245_eyes.jpg","examples/00538245.webp"], | |
["examples/00828003_00.jpg","examples/00828003_09.jpg","examples/00828003_99.jpg","examples/00828003.webp"], | |
["examples/00825000_00.jpg","examples/00825000_09.jpg","examples/00825000_99.jpg","examples/00825000.webp"], | |
["examples/00824008_00.jpg","examples/00824008_09.jpg","examples/00824008_99.jpg","examples/00824008.webp"], | |
["examples/prompt01_normal.jpg","examples/prompt01_mouth.jpg","examples/prompt01_eyes.jpg","examples/prompt01.webp"], | |
], | |
inputs=[image_normal,image_mouth,image_eyes,image_out], | |
) | |
gr.HTML( | |
gr.HTML(load_text("demo_footer.html")) | |
) | |
if __name__ == "__main__": | |
demo.launch() |