here2share

# tk_FFT_RGB_Image_Compressor.py

Nov 7th, 2025
182
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 6.21 KB | None | 0 0
  1. # tk_FFT_RGB_Image_Compressor.py
  2.  
  3. from tkinter import *
  4. from tkinter import filedialog
  5. from PIL import Image, ImageTk
  6. import cmath, struct, os, base64
  7.  
  8. def fft(x):
  9.     n = len(x)
  10.     if n <= 1: return x
  11.     even = fft(x[0::2]); odd = fft(x[1::2])
  12.     t = [cmath.exp(-2j*cmath.pi*k/n) * odd[k] for k in range(n//2)]
  13.     return [even[k] + t[k] for k in range(n//2)] + [even[k] - t[k] for k in range(n//2)]
  14.  
  15. def ifft(x):
  16.     n = len(x)
  17.     conj = [v.conjugate() for v in x]
  18.     y = fft(conj)
  19.     return [v.conjugate()/n for v in y]
  20.  
  21. def dft2d(m):
  22.     t = [fft(row) for row in m]
  23.     t2 = list(zip(*t))
  24.     t3 = [fft(list(col)) for col in t2]
  25.     return [list(row) for row in zip(*t3)]
  26.  
  27. def idft2d(m):
  28.     t = [ifft(row) for row in m]
  29.     t2 = list(zip(*t))
  30.     t3 = [ifft(list(col)) for col in t2]
  31.     return [list(row) for row in zip(*t3)]
  32.  
  33. def compress_fft_sorted(m,f):
  34.     vals = [abs(v) for r in m for v in r]
  35.     vals.sort(reverse=True)
  36.     k = int(len(vals) * f)
  37.     th = vals[k] if k < len(vals) else 0
  38.     return [[v if abs(v) >= th else 0 for v in r] for r in m]
  39.  
  40. def compress_image(img):
  41.     w,h = img.size
  42.     r = [[img.getpixel((x,y))[0] for x in range(w)] for y in range(h)]
  43.     g = [[img.getpixel((x,y))[1] for x in range(w)] for y in range(h)]
  44.     b = [[img.getpixel((x,y))[2] for x in range(w)] for y in range(h)]
  45.     return dft2d(r), dft2d(g), dft2d(b)
  46.  
  47. def reconstruct(fr,fg,fb,w,h,f):
  48.     fr = compress_fft_sorted(fr,f)
  49.     fg = compress_fft_sorted(fg,f)
  50.     fb = compress_fft_sorted(fb,f)
  51.     rr = idft2d(fr); rg = idft2d(fg); rb = idft2d(fb)
  52.     out = Image.new("RGB",(w,h))
  53.     for y in range(h):
  54.         for x in range(w):
  55.             rv = int(max(0,min(255,abs(rr[y][x]))))
  56.             gv = int(max(0,min(255,abs(rg[y][x]))))
  57.             bv = int(max(0,min(255,abs(rb[y][x]))))
  58.             out.putpixel((x,y),(rv,gv,bv))
  59.     return out
  60.  
  61. def save_binary(ms,w,h,p):
  62.     with open(p,"wb") as f:
  63.         f.write(struct.pack("II",w,h))
  64.         for mtx in ms:
  65.             for row in mtx:
  66.                 for v in row:
  67.                     f.write(struct.pack("ff",v.real,v.imag))
  68.  
  69. def load_binary(p):
  70.     with open(p,"rb") as f:
  71.         w,h = struct.unpack("II",f.read(8))
  72.         data = []
  73.         for _ in range(3):
  74.             m = []
  75.             for _ in range(h):
  76.                 row = []
  77.                 for _ in range(w):
  78.                     r,i = struct.unpack("ff",f.read(8))
  79.                     row.append(complex(r,i))
  80.                 m.append(row)
  81.             data.append(m)
  82.     return w,h,data
  83.  
  84. def load_image():
  85.     global fft_data,w,h,folder
  86.     p = filedialog.askopenfilename()
  87.     if not p: return
  88.     folder = os.path.dirname(p)
  89.     img = Image.open(p).convert("RGB")
  90.     fft_data = compress_image(img)
  91.     w,h = img.size
  92.     savepath = os.path.splitext(p)[0] + ".fftbin"
  93.     save_binary(fft_data,w,h,savepath)
  94.     generate_random_filename()
  95.     show_image()
  96.  
  97. def load_compression():
  98.     global fft_data,w,h,folder
  99.     p = filedialog.askopenfilename(filetypes=[("FFT Binary","*.fftbin")])
  100.     if not p: return
  101.     folder = os.path.dirname(p)
  102.     w,h,fft_data = load_binary(p)
  103.     generate_random_filename()
  104.     show_image()
  105.  
  106. def update_compression():
  107.     global ratio
  108.     if not fft_data: return
  109.     try: ratio = float(entry.get())
  110.     except: ratio = 0.1
  111.     show_image()
  112.  
  113. def save_png():
  114.     if not fft_data: return
  115.     out = reconstruct(fft_data[0],fft_data[1],fft_data[2],w,h,ratio)
  116.     p = filedialog.asksaveasfilename(defaultextension=".png")
  117.     if p: out.save(p)
  118.  
  119. def generate_random_filename():
  120.     global preview_name
  121.     rand = base64.b64encode(os.urandom(12)).decode("ascii")[:16]
  122.     preview_name = str(h).zfill(4) + str(w).zfill(4) + "_" + rand + ".png"
  123.     filename_label.config(text=preview_name)
  124.  
  125. def auto_rename_save():
  126.     if not fft_data or not folder: return
  127.     out = reconstruct(fft_data[0],fft_data[1],fft_data[2],w,h,ratio)
  128.     while True:
  129.         rand = base64.b64encode(os.urandom(12)).decode("ascii")[:16]
  130.         name = str(h).zfill(4) + str(w).zfill(4) + "_" + rand + ".png"
  131.         path = os.path.join(folder,name)
  132.         if not os.path.exists(path):
  133.             out.save(path)
  134.             generate_random_filename()
  135.             break
  136.  
  137. def show_image():
  138.     if not fft_data: return
  139.     out = reconstruct(fft_data[0],fft_data[1],fft_data[2],w,h,ratio)
  140.     tkimg = ImageTk.PhotoImage(out)
  141.     canvas.delete("all")
  142.     canvas.image = tkimg
  143.     canvas.create_image(0,0,image=tkimg,anchor=NW)
  144.     canvas.config(scrollregion=(0,0,w,h))
  145.  
  146. def start_pan(e): canvas.scan_mark(e.x,e.y)
  147. def drag_pan(e): canvas.scan_dragto(e.x,e.y,1)
  148.  
  149. fft_data = None
  150. ratio = 0.1
  151. w = h = 0
  152. folder = ""
  153. preview_name = ""
  154.  
  155. root = Tk()
  156. root.title("FFT RGB Image Compressor")
  157. root.geometry("+0+0")
  158.  
  159. main_frame = Frame(root)
  160. main_frame.pack(fill=BOTH, expand=True)
  161.  
  162. control_panel = Frame(main_frame, width=200)
  163. control_panel.pack(side=LEFT, fill=Y, padx=5, pady=5)
  164.  
  165. canvas_frame = Frame(main_frame)
  166. canvas_frame.pack(side=RIGHT, fill=BOTH, expand=True)
  167.  
  168. canvas = Canvas(canvas_frame, bg="black", width=1000, height=600)
  169. canvas.pack(side=LEFT, fill=BOTH, expand=True)
  170. scroll_y = Scrollbar(canvas_frame, orient=VERTICAL, command=canvas.yview)
  171. scroll_y.pack(side=RIGHT, fill=Y)
  172. canvas.configure(yscrollcommand=scroll_y.set)
  173. canvas.bind("<ButtonPress-1>", start_pan)
  174. canvas.bind("<B1-Motion>", drag_pan)
  175.  
  176. Button(control_panel,text="Load Image (auto save FFT)",command=load_image).pack(pady=5,fill=X)
  177. Button(control_panel,text="Load FFT Binary",command=load_compression).pack(pady=5,fill=X)
  178. Label(control_panel,text="Compression Ratio (0-1):").pack(pady=5)
  179. entry = Entry(control_panel); entry.insert(0,"0.1"); entry.pack(pady=5,fill=X)
  180. Button(control_panel,text="Update",command=update_compression).pack(pady=5,fill=X)
  181. Button(control_panel,text="Save Reconstructed PNG",command=save_png).pack(pady=5,fill=X)
  182. Button(control_panel,text="Auto Rename + Save",command=auto_rename_save).pack(pady=5,fill=X)
  183.  
  184. filename_label = Label(control_panel, text="No File Yet", bg="green", fg="white")
  185. filename_label.pack(pady=5, fill=X)
  186. Button(control_panel, text="Rerandomize Filename", command=generate_random_filename).pack(pady=5, fill=X)
  187.  
  188. root.mainloop()
  189.  
Add Comment
Please, Sign In to add comment