简体   繁体   English

画布填充填充笔触颜色

[英]Canvas flood fill stroke color

I'm building a small application using canvas. 我正在使用画布构建一个小型应用程序。 My application will have an option to fill a black and white image. 我的应用程序将具有填充黑白图像的选项。

I downloaded a code and is working fine, but It only works when the image stroke is black. 我下载了代码并且运行正常,但是仅在图像笔触为黑色时才有效。 All images that I am going to use have grey stroke. 我要使用的所有图像都有灰色笔触。

So, I would like to know what do I need to change to put the code working with grey strokes, instead of black strokes. 因此,我想知道需要进行哪些更改才能使代码使用灰色笔触而不是黑色笔触。

Here the code: 这里的代码:

https://jsfiddle.net/mx0fmdh3/ https://jsfiddle.net/mx0fmdh3/

HTML: HTML:

<canvas id="canvas" width=250 height=243></canvas>

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

Thank you. 谢谢。

The match stroke function: 比赛行程功能:

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

is only check whether rgb is a small number and is a painted stroke, as you directly paint your image on that canvas, rgb should now become something else, and alpha is now 255 (or unpredictable if your image has alpha). 仅检查rgb是否是一个小笔画,以及是否将其绘制为笔划,因为您直接在画布上绘制图像时,rgb现在应该变成其他东西,并且alpha现在为255 (如果图像具有alpha,则是不可预测的)。

Try change it to something that is aware of the storke's color, like sqrt distance: 尝试将其更改为可以识别storke颜色的东西,例如sqrt距离:

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

See Example jsfiddle 参见示例jsfiddle

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM