|
/* Bucker mode will fill an area with a color */
|
|
define([], function() {
|
|
|
|
function initGui() {
|
|
PaintApp.elements.bucketButton = document.getElementById('bucket-button');
|
|
PaintApp.paletteModesButtons.push(PaintApp.elements.bucketButton);
|
|
PaintApp.elements.bucketButton.addEventListener('click', function() {
|
|
PaintApp.paletteRemoveActiveClass();
|
|
PaintApp.addActiveClassToElement(PaintApp.elements.bucketButton);
|
|
PaintApp.switchMode('Bucket');
|
|
});
|
|
}
|
|
|
|
//Floodfill functions
|
|
function floodfill(x, y, fillcolor, ctx, width, height, tolerance) {
|
|
var img = ctx.getImageData(0, 0, width, height);
|
|
var data = img.data;
|
|
var length = data.length;
|
|
var Q = [];
|
|
var i = (x + y * width) * 4;
|
|
var e = i,
|
|
w = i,
|
|
me, mw, w2 = width * 4;
|
|
var targetcolor = [
|
|
data[i],
|
|
data[i + 1],
|
|
data[i + 2],
|
|
data[i + 3]
|
|
];
|
|
var targettotal = data[i] + data[i + 1] + data[i + 2] + data[i + 3];
|
|
if (!pixelCompare(i, targetcolor, targettotal, fillcolor, data, length, tolerance)) {
|
|
return false;
|
|
}
|
|
Q.push(i);
|
|
while (Q.length) {
|
|
i = Q.pop();
|
|
if (pixelCompareAndSet(i, targetcolor, targettotal, fillcolor, data, length, tolerance)) {
|
|
e = i;
|
|
w = i;
|
|
mw = parseInt(i / w2) * w2;
|
|
me = mw + w2;
|
|
while (mw < (w -= 4) && pixelCompareAndSet(w, targetcolor, targettotal, fillcolor, data, length, tolerance));
|
|
while (me > (e += 4) && pixelCompareAndSet(e, targetcolor, targettotal, fillcolor, data, length, tolerance));
|
|
for (var j = w; j < e; j += 4) {
|
|
if (j - w2 >= 0 && pixelCompare(j - w2, targetcolor, targettotal, fillcolor, data, length, tolerance))
|
|
Q.push(j - w2);
|
|
if (j + w2 < length && pixelCompare(j + w2, targetcolor, targettotal, fillcolor, data, length, tolerance))
|
|
Q.push(j + w2);
|
|
}
|
|
}
|
|
}
|
|
ctx.putImageData(img, 0, 0);
|
|
}
|
|
|
|
//Floodfill functions
|
|
function pixelCompare(i, targetcolor, targettotal, fillcolor, data, length, tolerance) {
|
|
if (i < 0 || i >= length)
|
|
return false;
|
|
if (data[i + 3] === 0)
|
|
return true;
|
|
if (targetcolor[3] === fillcolor.a && targetcolor[0] === fillcolor.r && targetcolor[1] === fillcolor.g && targetcolor[2] === fillcolor.b)
|
|
return false;
|
|
if (targetcolor[3] === data[i + 3] && targetcolor[0] === data[i] && targetcolor[1] === data[i + 1] && targetcolor[2] === data[i + 2])
|
|
return true;
|
|
if (Math.abs(targetcolor[3] - data[i + 3]) <= 255 - tolerance && Math.abs(targetcolor[0] - data[i]) <= tolerance && Math.abs(targetcolor[1] - data[i + 1]) <= tolerance && Math.abs(targetcolor[2] - data[i + 2]) <= tolerance)
|
|
return true;
|
|
return false;
|
|
}
|
|
|
|
//Floodfill functions
|
|
function pixelCompareAndSet(i, targetcolor, targettotal, fillcolor, data, length, tolerance) {
|
|
if (pixelCompare(i, targetcolor, targettotal, fillcolor, data, length, tolerance)) {
|
|
data[i] = fillcolor.r;
|
|
data[i + 1] = fillcolor.g;
|
|
data[i + 2] = fillcolor.b;
|
|
data[i + 3] = 255;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
var Bucket = {
|
|
initGui: initGui,
|
|
lock: false,
|
|
onMouseDown: function(event) {
|
|
if (PaintApp.modes.Bucket.lock) {
|
|
return;
|
|
}
|
|
var ctx = PaintApp.elements.canvas.getContext('2d');
|
|
|
|
/* Transformation of the color used inside the palette to match with the bucket fill functions prototypes */
|
|
var colorFillStrings = PaintApp.data.color.fill.slice(4, -1).split(',');
|
|
var colorFill = [
|
|
parseInt(colorFillStrings[0]),
|
|
parseInt(colorFillStrings[1]),
|
|
parseInt(colorFillStrings[2]),
|
|
0
|
|
];
|
|
var colorHex = colorFill.map(function(x) {
|
|
x = parseInt(x).toString(16);
|
|
return x.length == 1 ? '0' + x : x;
|
|
});
|
|
var fillColor = {
|
|
a: 1,
|
|
r: parseInt(colorFill[0]),
|
|
g: parseInt(colorFill[1]),
|
|
b: parseInt(colorFill[2])
|
|
};
|
|
|
|
|
|
/* Getting the clicked point */
|
|
var p = ctx.getImageData(event.point.x * window.devicePixelRatio, event.point.y * window.devicePixelRatio, 1, 1).data;
|
|
|
|
/* If the color of the point is too close to the required color we stop the process */
|
|
/* We can't do a strict equality because browsers will auto change a few colors and we cannot prevent it... */
|
|
if (Math.abs(p[0] - fillColor.r) <= 10 && Math.abs(p[1] - fillColor.g) <= 10 && Math.abs(p[2] - fillColor.b) <= 10) {
|
|
PaintApp.modes.Bucket.lock = false;
|
|
return;
|
|
}
|
|
/* Proceed with the bucket fill */
|
|
floodfill(parseInt(event.point.x * window.devicePixelRatio), parseInt(event.point.y * window.devicePixelRatio), fillColor, ctx, ctx.canvas.width, ctx.canvas.height, 5);
|
|
|
|
|
|
PaintApp.saveCanvas();
|
|
PaintApp.modes.Bucket.lock = false;
|
|
|
|
/* If inside a shared activity, send the new image to everyone */
|
|
if (PaintApp.data.isShared) {
|
|
try {
|
|
PaintApp.collaboration.sendMessage({
|
|
action: 'toDataURL',
|
|
data: {
|
|
width: PaintApp.elements.canvas.width / window.devicePixelRatio,
|
|
height: PaintApp.elements.canvas.height / window.devicePixelRatio,
|
|
src: PaintApp.collaboration.compress(PaintApp.elements.canvas.toDataURL())
|
|
}
|
|
})
|
|
} catch (e) {}
|
|
}
|
|
},
|
|
onMouseDrag: function(event) {},
|
|
onMouseUp: function(event) {}
|
|
};
|
|
return Bucket;
|
|
});
|