Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added .github/1.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added .github/GifCompress.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added .github/GifFrameEditor.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added .github/GifResize.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added .github/GifTextEditor.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added .github/MainUI.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added .github/Mp42Gif.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added .github/fear.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added .github/reaction-horse-megacompressed.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added .github/reaction-horse.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
output
pygifsicle
TEST
__pycache__
65 changes: 43 additions & 22 deletions AddTextToGif.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,18 @@
from PIL import Image, ImageTk, ImageDraw, ImageFont, ImageSequence
import os


class GifTextEditor:
def __init__(self, root):
self.root = root
self.root.title("GIF Text Editor")

self.gif_image = None
self.frames = []
self.duration = 100
self.frames = []
self.duration = 100
self.preview_image = None

self.text_x = 50
self.text_x = 50
self.text_y = 50

self.text_var = tk.StringVar(value="Enter your text here")
Expand All @@ -39,17 +40,20 @@ def __init__(self, root):

preview_frame = tk.Frame(root, bd=2, relief=tk.SUNKEN)
preview_frame.pack(side=tk.RIGHT, padx=5, pady=5)

self.canvas = tk.Canvas(preview_frame, width=500, height=500, bg="grey")

self.canvas = tk.Canvas(
preview_frame, width=500, height=500, bg="grey")
self.canvas.pack()
self.canvas.bind("<ButtonPress-1>", self.on_mouse_down)
self.canvas.bind("<B1-Motion>", self.on_mouse_drag)

load_btn = tk.Button(control_frame, text="Load GIF", command=self.load_gif)
load_btn = tk.Button(
control_frame, text="Load GIF", command=self.load_gif)
load_btn.pack(pady=2, fill=tk.X)

tk.Label(control_frame, text="Text:").pack(anchor="w")
text_entry = tk.Entry(control_frame, textvariable=self.text_var, width=40)
text_entry = tk.Entry(
control_frame, textvariable=self.text_var, width=40)
text_entry.pack(pady=2)
self.text_var.trace_add("write", lambda *args: self.update_preview())

Expand All @@ -63,7 +67,8 @@ def __init__(self, root):
tk.Spinbox(control_frame, from_=10, to=200, textvariable=self.font_size_var,
command=self.update_preview).pack(pady=2, fill=tk.X)

tk.Button(control_frame, text="Choose Font Color", command=self.choose_font_color).pack(pady=2, fill=tk.X)
tk.Button(control_frame, text="Choose Font Color",
command=self.choose_font_color).pack(pady=2, fill=tk.X)

tk.Label(control_frame, text="Textbox Width (px):").pack(anchor="w")
tk.Spinbox(control_frame, from_=50, to=1000, textvariable=self.textbox_width_var,
Expand All @@ -74,16 +79,19 @@ def __init__(self, root):
tk.Label(control_frame, text="Shadow Size:").pack(anchor="w")
tk.Spinbox(control_frame, from_=1, to=20, textvariable=self.shadow_size_var,
command=self.update_preview).pack(pady=2, fill=tk.X)
tk.Button(control_frame, text="Choose Shadow Color", command=self.choose_shadow_color).pack(pady=2, fill=tk.X)
tk.Button(control_frame, text="Choose Shadow Color",
command=self.choose_shadow_color).pack(pady=2, fill=tk.X)

tk.Checkbutton(control_frame, text="Enable Stroke", variable=self.stroke_enabled,
command=self.update_preview).pack(anchor="w")
tk.Label(control_frame, text="Stroke Size:").pack(anchor="w")
tk.Spinbox(control_frame, from_=1, to=20, textvariable=self.stroke_size_var,
command=self.update_preview).pack(pady=2, fill=tk.X)
tk.Button(control_frame, text="Choose Stroke Color", command=self.choose_stroke_color).pack(pady=2, fill=tk.X)
tk.Button(control_frame, text="Choose Stroke Color",
command=self.choose_stroke_color).pack(pady=2, fill=tk.X)

export_btn = tk.Button(control_frame, text="Export GIF", command=self.export_gif)
export_btn = tk.Button(
control_frame, text="Export GIF", command=self.export_gif)
export_btn.pack(pady=10, fill=tk.X)

def load_gif(self):
Expand Down Expand Up @@ -199,22 +207,26 @@ def update_preview(self):

if self.shadow_enabled.get():
shadow_offset = self.shadow_size_var.get()
shadow_pos = (self.text_x + shadow_offset, self.text_y + shadow_offset)
draw.multiline_text(shadow_pos, wrapped_text, font=font, fill=self.shadow_color)
shadow_pos = (self.text_x + shadow_offset,
self.text_y + shadow_offset)
draw.multiline_text(shadow_pos, wrapped_text,
font=font, fill=self.shadow_color)
if self.stroke_enabled.get():
draw.multiline_text((self.text_x, self.text_y), wrapped_text, font=font,
fill=self.font_color, stroke_width=self.stroke_size_var.get(),
stroke_fill=self.stroke_color)
else:
draw.multiline_text((self.text_x, self.text_y), wrapped_text, font=font, fill=self.font_color)
draw.multiline_text((self.text_x, self.text_y),
wrapped_text, font=font, fill=self.font_color)

self.preview_image = ImageTk.PhotoImage(preview)
self.canvas.delete("all")
self.canvas.create_image(0, 0, anchor="nw", image=self.preview_image)

def on_mouse_down(self, event):
font = self.get_font(self.font_size_var.get())
wrapped_text = self.wrap_text(self.text_var.get(), font, self.textbox_width_var.get())
wrapped_text = self.wrap_text(
self.text_var.get(), font, self.textbox_width_var.get())
text_size = self.get_multiline_text_size(wrapped_text, font)
x0, y0 = self.text_x, self.text_y
x1, y1 = x0 + text_size[0], y0 + text_size[1]
Expand Down Expand Up @@ -251,24 +263,33 @@ def export_gif(self):
draw = ImageDraw.Draw(frame)
if self.shadow_enabled.get():
shadow_offset = self.shadow_size_var.get()
shadow_pos = (self.text_x + shadow_offset, self.text_y + shadow_offset)
draw.multiline_text(shadow_pos, wrapped_text, font=font, fill=self.shadow_color)
shadow_pos = (self.text_x + shadow_offset,
self.text_y + shadow_offset)
draw.multiline_text(shadow_pos, wrapped_text,
font=font, fill=self.shadow_color)
if self.stroke_enabled.get():
draw.multiline_text((self.text_x, self.text_y), wrapped_text, font=font,
fill=self.font_color, stroke_width=self.stroke_size_var.get(),
stroke_fill=self.stroke_color)
else:
draw.multiline_text((self.text_x, self.text_y), wrapped_text, font=font, fill=self.font_color)
draw.multiline_text((self.text_x, self.text_y),
wrapped_text, font=font, fill=self.font_color)
new_frames.append(frame)

try:
new_frames[0].save(out_path, save_all=True, append_images=new_frames[1:],
duration=self.duration, loop=0, disposal=2)
messagebox.showinfo("Success", f"Exported GIF saved to:\n{out_path}")
duration=self.duration, loop=0, disposal=2)
messagebox.showinfo(
"Success", f"Exported GIF saved to:\n{out_path}")
except Exception as e:
messagebox.showerror("Error", f"Failed to export GIF:\n{e}")

if __name__ == "__main__":
root = tk.Tk()

def start_add_text_to_gif():
root = tk.Toplevel()
app = GifTextEditor(root)
root.mainloop()


if __name__ == "__main__":
start_add_text_to_gif()
138 changes: 138 additions & 0 deletions CompressGif.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
import tkinter as tk
from tkinter import filedialog, messagebox
import os
from pygifsicle import gifsicle
import ttkbootstrap as ttk


def browse_input():
file_path = filedialog.askopenfilename(filetypes=[("GIF files", "*.gif")])
if file_path:
entry_input.delete(0, tk.END)
entry_input.insert(0, file_path)


def browse_output():
file_path = filedialog.asksaveasfilename(
defaultextension=".gif", filetypes=[("GIF files", "*.gif")])
if file_path:
entry_output.delete(0, tk.END)
entry_output.insert(0, file_path)


def compress_gif():
input_file = entry_input.get()
output_file = entry_output.get()

if not os.path.exists(input_file):
messagebox.showerror("Error", "Input file does not exist.")
return
if not output_file:
messagebox.showerror("Error", "Please specify an output file.")
return

color_count = entry_color_count.get() if var_color.get() else None
quality = entry_quality.get() if var_lossy.get() else None

try:
# Set up options for gifsicle
options = {
'sources': [input_file],
'destination': output_file,
'optimize': True,
}

if color_count is not None:
options['colors'] = int(color_count)
if quality is not None:
options['options'] = [f'--lossy={int(quality)}']

gifsicle(**options) # Use the gifsicle function with options as kwargs

messagebox.showinfo("Success", "Compression completed successfully!")
except Exception as e:
messagebox.showerror("Error", f"An error occurred:\n{e}")
print(f"Error: {e}")


def toggle_options():
if var_color.get():
label_color_count.grid(row=7, column=0, padx=5, pady=5, sticky="e")
slider_color_count.grid(row=7, column=1, padx=5, pady=5, sticky="w")
entry_color_count.grid(row=7, column=2, padx=5, pady=5, sticky="w")
else:
label_color_count.grid_forget()
slider_color_count.grid_forget()
entry_color_count.grid_forget()

if var_lossy.get():
label_quality.grid(row=8, column=0, padx=5, pady=5, sticky="e")
slider_quality.grid(row=8, column=1, padx=5, pady=5, sticky="w")
entry_quality.grid(row=8, column=2, padx=5, pady=5, sticky="w")
else:
label_quality.grid_forget()
slider_quality.grid_forget()
entry_quality.grid_forget()


def update_color_count(value):
entry_color_count.delete(0, tk.END)
entry_color_count.insert(0, value)


def update_quality(value):
entry_quality.delete(0, tk.END)
entry_quality.insert(0, value)


def start_compress_gif():
global entry_input, entry_output, entry_color_count, entry_quality, var_color, var_lossy
global label_color_count, slider_color_count, label_quality, slider_quality

# Set up the GUI
root = tk.Toplevel()
root.title("GIF Compressor")

# Input file selection
tk.Label(root, text="Input GIF File:").grid(
row=0, column=0, padx=5, pady=5, sticky="e")
entry_input = tk.Entry(root, width=50)
entry_input.grid(row=0, column=1, padx=5, pady=5)
tk.Button(root, text="Browse", command=browse_input).grid(
row=0, column=2, padx=5, pady=5)

# Output file selection
tk.Label(root, text="Output GIF File:").grid(
row=1, column=0, padx=5, pady=5, sticky="e")
entry_output = tk.Entry(root, width=50)
entry_output.grid(row=1, column=1, padx=5, pady=5)
tk.Button(root, text="Browse", command=browse_output).grid(
row=1, column=2, padx=5, pady=5)

# Color reduction option
var_color = tk.BooleanVar()
tk.Checkbutton(root, text="Enable Color Reduction", variable=var_color,
command=toggle_options).grid(row=6, column=1, padx=5, pady=5, sticky="w")
label_color_count = tk.Label(root, text="Color Count (2-256):")
slider_color_count = tk.Scale(
root, from_=2, to=256, orient=tk.HORIZONTAL, command=update_color_count)
entry_color_count = tk.Entry(root)
entry_color_count.insert(0, "2") # default value

# Lossy GIF option
var_lossy = tk.BooleanVar()
tk.Checkbutton(root, text="Enable Lossy GIF", variable=var_lossy,
command=toggle_options).grid(row=6, column=2, padx=5, pady=5, sticky="w")
label_quality = tk.Label(root, text="Quality (30-200):")
slider_quality = tk.Scale(root, from_=30, to=200,
orient=tk.HORIZONTAL, command=update_quality)
entry_quality = tk.Entry(root)
entry_quality.insert(0, "30") # default value

# Compress button
tk.Button(root, text="Compress", command=compress_gif).grid(
row=9, column=1, padx=5, pady=15)


if __name__ == "__main__":
start_compress_gif()
Loading