|
import streamlit as st |
|
import os |
|
import base64 |
|
import tempfile |
|
from PIL import Image |
|
import numpy as np |
|
from moviepy.editor import VideoFileClip |
|
import moviepy.video.fx.all as vfx |
|
|
|
|
|
if 'clip_width' not in st.session_state: |
|
st.session_state.clip_width = 0 |
|
if 'clip_height' not in st.session_state: |
|
st.session_state.clip_height = 0 |
|
if 'clip_duration' not in st.session_state: |
|
st.session_state.clip_duration = 0 |
|
if 'clip_fps' not in st.session_state: |
|
st.session_state.clip_fps = 0 |
|
if 'clip_total_frames' not in st.session_state: |
|
st.session_state.clip_total_frames = 0 |
|
|
|
st.title('🎈 Animated GIF Maker') |
|
|
|
|
|
st.sidebar.header('Upload file') |
|
uploaded_file = st.sidebar.file_uploader("Choose a file", type=['mov', 'mp4']) |
|
st.sidebar.markdown(''' |
|
[Download example file](https://github.com/dataprofessor/animated-gif/raw/master/example/streamlit-app-starter-kit-screencast.mov) |
|
|
|
--- |
|
Made with ❤️ by Chanin Nantasenamat ([Data Professor](https://youtube.com/dataprofessor)) |
|
''') |
|
|
|
|
|
if uploaded_file is not None: |
|
|
|
tfile = tempfile.NamedTemporaryFile(delete=False) |
|
tfile.write(uploaded_file.read()) |
|
|
|
|
|
clip = VideoFileClip(tfile.name) |
|
|
|
st.session_state.clip_duration = clip.duration |
|
|
|
|
|
st.sidebar.header('Input parameters') |
|
selected_resolution_scaling = st.sidebar.slider('Scaling of video resolution', 0.0, 1.0, 0.5 ) |
|
selected_speedx = st.sidebar.slider('Playback speed', 0.1, 10.0, 5.0) |
|
selected_export_range = st.sidebar.slider('Duration range to export', 0, int(st.session_state.clip_duration), (0, int(st.session_state.clip_duration) )) |
|
|
|
|
|
clip = clip.resize(selected_resolution_scaling) |
|
|
|
st.session_state.clip_width = clip.w |
|
st.session_state.clip_height = clip.h |
|
st.session_state.clip_duration = clip.duration |
|
st.session_state.clip_total_frames = clip.duration * clip.fps |
|
st.session_state.clip_fps = st.sidebar.slider('FPS', 10, 60, 20) |
|
|
|
|
|
st.subheader('Metrics') |
|
col1, col2, col3, col4, col5 = st.columns(5) |
|
col1.metric('Width', st.session_state.clip_width, 'pixels') |
|
col2.metric('Height', st.session_state.clip_height, 'pixels') |
|
col3.metric('Duration', st.session_state.clip_duration, 'seconds') |
|
col4.metric('FPS', st.session_state.clip_fps, '') |
|
col5.metric('Total Frames', st.session_state.clip_total_frames, 'frames') |
|
|
|
|
|
st.subheader('Preview') |
|
|
|
with st.expander('Show image'): |
|
selected_frame = st.slider('Preview a time frame (s)', 0, int(st.session_state.clip_duration), int(np.median(st.session_state.clip_duration)) ) |
|
clip.save_frame('frame.gif', t=selected_frame) |
|
frame_image = Image.open('frame.gif') |
|
st.image(frame_image) |
|
|
|
|
|
st.subheader('Image parameters') |
|
with st.expander('Show image parameters'): |
|
st.write(f'File name: `{uploaded_file.name}`') |
|
st.write('Image size:', frame_image.size) |
|
st.write('Video resolution scaling', selected_resolution_scaling) |
|
st.write('Speed playback:', selected_speedx) |
|
st.write('Export duration:', selected_export_range) |
|
st.write('Frames per second (FPS):', st.session_state.clip_fps) |
|
|
|
|
|
st.subheader('Generate GIF') |
|
generate_gif = st.button('Generate Animated GIF') |
|
|
|
if generate_gif: |
|
clip = clip.subclip(selected_export_range[0], selected_export_range[1]).speedx(selected_speedx) |
|
|
|
frames = [] |
|
for frame in clip.iter_frames(): |
|
frames.append(np.array(frame)) |
|
|
|
image_list = [] |
|
|
|
for frame in frames: |
|
im = Image.fromarray(frame) |
|
image_list.append(im) |
|
|
|
image_list[0].save('export.gif', format = 'GIF', save_all = True, loop = 0, append_images = image_list) |
|
|
|
|
|
|
|
|
|
st.subheader('Download') |
|
|
|
|
|
|
|
|
|
|
|
file_ = open('export.gif', 'rb') |
|
contents = file_.read() |
|
data_url = base64.b64encode(contents).decode("utf-8") |
|
file_.close() |
|
st.markdown( |
|
f'<img src="data:image/gif;base64,{data_url}" alt="cat gif">', |
|
unsafe_allow_html=True, |
|
) |
|
|
|
fsize = round(os.path.getsize('export.gif')/(1024*1024), 1) |
|
st.info(f'File size of generated GIF: {fsize} MB', icon='💾') |
|
|
|
fname = uploaded_file.name.split('.')[0] |
|
with open('export.gif', 'rb') as file: |
|
btn = st.download_button( |
|
label='Download image', |
|
data=file, |
|
file_name=f'{fname}_scaling-{selected_resolution_scaling}_fps-{st.session_state.clip_fps}_speed-{selected_speedx}_duration-{selected_export_range[0]}-{selected_export_range[1]}.gif', |
|
mime='image/gif' |
|
) |
|
|
|
|
|
else: |
|
st.warning('👈 Upload a video file') |
|
|