-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit d792308
Showing
5 changed files
with
295 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,109 @@ | ||
''' | ||
project-name=GIF TO BOOT ANIMATION | ||
DATE=30-01-2024 | ||
DEVLOPER=SHASHAN SONI | ||
https://github.com/soni-shashan/ | ||
''' | ||
|
||
from customtkinter import * | ||
from tkinter import filedialog | ||
import threading | ||
import sys | ||
import os | ||
import shutil | ||
import signal | ||
import create_boot_animation | ||
|
||
def goTo(): | ||
if create_boot_animation.create(file_path,width,hight,fps,'OUTPUT'): | ||
os.remove('OUTPUT/desc.txt') | ||
shutil.rmtree('OUTPUT/part0') | ||
information.destroy() | ||
app.quit() | ||
|
||
def click_sumbit(): | ||
global width,hight,fps | ||
if width_entry.get()!="": | ||
width=width_entry.get() | ||
if not isinstance(width,int): | ||
width=int(width) | ||
else: | ||
width=1024 | ||
if hight_entry.get()!="": | ||
hight=hight_entry.get() | ||
if not isinstance(hight,int): | ||
hight=int(hight) | ||
else: | ||
hight=600 | ||
if fps_entry.get()!="": | ||
fps=fps_entry.get() | ||
if not isinstance(fps,int): | ||
fps=int(fps) | ||
else: | ||
fps=60 | ||
|
||
global command,information,file_path | ||
file_path=file_path.replace("/","\\\\") | ||
command=f"{sys._MEIPASS}/python {sys._MEIPASS}/create_boot_animation.py \"{file_path}\" {width} {hight} {fps} output -zip" | ||
label.destroy() | ||
width_text.destroy() | ||
width_entry.destroy() | ||
hight_text.destroy() | ||
hight_entry.destroy() | ||
fps_label.destroy() | ||
fps_entry.destroy() | ||
create_btn.destroy() | ||
information=CTkLabel(app,text="Please wait!! it may take 5-10 seconds.",fg_color="transparent",font=('arial',16)) | ||
information.place(relx=0.5,rely=0.5,anchor="center") | ||
therde=threading.Thread(target=goTo) | ||
therde.start() | ||
|
||
def select_gif_file(): | ||
global file_path,width_entry,hight_entry,fps_entry,label,width_text,hight_text,fps_entry,create_btn,fps_label | ||
file_path = filedialog.askopenfilename(filetypes=[("GIF files", "*.gif")]) | ||
# Do something with the selected GIF file path (e.g., display it, process it, etc.) | ||
if file_path!="": | ||
print("Selected GIF file: ", file_path) | ||
btn.destroy() | ||
|
||
label = CTkLabel(app, text="Selected GIF file: "+ file_path, fg_color="transparent",font=('arial',14)) | ||
label.place(relx=0.5, rely=0.1, anchor="center") | ||
|
||
width_text=CTkLabel(app,text="WIDTH (DEFUALT: 1024)",fg_color="transparent",font=('arial',16)) | ||
width_text.place(relx=0.5,rely=0.15,anchor="center") | ||
|
||
width_entry=CTkEntry(app,width=170,text_color="#000000") | ||
width_entry.place(relx=0.5,rely=0.22,anchor="center") | ||
|
||
hight_text=CTkLabel(app,text="HIGHT (DEFUALT: 600)",fg_color="transparent",font=('arial',16)) | ||
hight_text.place(relx=0.5,rely=0.3,anchor="center") | ||
|
||
hight_entry=CTkEntry(app,width=170,text_color="#000000") | ||
hight_entry.place(relx=0.5,rely=0.37,anchor="center") | ||
|
||
fps_label=CTkLabel(app,text="FPS (DEFUALT: 60)",fg_color="transparent",font=('arial',16)) | ||
fps_label.place(relx=0.5,rely=0.45,anchor="center") | ||
|
||
fps_entry=CTkEntry(app,width=170,text_color="#000000") | ||
fps_entry.place(relx=0.5,rely=0.52,anchor="center") | ||
|
||
create_btn=CTkButton(master=app,text='CREATE',corner_radius=20,fg_color="#C850C0",hover_color="#4158D0",border_color="#000000",border_width=2,width=150,height=50,command=click_sumbit) | ||
create_btn.place(relx=0.5,rely=0.65,anchor="center") | ||
width_entry.focus_set() | ||
|
||
def on_closing(): | ||
os.kill(os.getpid(), signal.SIGINT) | ||
sys.exit() | ||
|
||
if __name__=='__main__': | ||
app=CTk() | ||
app.geometry("512x512") | ||
app.minsize(512,512) | ||
app.maxsize(512,512) | ||
app.title('GIF TO BOOT ANIMATITON') | ||
app.protocol("WM_DELETE_WINDOW", on_closing) | ||
set_appearance_mode("light") | ||
app.iconbitmap(sys._MEIPASS+"\loading.ico") | ||
btn=CTkButton(master=app,text='Select Gif',corner_radius=20,fg_color="#C850C0",hover_color="#4158D0",border_color="#000000",border_width=2,width=150,height=50,command=select_gif_file) | ||
btn.place(relx=0.5,rely=0.1,anchor="center") | ||
app.mainloop() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,117 @@ | ||
import argparse | ||
import os | ||
import tempfile | ||
import zipfile | ||
from PIL import Image | ||
import gifextract | ||
|
||
def create(source, width, height, fps, save_to): | ||
zip=True | ||
source_dir = "" | ||
temp_dir = None | ||
if os.path.isdir(source): | ||
source_dir = source | ||
elif os.path.isfile(source) and get_extension(source) == "gif": | ||
temp_dir = tempfile.TemporaryDirectory() | ||
gifextract.processImage(source, temp_dir.name,width,height) | ||
source_dir = temp_dir.name | ||
else: | ||
print("Error: invalid source path: " + source) | ||
return | ||
|
||
images = get_images_paths(source_dir) | ||
if len(images) <= 0: | ||
print("Error: no images to process") | ||
return | ||
|
||
if not os.path.exists(save_to): | ||
os.makedirs(save_to) | ||
|
||
path_to_desc_file = create_desc_file(save_to, width, height, fps) | ||
|
||
dir_for_images = save_to + "/part0" | ||
if not os.path.exists(dir_for_images): | ||
os.makedirs(dir_for_images) | ||
|
||
count = 0 | ||
for img in images: | ||
count = transform_images(img, count, width, height, dir_for_images) | ||
|
||
with open(path_to_desc_file, "a") as f: | ||
print("p 1 0 part0", file=f) | ||
|
||
if zip is True: | ||
zip_file = zipfile.ZipFile(save_to + "/bootanimation.zip", mode="w", | ||
compression=zipfile.ZIP_STORED) | ||
|
||
zip_file.write(path_to_desc_file, | ||
arcname=os.path.basename(path_to_desc_file)) | ||
|
||
zip_dir(dir_for_images, zip_file) | ||
zip_file.close() | ||
|
||
print("Done") | ||
return True | ||
|
||
|
||
|
||
def get_extension(t_path): | ||
path_parts = str.split(t_path, '.') | ||
extension = path_parts[-1:][0] | ||
extension = extension.lower() | ||
return extension | ||
|
||
|
||
def get_images_paths(t_folder): | ||
if not os.path.isdir(t_folder): | ||
return list() | ||
|
||
image_extensions = ("jpg", "jpeg", "bmp", "png", "tiff") | ||
images = list() | ||
entries = os.listdir(t_folder) | ||
for entry in entries: | ||
file_path = os.path.join(t_folder, entry) | ||
extension = get_extension(file_path) | ||
if os.path.isfile(file_path) and extension in image_extensions: | ||
images.append(file_path) | ||
|
||
images.sort() | ||
return images | ||
|
||
|
||
def create_desc_file(t_folder, width, height, fps): | ||
file_name = t_folder + "/desc.txt" | ||
fd = open(file_name, mode="w+") | ||
print("{} {} {}".format(width, height, fps), file=fd) | ||
return file_name | ||
|
||
|
||
def transform_images(t_img_path, t_count, width, height, save_to_path): | ||
original_img = Image.open(t_img_path) | ||
|
||
# Scale image | ||
width_percent = (width / float(original_img.width)) | ||
height_size = int((float(original_img.height) * float(width_percent))) | ||
original_img = original_img.resize((width, height_size), Image.LANCZOS) | ||
|
||
result_image = Image.new("RGB", (width, height), "white") | ||
|
||
width_pos = 0 | ||
height_pos = int(height / 2 - original_img.height / 2) | ||
result_image.paste(original_img, (width_pos, height_pos)) | ||
|
||
result_img_name = "{0:0{width}}.png".format(t_count, width=5) | ||
result_img_path = save_to_path + "/" + result_img_name | ||
result_image.save(result_img_path) | ||
t_count += 1 | ||
return t_count | ||
|
||
|
||
def zip_dir(t_path, zip_file): | ||
path_head, last_dir = os.path.split(t_path) | ||
images = get_images_paths(t_path) | ||
for img in images: | ||
img_path_in_zip = last_dir + "/" + os.path.basename(img) | ||
zip_file.write(img, arcname=img_path_in_zip, | ||
compress_type=zipfile.ZIP_STORED) | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
from PIL import Image | ||
import os | ||
|
||
|
||
|
||
def analyseImage(path): | ||
""" | ||
Pre-process pass over the image to determine the mode (full or additive). | ||
Necessary as assessing single frames isn't reliable. Need to know the mode | ||
before processing all frames. | ||
""" | ||
im = Image.open(path) | ||
results = { | ||
'size': im.size, | ||
'mode': 'full', | ||
} | ||
|
||
try: | ||
while True: | ||
if im.tile: | ||
tile = im.tile[0] | ||
update_region = tile[1] | ||
update_region_dimensions = update_region[2:] | ||
if update_region_dimensions != im.size: | ||
results['mode'] = 'partial' | ||
break | ||
|
||
im.seek(im.tell() + 1) | ||
except EOFError: | ||
pass | ||
return results | ||
|
||
|
||
def processImage(path, output_folder,new_width, new_height): | ||
""" | ||
Iterate the GIF, extracting each frame. | ||
""" | ||
if not isinstance(new_width, int): | ||
new_width=int(new_width) | ||
if not isinstance(new_height, int): | ||
new_height=int(new_height) | ||
mode = analyseImage(path)['mode'] | ||
gif = Image.open(path) | ||
|
||
# Create the output folder if it doesn't exist | ||
if not os.path.exists(output_folder): | ||
os.makedirs(output_folder) | ||
|
||
for frame_number in range(gif.n_frames): | ||
gif.seek(frame_number) | ||
frame = gif.convert("RGBA") | ||
|
||
adjusted_frame_number = (frame_number - 1) % gif.n_frames | ||
|
||
resized_frame = frame.resize((new_width, new_height), Image.BOX) | ||
|
||
new_frame = Image.new('RGBA', (new_width,new_height)) | ||
|
||
if mode == 'partial': | ||
new_frame.paste(resized_frame) | ||
|
||
new_frame.paste(resized_frame, (0, 0), resized_frame) | ||
|
||
result_frame_path = os.path.join(output_folder, f"{adjusted_frame_number:05d}.png") | ||
new_frame.save(result_frame_path, 'PNG') | ||
|
||
gif.close() |
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
customtkinter==5.2.2 | ||
Pillow==10.2.0 |