您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Maps the drawing's colors to the current color palette.
当前为
// ==UserScript== // @name Style Transfer // @match https://sketchful.io/ // @grant none // @version 0.1 // @author Bell // @description Maps the drawing's colors to the current color palette. // @namespace https://greasyfork.org/users/281093 // jshint esversion: 6 // ==/UserScript== const canvas = document.querySelector("#canvas"); const ctx = canvas.getContext('2d'); const gameParent = document.querySelector("body > div.game > div.gameParent"); const colorButtons = document.querySelectorAll(".gameToolsColor"); const interfaceBar = document.querySelector("#gameInterface"); const buttonContainer = document.createElement("div"); const fastButton = document.createElement("button"); const slowButton = document.createElement("button"); const undoButton = document.createElement("button"); let palette = []; let paletteLab = []; let storedDrawings = []; let colorCache = []; (function init() { initInterface(); initListeners(); })(); function initInterface() { buttonContainer.style.marginLeft = "45%"; fastButton.style = `height: 50px;border: none;background-color: cornflowerblue; height: 30px;border-radius: 5px;margin-top: 10px; font-weight: 800`; slowButton.style = `height: 30px; border: none;background-color: chocolate; border-radius: 5px; margin-top: 10px; margin-left: 10px; font-weight: 800`; undoButton.style = `height: 30px; border: none;background-color: cadetblue; border-radius: 5px; margin-top: 10px; margin-left: 10px; font-weight: 800`; fastButton.textContent = "FAST"; slowButton.textContent = "ACCURATE"; undoButton.setAttribute("class", "fas fa-undo-alt"); buttonContainer.appendChild(fastButton); buttonContainer.appendChild(slowButton); buttonContainer.appendChild(undoButton); interfaceBar.appendChild(buttonContainer); } function initListeners() { fastButton.onpointerdown = () => { transformColor(true); }; slowButton.onpointerdown = () => { transformColor(false); }; undoButton.onpointerdown = () => { if (!storedDrawings.length) return; ctx.putImageData(storedDrawings.pop(), 0, 0); }; } function transformColor(fast) { getPalette(); storedDrawings.length < 15 && storedDrawings.push(ctx.getImageData(0, 0, canvas.width, canvas.height)); let imgData = ctx.getImageData(0, 0, canvas.width, canvas.height); let data = imgData.data; let closestColor; for (let i = 0; i < data.length; i += 4) { let rgb = data.slice(i, i + 3); closestColor = isCached(rgb) || findClosest(fast, rgb); data[i] = closestColor[0]; data[i + 1] = closestColor[1]; data[i + 2] = closestColor[2]; } ctx.putImageData(imgData, 0, 0); } function findClosest(fast, rgb) { let closestIndex = fast ? findClosestFast(rgb) : findClosestSlow(rgb); cacheColor(rgb, closestIndex); return palette[closestIndex]; } function findClosestFast(rgb) { let closest = {}; palette.forEach((color, index) => { let distance = Math.pow(((color[0] - rgb[0]) * 0.30), 2) + Math.pow(((color[1] - rgb[1]) * 0.59), 2) + Math.pow(((color[2] - rgb[2]) * 0.11), 2); if (index === 0 || distance < closest.dist) { closest = { dist: distance, idx: index }; } }); return closest.idx; } function findClosestSlow(rgb) { let closest = {}; let labColor = rgb2lab(rgb); paletteLab.forEach((color, index) => { let distance = deltaE(labColor, color); if (index === 0 || distance < closest.dist) { closest = { dist: distance, idx: index }; } }); return closest.idx; } function cacheColor(rgb, index) { if (colorCache.length > 127) return; colorCache.push({ idx: index, color: rgb }); } function isCached(rgb) { for (let cached of colorCache) { if (cached.color[0] === rgb[0] && cached.color[1] === rgb[1] && cached.color[2] === rgb[2]) { return palette[cached.idx]; } } return false; } function getPalette() { palette = []; paletteLab = []; colorCache = []; colorButtons.forEach(color => { if (color.style.background === "rgb(255, 255, 255)") return; palette.push(color.style.background.substring(4, color.style.background.length - 1) .replace(/ /g, '').split(',').map(x => parseInt(x))); }); palette.forEach(rgb => { paletteLab.push(rgb2lab(rgb)); }); } function canvasVisibility(mutations, observer) { for (let mutation of mutations) { if (isFreeDraw()) buttonContainer.style.display = ""; else buttonContainer.style.display = "none"; } } const canvasObserver = new MutationObserver(canvasVisibility); canvasObserver.observe(document.querySelector("body > div.game"), { attributes: true }); canvasObserver.observe(canvas, { attributes: true }); function isFreeDraw() { return canvas.style.display !== "none" && document.querySelector("#gameClock").style.display === "none" && document.querySelector("#gameSettings").style.display === "none"; } function deltaE(labA, labB) { let deltaL = labA[0] - labB[0]; let deltaA = labA[1] - labB[1]; let deltaB = labA[2] - labB[2]; let c1 = Math.sqrt(labA[1] * labA[1] + labA[2] * labA[2]); let c2 = Math.sqrt(labB[1] * labB[1] + labB[2] * labB[2]); let deltaC = c1 - c2; let deltaH = deltaA * deltaA + deltaB * deltaB - deltaC * deltaC; deltaH = deltaH < 0 ? 0 : Math.sqrt(deltaH); let sc = 1.0 + 0.045 * c1; let sh = 1.0 + 0.015 * c1; let deltaLKlsl = deltaL / (1.0); let deltaCkcsc = deltaC / (sc); let deltaHkhsh = deltaH / (sh); let i = deltaLKlsl * deltaLKlsl + deltaCkcsc * deltaCkcsc + deltaHkhsh * deltaHkhsh; return i < 0 ? 0 : Math.sqrt(i); } function rgb2lab(rgb) { let r = rgb[0] / 255, g = rgb[1] / 255, b = rgb[2] / 255, x, y, z; r = (r > 0.04045) ? Math.pow((r + 0.055) / 1.055, 2.4) : r / 12.92; g = (g > 0.04045) ? Math.pow((g + 0.055) / 1.055, 2.4) : g / 12.92; b = (b > 0.04045) ? Math.pow((b + 0.055) / 1.055, 2.4) : b / 12.92; x = (r * 0.4124 + g * 0.3576 + b * 0.1805) / 0.95047; y = (r * 0.2126 + g * 0.7152 + b * 0.0722) / 1.00000; z = (r * 0.0193 + g * 0.1192 + b * 0.9505) / 1.08883; x = (x > 0.008856) ? Math.pow(x, 1 / 3) : (7.787 * x) + 16 / 116; y = (y > 0.008856) ? Math.pow(y, 1 / 3) : (7.787 * y) + 16 / 116; z = (z > 0.008856) ? Math.pow(z, 1 / 3) : (7.787 * z) + 16 / 116; return [(116 * y) - 16, 500 * (x - y), 200 * (y - z)]; }