-
-
Save realmayus/8a3c3df95e039f4ae15e44f5b857dd25 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import sys | |
import time | |
import traceback | |
import urllib | |
import urllib.request | |
from io import BytesIO | |
from PIL import Image | |
from PIL import ImageTk as piltk | |
from appJar import gui | |
from pynput import mouse, keyboard | |
from pynput.mouse import Controller, Button | |
from selenium import webdriver | |
coords = { | |
"canvasTopLeft": None, | |
"colorsTopLeft": None, | |
} | |
actions = ["canvasTopLeft", "colorsTopLeft"] | |
img_path = None | |
img_object = None # only gets set when the user uses the "grab" feature | |
did_select_img = False | |
prefer_grabbed_img = False | |
size = (100, 75) # the max size of the image | |
# the color palette that's available on skribbl | |
available_colors = [255, 255, 255, 193, 193, 193, 239, 19, 11, 255, 115, 0, 255, 228, 0, 0, 204, 0, 0, 178, 255, 35, 31, 211, 163, 0, 186, 211, 124, 170, 160, 82, 45, 0, 0, 0, 76, 76, 76, 116, 11, 7, 194, 56, 0, 232, 162, 0, 0, 85, 16, 0, 86, 158, 14, 8, 101, 85, 0, 105, 167, 85, 116, 99, 48, 13] | |
# adding placeholders because Pillow pallets need to have exactly 768 values | |
for _t in range(768-66): | |
available_colors.append(0) | |
# Creating an image that we apply the skribbl.io palette to (using that later as a template) | |
pal_image = Image.new("P", (16, 16)) | |
pal_image.putpalette(available_colors) | |
DRIVER_PATH = "/home/marius/chromedriver" | |
wd = webdriver.Chrome(executable_path=DRIVER_PATH) | |
app = gui("AutoSkribbl", "350x400") | |
app.addLabel("title", "Please click on these positions in this order:") | |
app.setBg("white") | |
for _action in actions: | |
app.addLabel(_action, _action + ": unset") | |
current_coords = () | |
def on_click(x, y, button, pressed): | |
global current_coords | |
current_coords = (x, y) | |
if not pressed: | |
# Stop listener | |
return False | |
def set_coords(action): | |
global coords | |
with mouse.Listener( | |
on_click=on_click) as listener: | |
listener.join() | |
coords[action] = current_coords | |
app.setLabel(action, action + ": " + str(current_coords)) | |
def set_coords_wrapper(): | |
for action in actions: | |
set_coords(action) | |
def on_img_btn_click(): | |
global img_path, did_select_img, prefer_grabbed_img | |
img_path = app.openBox("Open Image", dirName="/home/marius/Pictures") | |
did_select_img = True if img_path else False | |
prefer_grabbed_img = False | |
app.setLabel("img", "Selected Image: " + ("Yes" if did_select_img else "No") + ". Using local image.") | |
def on_coords_btn_click(): | |
app.setLabel("currentAction", "Selecting coords…") | |
app.disableButton('setCoords') | |
app.threadCallback(set_coords_wrapper, done_coords) | |
def on_draw_btn_click(): | |
if not did_select_img: | |
app.warningBox("No image selected", "No image selected.\nPlease either grab or select an image.") | |
return | |
app.disableButton('startDraw') | |
app.disableButton('testClrs') | |
app.setLabel("currentAction", "Currently drawing…") | |
app.setLabel("currentActionSub", "Press ESC to kill") | |
# Enable the drawing button again after an error occurred | |
app.threadCallback(draw_img, done_drawing) | |
def done_drawing(x): | |
app.queueFunction(app.setLabel, "currentAction", " ") | |
app.queueFunction(app.setLabel, "currentActionSub", " ") | |
app.queueFunction(app.enableButton, "startDraw") | |
app.queueFunction(app.enableButton, "testClrs") | |
def done_coords(x): | |
app.queueFunction(app.setLabel, "currentAction", " ") | |
app.queueFunction(app.enableButton, "setCoords") | |
def draw_img(test_only=False): | |
pixel_colors = {} | |
try: | |
img = None | |
if not img_path and not img_object: | |
app.warningBox("No image selected", "No image selected.\nPlease either grab or select an image.") | |
elif img_object and img_path: | |
if prefer_grabbed_img: | |
img = img_object | |
else: | |
img = Image.open(img_path) | |
elif img_object: | |
img = img_object | |
elif img_path: | |
img = Image.open(img_path) | |
img.thumbnail(size, Image.NEAREST) | |
img = img.convert("RGB").quantize(palette=pal_image) | |
width, height = img.size | |
img = img.convert("RGB") | |
app_jar_image = piltk.PhotoImage(img) | |
app.setImageData("image", app_jar_image, fmt="PhotoImage") | |
for y in range(height): | |
for x in range(width): | |
r, g, b = img.getpixel((x, y)) | |
key = ' '.join([str(r), str(g), str(b)]) | |
if key not in pixel_colors: | |
pixel_colors[key] = [] | |
pixel_colors[key].append((x, y)) | |
print(pixel_colors) | |
for kay in pixel_colors: | |
print(kay) | |
r, g, b = kay.split(' ') | |
print(r, g, b) | |
set_color(r, g, b) | |
time.sleep(1) | |
if not test_only: | |
for pixel in pixel_colors[kay]: | |
x, y = pixel | |
draw_pixel(x, y, 8) # the brush has a diameter of 16 | |
time.sleep(0.0005) | |
except Exception as e: | |
print(traceback.format_exc()) | |
app.warningBox("An error occurred", "An error occurred:\n" + str(e)) | |
return False | |
mouse_controller = Controller() | |
def set_color(r, g, b): | |
"""yes I do know that this is dirty af but who cares :p""" | |
mouse_controller.position = coords["colorsTopLeft"] | |
print("setting color to " + str(r) + ", " + str(g) + ", " + str(b)) | |
r = int(r) | |
g = int(g) | |
b = int(b) | |
if r == 255 and g == 255 and b == 255: | |
mouse_controller.move(12, 12) | |
mouse_controller.press(Button.left) | |
mouse_controller.release(Button.left) | |
elif r == 193 and g == 193 and b == 193: | |
mouse_controller.move(24 + 12, 12) | |
mouse_controller.press(Button.left) | |
mouse_controller.release(Button.left) | |
elif r == 239 and g == 19 and b == 11: | |
mouse_controller.move(24 * 2 + 12, 12) | |
mouse_controller.press(Button.left) | |
mouse_controller.release(Button.left) | |
elif r == 255 and g == 115 and b == 0: | |
mouse_controller.move(24 * 3 + 12, 12) | |
mouse_controller.press(Button.left) | |
mouse_controller.release(Button.left) | |
elif r == 255 and g == 228 and b == 0: | |
mouse_controller.move(24 * 4 + 12, 12) | |
mouse_controller.press(Button.left) | |
mouse_controller.release(Button.left) | |
elif r == 0 and g == 204 and b == 0: | |
mouse_controller.move(24 * 5 + 12, 12) | |
mouse_controller.press(Button.left) | |
mouse_controller.release(Button.left) | |
elif r == 0 and g == 178 and b == 255: | |
mouse_controller.move(24 * 6 + 12, 12) | |
mouse_controller.press(Button.left) | |
mouse_controller.release(Button.left) | |
elif r == 35 and g == 31 and b == 211: | |
mouse_controller.move(24 * 7 + 12, 12) | |
mouse_controller.press(Button.left) | |
mouse_controller.release(Button.left) | |
elif r == 163 and g == 0 and b == 186: | |
mouse_controller.move(24 * 8 + 12, 12) | |
mouse_controller.press(Button.left) | |
mouse_controller.release(Button.left) | |
elif r == 211 and g == 124 and b == 170: | |
mouse_controller.move(24 * 9 + 12, 12) | |
mouse_controller.press(Button.left) | |
mouse_controller.release(Button.left) | |
elif r == 160 and g == 82 and b == 45: | |
mouse_controller.move(24 * 10 + 12, 12) | |
mouse_controller.press(Button.left) | |
mouse_controller.release(Button.left) | |
elif r == 0 and g == 0 and b == 0: | |
mouse_controller.move(12, 24 + 12) | |
mouse_controller.press(Button.left) | |
mouse_controller.release(Button.left) | |
elif r == 76 and g == 76 and b == 76: | |
mouse_controller.move(24 * 1 + 12, 24 + 12) | |
mouse_controller.press(Button.left) | |
mouse_controller.release(Button.left) | |
elif r == 116 and g == 11 and b == 7: | |
mouse_controller.move(24 * 2 + 12, 24 + 12) | |
mouse_controller.press(Button.left) | |
mouse_controller.release(Button.left) | |
elif r == 194 and g == 56 and b == 0: | |
mouse_controller.move(24 * 3 + 12, 24 + 12) | |
mouse_controller.press(Button.left) | |
mouse_controller.release(Button.left) | |
elif r == 232 and g == 162 and b == 0: | |
mouse_controller.move(24 * 4 + 12, 24 + 12) | |
mouse_controller.press(Button.left) | |
mouse_controller.release(Button.left) | |
elif r == 0 and g == 85 and b == 16: | |
mouse_controller.move(24 * 5 + 12, 24 + 12) | |
mouse_controller.press(Button.left) | |
mouse_controller.release(Button.left) | |
elif r == 0 and g == 86 and b == 158: | |
mouse_controller.move(24 * 6 + 12, 24 + 12) | |
mouse_controller.press(Button.left) | |
mouse_controller.release(Button.left) | |
elif r == 14 and g == 8 and b == 101: | |
mouse_controller.move(24 * 7 + 12, 24 + 12) | |
mouse_controller.press(Button.left) | |
mouse_controller.release(Button.left) | |
elif r == 85 and g == 0 and b == 105: | |
mouse_controller.move(24 * 8 + 12, 24 + 12) | |
mouse_controller.press(Button.left) | |
mouse_controller.release(Button.left) | |
elif r == 167 and g == 85 and b == 116: | |
mouse_controller.move(24 * 9 + 12, 24 + 12) | |
mouse_controller.press(Button.left) | |
mouse_controller.release(Button.left) | |
elif r == 99 and g == 48 and b == 13: | |
mouse_controller.move(24 * 10 + 12, 24 + 12) | |
mouse_controller.press(Button.left) | |
mouse_controller.release(Button.left) | |
else: | |
app.warningBox("Error", "Couldn't find color R" + str(r) + " G" + str(g) + " B" + str(b)) | |
prev_cursor = (0, 0) | |
def draw_pixel(x, y, step_size): | |
global prev_cursor | |
# mouse_controller.position = coords["canvasTopLeft"] | |
cX, cY = coords["canvasTopLeft"] | |
pX, pY = prev_cursor | |
if pX < x and pY < y: | |
mouse_controller.position = (cX + (x * step_size), cY + (y * step_size)) | |
elif pX > x and pY > y: | |
mouse_controller.position = (cX + (x * step_size), cY + (y * step_size)) | |
elif pX > x and pY < y: | |
mouse_controller.position = (cX + (x * step_size), cY + (y * step_size)) | |
elif pX < x and pY > y: | |
mouse_controller.position = (cX + (x * step_size), cY + (y * step_size)) | |
elif pX == x and pY > y: | |
mouse_controller.position = (cX + x, cY + (y * step_size)) | |
elif pX == x and pY < y: | |
mouse_controller.position = (cX + x, cY + (y * step_size)) | |
elif pX > x and pY == y: | |
mouse_controller.position = (cX + (x * step_size), cY + y) | |
elif pX < x and pY == y: | |
mouse_controller.position = (cX + (x * step_size), cY + y) | |
prev_cursor = mouse_controller.position | |
mouse_controller.click(Button.left) | |
def handle_esc(key): | |
if key == keyboard.Key.esc: | |
print("heyo") | |
app.stop() | |
sys.exit(1) | |
def on_test_btn_click(): | |
app.disableButton('startDraw') | |
app.disableButton('testClrs') | |
app.setLabel("currentAction", "Currently testing…") | |
app.setLabel("currentActionSub", "Press ESC to kill") | |
app.threadCallback(draw_img, done_drawing, True) | |
def on_grab_btn_click(): | |
thing = app.stringBox("Enter search Term", "Enter the thing you have to draw to search an image on Google:") | |
app.setLabel("currentAction", "Grabbing images…") | |
app.threadCallback(grab_wrapper, done_grabbing, thing) | |
def grab_wrapper(thing): | |
return fetch_image_urls(thing, 10, wd) | |
def done_grabbing(urls): | |
app.setLabel("currentAction", "") | |
app.setLabel("currentActionSub", "") | |
print(urls) | |
app.startSubWindow("imgGrabSelect", "Select Image to use", modal=True, blocking=True) | |
app.setBg("white") | |
app.setOnTop(stay=True) | |
app.setSize(1000, 800) | |
app.addLabel("selImgLbl", "Select Image to use", row=0) | |
row = 1 | |
col = 0 | |
for url in urls: | |
req = urllib.request.Request(url, headers={'User-Agent': 'Mozilla/5.0'}) | |
res = urllib.request.urlopen(req) | |
raw_data = res.read() | |
img = Image.open(BytesIO(raw_data)) | |
img.thumbnail((200, 200), Image.NEAREST) | |
img = img.convert("RGB") | |
app_jar_image = piltk.PhotoImage(img) | |
app.addImageData(url, app_jar_image, fmt="PhotoImage", row=row, column=col) | |
app.setImageSubmitFunction(url, img_grab_select) | |
if col <= 2: | |
col += 1 | |
else: | |
row += 1 | |
col = 0 | |
app.addButton("Cancel", app.img_grab_cancel_btn) | |
app.showSubWindow("imgGrabSelect") | |
def img_grab_cancel_btn(): | |
app.destroyAllSubWindows() # workaround | |
def img_grab_select(url): | |
global img_path, img_obj, did_select_img, prefer_grabbed_img | |
img_path = None | |
prefer_grabbed_img = True | |
req = urllib.request.Request(url, headers={'User-Agent': 'Mozilla/5.0'}) | |
res = urllib.request.urlopen(req) | |
raw_data = res.read() | |
img_obj = Image.open(BytesIO(raw_data)) | |
did_select_img = True | |
app.setLabel("img", "Selected Image: " + ("Yes" if did_select_img else "No") + ". Using grabbed image.") | |
app.destroySubWindow("imgGrabSelect") # workaround | |
def fetch_image_urls(query: str, max_links_to_fetch: int, wd: webdriver, sleep_between_interactions: int = 1): | |
def scroll_to_end(wd): | |
wd.execute_script("window.scrollTo(0, document.body.scrollHeight);") | |
time.sleep(sleep_between_interactions) | |
# build the google query | |
search_url = "https://www.google.com/search?safe=off&site=&tbm=isch&source=hp&q={q}&oq={q}&gs_l=img" | |
# load the page | |
wd.get(search_url.format(q=query)) | |
image_urls = set() | |
image_count = 0 | |
results_start = 0 | |
while image_count < max_links_to_fetch: | |
scroll_to_end(wd) | |
# get all image thumbnail results | |
thumbnail_results = wd.find_elements_by_css_selector("img.Q4LuWd") | |
number_results = len(thumbnail_results) | |
print(f"Found: {number_results} search results. Extracting links from {results_start}:{number_results}") | |
for img in thumbnail_results[results_start:number_results]: | |
app.setLabel("currentActionSub", str(image_count + 1) + "/10") | |
# try to click every thumbnail such that we can get the real image behind it | |
try: | |
img.click() | |
time.sleep(sleep_between_interactions) | |
except Exception: | |
continue | |
# extract image urls | |
actual_images = wd.find_elements_by_css_selector('img.n3VNCb') | |
for actual_image in actual_images: | |
if actual_image.get_attribute('src') and 'http' in actual_image.get_attribute('src'): | |
image_urls.add(actual_image.get_attribute('src')) | |
image_count = len(image_urls) | |
if len(image_urls) >= max_links_to_fetch: | |
print(f"Found: {len(image_urls)} image links, done!") | |
return image_urls | |
# move the result startpoint further down | |
results_start = len(thumbnail_results) | |
return None | |
key_listener = keyboard.Listener( | |
on_release=handle_esc) | |
key_listener.start() | |
app.addEmptyLabel("currentAction").config(font=("Sans Serif", "20", "bold")) | |
app.addEmptyLabel("currentActionSub").config(font=("Sans Serif", "15", "bold")) | |
app.addLabel("img", "Selected Image: " + ("Yes" if img_path else "No")) | |
app.addNamedButton(title="setCoords", name="Set Coords", func=on_coords_btn_click) | |
app.addNamedButton(title="setImg", name="Select Image", func=on_img_btn_click) | |
app.addNamedButton(title="grabImg", name="Grab Image", func=on_grab_btn_click) | |
app.addNamedButton(title="startDraw", name="Start drawing", func=on_draw_btn_click) | |
app.addNamedButton(title="testClrs", name="Test Colors", func=on_test_btn_click) | |
app.addImage("image", None) | |
app.setOnTop(stay=True) | |
app.go() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment