I am creating a drawing app. I have succeeded to do everything. When I paint the image with a dark color, some white pixels appear at the edges. I tried to change the value of r + g + b and also alpha but no use. Can any one help me out? You can check the live site from here. Anyone who will help me, I shall grant 50 bounty to him/her. Thanks. This is my code.
<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);
}