Untitled
unknown
plain_text
9 months ago
45 kB
8
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