Skip to content

Instantly share code, notes, and snippets.

@realmayus
Created May 3, 2020 11:52
Show Gist options
  • Save realmayus/8a3c3df95e039f4ae15e44f5b857dd25 to your computer and use it in GitHub Desktop.
Save realmayus/8a3c3df95e039f4ae15e44f5b857dd25 to your computer and use it in GitHub Desktop.
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