lokesh / color-thief

Grab the color palette from an image using just Javascript. Works in the browser and in Node.
https://lokeshdhakar.com/projects/color-thief/
MIT License
12.62k stars 1.32k forks source link

Cleanup on error #45

Open Gitii opened 10 years ago

Gitii commented 10 years ago

Hi,

the current version of ColorThief does not remove the canvas if an error has been thrown. The current versions of firefox throw an error if the passed in image has not been fully initializied (drawImage), therefore the clean up (removeCanvas) logic is never executed, a simply try ... finally takes care of this.

I rewrote/extended the logic this way: added try..finally extracted drawImage into separate function, otherwise the constructor fails and cleanup logic is never executed because image is still null.

[...] var CanvasImage = function (image) { this.canvas = document.createElement('canvas'); this.context = this.canvas.getContext('2d'); this.image = image;

document.body.appendChild(this.canvas);

this.width  = this.canvas.width  = image.width;
this.height = this.canvas.height = image.height;

};

CanvasImage.prototype.draw = function () { this.context.drawImage(this.image, 0, 0, this.width, this.height); }; [...] ColorThief.prototype.getPalette = function(sourceImage, colorCount, quality) {

if (typeof colorCount === 'undefined') {
    colorCount = 10;
}
if (typeof quality === 'undefined') {
    quality = 10;
}

var image = null;
var palette = null;
try {
    // Create custom CanvasImage object
    image          = new CanvasImage(sourceImage);
    image.draw();

    var imageData  = image.getImageData();
    var pixels     = imageData.data;
    var pixelCount = image.getPixelCount();

    // Store the RGB values in an array format suitable for quantize function
    var pixelArray = [];
    for (var i = 0, offset, r, g, b, a; i < pixelCount; i = i + quality) {
        offset = i * 4;
        r = pixels[offset + 0];
        g = pixels[offset + 1];
        b = pixels[offset + 2];
        a = pixels[offset + 3];
        // If pixel is mostly opaque and not white
        if (a >= 125) {
            if (!(r > 250 && g > 250 && b > 250)) {
                pixelArray.push([r, g, b]);
            }
        }
    }

    // Send array to quantize function which clusters values
    // using median cut algorithm
    var cmap    = MMCQ.quantize(pixelArray, colorCount);
    palette     = cmap.palette();

} finally {
    // Clean up
    if (image != null) {
        image.removeCanvas();
    }
}
return palette;

}; [...]

grks commented 10 years ago

I have experienced that MMCQ.quantize(pixelArray, colorCount); can return false, leading to a "undefined is not a function" error on palette = cmap.palette();

So it would be a good thing to add this to ensure that the page gets cleaned.

tannerlinsley commented 9 years ago

+1. Trying to use for the first time, and this is happening. Let's get this put in the code!