我正在创建一个绘图应用。我已经成功地做了一切。当我用深色绘制图像时,边缘会出现一些白色像素。我试图改变r + g + b的值以及alpha但没有用。谁能帮我吗?您可以从here查看实际网站。任何会帮助我的人,我都会给予他/她50美元的赏金。谢谢。这是我的代码。
<script type="text/javascript">
var initial = screen.width - 50;
if (initial < 1000) {
initial = 1000;
}
var firsttime = null;
var colorYellow = {
r: 255,
g: 207,
b: 51
};
var context;
var canvasWidth = initial;
var canvasHeight = initial;
var myColor = colorYellow;
var curColor = myColor;
var outlineImage = new Image();
var backgroundImage = new Image();
var drawingAreaX = 0;
var drawingAreaY = 0;
var drawingAreaWidth = initial;
var drawingAreaHeight = initial;
var colorLayerData;
var outlineLayerData;
var totalLoadResources = 2;
var curLoadResNum = 0;
var undoarr = new Array();
var redoarr = new Array();
function history(command) { // handles undo/redo button events.
var data;
if (command === "redo") {
data = historyManager.redo(); // get data for redo
} else
if (command === "undo") {
data = historyManager.undo(); // get data for undo
}
if (data !== undefined) { // if data has been found
setColorLayer(data); // set the data
}
}
// sets colour layer and creates copy into colorLayerData
function setColorLayer(data) {
context.putImageData(data, 0, 0);
colorLayerData = context.getImageData(0, 0, canvasWidth, canvasHeight);
context.drawImage(backgroundImage, 0, 0, canvasWidth, canvasHeight);
context.drawImage(outlineImage, 0, 0, drawingAreaWidth, drawingAreaHeight);
}
// Clears the canvas.
function clearCanvas() {
context.clearRect(0, 0, context.canvas.width, context.canvas.height);
}
// Draw the elements on the canvas
function redraw() {
uc = 0;
rc = 0;
var locX,
locY;
// Make sure required resources are loaded before redrawing
if (curLoadResNum < totalLoadResources) {
return; // To check if images are loaded successfully or not.
}
clearCanvas();
// Draw the current state of the color layer to the canvas
context.putImageData(colorLayerData, 0, 0);
historyManager.push(context.getImageData(0, 0, canvasWidth, canvasHeight));
redoarr = new Array();
// Draw the background
context.drawImage(backgroundImage, 0, 0, canvasWidth, canvasHeight);
// Draw the outline image on top of everything. We could move this to a separate
// canvas so we did not have to redraw this everyime.
context.drawImage(outlineImage, 0, 0, drawingAreaWidth, drawingAreaHeight);
};
function matchOutlineColor(r, g, b, a) {
return (r + g + b < 50 && a >= 50);
};
function matchStartColor(pixelPos, startR, startG, startB) {
var r = outlineLayerData.data[pixelPos],
g = outlineLayerData.data[pixelPos + 1],
b = outlineLayerData.data[pixelPos + 2],
a = outlineLayerData.data[pixelPos + 3];
// If current pixel of the outline image is black
if (matchOutlineColor(r, g, b, a)) {
return false;
}
r = colorLayerData.data[pixelPos];
g = colorLayerData.data[pixelPos + 1];
b = colorLayerData.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 === curColor.r && g === curColor.g && b === curColor.b) {
return false;
}
return true;
};
function colorPixel(pixelPos, r, g, b, a) {
colorLayerData.data[pixelPos] = r;
colorLayerData.data[pixelPos + 1] = g;
colorLayerData.data[pixelPos + 2] = b;
colorLayerData.data[pixelPos + 3] = a !== undefined ? a : 255;
};
function floodFill(startX, startY, startR, startG, startB) {
document.getElementById('color-lib-1').style.display = "none";
document.getElementById('color-lib-2').style.display = "none";
document.getElementById('color-lib-3').style.display = "none";
document.getElementById('color-lib-4').style.display = "none";
document.getElementById('color-lib-5').style.display = "none";
change = false;
var newPos,
x,
y,
pixelPos,
reachLeft,
reachRight,
drawingBoundLeft = drawingAreaX,
drawingBoundTop = drawingAreaY,
drawingBoundRight = drawingAreaX + drawingAreaWidth - 1,
drawingBoundBottom = drawingAreaY + drawingAreaHeight - 1,
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 >= drawingBoundTop && matchStartColor(pixelPos, startR, startG, startB)) {
y -= 1;
pixelPos -= canvasWidth * 4;
}
pixelPos += canvasWidth * 4;
y += 1;
reachLeft = false;
reachRight = false;
// Go down as long as the color matches and in inside the canvas
while (y <= drawingBoundBottom && matchStartColor(pixelPos, startR, startG, startB)) {
y += 1;
colorPixel(pixelPos, curColor.r, curColor.g, curColor.b);
if (x > drawingBoundLeft) {
if (matchStartColor(pixelPos - 4, startR, startG, startB)) {
if (!reachLeft) {
// Add pixel to stack
pixelStack.push([x - 1, y]);
reachLeft = true;
}
} else if (reachLeft) {
reachLeft = false;
}
}
if (x < drawingBoundRight) {
if (matchStartColor(pixelPos + 4, startR, startG, startB)) {
if (!reachRight) {
// Add pixel to stack
pixelStack.push([x + 1, y]);
reachRight = true;
}
} else if (reachRight) {
reachRight = false;
}
}
pixelPos += canvasWidth * 4;
}
}
};
// Start painting with paint bucket tool starting from pixel specified by startX and startY
function paintAt(startX, startY) {
var pixelPos = (startY * canvasWidth + startX) * 4,
r = colorLayerData.data[pixelPos],
g = colorLayerData.data[pixelPos + 1],
b = colorLayerData.data[pixelPos + 2],
a = colorLayerData.data[pixelPos + 3];
if (r === curColor.r && g === curColor.g && b === curColor.b) {
// Return because trying to fill with the same color
return;
}
if (matchOutlineColor(r, g, b, a)) {
// Return because clicked outline
return;
}
floodFill(startX, startY, r, g, b);
redraw();
};
// Add mouse event listeners to the canvas
function createMouseEvents() {
$('#canvas').mousedown(function(e) {
// Mouse down location
var mouseX = e.pageX - this.offsetLeft,
mouseY = e.pageY - this.offsetTop;
// assuming that the mouseX and mouseY are the mouse coords.
if (this.style.width) { // make sure there is a width in the style
// (assumes if width is there then height will be too
var w = Number(this.style.width.replace("px", "")); // warning this will not work if size is not in pixels
var h = Number(this.style.height.replace("px", "")); // convert the height to a number
var pixelW = this.width; // get the canvas resolution
var pixelH = this.height;
mouseX = Math.floor((mouseX / w) * pixelW); // convert the mouse coords to pixel coords
mouseY = Math.floor((mouseY / h) * pixelH);
}
if ((mouseY > drawingAreaY && mouseY < drawingAreaY + drawingAreaHeight) && (mouseX <= drawingAreaX + drawingAreaWidth)) {
paintAt(mouseX, mouseY);
}
});
};
resourceLoaded = function() {
curLoadResNum += 1;
//if (curLoadResNum === totalLoadResources) {
createMouseEvents();
redraw();
//}
};
var historyManager = (function() { // Anon for private (closure) scope
var uBuffer = []; // this is undo buff
var rBuffer = []; // this is redo buff
var currentState = undefined; // this holds the current history state
var undoElement = undefined;
var redoElement = undefined;
var manager = {
UI: { // UI interface just for disable and enabling redo undo buttons
assignUndoButton: function(element) {
undoElement = element;
this.update();
},
assignRedoButton: function(element) {
redoElement = element;
this.update();
},
update: function() {
if (redoElement !== undefined) {
redoElement.disabled = (rBuffer.length === 0);
}
if (undoElement !== undefined) {
undoElement.disabled = (uBuffer.length === 0);
}
}
},
reset: function() {
uBuffer.length = 0;
rBuffer.length = 0;
currentState = undefined;
this.UI.update();
},
push: function(data) {
if (currentState !== undefined) {
var same = true
for (i = 0; i < data.data.length; i++) {
if (data.data[i] !== currentState.data[i]) {
same = false;
break;
}
}
if (same) {
return;
}
}
if (currentState !== undefined) {
uBuffer.push(currentState);
}
currentState = data;
rBuffer.length = 0;
this.UI.update();
},
undo: function() {
if (uBuffer.length > 0) {
if (currentState !== undefined) {
rBuffer.push(currentState);
}
currentState = uBuffer.pop();
}
this.UI.update();
return currentState; // return data or unfefined
},
redo: function() {
if (rBuffer.length > 0) {
if (currentState !== undefined) {
uBuffer.push(currentState);
}
currentState = rBuffer.pop();
}
this.UI.update();
return currentState;
},
}
return manager;
})();
function start() {
var canvas = document.createElement('canvas');
canvas.setAttribute('width', canvasWidth);
canvas.setAttribute('height', canvasHeight);
canvas.setAttribute('id', 'canvas');
document.getElementById('canvasDiv').appendChild(canvas);
if (typeof G_vmlCanvasManager !== "undefined") {
canvas = G_vmlCanvasManager.initElement(canvas);
}
context = canvas.getContext("2d");
backgroundImage.onload = resourceLoaded();
backgroundImage.src = "images/t.png";
outlineImage.onload = function() {
context.drawImage(outlineImage, drawingAreaX, drawingAreaY, drawingAreaWidth, drawingAreaHeight);
try {
outlineLayerData = context.getImageData(0, 0, canvasWidth, canvasHeight);
} catch (ex) {
window.alert("Application cannot be run locally. Please run on a server.");
return;
}
clearCanvas();
colorLayerData = context.getImageData(0, 0, canvasWidth, canvasHeight);
resourceLoaded();
};
outlineImage.src = "images/products/<?php echo $product['product_image']; ?>";
};
if (historyManager !== undefined) {
// only for visual feedback and not required for the history manager to function.
historyManager.UI.assignUndoButton(document.querySelector("#undo-button"));
historyManager.UI.assignRedoButton(document.querySelector("#redo-button"));
}
getColor = function() {
};
</script>
答案 0 :(得分:2)
是的,&#34;白色&#34;遗漏的斑点实际上并不是白色,因为白色和黑色之间会出现一个微小的渐变。试着在这些方面给它一些余地:
if ((r <= curColor.r + 10 && r >= curColor.r - 10) && (r >= curColor.g - 10 && r <= curColor.g + 10) && (b >= curColor.b - 10 && b <= curColor.b + 10)) {
return false;
}
您可以修改10因子,直到它看起来不错。只需调整它直到它没问题。 (可能是糟糕的代码,我刚刚醒来,但你应该得到图片:D)
您还可以在单独的缓冲区中预处理图像并减少颜色数量。这样就可以更容易地填充渐变的开头,从而减少或消除您所描述的不良影响。
答案 1 :(得分:2)
老实说,绘图程序的错误并不是因为绘制图像的错误。 “白色”像素实际上是浅灰色,是用于在图像中绘制线条的画笔工具的副作用。有两种方法:
从图像中删除所有淡灰色像素并使其变白。使用颜色选择工具和铅笔工具将解决这个问题。唯一的副作用是某些点的线条可能看起来有点生涩。
在涉及到什么颜色的时候给予一些宽容。所以,不要只是替换直白色,而是替换浅灰色。任何颜色#CCC(或rgb(204,204,204))都应该着色。
选项二的代码如下:
if(r >= 204 && g >= 204 && b >= 204 && r === g && g === b){
return true;
}
这只是检查像素是否为浅灰度颜色,如果是,则返回true。使用它代替轮廓颜色检查功能。
答案 2 :(得分:2)
我建议进行两项修改:
在水平和垂直方向上填充,直到强度梯度的符号从+到 - 或 - 翻转到+,让我们填充整个区域,包括黑色边框的“一半”。通过检查梯度,我们确保不要超越强度最小值,从而避免填充邻近区域。
看看以下演示:
// Get pixel intensity:
function getIntensity(data, i) {
return data[i] + data[i + 1] + data[i + 2];
}
// Set pixel color:
function setColor(data, i, r, g, b) {
data[i] &= r;
data[i + 1] &= g;
data[i + 2] &= b;
}
// Fill a horizontal line:
function fill(x, y, data, width, r, g, b) {
var i_start = y * (width << 2);
var i = i_start + (x << 2);
var i_end = i_start + (width << 2);
var i_intensity = getIntensity(data, i);
// Horizontal line to the right:
var prev_gradient = 0;
var prev_intensity = i_intensity;
for (var j = i; j < i_end; j += 4) {
var intensity = getIntensity(data, j);
gradient = intensity - prev_intensity;
prev_intensity = intensity;
if ((prev_gradient > 0 && gradient < 0) || (prev_gradient < 0 && gradient > 0)) break;
if (gradient != 0) prev_gradient = gradient;
setColor(data, j, 255, 0, 0);
}
// Horizontal line to the left:
prev_gradient = 0;
prev_intensity = i_intensity;
for (var j = i - 4; j > i_start; j -= 4) {
var intensity = getIntensity(data, j);
gradient = intensity - prev_intensity;
prev_intensity = intensity;
if ((prev_gradient > 0 && gradient < 0) || (prev_gradient < 0 && gradient > 0)) break;
if (gradient != 0) prev_gradient = gradient;
setColor(data, j, 255, 0, 0);
}
}
// Demo canvas:
var canvas = document.getElementById('canvas');
var context = canvas.getContext('2d');
// Fill horizontal line on click:
canvas.addEventListener('mousedown', event => {
var rect = canvas.getBoundingClientRect();
var x = event.clientX - rect.left | 0;
var y = event.clientY - rect.top | 0;
var imageData = context.getImageData(0, 0, canvas.width, canvas.height);
fill(x, y, imageData.data, imageData.width);
context.putImageData(imageData, 0, 0);
});
// Load a sample image:
var image = new Image();
image.addEventListener('load', event => {
context.drawImage(event.target, 0, 0, canvas.width, canvas.height);
});
image.src = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAsAAAACCAIAAAABwbG5AAAAA3NCSVQICAjb4U/gAAAAGXRFWHRTb2Z0d2FyZQBnbm9tZS1zY3JlZW5zaG907wO/PgAAACZJREFUCJlj+I8Kbt68mZeXd/PmTbgIw38MsG/fvoKCgqdPn0K4ACAfPGrloJp1AAAAAElFTkSuQmCC';
<canvas id="canvas"></canvas>
您只需跟踪一个颜色通道,而不是将getIntensity
函数的全部三个相加,即可提高性能。
此外,由于混合模式,您需要先处理“清除”已填充区域,然后再使用其他颜色填充它。
你可以。 G。将背景图像的单通道灰度图像数据阵列保留在内存中,并将其用作填充算法的源图像。
(可手动或自动)将所有灰度图像转换为具有二进制边界的1位轮廓并将其用作填充算法的源,将结果平滑地与灰度图像混合可能更具性能。
答案 3 :(得分:0)