Untitled
unknown
plain_text
a month ago
45 kB
5
Indexable
import tkinter as tk from PIL import Image, ImageTk, ImageDraw import numpy as np import scipy.ndimage DEFAULT_PIXEL_SIZE = 10 DEFAULT_CANVAS_SIZE = 64 DEFAULT_FILL_COLOR = (30,120,130) DEFAULT_BG_COLOR_RGB = (255, 255, 255) DEFAULT_DRAW_COLOR_RGB = (0, 0, 0) # DEFAULT_DRAW_PREVIEW_COLOR_RGB = (128, 128, 128) DEFAULT_GRID_COLOR_HEX = "#9dc2c7" class SimpleDrawingApp: def __init__(self, master, canvas_size=DEFAULT_CANVAS_SIZE, pixel_size=DEFAULT_PIXEL_SIZE): self.master = master self.canvas_size = canvas_size self.pixel_size = pixel_size self.actual_size = canvas_size * pixel_size self.color = DEFAULT_DRAW_COLOR_RGB self.show_grid = tk.BooleanVar(value=False) # Track if grid is shown self.kreslenie = tk.IntVar(value = 0) self.points = [] self.temppoints = [0] # Initialize the Pillow image and draw object self.image = Image.new('RGB', (self.actual_size, self.actual_size), DEFAULT_BG_COLOR_RGB) self.draw = ImageDraw.Draw(self.image) # Add buttons and checkbox self.setup_controls() # Create a Tkinter canvas to display the image self.canvas = tk.Canvas(master, width=self.actual_size, height=self.actual_size, highlightthickness = 0) self.canvas.pack() # Bind mouse events self.canvas.bind('<B1-Motion>', self.paint) self.update_canvas() self.menu_bar = tk.Menu(self.master) self.filter_menu = tk.Menu(self.menu_bar, tearoff=True) self.filter_menu.add_command(label="Averaging Blur", command=self.averaging_blur) self.filter_menu.add_command(label="Gaussian Blur", command=self.gaussian_blur) self.filter_menu.add_command(label="Sobel Filter", command=self.sobel_filter) self.filter_menu.add_command(label="Sharpen Filter", command=self.sharpen_filter) self.menu_bar.add_cascade(label="Filters", menu=self.filter_menu) self.master.config(menu=self.menu_bar) def paint_bind(self): self.canvas.unbind("<B1-Motion>") self.canvas.unbind("<Button-1>") self.canvas.unbind("<ButtonRelease-1>") self.canvas.unbind('<Return>') self.canvas.unbind('<Escape>') self.canvas.bind('<Button-1>', self.paint) self.canvas.bind('<B1-Motion>', self.paint) def DDA_bind(self): self.canvas.unbind("<B1-Motion>") self.canvas.unbind("<Button-1>") self.canvas.unbind("<ButtonRelease-1>") self.canvas.unbind('<Return>') self.canvas.unbind('<Escape>') self.canvas.bind('<Button-1>', self.press) self.canvas.bind('<B1-Motion>', self.DDA) self.canvas.bind('<ButtonRelease-1>', self.DDA_release) self.bezierzrus() def Bresenhamline_bind(self): self.canvas.unbind("<B1-Motion>") self.canvas.unbind("<Button-1>") self.canvas.unbind("<ButtonRelease-1>") self.canvas.unbind('<Return>') self.canvas.unbind('<Escape>') self.canvas.bind('<Button-1>', self.press) self.canvas.bind('<B1-Motion>', self.Bresenham_line) self.canvas.bind('<ButtonRelease-1>', self.Bresenham_line_release) self.bezierzrus() def Bresenhamcircle_bind(self): self.canvas.unbind("<B1-Motion>") self.canvas.unbind("<Button-1>") self.canvas.unbind("<ButtonRelease-1>") self.canvas.unbind('<Return>') self.canvas.unbind('<Escape>') self.canvas.bind('<Button-1>', self.press) self.canvas.bind('<B1-Motion>', self.Bresenham_circle) self.canvas.bind('<ButtonRelease-1>', self.Bresenham_circle_release) self.bezierzrus() def Beziercurve_bind(self): self.canvas.unbind("<B1-Motion>") self.canvas.unbind("<Button-1>") self.canvas.unbind("<ButtonRelease-1>") self.canvas.unbind('<Return>') self.canvas.unbind('<Escape>') self.canvas.focus_set() self.canvas.bind('<Button - 1>', self.pridajtempbod) self.canvas.bind('<B1-Motion>', self.pridajtempbod) self.canvas.bind('<ButtonRelease-1>', self.pridajbod) self.canvas.bind('<Return>', self.bezierkoniec) self.canvas.bind('<Escape>', self.bezierzrus) def Floodfill_bind(self): self.canvas.unbind("<B1-Motion>") self.canvas.unbind("<Button-1>") self.canvas.unbind("<ButtonRelease-1>") self.canvas.unbind('<Return>') self.canvas.unbind('<Escape>') self.canvas.bind('<Button - 1>', self.floodfill_begin) self.bezierzrus() def Polygon_bind(self): self.canvas.unbind("<B1-Motion>") self.canvas.unbind("<Button-1>") self.canvas.unbind("<ButtonRelease-1>") self.canvas.unbind('<Return>') self.canvas.unbind('<Escape>') self.canvas.focus_set() self.canvas.bind('<Button - 1>', self.pridajtempbodpoly) self.canvas.bind('<B1-Motion>', self.pridajtempbodpoly) self.canvas.bind('<ButtonRelease-1>', self.pridajbodpoly) self.canvas.bind('<Escape>', self.polyzrus) self.bezierzrus() def setup_controls(self): # Create a frame to hold the controls controls_frame = tk.Frame(self.master) controls_frame.pack(side=tk.TOP, fill=tk.X) # Clear button clear_button = tk.Button(controls_frame, text="Clear", command=self.clear_canvas) clear_button.grid(row=0, column=0, padx=5, pady=5) grid_checkbox = tk.Checkbutton(controls_frame, text="Grid", variable=self.show_grid, command=self.toggle_grid) grid_checkbox.grid(row=0, column=1, padx=5, pady=5) brush_checkbox = tk.Radiobutton(controls_frame, text="Brush", variable=self.kreslenie, value=1, command=self.paint_bind) brush_checkbox.grid(row=0, column=2, padx=5, pady=5) DDA_checkbox = tk.Radiobutton(controls_frame, text="DDA line", variable=self.kreslenie, value=2, command=self.DDA_bind) DDA_checkbox.grid(row=0, column=3, padx=5, pady=5) Bresenhamline_checkbox = tk.Radiobutton(controls_frame, text="Bresenham line", variable=self.kreslenie, value=3, command=self.Bresenhamline_bind) Bresenhamline_checkbox.grid(row=0, column=4, padx=5, pady=5) Bresenhamcircle_checkbox = tk.Radiobutton(controls_frame, text='Bresenham circle', variable=self.kreslenie, value = 4, command=self.Bresenhamcircle_bind) Bresenhamcircle_checkbox.grid(row=0, column=5, padx=5, pady=5) Beziercurve_checkbox = tk.Radiobutton(controls_frame, text='Besier curve', variable=self.kreslenie, value = 5, command=self.Beziercurve_bind) Beziercurve_checkbox.grid(row=1, column=2, padx=5, pady=5) Floodfill_checkbox = tk.Radiobutton(controls_frame, text='Flood fill', variable=self.kreslenie, value = 6, command=self.Floodfill_bind) Floodfill_checkbox.grid(row=1, column=3, padx=5, pady=5) Polygon_checkbox = tk.Radiobutton(controls_frame, text='Polygon', variable=self.kreslenie, value = 7, command=self.Polygon_bind) Polygon_checkbox.grid(row=1, column=4, padx=5, pady=5) def averaging_blur(self): self.canvas.unbind("<B1-Motion>") self.canvas.unbind("<Button-1>") self.canvas.unbind("<ButtonRelease-1>") self.canvas.unbind('<Return>') self.canvas.unbind('<Escape>') self.kreslenie.set(0) matica = np.array(self.image, dtype=np.float32) pixely = np.zeros((self.canvas_size, self.canvas_size,3), dtype=np.float32) for i in range(self.canvas_size): for j in range(self.canvas_size): pixely[i, j] = matica[i*self.pixel_size+self.pixel_size//2, j*self.pixel_size+self.pixel_size//2] kernel = np.array([[1/9,1/9,1/9],[1/9,1/9,1/9],[1/9,1/9,1/9]], dtype=np.float32) rozmenit = scipy.ndimage.convolve(pixely, kernel[..., None], mode='mirror') rozmenit = np.clip(rozmenit, 0, 255).astype(np.uint8) obrazok = np.zeros((self.actual_size,self.actual_size,3), dtype=np.uint8) for i in range(self.canvas_size): for j in range(self.canvas_size): obrazok[i * self.pixel_size:(i + 1) * self.pixel_size, j * self.pixel_size:(j + 1) * self.pixel_size] = rozmenit[i, j] self.image = Image.fromarray(obrazok) self.update_canvas() def gaussian_blur(self): self.canvas.unbind("<B1-Motion>") self.canvas.unbind("<Button-1>") self.canvas.unbind("<ButtonRelease-1>") self.canvas.unbind('<Return>') self.canvas.unbind('<Escape>') self.kreslenie.set(0) matica = np.array(self.image, dtype=np.float32) pixely = np.zeros((self.canvas_size, self.canvas_size,3), dtype=np.float32) for i in range(self.canvas_size): for j in range(self.canvas_size): kde = matica[i * self.pixel_size:(i + 1) * self.pixel_size, j * self.pixel_size:(j + 1) * self.pixel_size] pixely[i, j] = np.mean(kde, axis = (0, 1)) kernel = np.array([[1/16,1/8,1/16],[1/8,1/4,1/8],[1/16,1/8,1/16]], dtype=np.float32) rozmenit = np.zeros((self.canvas_size, self.canvas_size,3), dtype=np.float32) rozmenit = scipy.ndimage.convolve(pixely, kernel[..., None], mode='mirror') rozmenit = np.clip(rozmenit, 0, 255).astype(np.uint8) obrazok = np.zeros((self.actual_size,self.actual_size,3), dtype=np.uint8) for i in range(self.canvas_size): for j in range(self.canvas_size): obrazok[i * self.pixel_size:(i + 1) * self.pixel_size, j * self.pixel_size:(j + 1) * self.pixel_size] = rozmenit[i, j] self.image = Image.fromarray(obrazok) self.update_canvas() def sobel_filter(self): self.canvas.unbind("<B1-Motion>") self.canvas.unbind("<Button-1>") self.canvas.unbind("<ButtonRelease-1>") self.canvas.unbind('<Return>') self.canvas.unbind('<Escape>') self.kreslenie.set(0) matica = np.array(self.image, dtype=np.float32) pixely = np.zeros((self.canvas_size, self.canvas_size, 3), dtype=np.float32) for i in range(self.canvas_size): for j in range(self.canvas_size): kde = matica[i * self.pixel_size:(i + 1) * self.pixel_size, j * self.pixel_size:(j + 1) * self.pixel_size] pixely[i, j] = np.mean(kde, axis=(0, 1)) grayscale = np.mean(pixely, axis=2) kernelx = np.array([[-1, 0, 1], [-2, 0, 2], [-1, 0, 1]], dtype=np.float32) kernely = np.array([[-1, -2, -1], [0, 0, 0], [1, 2, 1]], dtype=np.float32) gx = scipy.ndimage.convolve(grayscale, kernelx, mode='mirror') gy = scipy.ndimage.convolve(grayscale, kernely, mode='mirror') gradient_magnitude = np.sqrt(gx**2 + gy**2) max_val = gradient_magnitude.max() if max_val > 0: gradient_magnitude = (gradient_magnitude * (255.0 / max_val)).astype(np.float32) else: gradient_magnitude = gradient_magnitude.astype(np.uint32) gradient_magnitude = np.clip(gradient_magnitude, 0, 255).astype(np.uint8) obrazok = np.zeros((self.actual_size, self.actual_size, 3), dtype=np.uint8) for i in range(self.canvas_size): for j in range(self.canvas_size): farba = gradient_magnitude[i, j] obrazok[i * self.pixel_size:(i + 1) * self.pixel_size, j * self.pixel_size:(j + 1) * self.pixel_size] = (farba, farba,farba) self.image = Image.fromarray(obrazok) self.update_canvas() def sharpen_filter(self): self.canvas.unbind("<B1-Motion>") self.canvas.unbind("<Button-1>") self.canvas.unbind("<ButtonRelease-1>") self.canvas.unbind('<Return>') self.canvas.unbind('<Escape>') self.kreslenie.set(0) matica = np.array(self.image, dtype=np.float32) pixely = np.zeros((self.canvas_size, self.canvas_size,3), dtype=np.float32) for i in range(self.canvas_size): for j in range(self.canvas_size): kde = matica[i * self.pixel_size:(i + 1) * self.pixel_size, j * self.pixel_size:(j + 1) * self.pixel_size] pixely[i, j] = np.mean(kde, axis = (0, 1)) kernel = np.array([[0,-1,0],[-1,5,-1],[0,-1,0]], dtype=np.float32) rozmenit = np.zeros((self.canvas_size, self.canvas_size,3), dtype=np.float32) rozmenit = scipy.ndimage.convolve(pixely, kernel[..., None], mode='mirror') rozmenit = np.clip(rozmenit, 0, 255).astype(np.uint8) obrazok = np.zeros((self.actual_size,self.actual_size,3), dtype=np.uint8) for i in range(self.canvas_size): for j in range(self.canvas_size): obrazok[i * self.pixel_size:(i + 1) * self.pixel_size, j * self.pixel_size:(j + 1) * self.pixel_size] = rozmenit[i, j] self.image = Image.fromarray(obrazok) self.update_canvas() def draw_pixel(self, x, y, color): # Calculate the top-left and bottom-right corners of the enlarged pixel top_left = (x * self.pixel_size, y * self.pixel_size) bottom_right = ((x + 1) * self.pixel_size - 1, (y + 1) * self.pixel_size - 1) self.draw.rectangle([top_left, bottom_right], fill=color) self.update_canvas() def paint(self, event): # Calculate the logical pixel position self.kopia = self.image.copy() self.paintx = event.x//self.pixel_size self.painty = event.y//self.pixel_size temp_draw = ImageDraw.Draw(self.kopia) temp_draw.rectangle([((self.paintx) * self.pixel_size, (self.painty) * self.pixel_size), (((self.paintx) + 1) * self.pixel_size - 1, ((self.painty) + 1) * self.pixel_size - 1)], fill='black') self.kopiac = self.kopia.copy() if self.show_grid.get(): draw = ImageDraw.Draw(self.kopiac) for i in range(0, self.actual_size, self.pixel_size): line_color = DEFAULT_GRID_COLOR_HEX draw.line([(i, 0), (i, self.actual_size)], fill=line_color) draw.line([(0, i), (self.actual_size, i)], fill=line_color) self.tk_image = ImageTk.PhotoImage(self.kopiac) self.canvas.create_image(0, 0, anchor="nw", image=self.tk_image) self.image = self.kopia def press(self,event): self.kopia = self.image.copy() self.x1 = int(event.x // self.pixel_size) self.y1 = int(event.y // self.pixel_size) def DDA(self, event): self.kopia = self.image.copy() temp_draw = ImageDraw.Draw(self.kopia) self.DDAxt = int(event.x // self.pixel_size) self.DDAyt = int(event.y // self.pixel_size) self.dx = self.DDAxt - self.x1 self.dy = self.DDAyt - self.y1 self.dlzkapixelov = max(abs(self.dx), abs(self.dy)) if self.dlzkapixelov != 0: self.prirastokx = self.dx / self.dlzkapixelov self.prirastoky = self.dy / self.dlzkapixelov else: self.prirastokx = 0 self.prirastoky = 0 self.DDAx = self.x1 self.DDAy = self.y1 for i in range(0, self.dlzkapixelov + 1): temp_draw.rectangle([(round(self.DDAx) * self.pixel_size, round(self.DDAy) * self.pixel_size), ((round(self.DDAx) + 1) * self.pixel_size, (round(self.DDAy) + 1) * self.pixel_size)], fill='grey') self.DDAx = self.DDAx + self.prirastokx self.DDAy = self.DDAy + self.prirastoky self.kopiac = self.kopia.copy() if self.show_grid.get(): draw = ImageDraw.Draw(self.kopiac) for i in range(0, self.actual_size, self.pixel_size): line_color = DEFAULT_GRID_COLOR_HEX draw.line([(i, 0), (i, self.actual_size)], fill=line_color) draw.line([(0, i), (self.actual_size, i)], fill=line_color) self.tk_image = ImageTk.PhotoImage(self.kopiac) self.canvas.create_image(0, 0, anchor="nw", image=self.tk_image) def DDA_release(self,event): self.kopia = self.image.copy() temp_draw = ImageDraw.Draw(self.kopia) self.DDAx2 = int(event.x // self.pixel_size) self.DDAy2 = int(event.y // self.pixel_size) self.dx = self.DDAx2 - self.x1 self.dy = self.DDAy2 - self.y1 self.dlzkapixelov = max(abs(self.dx), abs(self.dy)) if self.dlzkapixelov != 0: self.prirastokx = self.dx / self.dlzkapixelov self.prirastoky = self.dy / self.dlzkapixelov else: self.prirastokx = 0 self.prirastoky = 0 self.DDAx = self.x1 self.DDAy = self.y1 for i in range(0, self.dlzkapixelov + 1): temp_draw.rectangle([(round(self.DDAx) * self.pixel_size, round(self.DDAy) * self.pixel_size), ((round(self.DDAx) + 1) * self.pixel_size, (round(self.DDAy) + 1) * self.pixel_size)], fill='black') self.DDAx = self.DDAx + self.prirastokx self.DDAy = self.DDAy + self.prirastoky self.kopiac = self.kopia.copy() if self.show_grid.get(): draw = ImageDraw.Draw(self.kopiac) for i in range(0, self.actual_size, self.pixel_size): line_color = DEFAULT_GRID_COLOR_HEX draw.line([(i, 0), (i, self.actual_size)], fill=line_color) draw.line([(0, i), (self.actual_size, i)], fill=line_color) self.tk_image = ImageTk.PhotoImage(self.kopiac) self.canvas.create_image(0, 0, anchor="nw", image=self.tk_image) self.image = self.kopia def Bresenham_line(self,event): self.kopia = self.image.copy() temp_draw = ImageDraw.Draw(self.kopia) self.Bresxt = event.x // self.pixel_size self.Bresyt = event.y // self.pixel_size self.Bresdx = self.Bresxt - self.x1 self.Bresdy = self.Bresyt - self.y1 self.krokx = 1 if self.Bresdx>=0 else -1 self.kroky = 1 if self.Bresdy>=0 else -1 self.chyba = abs(self.Bresdx)-abs(self.Bresdy) self.Bresx = self.x1 self.Bresy = self.y1 while self.Bresx != self.Bresxt or self.Bresy != self.Bresyt: temp_draw.rectangle([((self.Bresx) * self.pixel_size, (self.Bresy) * self.pixel_size), (((self.Bresx) + 1) * self.pixel_size - 1, ((self.Bresy) + 1) * self.pixel_size - 1)], fill='grey') self.chyba2 = 2* self.chyba if self.chyba2 > -abs(self.Bresdy): self.chyba = self.chyba - abs(self.Bresdy) self.Bresx = self.Bresx + self.krokx if self.chyba2 < abs(self.Bresdx): self.chyba = self.chyba + abs(self.Bresdx) self.Bresy = self.Bresy + self.kroky temp_draw.rectangle([((self.Bresxt) * self.pixel_size, (self.Bresyt) * self.pixel_size), (((self.Bresxt) + 1) * self.pixel_size - 1, ((self.Bresyt) + 1) * self.pixel_size - 1)], fill='grey') self.kopiac = self.kopia.copy() if self.show_grid.get(): draw = ImageDraw.Draw(self.kopiac) for i in range(0, self.actual_size, self.pixel_size): line_color = DEFAULT_GRID_COLOR_HEX draw.line([(i, 0), (i, self.actual_size)], fill=line_color) draw.line([(0, i), (self.actual_size, i)], fill=line_color) self.tk_image = ImageTk.PhotoImage(self.kopiac) self.canvas.create_image(0, 0, anchor="nw", image=self.tk_image) def Bresenham_line_release(self,event): self.kopia = self.image.copy() temp_draw = ImageDraw.Draw(self.kopia) self.Bresx2 = event.x // self.pixel_size self.Bresy2 = event.y // self.pixel_size self.Bresdx = self.Bresx2 - self.x1 self.Bresdy = self.Bresy2 - self.y1 self.krokx = 1 if self.Bresdx>=0 else -1 self.kroky = 1 if self.Bresdy>=0 else -1 self.chyba = abs(self.Bresdx)-abs(self.Bresdy) self.Bresx = self.x1 self.Bresy = self.y1 while self.Bresx != self.Bresx2 or self.Bresy != self.Bresy2: temp_draw.rectangle([((self.Bresx) * self.pixel_size, (self.Bresy) * self.pixel_size), (((self.Bresx) + 1) * self.pixel_size - 1, ((self.Bresy) + 1) * self.pixel_size - 1)], fill='black') self.chyba2 = 2* self.chyba if self.chyba2 > -abs(self.Bresdy): self.chyba = self.chyba - abs(self.Bresdy) self.Bresx = self.Bresx + self.krokx if self.chyba2 < abs(self.Bresdx): self.chyba = self.chyba + abs(self.Bresdx) self.Bresy = self.Bresy + self.kroky temp_draw.rectangle([((self.Bresx2) * self.pixel_size, (self.Bresy2) * self.pixel_size), (((self.Bresx2) + 1) * self.pixel_size - 1, ((self.Bresy2) + 1) * self.pixel_size - 1)], fill='black') self.kopiac = self.kopia.copy() if self.show_grid.get(): draw = ImageDraw.Draw(self.kopiac) for i in range(0, self.actual_size, self.pixel_size): line_color = DEFAULT_GRID_COLOR_HEX draw.line([(i, 0), (i, self.actual_size)], fill=line_color) draw.line([(0, i), (self.actual_size, i)], fill=line_color) self.tk_image = ImageTk.PhotoImage(self.kopiac) self.canvas.create_image(0, 0, anchor="nw", image=self.tk_image) self.image = self.kopia def Bresenham_circle(self,event): self.kopia = self.image.copy() temp_draw = ImageDraw.Draw(self.kopia) self.Brescxt = event.x // self.pixel_size self.Brescyt = event.y // self.pixel_size self.r = round(((self.Brescxt - self.x1) ** 2 + (self.Brescyt - self.y1) ** 2) ** 0.5) self.xc = self.x1 self.yc = self.y1 self.x = 0 self.y = self.r self.p = 1 - self.r while self.x <= self.y: temp_draw.rectangle([(int(self.xc + self.x) * self.pixel_size, int(self.yc + self.y) * self.pixel_size), ((int(self.xc + self.x) + 1) * self.pixel_size - 1, (int(self.yc + self.y) + 1) * self.pixel_size - 1)], fill='grey') temp_draw.rectangle([(int(self.xc - self.x) * self.pixel_size, int(self.yc + self.y) * self.pixel_size), ((int(self.xc - self.x) + 1) * self.pixel_size - 1, (int(self.yc + self.y) + 1) * self.pixel_size - 1)], fill='grey') temp_draw.rectangle([(int(self.xc + self.x) * self.pixel_size, int(self.yc - self.y) * self.pixel_size), ((int(self.xc + self.x) + 1) * self.pixel_size - 1, (int(self.yc - self.y) + 1) * self.pixel_size - 1)], fill='grey') temp_draw.rectangle([(int(self.xc - self.x) * self.pixel_size, int(self.yc - self.y) * self.pixel_size), ((int(self.xc - self.x) + 1) * self.pixel_size - 1, (int(self.yc - self.y) + 1) * self.pixel_size - 1)], fill='grey') temp_draw.rectangle([(int(self.xc + self.y) * self.pixel_size, int(self.yc + self.x) * self.pixel_size), ((int(self.xc + self.y) + 1) * self.pixel_size - 1, (int(self.yc + self.x) + 1) * self.pixel_size - 1)], fill='grey') temp_draw.rectangle([(int(self.xc - self.y) * self.pixel_size, int(self.yc + self.x) * self.pixel_size), ((int(self.xc - self.y) + 1) * self.pixel_size - 1, (int(self.yc + self.x) + 1) * self.pixel_size - 1)], fill='grey') temp_draw.rectangle([(int(self.xc + self.y) * self.pixel_size, int(self.yc - self.x) * self.pixel_size), ((int(self.xc + self.y) + 1) * self.pixel_size - 1, (int(self.yc - self.x) + 1) * self.pixel_size - 1)], fill='grey') temp_draw.rectangle([(int(self.xc - self.y) * self.pixel_size, int(self.yc - self.x) * self.pixel_size), ((int(self.xc - self.y) + 1) * self.pixel_size - 1, (int(self.yc - self.x) + 1) * self.pixel_size - 1)], fill='grey') self.x = self.x + 1 if self.p < 0: self.p = self.p+ 2 * self.x + 1 else: self.y =self.y - 1 self.p = self.p + 2 * (self.x - self.y) + 1 self.kopiac = self.kopia.copy() if self.show_grid.get(): draw = ImageDraw.Draw(self.kopiac) for i in range(0, self.actual_size, self.pixel_size): line_color = DEFAULT_GRID_COLOR_HEX draw.line([(i, 0), (i, self.actual_size)], fill=line_color) draw.line([(0, i), (self.actual_size, i)], fill=line_color) self.tk_image = ImageTk.PhotoImage(self.kopiac) self.canvas.create_image(0, 0, anchor="nw", image=self.tk_image) def Bresenham_circle_release(self,event): self.kopia = self.image.copy() final_draw = ImageDraw.Draw(self.kopia) self.Brescx2 = event.x // self.pixel_size self.Brescy2 = event.y // self.pixel_size self.r = round(((self.Brescx2 - self.x1) ** 2 + (self.Brescy2 - self.y1) ** 2) ** 0.5) self.xc = self.x1 self.yc = self.y1 self.x = 0 self.y = self.r self.p = 1 - self.r while self.x <= self.y: final_draw.rectangle([(int(self.xc + self.x) * self.pixel_size, int(self.yc + self.y) * self.pixel_size), ((int(self.xc + self.x) + 1) * self.pixel_size - 1, (int(self.yc + self.y) + 1) * self.pixel_size - 1)], fill='black') final_draw.rectangle([(int(self.xc - self.x) * self.pixel_size, int(self.yc + self.y) * self.pixel_size), ((int(self.xc - self.x) + 1) * self.pixel_size - 1, (int(self.yc + self.y) + 1) * self.pixel_size - 1)], fill='black') final_draw.rectangle([(int(self.xc + self.x) * self.pixel_size, int(self.yc - self.y) * self.pixel_size), ((int(self.xc + self.x) + 1) * self.pixel_size - 1, (int(self.yc - self.y) + 1) * self.pixel_size - 1)], fill='black') final_draw.rectangle([(int(self.xc - self.x) * self.pixel_size, int(self.yc - self.y) * self.pixel_size), ((int(self.xc - self.x) + 1) * self.pixel_size - 1, (int(self.yc - self.y) + 1) * self.pixel_size - 1)], fill='black') final_draw.rectangle([(int(self.xc + self.y) * self.pixel_size, int(self.yc + self.x) * self.pixel_size), ((int(self.xc + self.y) + 1) * self.pixel_size - 1, (int(self.yc + self.x) + 1) * self.pixel_size - 1)], fill='black') final_draw.rectangle([(int(self.xc - self.y) * self.pixel_size, int(self.yc + self.x) * self.pixel_size), ((int(self.xc - self.y) + 1) * self.pixel_size - 1, (int(self.yc + self.x) + 1) * self.pixel_size - 1)], fill='black') final_draw.rectangle([(int(self.xc + self.y) * self.pixel_size, int(self.yc - self.x) * self.pixel_size), ((int(self.xc + self.y) + 1) * self.pixel_size - 1, (int(self.yc - self.x) + 1) * self.pixel_size - 1)], fill='black') final_draw.rectangle([(int(self.xc - self.y) * self.pixel_size, int(self.yc - self.x) * self.pixel_size), ((int(self.xc - self.y) + 1) * self.pixel_size - 1, (int(self.yc - self.x) + 1) * self.pixel_size - 1)], fill='black') self.x = self.x + 1 if self.p < 0: self.p = self.p+ 2 * self.x + 1 else: self.y =self.y - 1 self.p = self.p + 2 * (self.x - self.y) + 1 self.kopiac = self.kopia.copy() if self.show_grid.get(): draw = ImageDraw.Draw(self.kopiac) for i in range(0, self.actual_size, self.pixel_size): line_color = DEFAULT_GRID_COLOR_HEX draw.line([(i, 0), (i, self.actual_size)], fill=line_color) draw.line([(0, i), (self.actual_size, i)], fill=line_color) self.tk_image = ImageTk.PhotoImage(self.kopiac) self.canvas.create_image(0, 0, anchor="nw", image=self.tk_image) self.image = self.kopia def pridajbod(self, event): x, y = event.x // self.pixel_size, event.y // self.pixel_size self.points.append((x, y)) self.temppoints = self.points + [0] def pridajtempbod(self, event): self.temppoints.pop() x, y = event.x // self.pixel_size, event.y // self.pixel_size self.temppoints.append((x,y)) self.bezierkrivkatemp(self.temppoints) def bezierkrivka(self, points): self.kopia = self.image.copy() final_draw = ImageDraw.Draw(self.kopia) for t in [i / 600 for i in range(600 + 1)]: x, y = self.decasteljeau(points, t) final_draw.rectangle([(round(x) * self.pixel_size, round(y) * self.pixel_size),(round(x) * self.pixel_size + self.pixel_size, round(y) * self.pixel_size + self.pixel_size)],fill='black') self.kopiac = self.kopia.copy() if self.show_grid.get(): draw = ImageDraw.Draw(self.kopiac) for i in range(0, self.actual_size, self.pixel_size): line_color = DEFAULT_GRID_COLOR_HEX draw.line([(i, 0), (i, self.actual_size)], fill=line_color) draw.line([(0, i), (self.actual_size, i)], fill=line_color) self.tk_image = ImageTk.PhotoImage(self.kopiac) self.canvas.create_image(0, 0, anchor="nw", image=self.tk_image) self.image = self.kopia def bezierkrivkatemp(self, temppoints): self.kopia = self.image.copy() temp_draw = ImageDraw.Draw(self.kopia) for t in [i / 600 for i in range(600 + 1)]: x, y = self.tempdecasteljeau(temppoints, t) temp_draw.rectangle([(round(x) * self.pixel_size, round(y) * self.pixel_size),(round(x) * self.pixel_size + self.pixel_size, round(y) * self.pixel_size + self.pixel_size)],fill='grey') for i in range (len(temppoints)-1): temp_draw.line([temppoints[i][0]* self.pixel_size,temppoints[i][1]* self.pixel_size,temppoints[i+1][0]* self.pixel_size,temppoints[i+1][1]* self.pixel_size],width=3,fill='black') temp_draw.ellipse([temppoints[i][0]* self.pixel_size-8,temppoints[i][1]* self.pixel_size-8,temppoints[i][0]* self.pixel_size+8,temppoints[i][1]* self.pixel_size+8],outline='blue',fill='white') temp_draw.ellipse([temppoints[len(temppoints)-1][0]* self.pixel_size-8,temppoints[len(temppoints)-1][1]* self.pixel_size-8,temppoints[len(temppoints)-1][0]* self.pixel_size+8,temppoints[len(temppoints)-1][1]* self.pixel_size+8],outline='red',fill='white') self.kopiac = self.kopia.copy() if self.show_grid.get(): draw = ImageDraw.Draw(self.kopiac) for i in range(0, self.actual_size, self.pixel_size): line_color = DEFAULT_GRID_COLOR_HEX draw.line([(i, 0), (i, self.actual_size)], fill=line_color) draw.line([(0, i), (self.actual_size, i)], fill=line_color) self.tk_image = ImageTk.PhotoImage(self.kopiac) self.canvas.create_image(0, 0, anchor="nw", image=self.tk_image) def tempdecasteljeau(self, temppoints, t): if len(temppoints) == 1: return temppoints[0] new_temppoints = [] for i in range(len(temppoints) - 1): x = temppoints[i][0] + t *( temppoints[i + 1][0] - temppoints[i][0]) y = temppoints[i][1] + t *( temppoints[i + 1][1] - temppoints[i][1]) new_temppoints.append((x, y)) return self.tempdecasteljeau(new_temppoints, t) def decasteljeau(self, points, t): if len(points) == 1: return points[0] new_points = [] for i in range(len(points) - 1): x = points[i][0] + t *( points[i + 1][0] - points[i][0]) y = points[i][1] + t *( points[i + 1][1] - points[i][1]) new_points.append((x, y)) return self.decasteljeau(new_points, t) def tempbezierkoniec(self): self.bezierkrivkatemp(self.temppoints) def bezierkoniec(self, event = None): if len(self.points) > 0: self.bezierkrivka(self.points) self.points = [] self.temppoints = [0] else: pass def bezierzrus(self, event = None): self.points = [] self.temppoints = [0] self.kopiac = self.image.copy() if self.show_grid.get(): draw = ImageDraw.Draw(self.kopiac) for i in range(0, self.actual_size, self.pixel_size): line_color = DEFAULT_GRID_COLOR_HEX draw.line([(i, 0), (i, self.actual_size)], fill=line_color) draw.line([(0, i), (self.actual_size, i)], fill=line_color) self.tk_image = ImageTk.PhotoImage(self.kopiac) self.canvas.create_image(0, 0, anchor="nw", image=self.tk_image) def floodfill_begin(self, event): global mamka, x1, x2 matica = np.array(self.image, dtype=np.uint8) pixely = np.zeros((self.canvas_size, self.canvas_size, 3), dtype=np.uint8) for i in range(self.canvas_size): for j in range(self.canvas_size): pixely[i, j] = matica[i * self.pixel_size + self.pixel_size // 2, j * self.pixel_size + self.pixel_size // 2] x1 = event.y // self.pixel_size x2 = event.x // self.pixel_size mamka = pixely[x1, x2] self.floodfill() def floodfill(self): global mamka, x1, x2 matica = np.array(self.image, dtype=np.uint8) pixely = np.zeros((self.canvas_size, self.canvas_size, 3), dtype=np.uint8) for i in range(self.canvas_size): for j in range(self.canvas_size): pixely[i, j] = matica[i * self.pixel_size + self.pixel_size // 2, j * self.pixel_size + self.pixel_size // 2] pixely[x1,x2] = DEFAULT_FILL_COLOR zasobnik = [(x1, x2)] ssd = [(1, 0), (-1, 0), (0, 1), (0, -1)] while zasobnik: x, y = zasobnik.pop() for dx, dy in ssd: novex = x + dx novey = y + dy if 0 <= novex < self.canvas_size and 0 <= novey < self.canvas_size: if np.all(pixely[novex, novey] == mamka): pixely[novex, novey] = DEFAULT_FILL_COLOR zasobnik.append((novex, novey)) obrazok = np.zeros((self.actual_size, self.actual_size, 3), dtype=np.uint8) for i in range(self.canvas_size): for j in range(self.canvas_size): obrazok[i * self.pixel_size:(i + 1) * self.pixel_size, j * self.pixel_size:(j + 1) * self.pixel_size] = pixely[i, j] self.image = Image.fromarray(obrazok) self.update_canvas() def pridajbodpoly(self, event): x, y = event.x // self.pixel_size, event.y // self.pixel_size self.points.append((x, y)) self.temppoints = self.points + [0] self.zaciatokx = self.points[0][0] self.zaciatoky = self.points[0][1] self.polykoniec(self.points) def pridajtempbodpoly(self, event): self.temppoints.pop() x, y = event.x // self.pixel_size, event.y // self.pixel_size self.temppoints.append((x,y)) self.polytemp(self.temppoints) def poly(self, points): self.kopia = self.image.copy() final_draw = ImageDraw.Draw(self.kopia) for i in range (1, len(points)): self.Bresxt = points[i][0] self.Bresyt = points[i][1] self.Bresx1 = points[i-1][0] self.Bresy1 = points[i-1][1] self.Bresdx = self.Bresxt - self.Bresx1 self.Bresdy = self.Bresyt - self.Bresy1 self.krokx = 1 if self.Bresdx>=0 else -1 self.kroky = 1 if self.Bresdy>=0 else -1 self.chyba = abs(self.Bresdx)-abs(self.Bresdy) self.Bresx = self.Bresx1 self.Bresy = self.Bresy1 while self.Bresx != self.Bresxt or self.Bresy != self.Bresyt: final_draw.rectangle([((self.Bresx) * self.pixel_size, (self.Bresy) * self.pixel_size), (((self.Bresx) + 1) * self.pixel_size - 1, ((self.Bresy) + 1) * self.pixel_size - 1)], fill='black') self.chyba2 = 2* self.chyba if self.chyba2 > -abs(self.Bresdy): self.chyba = self.chyba - abs(self.Bresdy) self.Bresx = self.Bresx + self.krokx if self.chyba2 < abs(self.Bresdx): self.chyba = self.chyba + abs(self.Bresdx) self.Bresy = self.Bresy + self.kroky final_draw.rectangle([((self.Bresxt) * self.pixel_size, (self.Bresyt) * self.pixel_size), (((self.Bresxt) + 1) * self.pixel_size - 1, ((self.Bresyt) + 1) * self.pixel_size - 1)], fill='black') self.kopiac = self.kopia.copy() if self.show_grid.get(): draw = ImageDraw.Draw(self.kopiac) for i in range(0, self.actual_size, self.pixel_size): line_color = DEFAULT_GRID_COLOR_HEX draw.line([(i, 0), (i, self.actual_size)], fill=line_color) draw.line([(0, i), (self.actual_size, i)], fill=line_color) self.tk_image = ImageTk.PhotoImage(self.kopiac) self.canvas.create_image(0, 0, anchor="nw", image=self.tk_image) self.image = self.kopia def polytemp(self, temppoints): self.kopia = self.image.copy() temp_draw = ImageDraw.Draw(self.kopia) for i in range (1, len(temppoints)): self.Bresxt = temppoints[i][0] self.Bresyt = temppoints[i][1] self.Bresx1 = temppoints[i-1][0] self.Bresy1 = temppoints[i-1][1] self.Bresdx = self.Bresxt - self.Bresx1 self.Bresdy = self.Bresyt - self.Bresy1 self.krokx = 1 if self.Bresdx>=0 else -1 self.kroky = 1 if self.Bresdy>=0 else -1 self.chyba = abs(self.Bresdx)-abs(self.Bresdy) self.Bresx = self.Bresx1 self.Bresy = self.Bresy1 while self.Bresx != self.Bresxt or self.Bresy != self.Bresyt: temp_draw.rectangle([((self.Bresx) * self.pixel_size, (self.Bresy) * self.pixel_size), (((self.Bresx) + 1) * self.pixel_size - 1, ((self.Bresy) + 1) * self.pixel_size - 1)], fill='grey') self.chyba2 = 2* self.chyba if self.chyba2 > -abs(self.Bresdy): self.chyba = self.chyba - abs(self.Bresdy) self.Bresx = self.Bresx + self.krokx if self.chyba2 < abs(self.Bresdx): self.chyba = self.chyba + abs(self.Bresdx) self.Bresy = self.Bresy + self.kroky temp_draw.rectangle([((self.Bresxt) * self.pixel_size, (self.Bresyt) * self.pixel_size), (((self.Bresxt) + 1) * self.pixel_size - 1, ((self.Bresyt) + 1) * self.pixel_size - 1)], fill='grey') for i in range (len(temppoints)-1): temp_draw.ellipse([temppoints[i][0]* self.pixel_size-8,temppoints[i][1]* self.pixel_size-8,temppoints[i][0]* self.pixel_size+8,temppoints[i][1]* self.pixel_size+8],outline='blue',fill='white') temp_draw.ellipse([temppoints[len(temppoints)-1][0]* self.pixel_size-8,temppoints[len(temppoints)-1][1]* self.pixel_size-8,temppoints[len(temppoints)-1][0]* self.pixel_size+8,temppoints[len(temppoints)-1][1]* self.pixel_size+8],outline='red',fill='white') self.polykoniec(self.points) self.kopiac = self.kopia.copy() if self.show_grid.get(): draw = ImageDraw.Draw(self.kopiac) for i in range(0, self.actual_size, self.pixel_size): line_color = DEFAULT_GRID_COLOR_HEX draw.line([(i, 0), (i, self.actual_size)], fill=line_color) draw.line([(0, i), (self.actual_size, i)], fill=line_color) self.tk_image = ImageTk.PhotoImage(self.kopiac) self.canvas.create_image(0, 0, anchor="nw", image=self.tk_image) def scanline_fill(self, points): self.kopia = self.image.copy() final_draw = ImageDraw.Draw(self.kopia) if len(points) < 3: return min_y = min(p[1] for p in points) max_y = max(p[1] for p in points) edge_table = {} for i in range(len(points)): x1, y1 = points[i] x2, y2 = points[(i + 1) % len(points)] if y1 == y2: continue if y1 > y2: x1, y1, x2, y2 = x2, y2, x1, y1 slope = (x2 - x1) / (y2 - y1) edge_table.setdefault(y1, []).append((x1, y2, slope)) active_edges = [] for y in range(min_y, max_y + 1): if y in edge_table: active_edges.extend(edge_table[y]) active_edges = [(x, y_max, slope) for (x, y_max, slope) in active_edges if y < y_max] active_edges.sort() for i in range(0, len(active_edges), 2): x_start = int(active_edges[i][0]) x_end = int(active_edges[i + 1][0]) for x in range(x_start+1, x_end+1): final_draw.rectangle([(x * self.pixel_size, y * self.pixel_size), ((x + 1) * self.pixel_size)-1, ((y + 1) * self.pixel_size)-1], fill=DEFAULT_FILL_COLOR) active_edges = [(x + slope, y_max, slope) for (x, y_max, slope) in active_edges] self.kopiac = self.kopia.copy() if self.show_grid.get(): draw = ImageDraw.Draw(self.kopiac) for i in range(0, self.actual_size, self.pixel_size): line_color = DEFAULT_GRID_COLOR_HEX draw.line([(i, 0), (i, self.actual_size)], fill=line_color) draw.line([(0, i), (self.actual_size, i)], fill=line_color) self.tk_image = ImageTk.PhotoImage(self.kopiac) self.canvas.create_image(0, 0, anchor="nw", image=self.tk_image) self.image=self.kopia def polykoniec(self, points): if len(points) > 1 and points[0] == points[-1]: self.points.append(points[0]) self.scanline_fill(self.points) self.poly(self.points) self.points = [] self.temppoints = [0] else: pass def polyzrus(self, event = None): self.points = [] self.temppoints = [0] self.kopiac = self.image.copy() if self.show_grid.get(): draw = ImageDraw.Draw(self.kopiac) for i in range(0, self.actual_size, self.pixel_size): line_color = DEFAULT_GRID_COLOR_HEX draw.line([(i, 0), (i, self.actual_size)], fill=line_color) draw.line([(0, i), (self.actual_size, i)], fill=line_color) self.tk_image = ImageTk.PhotoImage(self.kopiac) self.canvas.create_image(0, 0, anchor="nw", image=self.tk_image) def clear_canvas(self, event=None): self.image = Image.new('RGB', (self.actual_size, self.actual_size), (255, 255, 255)) self.draw = ImageDraw.Draw(self.image) self.bezierzrus() if self.show_grid.get(): self.draw_grid() self.update_canvas() def toggle_grid(self): self.bezierzrus() self.update_canvas() def update_canvas(self): self.kopiac = self.image.copy() if self.show_grid.get(): self.kopiac = self.draw_grid() self.tk_image = ImageTk.PhotoImage(self.kopiac) else: self.tk_image = ImageTk.PhotoImage(self.image) self.canvas.create_image(0, 0, anchor="nw", image=self.tk_image) def draw_grid(self): # Create a temporary image for grid overlay draw = ImageDraw.Draw(self.kopiac) for i in range(0, self.actual_size, self.pixel_size): line_color = DEFAULT_GRID_COLOR_HEX draw.line([(i, 0), (i, self.actual_size)], fill=line_color) draw.line([(0, i), (self.actual_size, i)], fill=line_color) return self.kopiac if __name__ == '__main__': root = tk.Tk() root.title("Simple Drawing App") app = SimpleDrawingApp(root) root.mainloop()
Editor is loading...
Leave a Comment