// ==UserScript==
// @name Gartic Auto Draw
// @namespace gartic-auto-draw
// @description Automatically draws an image on Gartic using dithering techniques.
// @version 1.6
// @license MIT
// @author EmersonxD
// @match https://gartic.io/*
// @grant none
// @run-at document-idle
// ==/UserScript==
(function () {
'use strict';
// Função para inverter um dicionário (mapa)
function invertDict(d) {
return Object.keys(d).reduce((acc, key) => {
acc[d[key]] = key;
return acc;
}, {});
}
// Função para criar um mapa de dithering
function createDitherMap(numTones) {
const step = 256 / (numTones - 1);
const map = {};
for (let i = 0; i < 256; i++) {
const value = Math.round(i / step) * step;
map[i] = value;
}
return map;
}
// Função para clicar em um ponto com retentativas
async function clickWithRetry(x, y, button = "left", retries = 5) {
const buttonCode = { left: 0, middle: 1, right: 2 }[button];
const element = document.elementFromPoint(x, y);
if (!element) return false;
const event = new MouseEvent("mousedown", {
bubbles: true,
cancelable: true,
view: window,
button: buttonCode,
buttons: 1,
clientX: x,
clientY: y,
screenX: x,
screenY: y,
});
element.dispatchEvent(event);
if (retries <= 0) return false;
const retry = () => clickWithRetry(x, y, button, retries - 1);
return new Promise((resolve) => {
setTimeout(() => {
if (document.activeElement !== element) {
retry().then(resolve);
} else {
const event = new MouseEvent("mouseup", {
bubbles: true,
cancelable: true,
view: window,
button: buttonCode,
buttons: 1,
clientX: x,
clientY: y,
screenX: x,
screenY: y,
});
document.activeElement.dispatchEvent(event);
resolve(true);
}
}, 50);
});
}
// Função principal para desenhar a imagem
async function createDrawing(image, scale = 100, interval = 2) {
if (!image || !image.type.startsWith("image/")) {
alert("Por favor, selecione um arquivo de imagem válido.");
return;
}
const canvas = document.querySelector(".game.canvas");
if (!canvas) {
alert("Canvas do Gartic não encontrado. Certifique-se de estar na página correta.");
return;
}
const context = canvas.getContext("2d");
const img = await new Promise((resolve) => {
const reader = new FileReader();
reader.onload = (event) => {
const img = new Image();
img.onload = () => resolve(img);
img.src = event.target.result;
};
reader.readAsDataURL(image);
});
const map = createDitherMap(scale);
const pixels = [];
// Redimensiona a imagem para o tamanho do canvas
const width = canvas.offsetWidth;
const height = canvas.offsetHeight;
const tempCanvas = document.createElement("canvas");
tempCanvas.width = width;
tempCanvas.height = height;
const tempContext = tempCanvas.getContext("2d");
tempContext.drawImage(img, 0, 0, width, height);
// Obtém os pixels da imagem redimensionada
const imageData = tempContext.getImageData(0, 0, width, height).data;
for (let y = 0; y < height; y++) {
for (let x = 0; x < width; x++) {
const index = (y * width + x) * 4;
const r = imageData[index];
const g = imageData[index + 1];
const b = imageData[index + 2];
const gray = Math.round((r + g + b) / 3);
const tone = map[gray];
pixels.push({ x, y, tone });
}
}
// Desenha os pixels no canvas do Gartic
for (let i = 0; i < pixels.length; i++) {
const { x, y, tone } = pixels[i];
try {
await clickWithRetry(x + canvas.offsetLeft, y + canvas.offsetTop, "left", 5);
const color = invertDict(map)[tone];
context.fillStyle = `#${color.toString(16).padStart(6, "0")}`;
context.fillRect(x, y, 1, 1);
} catch (error) {
console.error(`Erro ao desenhar o pixel (${x}, ${y}):`, error);
}
await new Promise((resolve) => setTimeout(resolve, interval));
}
alert("Desenho concluído!");
}
// Cria a interface do usuário
const input = document.createElement("input");
input.type = "file";
input.style.display = "none";
input.addEventListener("change", () => {
const file = input.files[0];
createDrawing(file);
});
document.body.appendChild(input);
const button = document.createElement("button");
button.type = "button";
button.innerText = "Desenhar";
button.style.position = "fixed";
button.style.top = "10px";
button.style.right = "10px";
button.style.zIndex = "9999";
button.style.padding = "10px";
button.style.backgroundColor = "#4CAF50";
button.style.color = "#fff";
button.style.border = "none";
button.style.borderRadius = "5px";
button.style.cursor = "pointer";
button.addEventListener("click", () => {
input.click();
});
document.body.appendChild(button);
})();