我正在使用画布构建一个小应用程序。我的应用程序可以选择填充黑白图像。
我下载了一个代码并且工作正常,但它仅在图像描边为黑色时才有效。我要使用的所有图像都有灰色笔画。
所以,我想知道我需要更改什么才能使代码使用灰色笔划而不是黑色笔划。
这里是代码:
https://jsfiddle.net/mx0fmdh3/
HTML:
<canvas id="canvas" width=250 height=243></canvas>
的JavaScript
var canvas = document.getElementById("canvas");
var context = canvas.getContext("2d");
var $canvas = $("#canvas");
var canvasOffset = $canvas.offset();
var offsetX = canvasOffset.left;
var offsetY = canvasOffset.top;
var canvasWidth = canvas.width;
var canvasHeight = canvas.height;
var strokeColor = {
r: 152,
g: 152,
b: 152
};
var fillColor = {
r: 101,
g: 155,
b: 65
};
var fillData;
var strokeData;
// load image
var img = new Image();
img.onload = function () {
start();
}
img.crossOrigin = "anonymous";
img.src = "http://i.imgur.com/kjY1kiE.png";
function matchstrokeColor(r, g, b, a) {
// never recolor the initial black divider strokes
// must check for near black because of anti-aliasing
return (r + g + b < 100 && a === 155);
}
function matchStartColor(pixelPos, startR, startG, startB) {
// get the color to be matched
var r = strokeData.data[pixelPos],
g = strokeData.data[pixelPos + 1],
b = strokeData.data[pixelPos + 2],
a = strokeData.data[pixelPos + 3];
// If current pixel of the outline image is black-ish
if (matchstrokeColor(r, g, b, a)) {
return false;
}
// get the potential replacement color
r = fillData.data[pixelPos];
g = fillData.data[pixelPos + 1];
b = fillData.data[pixelPos + 2];
// If the current pixel matches the clicked color
if (r === startR && g === startG && b === startB) {
return true;
}
// If current pixel matches the new color
if (r === fillColor.r && g === fillColor.g && b === fillColor.b) {
return false;
}
return true;
}
// Thank you William Malone!
function floodFill(startX, startY, startR, startG, startB) {
var newPos;
var x;
var y;
var pixelPos;
var neighborLeft;
var neighborRight;
var pixelStack = [
[startX, startY]
];
while (pixelStack.length) {
newPos = pixelStack.pop();
x = newPos[0];
y = newPos[1];
// Get current pixel position
pixelPos = (y * canvasWidth + x) * 4;
// Go up as long as the color matches and are inside the canvas
while (y >= 0 && matchStartColor(pixelPos, startR, startG, startB)) {
y -= 1;
pixelPos -= canvasWidth * 4;
}
pixelPos += canvasWidth * 4;
y += 1;
neighborLeft = false;
neighborRight = false;
// Go down as long as the color matches and in inside the canvas
while (y <= (canvasHeight - 1) && matchStartColor(pixelPos, startR, startG, startB)) {
y += 1;
fillData.data[pixelPos] = fillColor.r;
fillData.data[pixelPos + 1] = fillColor.g;
fillData.data[pixelPos + 2] = fillColor.b;
fillData.data[pixelPos + 3] = 255;
if (x > 0) {
if (matchStartColor(pixelPos - 4, startR, startG, startB)) {
if (!neighborLeft) {
// Add pixel to stack
pixelStack.push([x - 1, y]);
neighborLeft = true;
}
} else if (neighborLeft) {
neighborLeft = false;
}
}
if (x < (canvasWidth - 1)) {
if (matchStartColor(pixelPos + 4, startR, startG, startB)) {
if (!neighborRight) {
// Add pixel to stack
pixelStack.push([x + 1, y]);
neighborRight = true;
}
} else if (neighborRight) {
neighborRight = false;
}
}
pixelPos += canvasWidth * 4;
}
}
}
// Start a floodfill
// 1. Get the color under the mouseclick
// 2. Replace all of that color with the new color
// 3. But respect bounding areas! Replace only contiguous color.
function paintAt(startX, startY) {
// get the clicked pixel's [r,g,b,a] color data
var pixelPos = (startY * canvasWidth + startX) * 4,
r = fillData.data[pixelPos],
g = fillData.data[pixelPos + 1],
b = fillData.data[pixelPos + 2],
a = fillData.data[pixelPos + 3];
// this pixel's already filled
if (r === fillColor.r && g === fillColor.g && b === fillColor.b) {
return;
}
// this pixel is part of the original black image--don't fill
if (matchstrokeColor(r, g, b, a)) {
return;
}
// execute the floodfill
floodFill(startX, startY, r, g, b);
// put the colorized data back on the canvas
context.clearRect(0, 0, canvasWidth, canvasHeight);
context.putImageData(fillData, 0, 0);
context.drawImage(img, 0, 0);
}
// create a random color object {red,green,blue}
function randomColorRGB() {
var hex = Math.floor(Math.random() * 16777215).toString(16);
//var r = parseInt(hex.substring(0, 2), 16);
var r = 155;
var g = 155;
var b = 255;
//var g = parseInt(hex.substring(2, 4), 16);
//var b = parseInt(hex.substring(4, 6), 16);
return ({
r: r,
g: g,
b: b
});
}
// draw the image to the canvas and get its pixel array
// listen for mouse clicks and do floodfill when clicked
function start() {
context.drawImage(img, 0, 0);
strokeData = context.getImageData(0, 0, canvasWidth, canvasHeight);
context.clearRect(0, 0, context.canvas.width, context.canvas.height);
fillData = context.getImageData(0, 0, canvasWidth, canvasHeight);
context.drawImage(img, 0, 0);
$('#canvas').mousedown(function (e) {
// Mouse down location
var mouseX = parseInt(e.clientX - offsetX);
var mouseY = parseInt(e.clientY - offsetY);
// set a new random fillColor
fillColor = randomColorRGB();
// floodfill
paintAt(mouseX, mouseY);
});
谢谢。
答案 0 :(得分:0)
匹配笔划功能:
function matchstrokeColor(r, g, b, a) {
// never recolor the initial black divider strokes
// must check for near black because of anti-aliasing
return (r + g + b < 100 && a === 155);
}
只检查rgb
是否是一个小数字并且是一个画笔描边,因为你直接在画布上绘制图像,rgb现在应该成为其他东西,而alpha现在是255
(或如果您的图片有alpha),则无法预测。
尝试将其更改为能够识别storke颜色的内容,例如sqrt distance:
// A small threshold would make it fill closer to stroke.
var strokeThreshold = 1;
function matchstrokeColor(r, g, b, a) {
// Use sqrt difference to decide its storke or not.
var diffr = r - strokeColor.r;
var diffg = g - strokeColor.g;
var diffb= b - strokeColor.b;
var diff = Math.sqrt(diffr * diffr + diffg * diffg + diffb * diffb) / 3;
return (diff < strokeThreshold);
}