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 creatingCanvas
using JS for that JavaScript need to be enabled. -
onMessage
will be used for response callback
Lets provide source as
html
which will haveCanvas
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
- Fork complete project here
- Project demo