Akjava's picture
fix animation duration broken
cd30470
import spaces
import gradio as gr
import re
from PIL import Image,ImageEnhance
import os
import numpy as np
import hashlib
import io
import cv2
import time
def clear_old_files(dir,passed_time):
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)
print(f"file removed {file_path}")#TODO remove later
def get_image_id(image):
buffer = io.BytesIO()
image.save(buffer, format='PNG')
hash_object = hashlib.sha256(buffer.getvalue())
hex_dig = hash_object.hexdigest()
unique_id = hex_dig[:32]
return unique_id
dir_name ="images"
passed_time = 60*3
def process_create_webp(images,duration=100, loop=0,quality=85):
frames = []
for image_file in images:
frames.append(image_file)
output_buffer = io.BytesIO()
frames[0].save(output_buffer,
save_all=True,
append_images=frames[1:],
duration=duration,
loop=loop,
format='WebP',
quality=quality
)
return output_buffer.getvalue()
def process_create_apng(images,duration=100, disposal=1,blend=0,loop=0):
frames = []
for image_file in images:
frames.append(image_file)
output_buffer = io.BytesIO()
frames[0].save(output_buffer,
save_all=True,
append_images=frames[1:],
#duration=duration, disposal=0,blend=1,
duration=duration, disposal=disposal,blend=blend,
loop=loop,
format='png')
return output_buffer.getvalue()
def process_create_gif(images,duration=100, quantize=False,disposal=1,blend=0,loop=0):
frames = []
for image_file in images:
if quantize:
image_file = image_file.quantize(colors=256, method=2)
#image_file = image_file.quantize()
frames.append(image_file)
output_buffer = io.BytesIO()
frames[0].save(output_buffer,
save_all=True,
append_images=frames[1:],
#duration=duration, disposal=0,blend=1,
duration=duration, disposal=disposal,blend=blend,
loop=loop,
format='gif',
optimize=False
#dither=Image.FLOYDSTEINBERG
)
return output_buffer.getvalue()
def save_to_image(image,extension="png",quality=0.8):
id = get_image_id(image)
path = os.path.join(dir_name,f"{id}.{extension}")
if extension == "jpg" or extension == "jpeg" or extension == "webp":
image.convert("RGB").save(path,quality=quality)
else:
image.save(path)
return path
def convert_webp_to_images(webp_path):
# add list
frames = []
durations = []
Image.init()
image = Image.open(webp_path)
if hasattr(image,"n_frames"):
for i in range(image.n_frames):
image.seek(i)
frame = image.copy()
frames.append(frame)
# frame.info must be dictionary
duration = frame.info.get("duration",100)
durations.append(duration)
else:# webp never happen?
frames.append(image)
durations.append(100)#default
return frames,durations
def buffer_to_id(buffer_value):
hash_object = hashlib.sha256(buffer_value)
hex_dig = hash_object.hexdigest()
unique_id = hex_dig[:32]
return unique_id
def process_images(input_path,same_size=False,image_width=128,file_format="webp",webp_quality=85):
if input_path == None:
raise gr.Error("need image")
# cache control
if not os.path.exists(dir_name):
os.mkdir(dir_name)
clear_old_files(dir_name,passed_time)
images =[]
frames,durations = convert_webp_to_images(input_path)
new_frames = []
new_width,new_height = frames[0].size
if not same_size and image_width!=new_width:
ratio = new_height/new_width
new_height = int(image_width*ratio)
new_width = image_width
#print(f"ratio = {ratio} new size {new_width} x {new_height}")
for frame in frames:
new_frame = frame.resize((new_width,new_height))# extremly slow Image.LANCZOS
new_frames.append(new_frame)
else:
new_frames = frames
if file_format == "webp":
webp_buffer = process_create_webp(new_frames,durations,webp_quality)
webp_id = buffer_to_id(webp_buffer)
webp_path = os.path.join(dir_name,f"{webp_id}.webp")
with open(webp_path, 'wb') as f:
f.write(webp_buffer)
images.append((webp_path,"webp"))
elif file_format == "apng":
apng_buffer = process_create_apng(new_frames,durations)
apng_id = buffer_to_id(apng_buffer)
apng_path = os.path.join(dir_name,f"{apng_id}.apng")
with open(apng_path, 'wb') as f:
f.write(apng_buffer)
images.append((apng_path,"apng"))
elif file_format == "gif":
gif_buffer = process_create_gif(new_frames,durations,False)
gif_id = buffer_to_id(gif_buffer)
gif_path = os.path.join(dir_name,f"{gif_id}.gif")
with open(gif_path, 'wb') as f:
f.write(gif_buffer)
images.append((gif_path,"gif"))
else:
f,extension = file_format.split("-")
for i ,frame in enumerate(new_frames):
path = save_to_image(frame,extension,webp_quality)
images.append((path,f"index {i}"))
return images
def read_file(path: str) -> str:
with open(path, 'r', encoding='utf-8') as f:
content = f.read()
return content
def test_echo(param):
return param
def samesize_changed(check,slider):
return gr.Slider(label="Image Width",
minimum=8,
maximum=2048,
step=1,
value=slider,
interactive=not check)
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;
}
"""
js = """
function(path){
console.log(path)
return path
}
"""
with gr.Blocks(css=css, elem_id="demo-container") as demo:
with gr.Column():
gr.HTML(read_file("demo_header.html"))
gr.HTML(read_file("demo_tools.html"))
with gr.Row():
with gr.Column():
file = gr.File(label="WebP Upload")
image = gr.Image(sources=[],image_mode='RGB', elem_id="Image", type="filepath", label="Preview WebP")
#file.select(fn=test_echo,inputs=[file])
file.upload(fn=test_echo,inputs=[file],outputs=[image])
file.clear(fn=test_echo,inputs=[file],outputs=[image])
btn = gr.Button("Convert", elem_id="run_button",variant="primary")
# type choice
# size slider
file_format=gr.Dropdown(
["webp", "apng", "gif","images-png","images-jpg"], label="Animation Format", info="Convert to Animattion" )
same_size = gr.Checkbox(label="Same Size",value=False)
image_width = gr.Slider(
label="Image Width",info = "new animation size",
minimum=8,
maximum=2048,
step=1,
value=128,
interactive=True)
same_size.change(fn=samesize_changed,inputs=[same_size,image_width],outputs=[image_width])
with gr.Accordion(label="Advanced Settings", open=False):
with gr.Row( equal_height=True):
webp_quality = gr.Slider(
label="WebP Quality",info = "this change file size",
minimum=0,
maximum=100,
step=1,
value=85,
interactive=True)
with gr.Column():
image_out = gr.Gallery(height=800,label="Output", elem_id="output-img",format="webp", columns=[4],rows=[2],preview=True)
btn.click(fn=process_images, inputs=[file,same_size,image_width,file_format,webp_quality], outputs =[image_out], api_name='infer')
gr.Examples(
examples=[
["examples/1024.webp","examples/1024.webp"],
#["images/00346245_00006200.jpg", "images/00346245_00003200.jpg","images/00346245_mask.jpg",10,0,"images/00346245_mixed.jpg"]
]
,
inputs=[image,file]#example not fire event
)
gr.HTML(read_file("demo_footer.html"))
if __name__ == "__main__":
demo.launch()