diff --git a/keychain-utility.py b/keychain-utility.py index 787a5ae9445302a5c0685f5a95087d88c6ca40fe..e94fec56a1b57ce88e97ec34829baf3d833d6627 100644 --- a/keychain-utility.py +++ b/keychain-utility.py @@ -8,7 +8,7 @@ class UNLKeychainProgrammerApp: def __init__(self, root): self.root = root self.root.title("UNL Keychain Utility") - self.root.geometry("800x600") + self.root.geometry("850x650") # Create a notebook (tabbed interface) self.notebook = ttk.Notebook(root) @@ -105,12 +105,18 @@ class UNLKeychainProgrammerApp: self.upload_gif_button = ttk.Button(self.page3, text="Upload GIF", command=self.upload_gif) self.upload_gif_button.pack(pady=10) - # Label to display the number of frames - self.frame_count_label = ttk.Label(self.page3, text="Original number of frames: 0") - self.frame_count_label.pack(pady=5) + # Create a frame to hold the labels + self.frame_info_container = ttk.Frame(self.page3) + self.frame_info_container.pack(pady=5) + + self.frame_count_label = ttk.Label(self.frame_info_container, text="Original number of frames: 0") + self.frame_count_label.pack(side=tk.LEFT, padx=10) + + self.frame_duration_value_label = ttk.Label(self.frame_info_container, text="Average Frame Duration: 0 ms") + self.frame_duration_value_label.pack(side=tk.LEFT, padx=10) # Label to display the slider value (frames to output) - self.frame_slider_value_label = ttk.Label(self.page3, text="Frames to output: 0") + self.frame_slider_value_label = ttk.Label(self.page3, text="Frames to output: 0 (also output size in KB)") self.frame_slider_value_label.pack(pady=5) # Slider for number of frames @@ -141,11 +147,12 @@ class UNLKeychainProgrammerApp: self.gif_array_text.pack(padx=10, pady=10) # Add a "Copy to Clipboard" button - self.copy_text = ttk.Button(self.page3, text="Copy Code to Clipboard", command=self.copy_to_clipboard) - self.copy_text.pack(pady=10) + self.copy_gif_text = ttk.Button(self.page3, text="Copy Code to Clipboard", command=self.copy_gif_text_clipboard) + self.copy_gif_text.pack(pady=10) # Variable to track the preview loop self.after_id = None + self.uploaded_gif_path = None def toggle_options(self): """Toggle the visibility of the options frame.""" @@ -224,6 +231,13 @@ class UNLKeychainProgrammerApp: self.root.clipboard_append(text) self.root.update() + def copy_gif_text_clipboard(self): + """Copy the content of the ScrolledText widget to the clipboard.""" + text = self.gif_array_text.get("1.0", tk.END).strip() + self.root.clipboard_clear() + self.root.clipboard_append(text) + self.root.update() + def process_image_regular(self, filename, brightness=1.0): img = Image.open(filename).convert('L') enhancer = ImageEnhance.Brightness(img) @@ -320,6 +334,7 @@ class UNLKeychainProgrammerApp: if file_path: self.gif_path = file_path self.show_gif_preview(file_path) + self.update_frame_duration_vlaue_label(file_path) else: self.gif_preview_label.config(text="No GIF selected.") @@ -336,13 +351,26 @@ class UNLKeychainProgrammerApp: self.current_frame = 0 self.frame_count_label.config(text=f"Number of frames: {len(self.gif_frames)}") # Update frame count self.frame_slider.config(to=len(self.gif_frames)) # Update slider max value - self.frame_slider.set(int(len(self.gif_frames) * 0.75)) # Set default to 75% of total frames + self.frame_slider.set(int((len(self.gif_frames) - 1) * 0.50)) # Set default to 50% of total frames self.update_slider_value_label(self.frame_slider.get()) # Update the slider value label self.update_gif_preview() def update_slider_value_label(self, value): """Update the label to show the current slider value.""" - self.frame_slider_value_label.config(text=f"Frames to output: {int(float(value))}") + self.frame_slider_value_label.config(text=f"Frames to output: {int(float(value))} (also output size in KB)") + + def update_frame_duration_vlaue_label(self, gif_path): + gif = Image.open(gif_path) + total_frames = gif.n_frames + # Calculate total duration of original GIF + gif_duration = 0 + for i in range(total_frames): + gif.seek(i) + gif_duration += gif.info['duration'] + + # Calculate new duration per frame to maintain total duration + duration_per_frame = int(gif_duration / (total_frames)) + self.frame_duration_value_label.config(text=f"Average Frame Duration: {int(duration_per_frame)} ms") def update_gif_preview(self): if self.gif_frames: @@ -369,8 +397,18 @@ class UNLKeychainProgrammerApp: durations = [] total_frames = gif.n_frames step = total_frames / num_frames + + # Calculate total duration of original GIF + original_duration = 0 + for i in range(total_frames): + gif.seek(i) + original_duration += gif.info['duration'] + + # Calculate new duration per frame to maintain total duration + new_duration_per_frame = int(original_duration / (num_frames - 1)) # -1 because we skip first frame + - for i in range(num_frames): + for i in range(1, num_frames): frame_index = int(i * step) gif.seek(frame_index) @@ -381,7 +419,7 @@ class UNLKeychainProgrammerApp: bw_frame = resized_frame.convert("1") frames.append(bw_frame) - durations.append(gif.info['duration']) + durations.append(new_duration_per_frame) frames[0].save( output_path, @@ -398,7 +436,17 @@ class UNLKeychainProgrammerApp: c_arr = self.generate_c_array(pixels, f"const uint8_t gif{idx}[1024] = {{") self.gif_array_text.insert(tk.END, c_arr + "\n\n") - #messagebox.showinfo("Success", f"GIF converted to 128x64 black-and-white GIF and saved as {output_path}") + self.gif_array_text.insert(tk.END, f"const uint8_t * gif[{len(frames)}] = {{") + + for idx, frame in enumerate(frames): + if (idx != 0 and idx % 10 == 0): + self.gif_array_text.insert(tk.END, f" \\ \n\t\t") + if (idx == len(frames) - 1): + self.gif_array_text.insert(tk.END, f"gif{idx}}};\n\n") + else: + self.gif_array_text.insert(tk.END, f"gif{idx}, ") + + return output_path except Exception as e: messagebox.showerror("Error", f"An error occurred: {e}")