Lienzo: el relleno deja píxeles blancos en los bordes

Estoy creando una aplicación de dibujo. He logrado hacer todo. Cuando pinto la imagen con un color oscuro, aparecen algunos píxeles blancos en los bordes. Traté de cambiar el valor de r + g + b y también alfa pero no sirvió. ¿Puede alguien ayudarme? Puede consultar el sitio en vivo desdeaquí. Cualquiera que me ayude, le otorgaré 50 recompensas. Gracias. Este es mi codigo.

<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>

Respuestas a la pregunta(4)

Su respuesta a la pregunta