Get color palettes out of image

How to get image color palettes out of image provided.

October 15, 2017 - 5 minute read -
tutorial code react-native

What we have

Lets see what options we have when we want to get color palettes out of images and platform is React-Native.

  • We can use native 3rd party libraries out there in community.
  • We can build our own.

When we say build our own then lets see do we have any easy way out as far as React-Native is concern. I can see that we can do something with Canvas and now there is a new doubt that “how to use Canvas in React-Native”? And seems React-Native have solution for this also which is React-Native WebView component. Let see how we can use this.

React-Native WebView

First create a WebView

<WebView
	source=
	javaScriptEnabled={true}
	onMessage={imageResponseCallback}
/>
  • In source we will provide canvas html

  • JavaScriptEnabled: true as we will be creating Canvas using JS for that JavaScript need to be enabled.

  • onMessage will be used for response callback

Lets provide source as html which will have Canvas

let canvasHtml = `
      <!DOCTYPE html>
      <html>
      <script>
      const interval = setInterval(() => {
        const img = document.getElementById('__colorPickerCanvasImage');
        if (img.src.length != 0) {
          getColorPalettes();
          clearInterval(interval);
        }
      }, 10);   
  
      </script>
      <body>
        <img src='data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAJ4AAACeCAMAAAD0W0NJAAABKVBMVEX///8AAACP2PZisN9isN9RhMEYUpcybrY6bKYYUpdRhMEybrZGotlRhMEYU5disN9GotkYU5c6bKaP2PYYU5cYU5eP2PaP2PaP2PaP2PaP2PaP2PY6bKYYU5eP2PY6bKYYUpcYUpeP2PYYUpeP2PaP2PYYUpc6bKYYU5c6bKY6bKYYUpcYU5c6bKaP2PYYUpcYU5eP2PY6bKY6bKYYUpcYUpcYUpc6bKZbrd46bKY3aqVJf75isN86bKYYUpchWZtisN8YU5dRp9sYUpdRhMFRhMEYUpc6dLkaVJhZrN1FfL1gr98lXJ1drd5RhMEeV5otYqA+dropX58ybrY4aqU6bKZGotk0b7dRp9s6dLkYU5dLgL9DerxIo9k0Z6OP2PZisN8YUpdYq93h0Z0aAAAASHRSTlMAAIBAgIC/QL9AQICAv7+/QBBAv8+fQDDvYJ/fMGAQ7+8wUM8gr2AQr5+AUDCPcIDvz89wEJ9w30Cvv4BgII9AMHCA32AwIEDHFgI6AAADCElEQVR4XuzAgQAAAADDoPtT32AEtQAAcPbq4ARiEArC8K4tCE+fggdJroF0sJ1M/13sOcf31IGAfwHDd5vvo0N6mJjK8dwf4aVSMb1c+hSeRCyq6jCvnVjYncZ4KWNt6uRxdID6eCQdoF5ey2AkTt4JSrW5eB2kgotXwao5eAJawcEroFUdvAxeycwTELvMvAvEipkXQCyaeQXEbjMvgtkc3uZt3uZpYGb/XGqv4W3e5v3+zM6xCYVQEABBQUNBy/mBkZmI6XLJg8/1X4SZlwmCwk4F03/uN18e96b/54KLsBeYe4G5F5h7gbkXmHuJuZeYe4m5l5h7ibmXmHuJubdh7h1N2audsVc7Y692xl7tjL3aGXu1E/f2xru9ZXjTOt573DvZsUMCAAAQiIEgUB/pLf0zUQCBQO4STI9LQN6KvK4X1skwO8cmEAJAFAUvOxAs6xA2ED4vENH+67hwUxXRNxXM6d4432LlkJd6wdwL5l4w94K5F8y9YO4Fc2/H3CvMvcLcK8y9wtwrzL3C3CvMvW1R9npn7PXO2Oudsdc7Y693z/V+w1nT97o/O3avgjAQBAFYm3B16kAuBBJMCIH4h4I2glgEIqKNhTDv/xLWInK3u8eaIvMEHwcHMztdCcLwJt7Ea4x39pE4ZJ55+OY+QBw6T0GnwRswZl6PMfN6jJnX40+8haYuIvMqik6ft1TUYU3mJYo6bOiVIHXobgiXjM5z/I0rwuXEaCyxmg4tp1AZLZ1dcXixkg4tr47udHQ5sy2XWw2dzbhlPkkFuufvfPAK3tb45XtRdG5eIZlCSfelu4R8PFvLllrZ8HTw0kVn8ZCMDUcHD11eB9m5h6oj6+DS5cfs3Y4d4iAMwGAU5kkMSUnrqJ+Y2A0I1+D+ByEkkxOQkPBEn6357N8fzvDb9d39/HF5rHvs539/CS6HumZPyWvMvMbMa8y8xswrzLzCzCvMvMLMK8y8wswrzLwFMy/DzMtAzMtAzMtAzMtAzMtAzMtAzNsCMW9bEfOWle94/qZpmqYXVsy/bDxskC4AAAAASUVORK5CYII=' 
          id='__colorPickerCanvasImage' 
          onload='getColorPalettes()' />
      </body>
      </html>
    `;
};
  • So, basically we are planning to render base64 image inside Canvas.
  • Get color rgba values
  • Sending message with rgbaValues to callback handler

Now lets render image, for getting color palettes out of image we need to provide base64 value of image. You can use any online original image to base64 image. I will be using base64-image.de.

      function getColorPalettes() {  
        const imageElement = document.getElementById('__colorPickerCanvasImage');      
        const canvas = document.createElement('canvas');
        const canvasContext = canvas.getContext && canvas.getContext('2d');
  
        if (!canvasContext) return [0, 0, 0, 1];
        
        let imageWidth = canvas.width = imageElement.naturalWidth 
          || imageElement.offsetWidth 
          || imageElement.width;                
  
        const imageHeight = canvas.height = imageElement.naturalHeight 
          || imageElement.offsetHeight 
          || imageElement.height;                   
  
        canvasContext.drawImage(imageElement, 0, 0);
		
		....        

      }

Get Color Palettes out of image

      function getAllPalettes(width, height, context) {
        let distinctPalettes = []; 
		// loop through each and every pixels of image       
        for (let i=0; i<=height; i++) { 
          for (let j=0; j<=width; j++) { 
            try {
              data = context.getImageData(i, j, 1, 1);
              if (data.data.toString().trim() !== '0,0,0,0') {
                distinctPalettes.push(data.data);
              }
            } catch(e) {
              console.log(e);
            }
          }
        }  
        return distinctPalettes;
      }
  
	  // get dominant color palettes
      function getDominantPalettes(allPalettes, distinctCount, colorType) {
        const combinations = getPaletteOccurrences(allPalettes);
        let palettes = combinations[0];
        let occurrences = combinations[1];
        const dominantPalettes = [];
  
        while (distinctCount) {               
          let dominant = 0, dominantKey = 0;  
          occurrences.forEach((v, k) => {           
            if (v > dominant) {
              dominant = v;              
              dominantKey = k;                               
            }
          });
          dominantPalettes.push(palettes[dominantKey]);
            
          palettes.splice(dominantKey, 1);            
          occurrences.splice(dominantKey, 1);
          distinctCount--;
        }
        return dominantPalettes;
      }        
  
      // get palette occurrences
      function getPaletteOccurrences(palettes) {
        let paletteList = [], occurrenceList = [], previousPalette;
        palettes.sort();
        palettes.forEach((palette, key) => {
          if (palette.toString() !== previousPalette) {
            paletteList.push(palette);
            occurrenceList.push(1);
          } else {
            occurrenceList[occurrenceList.length-1]++;
          }
          previousPalette = palettes[key].toString();
        });
        return [paletteList, occurrenceList];
      }

In last we want to notify UI with retrieved color palettes. We will be using window.postMessage for sending data to callback method.

let palette = getDominantPalettes(getAllPalettes(imageWidth, imageHeight, canvasContext), 3, 'rgba');
window.postMessage(JSON.stringify({'message':'imageColorPicker','payload':palette}));

Complete project