import os import sys from PIL import Image, ImageSequence def gif_to_xbm(gif_path, output_h_path, var_name, target_w=None, target_h=None): im = Image.open(gif_path) frames = [] for frame in ImageSequence.Iterator(im): f = frame.convert('RGBA') # Weißer Hintergrund für transparente GIFs bg = Image.new('RGBA', f.size, (255, 255, 255)) f = Image.alpha_composite(bg, f).convert('1') # 1-Bit Schwarz/Weiß if target_w and target_h: f = f.resize((target_w, target_h), Image.Resampling.NEAREST) frames.append(f) w, h = frames[0].size bytes_per_row = (w + 7) // 8 with open(output_h_path, 'w') as out: out.write(f"#pragma once\n#include \n\n") out.write(f"// Abmessungen: {w}x{h}, {len(frames)} Frames\n") out.write(f"#define {var_name.upper()}_WIDTH {w}\n") out.write(f"#define {var_name.upper()}_HEIGHT {h}\n") out.write(f"#define {var_name.upper()}_FRAME_COUNT {len(frames)}\n\n") # 1. Einzelne Frames als XBM-Arrays schreiben (LSB-first) for idx, frame in enumerate(frames): out.write(f"const unsigned char {var_name}_frame_{idx}[] PROGMEM = {{\n ") pixels = frame.load() byte_list = [] for y in range(h): for byte_idx in range(bytes_per_row): byte_val = 0 for bit in range(8): x = byte_idx * 8 + bit if x < w: # 0 = Schwarz (Pixel an bei XBM), 1 = Weiß if pixels[x, y] == 0: byte_val |= (1 << bit) byte_list.append(f"0x{byte_val:02X}") out.write(", ".join(byte_list)) out.write("\n};\n\n") # 2. Master-Array aller Frame-Pointer out.write(f"const unsigned char* const {var_name}_frames[] PROGMEM = {{\n") for idx in range(len(frames)): out.write(f" {var_name}_frame_{idx},\n") out.write("};\n") print(f"Fertig! {len(frames)} Frames exportiert nach: {output_h_path}") # Aufruf: Datei, Ausgabedatei, Arrayname, Breite, Höhe if __name__ == "__main__": gif_to_xbm("fire.gif", "fire_frames.h", "fire_flames", 21, 32) gif_to_xbm("clock.gif", "clock_frames.h", "clock", 21, 21)