freaky
freaky

Reputation: 1010

jquery average image color

I try to get the average color of an image thanks to a canvas.

I want to calculate the average rgb color for each background-image of the same divs classname.

But I have an error :TypeError on line drawImage

I think it's due to my each loop and the way I get my source image url maybe. It seems that my canvas won't to be drawn.

$('.element').each( function(){
    var img = $(this).find('.element-imgT').css('background-image');
    img = img.replace('url(','').replace(')','').replace('"','');
    var rgb = getAverageRGB(img);
})

function getAverageRGB(imgEl) {
    var blockSize = 5,
        defaultRGB = {r:255,g:255,b:255},
        canvas = document.createElement('canvas'),
        context = canvas.getContext && canvas.getContext('2d'),
        data, width, height,
        i = -4,
        length,
        rgb = {r:0,g:0,b:0},
        count = 0;  
    if (!context) {
        return defaultRGB;
    }
    height = canvas.height = imgEl.naturalHeight || imgEl.offsetHeight || imgEl.height;
    width = canvas.width = imgEl.naturalWidth || imgEl.offsetWidth || imgEl.width;
    context.drawImage(imgEl, 0, 0);
    try {
        data = context.getImageData(0, 0, width, height);
    } catch(e) {
        console.log('alert')
        return defaultRGB;
    } 
    length = data.data.length;
    while ( (i += blockSize * 4) < length ) {
        ++count;
        rgb.r += data.data[i];
        rgb.g += data.data[i+1];
        rgb.b += data.data[i+2];
    }
    rgb.r = ~~(rgb.r/count);
    rgb.g = ~~(rgb.g/count);
    rgb.b = ~~(rgb.b/count);
    return rgb;  
}

and the fiddle: http://jsfiddle.net/dsPmR/3/

I don't know what is the way to solve this problem...

EDIT:

NEW WORKING FIDDLE : http://jsfiddle.net/dsPmR/5/ (answer by Fabrício Matté )

Upvotes: 1

Views: 2103

Answers (1)

Fabr&#237;cio Matt&#233;
Fabr&#237;cio Matt&#233;

Reputation: 70169

The issue was that a string was being passed to getAverageRGB which expects HTMLImageElement.

You can create an image element, wait for it to load (so that getAverageRGB can properly read the image data) then pass it to the function.

$('.element').each( function(){
    var bgImg = $(this).find('.element-imgT').css('background-image');
    var url = bgImg.replace(/^url\(["']?|["']?\)$/g, '');

    // Setting load handler before the src property as an extra caution
    // against cached resources
    $('<img>').load(function() {
        var rgb = getAverageRGB(this);
        console.log(rgb);
    }).prop('src', url);
});

Note: this method may not work for images from different domains. The good old same-origin policy will block the getImageData from reading image data from canvases that contain resources which do not satisfy the same origin policy rules.

Upvotes: 1

Related Questions