Skip to content
Snippets Groups Projects
Commit f6f056da authored by paulscalise1's avatar paulscalise1
Browse files

gif support in the utility, added herbie gif in code

parent 8eab1a68
No related branches found
No related tags found
No related merge requests found
......@@ -51,6 +51,8 @@
const uint8_t * flag[20] = {Frame0, Frame1, Frame2, Frame3, Frame4, Frame5, Frame6, Frame7, Frame8, Frame9, Frame10, \
Frame11, Frame12, Frame13, Frame14, Frame15, Frame16, Frame17, Frame18, Frame19};
const uint8_t * gif[18] = {gif1, gif2, gif3, gif4, gif5, gif6, gif7, gif8, gif9, gif10, \
gif11, gif12, gif13, gif14, gif15, gif16, gif17, gif18};
const uint8_t * pointers[9] = {gbr0, gbr1, gbr2, gbr3, gbr4, gbr5, gbr6, gbr7, gbr8};
uint8_t init1[5] = {0x00, 0xAE, 0xD5, 0x80, 0xA8};
......
This diff is collapsed.
import tkinter as tk
from tkinter import ttk, filedialog, scrolledtext
from PIL import Image, ImageTk, ImageEnhance
from tkinter import ttk, filedialog, scrolledtext, messagebox
from PIL import Image, ImageTk, ImageEnhance, ImageOps
import subprocess
import os
......@@ -96,20 +96,57 @@ class UNLKeychainProgrammerApp:
# Add a "Copy to Clipboard" button
self.copy_button = ttk.Button(self.page2, text="Copy Code to Clipboard", command=self.copy_to_clipboard)
self.copy_button.pack(pady=10)
'''
# Page 3: Information Page
# Page 3: GIF to Bitmap Converter
self.page3 = ttk.Frame(self.notebook)
self.notebook.add(self.page3, text="Information")
self.notebook.add(self.page3, text="GIF Playground")
# Upload GIF button
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)
# 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.pack(pady=5)
# Slider for number of frames
self.frame_slider_label = ttk.Label(self.page3)
#self.frame_slider_label.pack(pady=5)
self.frame_slider = ttk.Scale(self.page3, from_=1, to=100, orient=tk.HORIZONTAL)
self.frame_slider.pack(pady=5)
# Bind the slider to update the label
self.frame_slider.config(command=self.update_slider_value_label)
# Checkbox for retaining aspect ratio
self.aspect_ratio_var = tk.BooleanVar(value=True)
self.aspect_ratio_checkbox = ttk.Checkbutton(self.page3, text="Retain Aspect Ratio", variable=self.aspect_ratio_var)
self.aspect_ratio_checkbox.pack(pady=5)
# Save GIF button
self.save_gif_button = ttk.Button(self.page3, text="Generate GIF Frame Code", command=self.save_gif)
self.save_gif_button.pack(pady=10)
# GIF preview window
self.gif_preview_label = ttk.Label(self.page3)
self.gif_preview_label.pack(pady=10)
# Scrollable text window
self.info_text = scrolledtext.ScrolledText(self.page3, wrap=tk.WORD, width=80, height=20)
self.info_text.pack(padx=10, pady=10)
# C Array output text box
self.gif_array_text = scrolledtext.ScrolledText(self.page3, wrap=tk.WORD, width=100, height=13)
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)
# Variable to track the preview loop
self.after_id = None
# Add some initial text to the information page
self.info_text.insert(tk.END, "Welcome to the UNL Keychain Programmer Application.\n\n")
self.info_text.insert(tk.END, "This application allows you to program your UNL Keychain device and convert images to bitmaps.\n")
'''
def toggle_options(self):
"""Toggle the visibility of the options frame."""
if self.options_visible:
......@@ -168,7 +205,7 @@ class UNLKeychainProgrammerApp:
else:
pixels = self.process_image_regular(self.image_path, brightness)
c_arr = self.generate_c_array(pixels)
c_arr = self.generate_c_array(pixels, "const uint8_t custom_frame[1024] = {")
self.c_array_text.delete(1.0, tk.END)
self.c_array_text.insert(tk.END, c_arr)
......@@ -182,18 +219,15 @@ class UNLKeychainProgrammerApp:
def copy_to_clipboard(self):
"""Copy the content of the ScrolledText widget to the clipboard."""
# Enable the widget temporarily to get its content
text = self.c_array_text.get("1.0", tk.END).strip() # Get all text and remove trailing newline
# Copy the text to the clipboard
text = self.c_array_text.get("1.0", tk.END).strip()
self.root.clipboard_clear()
self.root.clipboard_append(text)
self.root.update() # Ensure the clipboard is updated
self.root.update()
def process_image_regular(self, filename, brightness=1.0):
img = Image.open(filename).convert('L')
enhancer = ImageEnhance.Brightness(img)
img = enhancer.enhance(brightness) # Apply brightness adjustment
img = enhancer.enhance(brightness)
img = img.resize((128, 64))
img.save('greyscale3.png')
......@@ -210,7 +244,6 @@ class UNLKeychainProgrammerApp:
mono = Image.new(mono.mode, mono.size)
mono.putdata(pixels)
# Extract the base filename and prepend 'monochrome_'
base_filename = os.path.basename(filename)
output_filename = f'monochrome_{base_filename}'
mono.save(output_filename)
......@@ -219,11 +252,8 @@ class UNLKeychainProgrammerApp:
def process_image_mono(self, filename):
img = Image.open(filename).convert('L')
# Resize image
img = img.resize((128, 64))
# Manual binary thresholding
threshold = 128
mono = img.point(lambda p: 255 if p > threshold else 0, '1')
......@@ -231,38 +261,34 @@ class UNLKeychainProgrammerApp:
white = pixels.count(255)
black = pixels.count(0)
# Invert colors if needed
if white > black:
pixels = [0 if elem == 255 else 255 for elem in pixels]
# Create monochrome image
mono = Image.new('1', (128, 64))
mono.putdata(pixels)
# Extract the base filename and prepend 'monochrome_'
base_filename = os.path.basename(filename)
output_filename = f'monochrome_{base_filename}'
mono.save(output_filename)
return pixels
def generate_c_array(self, pixels):
c_arr = 'const uint8_t custom_frame[1024] = {'
def generate_c_array(self, pixels, c_arr_str):
c_arr = c_arr_str
q = 0
for i in range(len(pixels)):
j = i % 8
if j == 0 and i != 0:
c_arr += f"0x{q:02x},"
q = 0
if pixels[i] == 255: # Adjust for binary value
if pixels[i] == 255:
q += 1 << (7 - j)
c_arr += f"0x{q:02x}" # Include the last byte
c_arr += f"0x{q:02x}"
c_arr += '};'
# Obtaining the raw hex values of the bitmap array, and converting them to the displays paging format
start_index = c_arr.find("{") + 1 # Find the index after '{'
end_index = c_arr.find("}") # Find the index before '}'
hex_values_str = c_arr[start_index:end_index] # Extract the substring
start_index = c_arr.find("{") + 1
end_index = c_arr.find("}")
hex_values_str = c_arr[start_index:end_index]
hex_values_list = hex_values_str.split(",")
reg_bitmap = [int(x.strip(), 16) for x in hex_values_list]
......@@ -275,20 +301,128 @@ class UNLKeychainProgrammerApp:
for e in range(8):
buff[e] = buff[e] | ((b & 0x01) << col)
b = b >> 1
# Append buff to output
paged_bitmap.extend(buff)
hex_strings = [f"0x{byte:02x}" for byte in paged_bitmap]
chunks = [hex_strings[i:i + 16] for i in range(0, len(hex_strings), 16)]
rows = [", ".join(chunk) for chunk in chunks]
return "const uint8_t display_bitmap[1024] = {\n " + ",\n ".join(rows) + "};"
return c_arr_str + "\n " + ",\n ".join(rows) + "};"
def show_image_preview(self, image_path):
image = Image.open(image_path)
image = image.resize((128, 64)) # Resize for better preview
image = image.resize((128, 64))
photo = ImageTk.PhotoImage(image)
self.image_preview_label.config(image=photo)
self.image_preview_label.image = photo # Keep a reference to avoid garbage collection
self.image_preview_label.image = photo
def upload_gif(self):
file_path = filedialog.askopenfilename(filetypes=[("GIF files", "*.gif")])
if file_path:
self.gif_path = file_path
self.show_gif_preview(file_path)
else:
self.gif_preview_label.config(text="No GIF selected.")
def show_gif_preview(self, gif_path):
if self.after_id:
self.root.after_cancel(self.after_id) # Stop the previous loop
gif = Image.open(gif_path)
self.gif_frames = []
self.frame_durations = []
for frame in range(gif.n_frames):
gif.seek(frame)
self.gif_frames.append(gif.copy())
self.frame_durations.append(gif.info['duration'])
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.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))}")
def update_gif_preview(self):
if self.gif_frames:
frame_image = ImageTk.PhotoImage(self.gif_frames[self.current_frame])
self.gif_preview_label.config(image=frame_image)
self.gif_preview_label.image = frame_image
self.current_frame = (self.current_frame + 1) % len(self.gif_frames)
self.after_id = self.root.after(self.frame_durations[self.current_frame], self.update_gif_preview)
def save_gif(self):
if hasattr(self, 'gif_path'):
num_frames = int(self.frame_slider.get()) # Get the slider value
retain_aspect_ratio = self.aspect_ratio_var.get()
output_path = os.path.join(os.getcwd(), "output.gif")
self.convert_gif_to_bw_gif(self.gif_path, output_path, num_frames, retain_aspect_ratio)
self.show_gif_preview(output_path)
else:
messagebox.showerror("Error", "No valid GIF file uploaded.")
def convert_gif_to_bw_gif(self, gif_path, output_path, num_frames, retain_aspect_ratio):
try:
gif = Image.open(gif_path)
frames = []
durations = []
total_frames = gif.n_frames
step = total_frames / num_frames
for i in range(num_frames):
frame_index = int(i * step)
gif.seek(frame_index)
if retain_aspect_ratio:
resized_frame = self.resize_with_aspect_ratio(gif, (128, 64))
else:
resized_frame = gif.resize((128, 64))
bw_frame = resized_frame.convert("1")
frames.append(bw_frame)
durations.append(gif.info['duration'])
frames[0].save(
output_path,
save_all=True,
append_images=frames[1:],
loop=0,
duration=durations,
disposal=2
)
self.gif_array_text.delete(1.0, tk.END)
for idx, frame in enumerate(frames):
pixels = list(frame.getdata())
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}")
return output_path
except Exception as e:
messagebox.showerror("Error", f"An error occurred: {e}")
return None
def resize_with_aspect_ratio(self, frame, target_size):
original_width, original_height = frame.size
target_width, target_height = target_size
aspect_ratio = original_width / original_height
if aspect_ratio > (target_width / target_height):
new_width = target_width
new_height = int(target_width / aspect_ratio)
else:
new_height = target_height
new_width = int(target_height * aspect_ratio)
resized_frame = frame.resize((new_width, new_height))
padded_frame = Image.new("1", target_size, 0)
padded_frame.paste(resized_frame, (
(target_width - new_width) // 2,
(target_height - new_height) // 2
))
return padded_frame
if __name__ == "__main__":
root = tk.Tk()
......
......@@ -91,11 +91,11 @@ void ssd1306_bitmap(const uint8_t *bitmap){
HAL_I2C_Master_Transmit(&hi2c1, SSD1306_ADDR, transmit, 1025, 5000);
}
void Display_On(){
void Display_On(void){
HAL_I2C_Master_Transmit(&hi2c1, SSD1306_ADDR, software_on, 2, 5000);
}
void ssd1306_clear()
void ssd1306_clear(void)
{
HAL_I2C_Master_Transmit(&hi2c1, SSD1306_ADDR, bitmap1, 6, 5000);
......@@ -106,7 +106,7 @@ void ssd1306_clear()
}
}
void ssd1306_init()
void ssd1306_init(void)
{
for(int i = 0; i < 12; i++)
{
......@@ -137,7 +137,7 @@ void displayArray(const uint8_t ** image, int repeat, int frames, int reverse, i
}
}
void SysTick_Handler()
void SysTick_Handler(void)
{
HAL_IncTick();
}
......@@ -288,7 +288,7 @@ void GPIO_I2C_Init(void) {
//HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
}
void display_Switch_Init(){
void display_Switch_Init(void){
GPIO_InitTypeDef GPIO_InitStruct = {0};
GPIO_InitStruct.Pin = GPIO_PIN_1;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
......@@ -298,12 +298,12 @@ void display_Switch_Init(){
HAL_Delay(5);
}
void display_Power_On(){
void display_Power_On(void){
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_1, GPIO_PIN_SET);
HAL_Delay(100);
LPTIM_Delay(100);
}
void display_Power_Off(){
void display_Power_Off(void){
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_1, GPIO_PIN_RESET);
}
......@@ -347,7 +347,7 @@ uint8_t Accel_ReadReg(uint8_t reg){
return reg_value;
}
void LED_Init(){
void LED_Init(void){
__HAL_RCC_GPIOA_CLK_ENABLE(); // Enable GPIOA clock
GPIO_InitTypeDef GPIO_InitStruct = {0};
GPIO_InitStruct.Pin = GPIO_PIN_2;
......@@ -357,11 +357,11 @@ void LED_Init(){
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
}
void Toggle_LED(){
void Toggle_LED(void){
HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_2);
}
void Accel_Init(){
void Accel_Init(void){
// Inits the accelerometer to send an interrupt signal on any axis movement.
HAL_Delay(10);
Accel_WriteReg(CTRL_REG1, 0x5F); // Turn on the sensor and enable X, Y, and Z, low power mode
......@@ -377,7 +377,7 @@ void Accel_Init(){
//Accel_WriteReg(INT1_CFG, 0x7F);
}
void EXTI_Init(){
void EXTI_Init(void){
/* Configure GPIO pin */
GPIO_InitTypeDef GPIO_InitStruct={0};
__HAL_RCC_GPIOA_CLK_ENABLE(); // Enable GPIOA clock
......@@ -393,7 +393,7 @@ void EXTI_Init(){
HAL_NVIC_SetPriority(EXTI4_15_IRQn, 0, 0);
}
void Stop_Mode_EXTI_Init(){
void Stop_Mode_EXTI_Init(void){
__HAL_RCC_SYSCFG_CLK_ENABLE();
__HAL_RCC_PWR_CLK_ENABLE();
GPIO_InitTypeDef GPIO_InitStruct={0};
......@@ -413,22 +413,24 @@ void EXTI4_15_IRQHandler(void)
HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_5);
}
void Display_UNL_Info(){
void Display_UNL_Info(void){
displayArray(gif, 4, 18, 0, 63);
ssd1306_bitmap(dept);
LPTIM_Delay(4000);
displayArray(flag, 2, 20, 0, 10);
displayArray(pointers, 2, 8, 1, 5);
ssd1306_bitmap((const uint8_t *)dept);
LPTIM_Delay(3000);
displayArray(flag, 2, 20, 0, 10);
displayArray(pointers, 2, 8, 1, 5);
ssd1306_bitmap((const uint8_t *)dept);
LPTIM_Delay(3000);
displayArray(pointers, 2, 8, 1, 7);
///ssd1306_bitmap((const uint8_t *)dept);
//LPTIM_Delay(4000);
//ssd1306_bitmap((const uint8_t *)apply_qr);
//LPTIM_Delay(5000);
//displayArray(gif, 4, 18, 0, 63);
}
void Sleep(){
void Sleep(void){
HAL_I2C_Master_Transmit(&hi2c1, SSD1306_ADDR, software_off, 2, 5000);
display_Power_Off();
HAL_SuspendTick();
// Enter STOP mode
/// Enter STOP mode
HAL_PWR_EnterSTOPMode(PWR_LOWPOWERREGULATOR_ON, PWR_STOPENTRY_WFI);
// After waking up
HAL_ResumeTick();
......@@ -437,7 +439,7 @@ void Sleep(){
ssd1306_init();
}
void ssd1306_rotate_180(){
void ssd1306_rotate_180(void){
uint8_t rotate[] = {0x00,0xA1,0xC8};
HAL_I2C_Master_Transmit(&hi2c1, SSD1306_ADDR, rotate, 3, 5000);
}
......@@ -456,7 +458,7 @@ int main (void)
I2C_Init();
Accel_Init();
EXTI_Init();
LED_Init();
//LED_Init();
ssd1306_init();
while (1) {
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment