here2share

# tk_PIL_Control.py

Jul 20th, 2026 (edited)
71
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 7.10 KB | None | 0 0
  1. # tk_PIL_Control.py
  2.  
  3. import tkinter as tk
  4. from tkinter import ttk
  5. from PIL import Image, ImageTk, ImageDraw, ImageFont, ImageFilter, ImageEnhance, ImageChops
  6. import math
  7. from itertools import combinations
  8. import random
  9.  
  10. WW, HH = 640, 640
  11. cx, cy = WW // 2 - 1, HH // 2 - 1
  12. w, h = WW * 2, WW * 2
  13. zoom_factor = 0.9
  14. sz = 59
  15.  
  16. root = tk.Tk()
  17. root.title("# tk_PIL_Control.py")
  18. root.geometry('+0+0')
  19. canvas = tk.Canvas(root, width=WW, height=HH)
  20. canvas.pack()
  21.  
  22. base = {
  23.     (0, 0): (255, 255, 255), (0, 1): (255, 255, 0), (0, 2): (0, 255, 0),
  24.     (1, 0): (255, 128, 0),   (1, 1): (128, 128, 128), (1, 2): (0, 0, 255),
  25.     (2, 0): (255, 0, 0),     (2, 1): (128, 0, 128), (2, 2): (0, 0, 0)
  26. }
  27.  
  28. small_img = Image.new('RGB', (3, 3))
  29. for y in range(3):
  30.     for x in range(3):
  31.         small_img.putpixel((x, y), base[(x, y)])
  32.  
  33. init_img = small_img.resize((WW, HH), Image.LANCZOS).convert("RGBA")
  34. base_img = init_img.copy()
  35.  
  36. colors = [(255, 192, 203), (165, 42, 42), (0, 255, 255)]
  37. colors = list(base.values()) + colors
  38.  
  39. pairs = list(combinations(colors, 2))
  40. combos = []
  41. used_pairs = set()
  42.  
  43. current_pair = pairs.pop(0)
  44. combos.extend(current_pair)
  45. used_pairs.add(current_pair)
  46.  
  47. while pairs:
  48.     last_color = combos[-1]
  49.     next_pair = None
  50.     for p in pairs:
  51.         if p not in used_pairs:
  52.             if p == last_color:
  53.                 next_pair = p
  54.                 rev = False
  55.                 break
  56.             elif p == last_color:
  57.                 next_pair = p
  58.                 rev = True
  59.                 break
  60.     if next_pair:
  61.         pairs.remove(next_pair)
  62.         used_pairs.add(next_pair)
  63.         if rev:
  64.             combos.append(next_pair[0])
  65.         else:
  66.             combos.append(next_pair[1])
  67.     else:
  68.         p = pairs.pop(0)
  69.         used_pairs.add(p)
  70.         combos.extend(p)
  71.  
  72. gradient_width = 80
  73. total_width = len(combos) * gradient_width
  74. gradient_img = Image.new("RGB", (len(combos), 1))
  75. for i, color in enumerate(combos):
  76.     gradient_img.putpixel((i, 0), color)
  77. gradient_img = gradient_img.resize((total_width, 1), resample=Image.LANCZOS)
  78. colors_data = list(gradient_img.getdata())
  79.  
  80. mid4_cache = [(cx + px, cy + py) for (px, py) in [(0, 0), (0, 1), (1, 0), (1, 1)]]
  81.  
  82. new_sz = int(WW * zoom_factor)
  83. TL = (WW - new_sz) // 2
  84. BR = TL + new_sz
  85.  
  86. photo = ImageTk.PhotoImage(base_img)
  87. canvas.create_image(0, 0, anchor=tk.NW, image=photo)
  88.  
  89. ctrl_win = tk.Toplevel(root)
  90. ctrl_win.title("PIL/Cache Control")
  91. ctrl_win.geometry('600x660+660+0')
  92.  
  93. main_frame = tk.Frame(ctrl_win)
  94. main_frame.pack(fill='both', expand=True)
  95.  
  96. ctrl_canvas = tk.Canvas(main_frame, borderwidth=0)
  97. scrollbar = ttk.Scrollbar(main_frame, orient="vertical", command=ctrl_canvas.yview)
  98. scroll_content = tk.Frame(ctrl_canvas)
  99.  
  100. scroll_content.bind("<Configure>", lambda e: ctrl_canvas.configure(scrollregion=ctrl_canvas.bbox("all")))
  101. ctrl_canvas.create_window((0, 0), window=scroll_content, anchor="nw")
  102. ctrl_canvas.configure(yscrollcommand=scrollbar.set)
  103.  
  104. ctrl_canvas.pack(side="left", fill="both", expand=True)
  105. scrollbar.pack(side="right", fill="y")
  106.  
  107. pil_modes = [
  108.     {"label": "Absolute Difference", "id": "difference", "var": tk.BooleanVar(value=True)},
  109.     {"label": "Standard Multiply", "id": "multiply", "var": tk.BooleanVar(value=False)},
  110.     {"label": "Screen Brighten", "id": "screen", "var": tk.BooleanVar(value=False)},
  111.     {"label": "Darker Extraction", "id": "darker", "var": tk.BooleanVar(value=False)},
  112.     {"label": "Lighter Extraction", "id": "lighter", "var": tk.BooleanVar(value=False)},
  113.     {"label": "Add Linear (Clipped)", "id": "add", "var": tk.BooleanVar(value=False)},
  114.     {"label": "Add Modulo (Wrap)", "id": "add_modulo", "var": tk.BooleanVar(value=False)},
  115.     {"label": "Subtract (Clipped)", "id": "subtract", "var": tk.BooleanVar(value=False)},
  116.     {"label": "Subtract Modulo", "id": "subtract_modulo", "var": tk.BooleanVar(value=False)},
  117.     {"label": "Hard Light Sharpness", "id": "hard_light", "var": tk.BooleanVar(value=False)},
  118.     {"label": "Soft Light Gradients", "id": "soft_light", "var": tk.BooleanVar(value=False)},
  119.     {"label": "Overlay Blend", "id": "overlay", "var": tk.BooleanVar(value=False)},
  120.     {"label": "Invert Channels Pass", "id": "invert", "var": tk.BooleanVar(value=False)},
  121.     {"label": "Logical Bitwise AND", "id": "logical_and", "var": tk.BooleanVar(value=False)},
  122.     {"label": "Logical Bitwise OR", "id": "logical_or", "var": tk.BooleanVar(value=False)},
  123.     {"label": "Logical Bitwise XOR", "id": "logical_xor", "var": tk.BooleanVar(value=False)}
  124. ]
  125.  
  126. blend_alpha = tk.DoubleVar(value=0.01)
  127. refresh = False
  128.  
  129. def trigger_restart():
  130.     global refresh
  131.     refresh = True
  132.  
  133. row_frames = []
  134.  
  135. def move_up(idx):
  136.     if idx > 0:
  137.         pil_modes[idx], pil_modes[idx-1] = pil_modes[idx-1], pil_modes[idx]
  138.         rebuild_ui_list()
  139.  
  140. def move_down(idx):
  141.     if idx < len(pil_modes) - 1:
  142.         pil_modes[idx], pil_modes[idx+1] = pil_modes[idx+1], pil_modes[idx]
  143.         rebuild_ui_list()
  144.  
  145. def rebuild_ui_list():
  146.     global row_frames
  147.     for frame in row_frames:
  148.         frame.destroy()
  149.     row_frames.clear()
  150.    
  151.     for i, mode in enumerate(pil_modes):
  152.         f = tk.Frame(list_container)
  153.         f.grid(row=i, column=0, sticky='w', pady=2)
  154.         row_frames.append(f)
  155.        
  156.         btn_up = ttk.Button(f, text="^", width=3, command=lambda idx=i: move_up(idx))
  157.         btn_up.pack(side='left', padx=2)
  158.        
  159.         btn_down = ttk.Button(f, text="v", width=3, command=lambda idx=i: move_down(idx))
  160.         btn_down.pack(side='left', padx=2)
  161.        
  162.         chk = ttk.Checkbutton(f, text=mode["label"], variable=mode["var"])
  163.         chk.pack(side='left', padx=5)
  164.  
  165. ttk.Label(scroll_content, text="Configurations:", font=('Helvetica', 10, 'bold')).pack(anchor=tk.W, padx=10, pady=5)
  166.  
  167. list_container = tk.Frame(scroll_content)
  168. list_container.pack(fill='both', expand=True, padx=10)
  169.  
  170. list_container.columnconfigure(0, weight=2)
  171. list_container.columnconfigure(1, weight=1)
  172.  
  173. rebuild_ui_list()
  174.  
  175. btn_restart = ttk.Button(list_container, text="Reset Buffer", command=trigger_restart)
  176. btn_restart.grid(row=3, column=1, sticky='ew', padx=15, pady=5)
  177.  
  178. alpha_header_frame = tk.Frame(scroll_content)
  179. alpha_header_frame.pack(fill='x', padx=10)
  180.  
  181. ttk.Label(alpha_header_frame, text="Blend Strength:", font=('Helvetica', 10, 'bold')).pack(side='left')
  182. lbl_alpha_val = ttk.Label(alpha_header_frame, text=blend_alpha.get(), font=('Helvetica', 10, 'bold'), foreground="blue")
  183. lbl_alpha_val.pack(side='right', padx=10)
  184.  
  185. alpha = 0
  186. while 1:
  187.     if refresh:
  188.         base_img = init_img.copy()
  189.         refresh = False
  190.  
  191.     base_img = base_img.crop((TL, TL, BR, BR))
  192.     base_img = base_img.resize((WW, HH), Image.LANCZOS)
  193.    
  194.     px_base = base_img.load()
  195.     rgb = colors_data.pop(0)
  196.     colors_data.append(rgb)
  197.    
  198.     for x, y in mid4_cache:
  199.         px_base[x, y] = (*rgb, 255)
  200.        
  201.     current_pass = base_img.copy()
  202.    
  203.     active_ops = [mode["id"] for mode in pil_modes if mode["var"].get()]
  204.  
  205.     fractal_img = ImageChops.blend(base_img, current_pass, alpha)
  206.    
  207.     base_img = fractal_img.copy()
  208.    
  209.     photo.paste(fractal_img)
  210.     root.update()
  211.  
Advertisement
Add Comment
Please, Sign In to add comment