Skip to content

Commit 48373a0

Browse files
committed
Initial commit
0 parents  commit 48373a0

File tree

4 files changed

+415
-0
lines changed

4 files changed

+415
-0
lines changed

connector.py

Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
import tkinter as tk
2+
import socket
3+
import threading
4+
5+
PORT = 12345
6+
7+
USAGE="""USAGE: To connect to existing server input IP-Address on the right
8+
USAGE: To start a server click on \"Listen\" Button"""
9+
10+
class Connector(tk.Frame):
11+
def __init__(self, master):
12+
print(USAGE)
13+
super().__init__(master)
14+
15+
self.master = master
16+
self.successful = False
17+
self.in_mainloop = True
18+
self.frm_connect = tk.Frame(self)
19+
self.frm_connect.columnconfigure(1, minsize=100)
20+
self.btn_connect = tk.Button(self.frm_connect, text="Connect", command=lambda: self.start(self.connect))
21+
self.ent_ip = tk.Entry(self.frm_connect)
22+
self.btn_connect.grid(row=0, column=0, padx=5, pady=2.5)
23+
self.ent_ip.grid(row=0, column=1, padx=5)
24+
25+
self.rowconfigure([0, 1], minsize=30)
26+
self.frm_connect.grid(row=0, columnspan=2)
27+
self.btn_listen = tk.Button(self, text="Listen", command=lambda: self.start(self.listen))
28+
self.btn_listen.grid(row=1, column=0, padx=5, pady=2.5, sticky="w")
29+
self.btn_cancel = tk.Button(self, text="Cancel", command=self.stop)
30+
self.btn_cancel.grid(row=1, column=1, sticky="w")
31+
self.btn_cancel.grid_remove()
32+
33+
self.thread = threading.Thread(target=lambda: "dummy")
34+
35+
def enable_buttons(self):
36+
self.btn_connect["state"] = "active"
37+
self.btn_listen["state"] = "active"
38+
39+
def disable_buttons(self):
40+
self.btn_connect["state"] = "disable"
41+
self.btn_listen["state"] = "disable"
42+
43+
def start(self, target):
44+
self.disable_buttons()
45+
self.btn_cancel.grid()
46+
self.thread = threading.Thread(target=target)
47+
self.thread.start()
48+
49+
def stop(self):
50+
if self.in_mainloop:
51+
self.enable_buttons()
52+
self.btn_cancel.grid_remove()
53+
self.sock.close()
54+
55+
def listen(self):
56+
print(f"STATUS: Listening on port {PORT}")
57+
self.sock = socket.socket()
58+
try:
59+
self.sock.bind(("", PORT))
60+
self.sock.listen(1)
61+
self.conn, addr = self.sock.accept()
62+
except OSError as e:
63+
print(e)
64+
self.stop()
65+
return
66+
print(f"STATUS: Got connection from {addr[0]}")
67+
self.successful = True
68+
self.role = "server"
69+
self.master.quit()
70+
71+
def connect(self):
72+
self.sock = socket.socket()
73+
ip = self.ent_ip.get()
74+
#[DEBUG]
75+
if not ip: ip = "localhost"
76+
print(f"STATUS: Connecting to {ip}")
77+
try: self.sock.connect((ip, PORT))
78+
except OSError as e:
79+
self.stop()
80+
print(e)
81+
return
82+
print("STATUS: Connection successful")
83+
self.successful = True
84+
self.conn = self.sock
85+
self.role = "client"
86+
self.master.quit()
87+
88+
def cleanup(self):
89+
self.in_mainloop = False
90+
if self.thread.is_alive(): self.sock.close()
91+
92+
def is_successful(self):
93+
return self.successful
94+
95+
def get_results(self):
96+
return self.conn, self.role
97+
98+
if __name__ == "__main__":
99+
connector = Connector()
100+
connector.mainloop()
101+
if connector.successful:
102+
connection = connector.conn
103+
role = connector.role
104+
connector.destroy()
105+
#WTF window has to be destroyed before communication otherwise very laggy
106+
if role == "server":
107+
connection.send(b"Hello from the server side!")
108+
print(connection.recv(50).decode())
109+
elif role == "client":
110+
print(connection.recv(50).decode())
111+
connection.send(b"Hello from the client side!")
112+
input("close...")
113+
connection.close()
114+
elif connector.thread.is_alive(): connector.sock.close()
115+

editor.py

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
import tkinter as tk
2+
from PIL import ImageTk, Image, ImageFilter, ImageDraw
3+
4+
USAGE = """USAGE: Mousewheel Up = Blur+
5+
USAGE: Mousewheel Down = Blur-
6+
USAGE: Mousebutton Left = Create Rectangle (Drag)
7+
USAGE: Mousebutton Right = Delete Rectangle (Click)
8+
USAGE: Enter = Confirm and Exchange"""
9+
10+
class Editor(tk.Canvas):
11+
def __init__(self, master, filename, **kwargs):
12+
print(USAGE)
13+
self.successful = False
14+
self.master = master
15+
self.rects = {}
16+
self.current_rect = -1
17+
self.blur = 0.0
18+
self.image = Image.open(filename)
19+
self.blurred = self.image.copy()
20+
self.image_gui = ImageTk.PhotoImage(self.blurred)
21+
kwargs["width"] = self.image_gui.width()
22+
kwargs["height"] = self.image_gui.height()
23+
super().__init__(master, **kwargs)
24+
self.image_id = self.create_image(0, 0, image=self.image_gui, anchor="nw")
25+
self.bind("<MouseWheel>", self.change_blur)
26+
self.bind("<Button-1>", self.new_rect)
27+
self.bind("<B1-Motion>", self.resize_rect)
28+
self.bind("<ButtonRelease-1>", self.create_rect)
29+
self.bind("<Return>", self.finish)
30+
self.focus_force()
31+
32+
def change_blur(self, event):
33+
self.blur += 0.5 * (event.delta / 120)
34+
self.blur = max(0.0, self.blur)
35+
tmp = self.blurred
36+
self.blurred = self.image.filter(ImageFilter.GaussianBlur(self.blur))
37+
tmp.close()
38+
self.image_gui = ImageTk.PhotoImage(self.blurred)
39+
self.itemconfigure(self.image_id, image=self.image_gui)
40+
41+
def new_rect(self, event):
42+
coords = [event.x, event.y, event.x, event.y]
43+
self.current_rect = self.create_rectangle(*coords)
44+
self.rects[self.current_rect] = coords
45+
46+
47+
def resize_rect(self, event):
48+
self.rects[self.current_rect][2] = event.x
49+
self.rects[self.current_rect][3] = event.y
50+
self.coords(self.current_rect, *self.rects[self.current_rect])
51+
52+
def create_rect(self, _):
53+
def make_deleter(handle):
54+
return lambda _: self.delete_rect(handle)
55+
self.itemconfigure(self.current_rect, fill="BLACK")
56+
self.tag_bind(self.current_rect, "<Button-3>", make_deleter(self.current_rect))
57+
58+
def delete_rect(self, rect):
59+
self.delete(rect)
60+
del self.rects[rect]
61+
62+
def finish(self, _):
63+
print("STATUS: Image locked and sent")
64+
self.successful = True
65+
self.master.quit()
66+
67+
def cleanup(self):
68+
self.image.close()
69+
self.blurred.close()
70+
71+
def is_successful(self):
72+
return self.successful
73+
74+
def get_results(self):
75+
imgs_with_rects = [self.blurred, self.image.copy()]
76+
for img in imgs_with_rects:
77+
for rect in self.rects.values():
78+
draw = ImageDraw.Draw(img)
79+
draw.rectangle(rect, "BLACK", "BLACK")
80+
return imgs_with_rects[0], imgs_with_rects[1], self.image
81+
82+
if __name__ == "__main__":
83+
window = tk.Tk()
84+
editor = Editor(window, "test.png")
85+
editor.pack()
86+
window.mainloop()

protocol.py

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
from os import system
2+
import tkinter as tk
3+
from tkinter.filedialog import askopenfilename, asksaveasfilename
4+
from connector import Connector
5+
from editor import Editor
6+
from verifier import Verifier
7+
8+
FILETYPES = [("Image Files", (".png", ".jpg", ".jpeg"))]
9+
10+
def main():
11+
window = tk.Tk()
12+
connector = Connector(window)
13+
connector.pack()
14+
window.mainloop()
15+
if not connector.is_successful():
16+
# triggered only when exiting forcefully
17+
connector.cleanup()
18+
return
19+
conn, role = connector.get_results()
20+
connector.destroy()
21+
22+
while True:
23+
filename = askopenfilename(parent=window, filetypes=FILETYPES)
24+
if not filename:
25+
conn.close()
26+
return
27+
editor = Editor(window, filename)
28+
editor.pack()
29+
window.mainloop()
30+
if not editor.is_successful():
31+
conn.close()
32+
editor.cleanup()
33+
return
34+
images = editor.get_results()
35+
editor.destroy()
36+
37+
verifier = Verifier(window, conn, role, images)
38+
if verifier.has_paniced():
39+
verifier.cleanup()
40+
return
41+
verifier.pack()
42+
window.mainloop()
43+
if not verifier.is_successful():
44+
verifier.cleanup()
45+
return
46+
image = verifier.get_results()
47+
48+
filename = asksaveasfilename(parent=window, filetypes=[("Image Files", ".png")])
49+
if filename:
50+
if not ".png" in filename: filename += ".png"
51+
image.save(filename)
52+
53+
if not verifier.ask_resume():
54+
print("INFO: One party wanted to stop")
55+
verifier.cleanup()
56+
break
57+
58+
for img in images:
59+
img.close()
60+
verifier.destroy()
61+
system("cls")
62+
63+
window.destroy()
64+
65+
66+
if __name__ == "__main__": main()

0 commit comments

Comments
 (0)