1- import {
2- argbFromRgb ,
3- QuantizerCelebi ,
4- Score ,
5- } from "@material/material-color-utilities" ;
1+ import { argbFromRgb } from "@material/material-color-utilities" ;
2+ import quantize from "@lokesh.dhakar/quantize" ;
63
74export function findDominantColorsFromPixelData (
85 pixelData : Uint8ClampedArray | Uint8Array ,
96 amount : number = 3 ,
107) : number [ ] {
11- const pixels : number [ ] = [ ] ;
8+ const pixels : number [ ] [ ] = [ ] ;
129 for ( let i = 0 ; i < pixelData . length ; i += 4 ) {
1310 const r = pixelData [ i ] ! ;
1411 const g = pixelData [ i + 1 ] ! ;
@@ -17,13 +14,26 @@ export function findDominantColorsFromPixelData(
1714 if ( a < 255 ) {
1815 continue ;
1916 }
20- const argb = argbFromRgb ( r , g , b ) ;
21- pixels . push ( argb ) ;
17+ pixels . push ( [ r , g , b ] ) ;
2218 }
2319
24- const result = QuantizerCelebi . quantize ( pixels , 128 ) ;
25- const ranked = Score . score ( result ) ;
26- return ranked . slice ( 0 , amount ) ;
20+ // Replace Material quantize because of inconsistency: https://github.com/material-foundation/material-color-utilities/issues/132
21+ // const result = QuantizerCelebi.quantize(pixels, 128);
22+ // const ranked = Score.score(result);
23+
24+ try {
25+ const cmap = quantize ( pixels , amount ) ;
26+
27+ if ( ! cmap ) {
28+ return [ ] ;
29+ }
30+
31+ const palette = cmap . palette ( ) ;
32+ return palette . map ( ( [ r , g , b ] ) => argbFromRgb ( r , g , b ) ) . slice ( 0 , amount ) ;
33+ } catch ( err ) {
34+ console . error ( err ) ;
35+ return [ ] ;
36+ }
2737}
2838
2939// Original function: https://github.com/material-foundation/material-color-utilities/blob/be615fc90286787bbe0c04ef58a6987e0e8fdc29/typescript/utils/image_utils.ts#L29
@@ -33,10 +43,14 @@ export async function sourceColorFromImage(
3343 amount : number = 3 ,
3444 grid ?: Array < 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 > ,
3545) {
46+ const isPartialImage = grid && grid . length > 0 && grid . length < 9 ;
47+
3648 // Convert Image data to Pixel Array
3749 const imageBytes = await new Promise < Uint8ClampedArray > ( ( resolve , reject ) => {
3850 const canvas = document . createElement ( "canvas" ) ;
39- const context = canvas . getContext ( "2d" ) ;
51+ const context = canvas . getContext ( "2d" , {
52+ willReadFrequently : isPartialImage ,
53+ } ) ;
4054 if ( ! context ) {
4155 reject ( new Error ( "Could not get canvas context" ) ) ;
4256 return ;
@@ -46,7 +60,7 @@ export async function sourceColorFromImage(
4660 canvas . height = image . height ;
4761 context . drawImage ( image , 0 , 0 ) ;
4862
49- if ( grid ) {
63+ if ( isPartialImage ) {
5064 const cellWidth = image . width / 3 ;
5165 const cellHeight = image . height / 3 ;
5266
0 commit comments