Ramos da Informática

Como pegar as cores de uma imagem via Javascript?

Neste artigo, dois exemplos práticos de como pegar a cor predominante de uma imagem e aplicar em seu site ou aplicativo utilizando Javascript.

Exemplo JavaSctpt 1

O seguinte código monta um objeto contendo o histograma e recupera a cor mais comum usando um elemento canvas invisível:

//carrega uma imagem
var img = new Image();
img.src = ...

//cria um canvas invisível
var canvas = document.createElement('canvas');
canvas.width = img.width;
canvas.height = img.height;
var context = canvas.getContext('2d');

//desenha a imagem no canvas
context.drawImage(img, , );

//recupera vetor de cores
var map = context.getImageData(, , img.width, img.height).data;

//monta histograma
var hex, r,g,b; //,alpha;
var histograma = {};
for (var i = , len = map.length; i < len; i += 4) {

    //recupera componentes de um ponto
    r = arredonda(map[i]);
    g = arredonda(map[i+1]);
    b = arredonda(map[i+2]);
    //alpha = map[i+2]; //ignora canal alpha

    //valor em hexadecimal
    hex = rgbToHex(r, g, b);

    //adiciona no histograma ou incrementa se já existir
    if (histograma[hex] === undefined) {
        histograma[hex] = 1;
    } else {
        histograma[hex]++;
    }
}

//recupera cor mais comum
var corMaisComum = null;
var frequenciaCorMaisComum = ;
for (var cor in histograma) {
    if (frequenciaCorMaisComum < histograma[cor]) {
        corMaisComum = cor;
        frequenciaCorMaisComum = histograma[cor];
    }
}

console.log(corMaisComum);

O histograma nada mais é do que um tipo de mapa onde a chave é a cor em notação hexadecimal e o valor é a frequência com que a mesma ocorre na imagem.

Nesse algoritmo, usei a função arredonda ao recuperar a cor para arredondá-la para o múltiplo de 5 mais próximo. Dessa forma, pequenas variações na cor não irão atrapalhar o resultado final.

Note que com p histograma não somente podemos obter a cor mais comum, mas também as primeiras N cores mais comuns. Para isso teríamos apenas que criar um vetor com as cores ordenado pela frequência.

Evento gratuito de tecnologia: inscreva-se na 3ª edição do Dev Summit:

  1. Vem ai a 3ª edição do maior evento hands-on de desenvolvimento de software do Brasil. Vamos apresentar tecnologias, ferramentas e práticas em mais de 20 horas em sessões ao vivo com profissionais de referência em Full Stack, Flutter, Angular, React e muito mais.
  2.  



    O código anterior pode ser visto executanto no site jsdo.it, mas postarei o mesmo completo, caso se torne inacessível um dia:

    //"arredonda" o número para o múltiplo de 5 mais próximo
    //isso adiciona uma certa tolerância para os tons próximos
    function arredonda(v) {
        return 5 * (Math.round(v / 5));
    }
    
    function componentToHex(c) {
        var hex = c.toString(16);
        return hex.length == 1 ? "0" + hex : hex;
    }
    
    function rgbToHex(r, g, b) {
        return "#" + componentToHex(r) + componentToHex(g) + componentToHex(b);
    }
    
    //carrega uma imagem
    var img = new Image();
    img.src = 'http://jsrun.it/assets/8/O/3/U/8O3Ux.jpg';
    img.onload = function() {
    
        $(document.body).append(img);
    
        //cria um canvas invisível
        var canvas = document.createElement('canvas');
        canvas.width = img.width;
        canvas.height = img.height;
        var context = canvas.getContext('2d');
    
        //desenha a imagem no canvas
        context.drawImage(img, , );
    
        //recupera vetor de cores
        var map = context.getImageData(, , img.width, img.height).data;
    
        var hex, r,g,b; //,alpha;
        var histograma = {};
        for (var i = , len = map.length; i < len; i += 4) {
    
            //recupera componentes de um ponto
            r = arredonda(map[i]);
            g = arredonda(map[i+1]);
            b = arredonda(map[i+2]);
            //alpha = map[i+2]; //ignora canal alpha
    
            //valor em hexadecimal
            hex = rgbToHex(r, g, b);
    
            //adiciona no histograma ou incrementa se já existir
            if (histograma[hex] === undefined) {
                histograma[hex] = 1;
            } else {
                histograma[hex]++;
            }
        }
    
        //recupera cor mais comum
        var corMaisComum = null;
        var frequenciaCorMaisComum = ;
        for (var cor in histograma) {
            if (frequenciaCorMaisComum < histograma[cor]) {
                corMaisComum = cor;
                frequenciaCorMaisComum = histograma[cor];
            }
        }
    
        console.log(corMaisComum);
    
        //adiciona um div como exemplo
        $(document.body).append(
            $('<div>').css({
                'background-color': corMaisComum,
                'width': '200px',
                'height': '200px',
                'border': '1px solid #000'
            })
        );
    
    };

    O resultado visual fica como na imagem abaixo:

    Exemplo JavaScript 2

    Você pode utilizar da tecnologia Canvas que é contida nos navegadores que suportam HTML5(atualmente a maioria), e com ele você pode fazer uma função JavaScript que recebe como parâmetro sua imagem e verifica de 5 em 5 pixels qual a determinada cor, e verifica na imagem inteira, e então a cor predominante é setada via R,G,B(red,green,blue) no fundo de sua página.

    HTML Exemplar seria:

    <span> Background é setado para a cor predominante desta imagem: </span>
    <img id="i" src="data:image/jpeg;base64,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
    BhSLCA6lqWSpRuTC0Uho6Gto0j//2Q=="/>

    Obs: Converti sua imagem em  🙂

    E a função que faz a mágica seria esta:

        var rgb = getAverageRGB(document.getElementById('i'));
        document.body.style.backgroundColor = 'rgb('+rgb.r+','+rgb.g+','+rgb.b+')';
    
    function getAverageRGB(imgEl) {
    
        var blockSize = 5, //checa a cor à cada 5 pixels
            defaultRGB = {r:,g:,b:}, // para browsers com incompatibilidade
            canvas = document.createElement('canvas'),
            context = canvas.getContext && canvas.getContext('2d'),
            data, width, height,
            i = -4,
            length,
            rgb = {r:,g:,b:},
            count = ; //zera o contador
    
        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, , ); //desenha a imagem cria o canvas
    
        try {
            data = context.getImageData(, , width, height);
        } catch(e) {
            /* gera um erro de segurança, se a imagem for de dominio diferente */alert('x');
            return defaultRGB;//retorna  a cor padrão
        }
    
        length = data.data.length; //tamanho do array dos dados da imagem
    
        while ( (i += blockSize * 4) < length ) {
            ++count; //incrementa o contador previamente zerado
            rgb.r += data.data[i];
            rgb.g += data.data[i+1];
            rgb.b += data.data[i+2];
        }
    
        // ~~ usado para arrendondar valores para baixo
        rgb.r = ~~(rgb.r/count);
        rgb.g = ~~(rgb.g/count);
        rgb.b = ~~(rgb.b/count);
    
        return rgb;
    
    }

    Exemplo funcionando no JSFiddle com sua imagem.

     

Sair da versão mobile