Gartic Auto Draw

Automatically draws an image on Gartic using dithering techniques.

目前为 2023-08-03 提交的版本。查看 最新版本

// ==UserScript==
// @name         Gartic Auto Draw
// @namespace    gartic-auto-draw
// @description  Automatically draws an image on Gartic using dithering techniques.
// @version      1.2
// @license      MIT
// @author       EmersonxD
// @match        https://gartic.io/*
// @grant        none
// ==/UserScript==

function invertDict(d) {
  return Object.keys(d).reduce((acc, key) => {
    acc[d[key]] = key;
    return acc;
  }, {});
}

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;
}

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);
  });
}

async function createDrawing(image, scale = 100, interval = 10) {
  if (!image || !image.type.startsWith("image/")) {
    console.error("Por favor, selecione um arquivo de imagem válido.");
    return;
  }
  const canvas = document.querySelector(".game.canvas");
  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 = [];
  for (let y = 0; y < img.height; y++) {
    for (let x = 0; x < img.width; x++) {
      const pixel = context.getImageData(x, y, 1, 1).data;
      const gray = Math.round(
        (pixel[0] + pixel[1] + pixel[2]) / 3
      );
      const tone = map[gray];
      pixels.push({ x, y, tone });
    }
  }
  for (let i = 0; i < pixels.length; i++) {
    const { x, y, tone } = pixels[i];
    const px = x * canvas.offsetWidth / img.width;
    const py = y * canvas.offsetHeight / img.height;
    try {
      await clickWithRetry(
        px + canvas.offsetLeft,
        py + 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));
  }
}

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;
  top: 10px;
  right: 10px;
  z-index: 9999;
`;
button.addEventListener("click", () => {
  input.click();
});
document.body.appendChild(button);

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址