帆布填充笔划颜色

时间:2015-10-30 19:44:45

标签: javascript canvas

我正在使用画布构建一个小应用程序。我的应用程序可以选择填充黑白图像。

我下载了一个代码并且工作正常,但它仅在图像描边为黑色时才有效。我要使用的所有图像都有灰色笔画。

所以,我想知道我需要更改什么才能使代码使用灰色笔划而不是黑色笔划。

这里是代码:

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);
    });

谢谢。

1 个答案:

答案 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);
}

请参阅Example jsfiddle