react-extract-colors
Version:
A react component to extract dominant colors from an image
2 lines (1 loc) • 4.51 kB
JavaScript
import{useState as r,useEffect as o}from'react';function t(r,o,t,n){return new(t||(t=Promise))(((e,a)=>{function l(r){try{s(n.next(r))}catch(r){a(r)}}function i(r){try{s(n.throw(r))}catch(r){a(r)}}function s(r){var o;r.done?e(r.value):(o=r.value,o instanceof t?o:new t((r=>{r(o)}))).then(l,i)}s((n=n.apply(r,o||[])).next())}))}'function'==typeof SuppressedError&&SuppressedError;const n={maxColors:3,format:'rgba',maxSize:18,colorSimilarityThreshold:50,sortBy:'dominance'},useExtractColors=(u,d={})=>{const m=Object.assign(Object.assign({},n),d),[g,C]=r([]),[f,b]=r(null),[p,M]=r(null),[$,k]=r(null),[v,w]=r(!0),[x,y]=r(null);return o((()=>{let r=!0;return t(void 0,void 0,void 0,(function*(){try{if(r){const r=yield function(r,o){return t(this,void 0,void 0,(function*(){const{maxSize:t,colorSimilarityThreshold:n,sortBy:e}=o;return new Promise(((o,a)=>{const l=new Image;l.crossOrigin='Anonymous',l.onload=()=>{const r=document.createElement('canvas'),i=r.getContext('2d');if(!i)return void a(new Error('Failed to get canvas context'));const{width:u,height:d}=l,m=Math.min(1,t/Math.max(u,d));r.width=u*m,r.height=d*m,i.drawImage(l,0,0,r.width,r.height);const g=((r,o,t)=>{const n={},e={};for(let a=0;a<r.length;a+=4){const l=r[a],i=r[a+1],s=r[a+2],h=r[a+3];if(h>=125){const r=[l,i,s,h];let a=!1;for(const l in e){const i=e[l];if(c(r,i)<o){'dominance'===t&&n[l]++,a=!0;break}}if(!a){const o=`${l},${i},${s},${h}`;e[o]=r,n[o]=1}}}return n})(i.getImageData(0,0,r.width,r.height).data,n,e),C=Object.keys(g).map((r=>{const[o,t,n,e]=r.split(',').map(Number),a=s({r:o,g:t,b:n,a:e}),{s:l,v:i}=h(a);return{r:o,g:t,b:n,a:e,count:g[r],saturation:l*i}})).sort(((r,o)=>'dominance'===e?o.count-r.count:o.saturation-r.saturation));let f=null,b=null,p=null;C.length>0&&(f=C[0],b=(r=>{const{r:o,g:t,b:n,a:e}=r,a=Math.max(0,o-50),l=Math.max(0,t-50),i=Math.max(0,n-50);return{r:a,g:l,b:i,a:e,count:r.count}})(f),p=(r=>{const{r:o,g:t,b:n,a:e}=r,a=Math.min(255,o+30),l=Math.min(255,t+30),i=Math.min(255,n+30);return{r:a,g:l,b:i,a:e,count:r.count}})(f)),o({dominantColor:f,darkerColor:b,lighterColor:p,colors:C})},l.onerror=r=>{a(r)},l.src=r}))}))}(u,m),o=((r,o)=>{const{format:t,maxColors:n}=o;switch(t){case'hex':return{dominantColor:a(r.dominantColor),darkerColor:a(r.darkerColor),lighterColor:a(r.lighterColor),colors:r.colors.slice(0,n).map((r=>a(r)))};case'rgb':return{dominantColor:l(r.dominantColor),darkerColor:l(r.darkerColor),lighterColor:l(r.lighterColor),colors:r.colors.slice(0,n).map((r=>l(r)))};case'hsl':return{dominantColor:i(r.dominantColor),darkerColor:i(r.darkerColor),lighterColor:i(r.lighterColor),colors:r.colors.slice(0,n).map((r=>i(r)))};case'hsv':return{dominantColor:s(r.dominantColor),darkerColor:s(r.darkerColor),lighterColor:s(r.lighterColor),colors:r.colors.slice(0,n).map((r=>s(r)))};default:return{dominantColor:e(r.dominantColor),darkerColor:e(r.darkerColor),lighterColor:e(r.lighterColor),colors:r.colors.slice(0,n).map((r=>e(r)))}}})(r,m);b(o.dominantColor),M(o.darkerColor),k(o.lighterColor),C(o.colors)}}catch(o){r&&y(o)}finally{r&&w(!1)}})),()=>{r=!1}}),[u]),{dominantColor:f,darkerColor:p,lighterColor:$,loading:v,error:x,colors:g}};const e=r=>{if(!r)return'rgba(0,0,0,0)';const{r:o,g:t,b:n,a:e}=r;return`rgba(${o},${t},${n},${e})`},a=r=>{if(!r)return'#000000';const{r:o,g:t,b:n}=r;return`#${((1<<24)+(o<<16)+(t<<8)+n).toString(16).slice(1)}`},l=r=>{if(!r)return'rgb(0,0,0)';const{r:o,g:t,b:n}=r;return`rgb(${o},${t},${n})`},i=r=>{if(!r)return'hsl(0,0%,0%)';const o=r.r/255,t=r.g/255,n=r.b/255,e=Math.max(o,t,n),a=Math.min(o,t,n),l=e-a;let i=0,s=0;const c=(e+a)/2;if(0!==l){switch(s=c>.5?l/(2-e-a):l/(e+a),e){case o:i=(t-n)/l+(t<n?6:0);break;case t:i=(n-o)/l+2;break;case n:i=(o-t)/l+4}i/=6}return`hsl(${Math.round(360*i)}, ${Math.round(100*s)}%, ${Math.round(100*c)}%)`},s=r=>{if(!r)return'hsv(0,0%,0%)';const o=r.r/255,t=r.g/255,n=r.b/255,e=Math.max(o,t,n),a=Math.min(o,t,n),l=e-a;let i,s;const c=e;if(0===e)return s=0,i=0,`hsv(${i}, ${s}%, ${100*c}%)`;if(s=l/e,e===a)i=0;else{switch(e){case o:i=(t-n)/l+(t<n?6:0);break;case t:i=(n-o)/l+2;break;case n:i=(o-t)/l+4;break;default:i=0}i/=6}return`hsv(${Math.round(360*i)}, ${Math.round(100*s)}%, ${Math.round(100*c)}%)`},c=(r,o)=>{const[t,n,e]=r,[a,l,i]=o;return Math.sqrt(Math.pow(t-a,2)+Math.pow(n-l,2)+Math.pow(e-i,2))},h=r=>{const o=r.match(/hsv\((\d+),\s*(\d+)%?,\s*(\d+)%?\)/);if(!o)throw new Error('Invalid HSV string format');return{h:parseInt(o[1],10)/360,s:parseInt(o[2],10)/100,v:parseInt(o[3],10)/100}};export{useExtractColors};