Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- # tk_subtractive_blend_polygons.py
- import tkinter as tk
- from PIL import Image, ImageDraw, ImageTk, ImageChops
- import math
- sz = 600
- def center_coords(coords_list, sz):
- xs = [x for coords in coords_list for x, y in coords]
- ys = [y for coords in coords_list for x, y in coords]
- min_x, max_x = min(xs), max(xs)
- min_y, max_y = min(ys), max(ys)
- width = max_x - min_x
- height = max_y - min_y
- offset_x = (sz - width) / 2 - min_x
- offset_y = (sz - height) / 2 - min_y
- return [[(x + offset_x, y + offset_y) for x, y in coords] for coords in coords_list]
- def srgb_from_linear(x):
- if x <= 0.0031308:
- return 12.92 * x
- return 1.055 * (x ** (1/2.4)) - 0.055
- def linear_from_srgb(x):
- if x <= 0.04045:
- return x / 12.92
- return ((x + 0.055) / 1.055) ** 2.4
- def channel_transmission(v_srgb, leak, gamma):
- v_lin = linear_from_srgb(v_srgb)
- t = leak + (1.0 - leak) * (v_lin ** gamma)
- return max(0.0, min(1.0, t))
- def subtractive_blend(c1, c2,
- leak1=(0.02, 0.20, 0.85),
- gamma1=(1.6, 1.4, 1.0),
- leak2=(0.85, 0.90, 0.02),
- gamma2=(1.0, 1.0, 1.6)):
- r1, g1, b1 = [v/255.0 for v in c1[:3]]
- r2, g2, b2 = [v/255.0 for v in c2[:3]]
- t1_r = channel_transmission(r1, leak1[0], gamma1[0])
- t1_g = channel_transmission(g1, leak1[1], gamma1[1])
- t1_b = channel_transmission(b1, leak1[2], gamma1[2])
- t2_r = channel_transmission(r2, leak2[0], gamma2[0])
- t2_g = channel_transmission(g2, leak2[1], gamma2[1])
- t2_b = channel_transmission(b2, leak2[2], gamma2[2])
- t_r = t1_r * t2_r
- t_g = t1_g * t2_g
- t_b = t1_b * t2_b
- R = int(round(255 * srgb_from_linear(t_r)))
- G = int(round(255 * srgb_from_linear(t_g)))
- B = int(round(255 * srgb_from_linear(t_b)))
- A = max(c1[3], c2[3])
- return (R, G, B, A)
- def composite_shapes(shapes, sz):
- result = Image.new("RGBA", (sz, sz), (255, 255, 255, 255))
- accumulated_mask = Image.new("L", (sz, sz), 0)
- accumulated_color = None
- for coords, color in shapes:
- layer = Image.new("RGBA", (sz, sz), (0, 0, 0, 0))
- ImageDraw.Draw(layer).polygon(coords, fill=color)
- mask = layer.split()[3]
- overlap = ImageChops.multiply(accumulated_mask, mask)
- only_new = ImageChops.subtract(mask, overlap)
- if accumulated_color:
- blended = subtractive_blend(accumulated_color, color)
- result.paste(blended, mask=overlap)
- result.paste(color, mask=only_new)
- accumulated_mask = ImageChops.add(accumulated_mask, mask)
- accumulated_color = color
- return result
- # Example: two triangles
- blue_coords = [(0, 0), (500, 0), (250, 450)]
- cx = sum(x for x, y in blue_coords) / 3
- cy = sum(y for x, y in blue_coords) / 3
- theta = math.radians(30)
- yellow_coords = []
- for (x, y) in blue_coords:
- x_new = cx + (x - cx) * math.cos(theta) - (y - cy) * math.sin(theta)
- y_new = cy + (x - cx) * math.sin(theta) + (y - cy) * math.cos(theta)
- yellow_coords.append((x_new, y_new))
- blue_coords, yellow_coords = center_coords([blue_coords, yellow_coords], sz)
- shapes = [
- (blue_coords, (0, 0, 255, 255)),
- (yellow_coords, (255, 255, 0, 255)),
- ]
- result = composite_shapes(shapes, sz)
- root = tk.Tk()
- root.geometry(f"{sz}x{sz}+0+0")
- canvas = tk.Canvas(root, width=sz, height=sz, bg="white", highlightthickness=0)
- canvas.pack()
- tk_img = ImageTk.PhotoImage(result)
- canvas.create_image(0, 0, anchor="nw", image=tk_img)
- root.mainloop()
Advertisement
Add Comment
Please, Sign In to add comment