From 707e6663131d397d2997813f2f7f2dd816eee147 Mon Sep 17 00:00:00 2001 From: rtcoder Date: Wed, 20 May 2026 19:45:51 +0200 Subject: [PATCH 1/9] Add error handling and test configuration for dominant color detection --- README.md | 8 +++- dist/dominant-color.d.ts | 2 +- dist/dominant-color.js | 81 ++++++++++++++++++++++++--------- dist/dominant-color.js.map | 2 +- dist/interface.d.ts | 2 + jestconfig.json | 3 ++ package.json | 1 + src/dominant-color.ts | 92 +++++++++++++++++++++++++++++--------- src/interface.ts | 2 + tsconfig.json | 4 +- 10 files changed, 150 insertions(+), 47 deletions(-) diff --git a/README.md b/README.md index 1a567ce..e0d97b9 100644 --- a/README.md +++ b/README.md @@ -35,6 +35,9 @@ getDominantColor(img, { colorFormat: 'rgb', callback: (color, palette) => { // Your code here + }, + errorCallback: (error) => { + // Handle image loading or canvas errors here } }); ``` @@ -49,8 +52,9 @@ The `getDominantColor` function accepts the following configuration options: | `skipPixels` | number | 0 | Skips every `n` pixels while determining the dominant color. Recommended for large images. | | `colorsPaletteLength` | number | 5 | Length of the returned color palette. | | `paletteWithCountOfOccurrences` | boolean | false | Determines whether to return colors with the number of occurrences. | -| `colorFormat` | string | `'rgb'` | Defines the format of the returned colors. Available values are `'rgb'`, `'hsl'`, and `'hex'`. | +| `colorFormat` | string | `'rgb'` | Defines the format of the returned dominant color and palette colors. Available values are `'rgb'`, `'hsl'`, and `'hex'`. | | `callback` | function | [empty function] | Callback function that receives the dominant color and the colors palette. | +| `errorCallback` | function | [empty function] | Callback function that receives image loading, canvas, and processing errors. | ## Interfaces @@ -71,9 +75,11 @@ interface DominantColorOptions { paletteWithCountOfOccurrences: boolean; colorFormat: ColorFormat; callback: DominantColorCallback; + errorCallback: DominantColorErrorCallback; } type DominantColorCallback = (dominant: string, colorsPalette: string[] | PrimaryColor[]) => void; +type DominantColorErrorCallback = (error: Error) => void; function getDominantColor(element: HTMLImageElement, options: Partial): void; ``` diff --git a/dist/dominant-color.d.ts b/dist/dominant-color.d.ts index 4222b12..221b611 100644 --- a/dist/dominant-color.d.ts +++ b/dist/dominant-color.d.ts @@ -1,2 +1,2 @@ import { DominantColorOptions } from './interface'; -export declare function getDominantColor(element: HTMLImageElement, options: Partial): void; +export declare function getDominantColor(element: HTMLImageElement, options?: Partial): void; diff --git a/dist/dominant-color.js b/dist/dominant-color.js index f3e227c..11744c7 100644 --- a/dist/dominant-color.js +++ b/dist/dominant-color.js @@ -1,9 +1,9 @@ function rgbToHex(rgb) { - const [_r, _g, _b] = rgb.match(/\d+/g).map((val) => (+val).toString(16).padStart(2, '0')); + const [_r, _g, _b] = getRgbValues(rgb).map((val) => val.toString(16).padStart(2, '0')); return `#${_r}${_g}${_b}`; } function rgbToHsl(rgb) { - const [_r, _g, _b] = rgb.match(/\d+/g).map(Number); + const [_r, _g, _b] = getRgbValues(rgb); const r = _r / 255; const g = _g / 255; const b = _b / 255; @@ -30,11 +30,12 @@ function rgbToHsl(rgb) { const s = delta === 0 ? 0 : delta / (1 - Math.abs(2 * l - 1)); return `hsl(${h},${(s * 100).toFixed(1)}%,${(l * 100).toFixed(1)}%)`; } -function isApproximateColor(color1, color2, threshold = 25) { - const [r1, g1, b1] = color1.split(',').map(Number); - const [r2, g2, b2] = color2.split(',').map(Number); - const distanceSquared = (r1 - r2) ** 2 + (g1 - g2) ** 2 + (b1 - b2) ** 2; - return distanceSquared < threshold ** 2; +function getRgbValues(rgb) { + const values = rgb.match(/\d+/g); + if (!values || values.length < 3) { + throw new Error(`Invalid RGB color: ${rgb}`); + } + return values.slice(0, 3).map(Number); } function detectColor(imageData, skip = 0) { const { data } = imageData; @@ -55,13 +56,13 @@ function detectColor(imageData, skip = 0) { return [{ color: primaryColor, count: maxCount }, colors]; } function getImageData(img, downScaleFactor = 1) { - if (downScaleFactor < 1) { - throw new Error('downScaleFactor must be equal to 1 or greater'); - } const canvas = document.createElement('canvas'); const context = canvas.getContext('2d'); - const scaledWidth = Math.floor(img.width / downScaleFactor); - const scaledHeight = Math.floor(img.height / downScaleFactor); + const scaledWidth = Math.max(1, Math.floor(img.width / downScaleFactor)); + const scaledHeight = Math.max(1, Math.floor(img.height / downScaleFactor)); + if (!context) { + throw new Error('Canvas 2D context is not available'); + } canvas.width = scaledWidth; canvas.height = scaledHeight; context.drawImage(img, 0, 0, scaledWidth, scaledHeight); @@ -76,6 +77,12 @@ function sortColors(colors, withOccurrences = false) { })) : sorted; } +function formatPalette(colorsPalette, format) { + if (!colorsPalette.length || typeof colorsPalette[0] === 'string') { + return colorsPalette.map((color) => getColorByFormat(color, format)); + } + return colorsPalette.map((item) => (Object.assign(Object.assign({}, item), { color: getColorByFormat(item.color, format) }))); +} function getColorByFormat(color, format) { switch (format) { case 'rgb': @@ -90,7 +97,18 @@ function getColorByFormat(color, format) { } return color; } -export function getDominantColor(element, options) { +function validateOptions(config) { + if (!Number.isFinite(config.downScaleFactor) || config.downScaleFactor < 1) { + throw new Error('downScaleFactor must be equal to 1 or greater'); + } + if (!Number.isInteger(config.skipPixels) || config.skipPixels < 0) { + throw new Error('skipPixels must be a non-negative integer'); + } + if (!Number.isInteger(config.colorsPaletteLength) || config.colorsPaletteLength < 0) { + throw new Error('colorsPaletteLength must be a non-negative integer'); + } +} +export function getDominantColor(element, options = {}) { const defaultOptions = { downScaleFactor: 1, skipPixels: 0, @@ -100,19 +118,40 @@ export function getDominantColor(element, options) { callback: () => { // callback }, + errorCallback: () => { + // error callback + }, }; const config = Object.assign(Object.assign({}, defaultOptions), options); + validateOptions(config); + const source = element.currentSrc || element.src; + if (!source) { + config.errorCallback(new Error('Image source is empty')); + return; + } const img = new Image(); img.crossOrigin = 'Anonymous'; img.onload = () => { - const imageData = getImageData(img, config.downScaleFactor); - const [primaryColor, colors] = detectColor(imageData, config.skipPixels); - const colorsPalette = config.colorsPaletteLength - ? sortColors(colors, config.paletteWithCountOfOccurrences).slice(0, config.colorsPaletteLength) - : []; - const dominant = getColorByFormat(primaryColor.color, config.colorFormat); - config.callback(dominant, colorsPalette); + try { + const imageData = getImageData(img, config.downScaleFactor); + const [primaryColor, colors] = detectColor(imageData, config.skipPixels); + const colorsPalette = config.colorsPaletteLength + ? sortColors(colors, config.paletteWithCountOfOccurrences).slice(0, config.colorsPaletteLength) + : []; + if (!primaryColor.color) { + config.callback('', []); + return; + } + const dominant = getColorByFormat(primaryColor.color, config.colorFormat); + config.callback(dominant, formatPalette(colorsPalette, config.colorFormat)); + } + catch (error) { + config.errorCallback(error instanceof Error ? error : new Error(String(error))); + } + }; + img.onerror = () => { + config.errorCallback(new Error(`Unable to load image: ${source}`)); }; - img.src = element.src; + img.src = source; } //# sourceMappingURL=dominant-color.js.map \ No newline at end of file diff --git a/dist/dominant-color.js.map b/dist/dominant-color.js.map index 9a326f9..c6a0a03 100644 --- a/dist/dominant-color.js.map +++ b/dist/dominant-color.js.map @@ -1 +1 @@ -{"version":3,"file":"dominant-color.js","sourceRoot":"","sources":["../src/dominant-color.ts"],"names":[],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"dominant-color.js","sourceRoot":"","sources":["../src/dominant-color.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/dist/interface.d.ts b/dist/interface.d.ts index 0ac0372..63abadb 100644 --- a/dist/interface.d.ts +++ b/dist/interface.d.ts @@ -13,5 +13,7 @@ export interface DominantColorOptions { paletteWithCountOfOccurrences: boolean; colorFormat: ColorFormat; callback: DominantColorCallback; + errorCallback: DominantColorErrorCallback; } export declare type DominantColorCallback = (dominant: string, colorsPalette: string[] | PrimaryColor[]) => void; +export declare type DominantColorErrorCallback = (error: Error) => void; diff --git a/jestconfig.json b/jestconfig.json index 420d1de..f326839 100644 --- a/jestconfig.json +++ b/jestconfig.json @@ -1,4 +1,7 @@ { + "roots": [ + "/src" + ], "transform": { "^.+\\.(t|j)sx?$": "ts-jest" }, diff --git a/package.json b/package.json index cc60ad4..af7c2a5 100644 --- a/package.json +++ b/package.json @@ -6,6 +6,7 @@ "types": "dist/dominant-color.d.ts", "scripts": { "build": "tsc", + "test": "jest --config jestconfig.json", "format": "prettier --write \"src/**/*.ts\"", "lint": "tslint -p tsconfig.json", "prepare": "npm run build", diff --git a/src/dominant-color.ts b/src/dominant-color.ts index 6cfde83..ca0822f 100644 --- a/src/dominant-color.ts +++ b/src/dominant-color.ts @@ -1,12 +1,12 @@ import { ColorFormat, Colors, DominantColorOptions, PrimaryColor } from './interface'; function rgbToHex(rgb: string): string { - const [_r, _g, _b] = rgb.match(/\d+/g)!.map((val) => (+val).toString(16).padStart(2, '0')); + const [_r, _g, _b] = getRgbValues(rgb).map((val) => val.toString(16).padStart(2, '0')); return `#${_r}${_g}${_b}`; } function rgbToHsl(rgb: string): string { - const [_r, _g, _b] = rgb.match(/\d+/g)!.map(Number); + const [_r, _g, _b] = getRgbValues(rgb); const r = _r / 255; const g = _g / 255; const b = _b / 255; @@ -36,11 +36,12 @@ function rgbToHsl(rgb: string): string { return `hsl(${h},${(s * 100).toFixed(1)}%,${(l * 100).toFixed(1)}%)`; } -function isApproximateColor(color1: string, color2: string, threshold = 25): boolean { - const [r1, g1, b1] = color1.split(',').map(Number); - const [r2, g2, b2] = color2.split(',').map(Number); - const distanceSquared = (r1 - r2) ** 2 + (g1 - g2) ** 2 + (b1 - b2) ** 2; - return distanceSquared < threshold ** 2; +function getRgbValues(rgb: string): number[] { + const values = rgb.match(/\d+/g); + if (!values || values.length < 3) { + throw new Error(`Invalid RGB color: ${rgb}`); + } + return values.slice(0, 3).map(Number); } function detectColor(imageData: ImageData, skip = 0): [PrimaryColor, Colors] { @@ -64,13 +65,14 @@ function detectColor(imageData: ImageData, skip = 0): [PrimaryColor, Colors] { } function getImageData(img: HTMLImageElement, downScaleFactor = 1): ImageData { - if (downScaleFactor < 1) { - throw new Error('downScaleFactor must be equal to 1 or greater'); - } const canvas = document.createElement('canvas') as HTMLCanvasElement; - const context = canvas.getContext('2d')!; - const scaledWidth = Math.floor(img.width / downScaleFactor); - const scaledHeight = Math.floor(img.height / downScaleFactor); + const context = canvas.getContext('2d'); + const scaledWidth = Math.max(1, Math.floor(img.width / downScaleFactor)); + const scaledHeight = Math.max(1, Math.floor(img.height / downScaleFactor)); + + if (!context) { + throw new Error('Canvas 2D context is not available'); + } canvas.width = scaledWidth; canvas.height = scaledHeight; @@ -88,6 +90,16 @@ function sortColors(colors: Colors, withOccurrences = false): string[] | Primary : sorted; } +function formatPalette(colorsPalette: string[] | PrimaryColor[], format: ColorFormat): string[] | PrimaryColor[] { + if (!colorsPalette.length || typeof colorsPalette[0] === 'string') { + return (colorsPalette as string[]).map((color) => getColorByFormat(color, format)); + } + return (colorsPalette as PrimaryColor[]).map((item) => ({ + ...item, + color: getColorByFormat(item.color, format), + })); +} + function getColorByFormat(color: string, format: ColorFormat): string { switch (format) { case 'rgb': @@ -102,7 +114,20 @@ function getColorByFormat(color: string, format: ColorFormat): string { } return color; } -export function getDominantColor(element: HTMLImageElement, options: Partial): void { + +function validateOptions(config: DominantColorOptions): void { + if (!Number.isFinite(config.downScaleFactor) || config.downScaleFactor < 1) { + throw new Error('downScaleFactor must be equal to 1 or greater'); + } + if (!Number.isInteger(config.skipPixels) || config.skipPixels < 0) { + throw new Error('skipPixels must be a non-negative integer'); + } + if (!Number.isInteger(config.colorsPaletteLength) || config.colorsPaletteLength < 0) { + throw new Error('colorsPaletteLength must be a non-negative integer'); + } +} + +export function getDominantColor(element: HTMLImageElement, options: Partial = {}): void { const defaultOptions: DominantColorOptions = { downScaleFactor: 1, skipPixels: 0, @@ -112,20 +137,43 @@ export function getDominantColor(element: HTMLImageElement, options: Partial { // callback }, + errorCallback: () => { + // error callback + }, }; const config: DominantColorOptions = { ...defaultOptions, ...options }; + validateOptions(config); + + const source = element.currentSrc || element.src; + if (!source) { + config.errorCallback(new Error('Image source is empty')); + return; + } const img = new Image(); img.crossOrigin = 'Anonymous'; img.onload = () => { - const imageData = getImageData(img, config.downScaleFactor); - const [primaryColor, colors] = detectColor(imageData, config.skipPixels); - const colorsPalette = config.colorsPaletteLength - ? sortColors(colors, config.paletteWithCountOfOccurrences).slice(0, config.colorsPaletteLength) - : []; - const dominant = getColorByFormat(primaryColor.color, config.colorFormat); - config.callback!(dominant, colorsPalette); + try { + const imageData = getImageData(img, config.downScaleFactor); + const [primaryColor, colors] = detectColor(imageData, config.skipPixels); + const colorsPalette = config.colorsPaletteLength + ? sortColors(colors, config.paletteWithCountOfOccurrences).slice(0, config.colorsPaletteLength) + : []; + + if (!primaryColor.color) { + config.callback('', []); + return; + } + + const dominant = getColorByFormat(primaryColor.color, config.colorFormat); + config.callback(dominant, formatPalette(colorsPalette, config.colorFormat)); + } catch (error) { + config.errorCallback(error instanceof Error ? error : new Error(String(error))); + } + }; + img.onerror = () => { + config.errorCallback(new Error(`Unable to load image: ${source}`)); }; - img.src = element.src; + img.src = source; } diff --git a/src/interface.ts b/src/interface.ts index fee254c..3cf7dc5 100644 --- a/src/interface.ts +++ b/src/interface.ts @@ -16,6 +16,8 @@ export interface DominantColorOptions { paletteWithCountOfOccurrences: boolean; colorFormat: ColorFormat; callback: DominantColorCallback; + errorCallback: DominantColorErrorCallback; } export type DominantColorCallback = (dominant: string, colorsPalette: string[] | PrimaryColor[]) => void; +export type DominantColorErrorCallback = (error: Error) => void; diff --git a/tsconfig.json b/tsconfig.json index be6bf61..73a0178 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -14,6 +14,8 @@ ], "exclude": [ "node_modules", - "**/__tests__/*" + "**/__tests__/*", + "**/*.spec.ts", + "**/*.test.ts" ] } From 62c7b04af33aa0f26fd3447cf024c3dd667789bd Mon Sep 17 00:00:00 2001 From: rtcoder Date: Wed, 20 May 2026 19:49:42 +0200 Subject: [PATCH 2/9] Add color grouping threshold to dominant color detection --- .gitignore | Bin 34 -> 15 bytes .idea/php.xml | 19 ++++ README.md | 3 + dist/dominant-color.js | 50 ++++++++++- dist/dominant-color.js.map | 2 +- dist/interface.d.ts | 1 + src/dominant-color.spec.ts | 177 +++++++++++++++++++++++++++++++++++++ src/dominant-color.ts | 67 +++++++++++++- src/interface.ts | 1 + 9 files changed, 313 insertions(+), 7 deletions(-) create mode 100644 .idea/php.xml create mode 100644 src/dominant-color.spec.ts diff --git a/.gitignore b/.gitignore index 63dc9c9c337ffa4aa6e1797029d06b2ffe10874c..2ccbe4656c6078ded72491cf2ee9c5ec20219624 100644 GIT binary patch literal 15 WcmdPT%TGy-&&^LM%}FiR=K=sNYz1ck literal 34 kcmezWPoE)=A)g_IA(bJXAs5UlWyk^YiW&47cp11D0H|aKaR2}S diff --git a/.idea/php.xml b/.idea/php.xml new file mode 100644 index 0000000..f324872 --- /dev/null +++ b/.idea/php.xml @@ -0,0 +1,19 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/README.md b/README.md index e0d97b9..028e394 100644 --- a/README.md +++ b/README.md @@ -31,6 +31,7 @@ getDominantColor(img, { downScaleFactor: 1, skipPixels: 0, colorsPaletteLength: 5, + colorGroupingThreshold: 0, paletteWithCountOfOccurrences: false, colorFormat: 'rgb', callback: (color, palette) => { @@ -51,6 +52,7 @@ The `getDominantColor` function accepts the following configuration options: | `downScaleFactor` | number | 1 | Factor of scale down for the image. Recommended for large images. | | `skipPixels` | number | 0 | Skips every `n` pixels while determining the dominant color. Recommended for large images. | | `colorsPaletteLength` | number | 5 | Length of the returned color palette. | +| `colorGroupingThreshold` | number | 0 | Groups similar RGB colors before sorting. Use `0` for exact pixel matching, or a larger value such as `10`-`30` for photos. | | `paletteWithCountOfOccurrences` | boolean | false | Determines whether to return colors with the number of occurrences. | | `colorFormat` | string | `'rgb'` | Defines the format of the returned dominant color and palette colors. Available values are `'rgb'`, `'hsl'`, and `'hex'`. | | `callback` | function | [empty function] | Callback function that receives the dominant color and the colors palette. | @@ -72,6 +74,7 @@ interface DominantColorOptions { downScaleFactor: number; skipPixels: number; colorsPaletteLength: number; + colorGroupingThreshold: number; paletteWithCountOfOccurrences: boolean; colorFormat: ColorFormat; callback: DominantColorCallback; diff --git a/dist/dominant-color.js b/dist/dominant-color.js index 11744c7..c0e463e 100644 --- a/dist/dominant-color.js +++ b/dist/dominant-color.js @@ -37,7 +37,38 @@ function getRgbValues(rgb) { } return values.slice(0, 3).map(Number); } -function detectColor(imageData, skip = 0) { +function toRgbKey(r, g, b) { + return `${Math.round(r)},${Math.round(g)},${Math.round(b)}`; +} +function getColorDistanceSquared(r1, g1, b1, r2, g2, b2) { + return (r1 - r2) ** 2 + (g1 - g2) ** 2 + (b1 - b2) ** 2; +} +function groupColors(colors, threshold) { + if (threshold === 0) { + return colors; + } + const groups = []; + const thresholdSquared = threshold ** 2; + Object.keys(colors).forEach((color) => { + const [r, g, b] = getRgbValues(color); + const group = groups.find((item) => getColorDistanceSquared(item.r, item.g, item.b, r, g, b) <= thresholdSquared); + if (!group) { + groups.push({ r, g, b, count: colors[color] }); + return; + } + const totalCount = group.count + colors[color]; + group.r = (group.r * group.count + r * colors[color]) / totalCount; + group.g = (group.g * group.count + g * colors[color]) / totalCount; + group.b = (group.b * group.count + b * colors[color]) / totalCount; + group.count = totalCount; + }); + return groups.reduce((groupedColors, group) => { + const color = toRgbKey(group.r, group.g, group.b); + groupedColors[color] = (groupedColors[color] || 0) + group.count; + return groupedColors; + }, {}); +} +function detectColor(imageData, skip = 0, colorGroupingThreshold = 0) { const { data } = imageData; const colors = {}; let primaryColor = ''; @@ -53,7 +84,16 @@ function detectColor(imageData, skip = 0) { maxCount = colors[rgb]; } } - return [{ color: primaryColor, count: maxCount }, colors]; + const groupedColors = groupColors(colors, colorGroupingThreshold); + primaryColor = ''; + maxCount = 0; + Object.keys(groupedColors).forEach((color) => { + if (groupedColors[color] > maxCount) { + primaryColor = color; + maxCount = groupedColors[color]; + } + }); + return [{ color: primaryColor, count: maxCount }, groupedColors]; } function getImageData(img, downScaleFactor = 1) { const canvas = document.createElement('canvas'); @@ -107,12 +147,16 @@ function validateOptions(config) { if (!Number.isInteger(config.colorsPaletteLength) || config.colorsPaletteLength < 0) { throw new Error('colorsPaletteLength must be a non-negative integer'); } + if (!Number.isFinite(config.colorGroupingThreshold) || config.colorGroupingThreshold < 0) { + throw new Error('colorGroupingThreshold must be a non-negative number'); + } } export function getDominantColor(element, options = {}) { const defaultOptions = { downScaleFactor: 1, skipPixels: 0, colorsPaletteLength: 5, + colorGroupingThreshold: 0, paletteWithCountOfOccurrences: false, colorFormat: 'rgb', callback: () => { @@ -134,7 +178,7 @@ export function getDominantColor(element, options = {}) { img.onload = () => { try { const imageData = getImageData(img, config.downScaleFactor); - const [primaryColor, colors] = detectColor(imageData, config.skipPixels); + const [primaryColor, colors] = detectColor(imageData, config.skipPixels, config.colorGroupingThreshold); const colorsPalette = config.colorsPaletteLength ? sortColors(colors, config.paletteWithCountOfOccurrences).slice(0, config.colorsPaletteLength) : []; diff --git a/dist/dominant-color.js.map b/dist/dominant-color.js.map index c6a0a03..b0ebe6d 100644 --- a/dist/dominant-color.js.map +++ b/dist/dominant-color.js.map @@ -1 +1 @@ -{"version":3,"file":"dominant-color.js","sourceRoot":"","sources":["../src/dominant-color.ts"],"names":[],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"dominant-color.js","sourceRoot":"","sources":["../src/dominant-color.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/dist/interface.d.ts b/dist/interface.d.ts index 63abadb..9989b1c 100644 --- a/dist/interface.d.ts +++ b/dist/interface.d.ts @@ -10,6 +10,7 @@ export interface DominantColorOptions { downScaleFactor: number; skipPixels: number; colorsPaletteLength: number; + colorGroupingThreshold: number; paletteWithCountOfOccurrences: boolean; colorFormat: ColorFormat; callback: DominantColorCallback; diff --git a/src/dominant-color.spec.ts b/src/dominant-color.spec.ts new file mode 100644 index 0000000..189bd2b --- /dev/null +++ b/src/dominant-color.spec.ts @@ -0,0 +1,177 @@ +import { getDominantColor } from './dominant-color'; + +let pixels: Uint8ClampedArray; +let shouldFailImageLoad = false; + +class MockImage { + public crossOrigin = ''; + public currentSrc = ''; + public height = 2; + public onerror: (() => void) | null = null; + public onload: (() => void) | null = null; + public width = 2; + private imageSrc = ''; + + public get src(): string { + return this.imageSrc; + } + + public set src(value: string) { + this.imageSrc = value; + if (shouldFailImageLoad) { + this.onerror?.(); + return; + } + this.onload?.(); + } +} + +function mockCanvas(): void { + const getImageData = jest.fn(() => ({ + data: pixels, + height: 2, + width: 2, + })); + const drawImage = jest.fn(); + const getContext = jest.fn(() => ({ + drawImage, + getImageData, + })); + + (global as any).document = { + createElement: jest.fn(() => ({ + getContext, + height: 0, + width: 0, + })), + }; +} + +beforeEach(() => { + shouldFailImageLoad = false; + pixels = new Uint8ClampedArray([ + 255, + 0, + 0, + 255, + 255, + 0, + 0, + 255, + 0, + 0, + 255, + 255, + 0, + 255, + 0, + 255, + ]); + mockCanvas(); + (global as any).Image = MockImage; +}); + +it('returns dominant color and palette in the requested format', () => { + const callback = jest.fn(); + + getDominantColor({ src: 'image.jpg' } as HTMLImageElement, { + callback, + colorFormat: 'hex', + colorsPaletteLength: 2, + }); + + expect(callback).toHaveBeenCalledWith('#ff0000', ['#ff0000', '#0000ff']); +}); + +it('uses default options when they are not provided', () => { + const callback = jest.fn(); + + getDominantColor({ src: 'image.jpg' } as HTMLImageElement, { + callback, + }); + + expect(callback).toHaveBeenCalledWith('rgb(255,0,0)', ['rgb(255,0,0)', 'rgb(0,0,255)', 'rgb(0,255,0)']); +}); + +it('formats colors with occurrence counts', () => { + const callback = jest.fn(); + + getDominantColor({ src: 'image.jpg' } as HTMLImageElement, { + callback, + colorFormat: 'rgb', + colorsPaletteLength: 2, + paletteWithCountOfOccurrences: true, + }); + + expect(callback).toHaveBeenCalledWith('rgb(255,0,0)', [ + { color: 'rgb(255,0,0)', count: 2 }, + { color: 'rgb(0,0,255)', count: 1 }, + ]); +}); + +it('groups similar colors when colorGroupingThreshold is provided', () => { + pixels = new Uint8ClampedArray([ + 255, + 0, + 0, + 255, + 250, + 5, + 0, + 255, + 0, + 0, + 255, + 255, + ]); + const callback = jest.fn(); + + getDominantColor({ src: 'image.jpg' } as HTMLImageElement, { + callback, + colorFormat: 'hex', + colorGroupingThreshold: 10, + colorsPaletteLength: 2, + }); + + expect(callback).toHaveBeenCalledWith('#fd0300', ['#fd0300', '#0000ff']); +}); + +it('returns an empty result when all pixels are transparent', () => { + pixels = new Uint8ClampedArray([255, 0, 0, 0, 0, 0, 255, 0]); + const callback = jest.fn(); + + getDominantColor({ src: 'image.jpg' } as HTMLImageElement, { + callback, + colorFormat: 'hex', + }); + + expect(callback).toHaveBeenCalledWith('', []); +}); + +it('throws for invalid skipPixels values before loading the image', () => { + expect(() => + getDominantColor({ src: 'image.jpg' } as HTMLImageElement, { + skipPixels: -1, + }), + ).toThrow('skipPixels must be a non-negative integer'); +}); + +it('throws for invalid colorGroupingThreshold values before loading the image', () => { + expect(() => + getDominantColor({ src: 'image.jpg' } as HTMLImageElement, { + colorGroupingThreshold: -1, + }), + ).toThrow('colorGroupingThreshold must be a non-negative number'); +}); + +it('reports image load errors through errorCallback', () => { + shouldFailImageLoad = true; + const errorCallback = jest.fn(); + + getDominantColor({ src: 'missing.jpg' } as HTMLImageElement, { + errorCallback, + }); + + expect(errorCallback).toHaveBeenCalledWith(expect.any(Error)); + expect(errorCallback.mock.calls[0][0].message).toContain('Unable to load image'); +}); diff --git a/src/dominant-color.ts b/src/dominant-color.ts index ca0822f..cb30b8b 100644 --- a/src/dominant-color.ts +++ b/src/dominant-color.ts @@ -1,5 +1,12 @@ import { ColorFormat, Colors, DominantColorOptions, PrimaryColor } from './interface'; +interface ColorGroup { + b: number; + count: number; + g: number; + r: number; +} + function rgbToHex(rgb: string): string { const [_r, _g, _b] = getRgbValues(rgb).map((val) => val.toString(16).padStart(2, '0')); return `#${_r}${_g}${_b}`; @@ -44,7 +51,46 @@ function getRgbValues(rgb: string): number[] { return values.slice(0, 3).map(Number); } -function detectColor(imageData: ImageData, skip = 0): [PrimaryColor, Colors] { +function toRgbKey(r: number, g: number, b: number): string { + return `${Math.round(r)},${Math.round(g)},${Math.round(b)}`; +} + +function getColorDistanceSquared(r1: number, g1: number, b1: number, r2: number, g2: number, b2: number): number { + return (r1 - r2) ** 2 + (g1 - g2) ** 2 + (b1 - b2) ** 2; +} + +function groupColors(colors: Colors, threshold: number): Colors { + if (threshold === 0) { + return colors; + } + + const groups: ColorGroup[] = []; + const thresholdSquared = threshold ** 2; + + Object.keys(colors).forEach((color) => { + const [r, g, b] = getRgbValues(color); + const group = groups.find((item) => getColorDistanceSquared(item.r, item.g, item.b, r, g, b) <= thresholdSquared); + + if (!group) { + groups.push({ r, g, b, count: colors[color] }); + return; + } + + const totalCount = group.count + colors[color]; + group.r = (group.r * group.count + r * colors[color]) / totalCount; + group.g = (group.g * group.count + g * colors[color]) / totalCount; + group.b = (group.b * group.count + b * colors[color]) / totalCount; + group.count = totalCount; + }); + + return groups.reduce((groupedColors, group) => { + const color = toRgbKey(group.r, group.g, group.b); + groupedColors[color] = (groupedColors[color] || 0) + group.count; + return groupedColors; + }, {} as Colors); +} + +function detectColor(imageData: ImageData, skip = 0, colorGroupingThreshold = 0): [PrimaryColor, Colors] { const { data } = imageData; const colors: Colors = {}; let primaryColor = ''; @@ -61,7 +107,18 @@ function detectColor(imageData: ImageData, skip = 0): [PrimaryColor, Colors] { maxCount = colors[rgb]; } } - return [{ color: primaryColor, count: maxCount }, colors]; + + const groupedColors = groupColors(colors, colorGroupingThreshold); + primaryColor = ''; + maxCount = 0; + Object.keys(groupedColors).forEach((color) => { + if (groupedColors[color] > maxCount) { + primaryColor = color; + maxCount = groupedColors[color]; + } + }); + + return [{ color: primaryColor, count: maxCount }, groupedColors]; } function getImageData(img: HTMLImageElement, downScaleFactor = 1): ImageData { @@ -125,6 +182,9 @@ function validateOptions(config: DominantColorOptions): void { if (!Number.isInteger(config.colorsPaletteLength) || config.colorsPaletteLength < 0) { throw new Error('colorsPaletteLength must be a non-negative integer'); } + if (!Number.isFinite(config.colorGroupingThreshold) || config.colorGroupingThreshold < 0) { + throw new Error('colorGroupingThreshold must be a non-negative number'); + } } export function getDominantColor(element: HTMLImageElement, options: Partial = {}): void { @@ -132,6 +192,7 @@ export function getDominantColor(element: HTMLImageElement, options: Partial { @@ -155,7 +216,7 @@ export function getDominantColor(element: HTMLImageElement, options: Partial { try { const imageData = getImageData(img, config.downScaleFactor); - const [primaryColor, colors] = detectColor(imageData, config.skipPixels); + const [primaryColor, colors] = detectColor(imageData, config.skipPixels, config.colorGroupingThreshold); const colorsPalette = config.colorsPaletteLength ? sortColors(colors, config.paletteWithCountOfOccurrences).slice(0, config.colorsPaletteLength) : []; diff --git a/src/interface.ts b/src/interface.ts index 3cf7dc5..8912d46 100644 --- a/src/interface.ts +++ b/src/interface.ts @@ -13,6 +13,7 @@ export interface DominantColorOptions { downScaleFactor: number; skipPixels: number; colorsPaletteLength: number; + colorGroupingThreshold: number; paletteWithCountOfOccurrences: boolean; colorFormat: ColorFormat; callback: DominantColorCallback; From 6c4206eb6473a01efb007b0de5fe587b7c65938f Mon Sep 17 00:00:00 2001 From: rtcoder Date: Wed, 20 May 2026 19:56:24 +0200 Subject: [PATCH 3/9] Add async API and bucket-based quantization to dominant color detection --- README.md | 30 +++++++++-- dist/dominant-color.d.ts | 4 +- dist/dominant-color.js | 77 +++++++++++++++++++------- dist/dominant-color.js.map | 2 +- dist/interface.d.ts | 7 +++ package.json | 11 ++++ src/dominant-color.spec.ts | 56 ++++++++++++++++++- src/dominant-color.ts | 108 ++++++++++++++++++++++++++++++------- src/interface.ts | 8 +++ 9 files changed, 257 insertions(+), 46 deletions(-) diff --git a/README.md b/README.md index 028e394..ebde751 100644 --- a/README.md +++ b/README.md @@ -12,10 +12,10 @@ npm i @rtcoder/dominant-color ## Usage -Import the `getDominantColor` function from `@rtcoder/dominant-color` in your JavaScript file: +Import the `getDominantColor` or `getDominantColorAsync` function from `@rtcoder/dominant-color` in your JavaScript file: ```javascript -import { getDominantColor } from "@rtcoder/dominant-color"; +import { getDominantColor, getDominantColorAsync } from "@rtcoder/dominant-color"; ``` Select an image element from your HTML: @@ -31,7 +31,9 @@ getDominantColor(img, { downScaleFactor: 1, skipPixels: 0, colorsPaletteLength: 5, + colorBucketSize: 24, colorGroupingThreshold: 0, + colorQuantization: 'exact', paletteWithCountOfOccurrences: false, colorFormat: 'rgb', callback: (color, palette) => { @@ -43,16 +45,27 @@ getDominantColor(img, { }); ``` +You can also use the Promise-based API: + +```javascript +const { dominant, colorsPalette } = await getDominantColorAsync(img, { + colorFormat: 'hex', + colorQuantization: 'bucket' +}); +``` + ## Configuration Options -The `getDominantColor` function accepts the following configuration options: +The `getDominantColor` and `getDominantColorAsync` functions accept the following configuration options: | Name | Type | Default Value | Description | | --------------------------- | -------- | ------------- | ------------------------------------------------------------ | | `downScaleFactor` | number | 1 | Factor of scale down for the image. Recommended for large images. | | `skipPixels` | number | 0 | Skips every `n` pixels while determining the dominant color. Recommended for large images. | | `colorsPaletteLength` | number | 5 | Length of the returned color palette. | +| `colorBucketSize` | number | 24 | RGB bucket size used when `colorQuantization` is `'bucket'`. Smaller values keep more detail; larger values merge more colors. | | `colorGroupingThreshold` | number | 0 | Groups similar RGB colors before sorting. Use `0` for exact pixel matching, or a larger value such as `10`-`30` for photos. | +| `colorQuantization` | string | `'exact'` | Defines the color counting algorithm. Use `'exact'` for exact RGB matching or `'bucket'` for more stable photo palettes. | | `paletteWithCountOfOccurrences` | boolean | false | Determines whether to return colors with the number of occurrences. | | `colorFormat` | string | `'rgb'` | Defines the format of the returned dominant color and palette colors. Available values are `'rgb'`, `'hsl'`, and `'hex'`. | | `callback` | function | [empty function] | Callback function that receives the dominant color and the colors palette. | @@ -64,6 +77,7 @@ The library provides the following interfaces for type checking: ```typescript type ColorFormat = 'rgb' | 'hsl' | 'hex'; +type ColorQuantization = 'exact' | 'bucket'; interface PrimaryColor { color: string; @@ -74,7 +88,9 @@ interface DominantColorOptions { downScaleFactor: number; skipPixels: number; colorsPaletteLength: number; + colorBucketSize: number; colorGroupingThreshold: number; + colorQuantization: ColorQuantization; paletteWithCountOfOccurrences: boolean; colorFormat: ColorFormat; callback: DominantColorCallback; @@ -84,7 +100,13 @@ interface DominantColorOptions { type DominantColorCallback = (dominant: string, colorsPalette: string[] | PrimaryColor[]) => void; type DominantColorErrorCallback = (error: Error) => void; -function getDominantColor(element: HTMLImageElement, options: Partial): void; +interface DominantColorResult { + dominant: string; + colorsPalette: string[] | PrimaryColor[]; +} + +function getDominantColor(element: HTMLImageElement, options?: Partial): void; +function getDominantColorAsync(element: HTMLImageElement, options?: Partial): Promise; ``` Feel free to explore and utilize these interfaces for better code development. diff --git a/dist/dominant-color.d.ts b/dist/dominant-color.d.ts index 221b611..67ec6e8 100644 --- a/dist/dominant-color.d.ts +++ b/dist/dominant-color.d.ts @@ -1,2 +1,4 @@ -import { DominantColorOptions } from './interface'; +import { DominantColorOptions, DominantColorResult } from './interface'; +export type { ColorFormat, ColorQuantization, Colors, DominantColorCallback, DominantColorErrorCallback, DominantColorOptions, DominantColorResult, PrimaryColor, } from './interface'; export declare function getDominantColor(element: HTMLImageElement, options?: Partial): void; +export declare function getDominantColorAsync(element: HTMLImageElement, options?: Partial): Promise; diff --git a/dist/dominant-color.js b/dist/dominant-color.js index c0e463e..921a5ed 100644 --- a/dist/dominant-color.js +++ b/dist/dominant-color.js @@ -40,6 +40,21 @@ function getRgbValues(rgb) { function toRgbKey(r, g, b) { return `${Math.round(r)},${Math.round(g)},${Math.round(b)}`; } +function quantizeColor(color, bucketSize) { + const [r, g, b] = getRgbValues(color); + const maxColorValue = 255; + return toRgbKey(Math.min(maxColorValue, Math.floor(r / bucketSize) * bucketSize + bucketSize / 2), Math.min(maxColorValue, Math.floor(g / bucketSize) * bucketSize + bucketSize / 2), Math.min(maxColorValue, Math.floor(b / bucketSize) * bucketSize + bucketSize / 2)); +} +function quantizeColors(colors, config) { + if (config.colorQuantization === 'exact') { + return colors; + } + return Object.keys(colors).reduce((quantizedColors, color) => { + const quantizedColor = quantizeColor(color, config.colorBucketSize); + quantizedColors[quantizedColor] = (quantizedColors[quantizedColor] || 0) + colors[color]; + return quantizedColors; + }, {}); +} function getColorDistanceSquared(r1, g1, b1, r2, g2, b2) { return (r1 - r2) ** 2 + (g1 - g2) ** 2 + (b1 - b2) ** 2; } @@ -68,12 +83,12 @@ function groupColors(colors, threshold) { return groupedColors; }, {}); } -function detectColor(imageData, skip = 0, colorGroupingThreshold = 0) { +function detectColor(imageData, config) { const { data } = imageData; const colors = {}; let primaryColor = ''; let maxCount = 0; - for (let px = 0; px < data.length; px += (skip + 1) * 4) { + for (let px = 0; px < data.length; px += (config.skipPixels + 1) * 4) { if (data[px + 3] < 255) { continue; // Ignore transparent pixels } @@ -84,7 +99,8 @@ function detectColor(imageData, skip = 0, colorGroupingThreshold = 0) { maxCount = colors[rgb]; } } - const groupedColors = groupColors(colors, colorGroupingThreshold); + const quantizedColors = quantizeColors(colors, config); + const groupedColors = groupColors(quantizedColors, config.colorGroupingThreshold); primaryColor = ''; maxCount = 0; Object.keys(groupedColors).forEach((color) => { @@ -147,27 +163,50 @@ function validateOptions(config) { if (!Number.isInteger(config.colorsPaletteLength) || config.colorsPaletteLength < 0) { throw new Error('colorsPaletteLength must be a non-negative integer'); } + if (!Number.isInteger(config.colorBucketSize) || config.colorBucketSize < 1 || config.colorBucketSize > 256) { + throw new Error('colorBucketSize must be an integer between 1 and 256'); + } if (!Number.isFinite(config.colorGroupingThreshold) || config.colorGroupingThreshold < 0) { throw new Error('colorGroupingThreshold must be a non-negative number'); } + if (!['exact', 'bucket'].includes(config.colorQuantization)) { + throw new Error('colorQuantization must be "exact" or "bucket"'); + } } -export function getDominantColor(element, options = {}) { - const defaultOptions = { - downScaleFactor: 1, - skipPixels: 0, - colorsPaletteLength: 5, - colorGroupingThreshold: 0, - paletteWithCountOfOccurrences: false, - colorFormat: 'rgb', - callback: () => { - // callback - }, - errorCallback: () => { - // error callback - }, - }; +const defaultOptions = { + downScaleFactor: 1, + skipPixels: 0, + colorsPaletteLength: 5, + colorBucketSize: 24, + colorGroupingThreshold: 0, + colorQuantization: 'exact', + paletteWithCountOfOccurrences: false, + colorFormat: 'rgb', + callback: () => { + // callback + }, + errorCallback: () => { + // error callback + }, +}; +function getDominantColorConfig(options) { const config = Object.assign(Object.assign({}, defaultOptions), options); validateOptions(config); + return config; +} +export function getDominantColor(element, options = {}) { + const config = getDominantColorConfig(options); + processDominantColor(element, config); +} +export function getDominantColorAsync(element, options = {}) { + return new Promise((resolve, reject) => { + const config = getDominantColorConfig(Object.assign(Object.assign({}, options), { callback: (dominant, colorsPalette) => { + resolve({ dominant, colorsPalette }); + }, errorCallback: reject })); + processDominantColor(element, config); + }); +} +function processDominantColor(element, config) { const source = element.currentSrc || element.src; if (!source) { config.errorCallback(new Error('Image source is empty')); @@ -178,7 +217,7 @@ export function getDominantColor(element, options = {}) { img.onload = () => { try { const imageData = getImageData(img, config.downScaleFactor); - const [primaryColor, colors] = detectColor(imageData, config.skipPixels, config.colorGroupingThreshold); + const [primaryColor, colors] = detectColor(imageData, config); const colorsPalette = config.colorsPaletteLength ? sortColors(colors, config.paletteWithCountOfOccurrences).slice(0, config.colorsPaletteLength) : []; diff --git a/dist/dominant-color.js.map b/dist/dominant-color.js.map index b0ebe6d..bd123d4 100644 --- a/dist/dominant-color.js.map +++ b/dist/dominant-color.js.map @@ -1 +1 @@ -{"version":3,"file":"dominant-color.js","sourceRoot":"","sources":["../src/dominant-color.ts"],"names":[],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"dominant-color.js","sourceRoot":"","sources":["../src/dominant-color.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/dist/interface.d.ts b/dist/interface.d.ts index 9989b1c..57fb4d0 100644 --- a/dist/interface.d.ts +++ b/dist/interface.d.ts @@ -1,4 +1,5 @@ export declare type ColorFormat = 'rgb' | 'hsl' | 'hex'; +export declare type ColorQuantization = 'exact' | 'bucket'; export interface PrimaryColor { color: string; count: number; @@ -10,7 +11,9 @@ export interface DominantColorOptions { downScaleFactor: number; skipPixels: number; colorsPaletteLength: number; + colorBucketSize: number; colorGroupingThreshold: number; + colorQuantization: ColorQuantization; paletteWithCountOfOccurrences: boolean; colorFormat: ColorFormat; callback: DominantColorCallback; @@ -18,3 +21,7 @@ export interface DominantColorOptions { } export declare type DominantColorCallback = (dominant: string, colorsPalette: string[] | PrimaryColor[]) => void; export declare type DominantColorErrorCallback = (error: Error) => void; +export interface DominantColorResult { + dominant: string; + colorsPalette: string[] | PrimaryColor[]; +} diff --git a/package.json b/package.json index af7c2a5..94836b6 100644 --- a/package.json +++ b/package.json @@ -2,8 +2,19 @@ "name": "@rtcoder/dominant-color", "version": "0.1.4", "description": "Get dominant color and palette of colors from an image", + "type": "module", "main": "dist/dominant-color.js", + "module": "dist/dominant-color.js", "types": "dist/dominant-color.d.ts", + "exports": { + ".": { + "types": "./dist/dominant-color.d.ts", + "import": "./dist/dominant-color.js", + "default": "./dist/dominant-color.js" + }, + "./package.json": "./package.json" + }, + "sideEffects": false, "scripts": { "build": "tsc", "test": "jest --config jestconfig.json", diff --git a/src/dominant-color.spec.ts b/src/dominant-color.spec.ts index 189bd2b..6e41de2 100644 --- a/src/dominant-color.spec.ts +++ b/src/dominant-color.spec.ts @@ -1,4 +1,4 @@ -import { getDominantColor } from './dominant-color'; +import { getDominantColor, getDominantColorAsync } from './dominant-color'; let pixels: Uint8ClampedArray; let shouldFailImageLoad = false; @@ -136,6 +136,52 @@ it('groups similar colors when colorGroupingThreshold is provided', () => { expect(callback).toHaveBeenCalledWith('#fd0300', ['#fd0300', '#0000ff']); }); +it('quantizes colors into buckets when bucket quantization is enabled', () => { + pixels = new Uint8ClampedArray([ + 255, + 0, + 0, + 255, + 250, + 5, + 0, + 255, + 0, + 0, + 255, + 255, + ]); + const callback = jest.fn(); + + getDominantColor({ src: 'image.jpg' } as HTMLImageElement, { + callback, + colorFormat: 'hex', + colorQuantization: 'bucket', + colorBucketSize: 24, + colorsPaletteLength: 2, + }); + + expect(callback).toHaveBeenCalledWith('#fc0c0c', ['#fc0c0c', '#0c0cfc']); +}); + +it('returns a promise result from getDominantColorAsync', async () => { + await expect( + getDominantColorAsync({ src: 'image.jpg' } as HTMLImageElement, { + colorFormat: 'hex', + colorsPaletteLength: 2, + }), + ).resolves.toEqual({ + dominant: '#ff0000', + colorsPalette: ['#ff0000', '#0000ff'], + }); +}); + +it('rejects getDominantColorAsync on image load errors', async () => { + shouldFailImageLoad = true; + + await expect(getDominantColorAsync({ src: 'missing.jpg' } as HTMLImageElement)).rejects.toThrow('Unable to load image'); +}); + it('returns an empty result when all pixels are transparent', () => { pixels = new Uint8ClampedArray([255, 0, 0, 0, 0, 0, 255, 0]); const callback = jest.fn(); @@ -164,6 +210,14 @@ it('throws for invalid colorGroupingThreshold values before loading the image', ).toThrow('colorGroupingThreshold must be a non-negative number'); }); +it('throws for invalid colorQuantization values before loading the image', () => { + expect(() => + getDominantColor({ src: 'image.jpg' } as HTMLImageElement, { + colorQuantization: 'median-cut' as any, + }), + ).toThrow('colorQuantization must be "exact" or "bucket"'); +}); + it('reports image load errors through errorCallback', () => { shouldFailImageLoad = true; const errorCallback = jest.fn(); diff --git a/src/dominant-color.ts b/src/dominant-color.ts index cb30b8b..dc5946d 100644 --- a/src/dominant-color.ts +++ b/src/dominant-color.ts @@ -1,4 +1,15 @@ -import { ColorFormat, Colors, DominantColorOptions, PrimaryColor } from './interface'; +import { ColorFormat, Colors, DominantColorOptions, DominantColorResult, PrimaryColor } from './interface'; + +export type { + ColorFormat, + ColorQuantization, + Colors, + DominantColorCallback, + DominantColorErrorCallback, + DominantColorOptions, + DominantColorResult, + PrimaryColor, +} from './interface'; interface ColorGroup { b: number; @@ -55,6 +66,28 @@ function toRgbKey(r: number, g: number, b: number): string { return `${Math.round(r)},${Math.round(g)},${Math.round(b)}`; } +function quantizeColor(color: string, bucketSize: number): string { + const [r, g, b] = getRgbValues(color); + const maxColorValue = 255; + return toRgbKey( + Math.min(maxColorValue, Math.floor(r / bucketSize) * bucketSize + bucketSize / 2), + Math.min(maxColorValue, Math.floor(g / bucketSize) * bucketSize + bucketSize / 2), + Math.min(maxColorValue, Math.floor(b / bucketSize) * bucketSize + bucketSize / 2), + ); +} + +function quantizeColors(colors: Colors, config: DominantColorOptions): Colors { + if (config.colorQuantization === 'exact') { + return colors; + } + + return Object.keys(colors).reduce((quantizedColors, color) => { + const quantizedColor = quantizeColor(color, config.colorBucketSize); + quantizedColors[quantizedColor] = (quantizedColors[quantizedColor] || 0) + colors[color]; + return quantizedColors; + }, {} as Colors); +} + function getColorDistanceSquared(r1: number, g1: number, b1: number, r2: number, g2: number, b2: number): number { return (r1 - r2) ** 2 + (g1 - g2) ** 2 + (b1 - b2) ** 2; } @@ -90,13 +123,13 @@ function groupColors(colors: Colors, threshold: number): Colors { }, {} as Colors); } -function detectColor(imageData: ImageData, skip = 0, colorGroupingThreshold = 0): [PrimaryColor, Colors] { +function detectColor(imageData: ImageData, config: DominantColorOptions): [PrimaryColor, Colors] { const { data } = imageData; const colors: Colors = {}; let primaryColor = ''; let maxCount = 0; - for (let px = 0; px < data.length; px += (skip + 1) * 4) { + for (let px = 0; px < data.length; px += (config.skipPixels + 1) * 4) { if (data[px + 3] < 255) { continue; // Ignore transparent pixels } @@ -108,7 +141,8 @@ function detectColor(imageData: ImageData, skip = 0, colorGroupingThreshold = 0) } } - const groupedColors = groupColors(colors, colorGroupingThreshold); + const quantizedColors = quantizeColors(colors, config); + const groupedColors = groupColors(quantizedColors, config.colorGroupingThreshold); primaryColor = ''; maxCount = 0; Object.keys(groupedColors).forEach((color) => { @@ -182,29 +216,63 @@ function validateOptions(config: DominantColorOptions): void { if (!Number.isInteger(config.colorsPaletteLength) || config.colorsPaletteLength < 0) { throw new Error('colorsPaletteLength must be a non-negative integer'); } + if (!Number.isInteger(config.colorBucketSize) || config.colorBucketSize < 1 || config.colorBucketSize > 256) { + throw new Error('colorBucketSize must be an integer between 1 and 256'); + } if (!Number.isFinite(config.colorGroupingThreshold) || config.colorGroupingThreshold < 0) { throw new Error('colorGroupingThreshold must be a non-negative number'); } + if (!['exact', 'bucket'].includes(config.colorQuantization)) { + throw new Error('colorQuantization must be "exact" or "bucket"'); + } } -export function getDominantColor(element: HTMLImageElement, options: Partial = {}): void { - const defaultOptions: DominantColorOptions = { - downScaleFactor: 1, - skipPixels: 0, - colorsPaletteLength: 5, - colorGroupingThreshold: 0, - paletteWithCountOfOccurrences: false, - colorFormat: 'rgb', - callback: () => { - // callback - }, - errorCallback: () => { - // error callback - }, - }; +const defaultOptions: DominantColorOptions = { + downScaleFactor: 1, + skipPixels: 0, + colorsPaletteLength: 5, + colorBucketSize: 24, + colorGroupingThreshold: 0, + colorQuantization: 'exact', + paletteWithCountOfOccurrences: false, + colorFormat: 'rgb', + callback: () => { + // callback + }, + errorCallback: () => { + // error callback + }, +}; + +function getDominantColorConfig(options: Partial): DominantColorOptions { const config: DominantColorOptions = { ...defaultOptions, ...options }; validateOptions(config); + return config; +} + +export function getDominantColor(element: HTMLImageElement, options: Partial = {}): void { + const config = getDominantColorConfig(options); + processDominantColor(element, config); +} + +export function getDominantColorAsync( + element: HTMLImageElement, + options: Partial = {}, +): Promise { + return new Promise((resolve, reject) => { + const config = getDominantColorConfig({ + ...options, + callback: (dominant, colorsPalette) => { + resolve({ dominant, colorsPalette }); + }, + errorCallback: reject, + }); + + processDominantColor(element, config); + }); +} +function processDominantColor(element: HTMLImageElement, config: DominantColorOptions): void { const source = element.currentSrc || element.src; if (!source) { config.errorCallback(new Error('Image source is empty')); @@ -216,7 +284,7 @@ export function getDominantColor(element: HTMLImageElement, options: Partial { try { const imageData = getImageData(img, config.downScaleFactor); - const [primaryColor, colors] = detectColor(imageData, config.skipPixels, config.colorGroupingThreshold); + const [primaryColor, colors] = detectColor(imageData, config); const colorsPalette = config.colorsPaletteLength ? sortColors(colors, config.paletteWithCountOfOccurrences).slice(0, config.colorsPaletteLength) : []; diff --git a/src/interface.ts b/src/interface.ts index 8912d46..ff1af0d 100644 --- a/src/interface.ts +++ b/src/interface.ts @@ -1,4 +1,5 @@ export type ColorFormat = 'rgb' | 'hsl' | 'hex'; +export type ColorQuantization = 'exact' | 'bucket'; export interface PrimaryColor { color: string; @@ -13,7 +14,9 @@ export interface DominantColorOptions { downScaleFactor: number; skipPixels: number; colorsPaletteLength: number; + colorBucketSize: number; colorGroupingThreshold: number; + colorQuantization: ColorQuantization; paletteWithCountOfOccurrences: boolean; colorFormat: ColorFormat; callback: DominantColorCallback; @@ -22,3 +25,8 @@ export interface DominantColorOptions { export type DominantColorCallback = (dominant: string, colorsPalette: string[] | PrimaryColor[]) => void; export type DominantColorErrorCallback = (error: Error) => void; + +export interface DominantColorResult { + dominant: string; + colorsPalette: string[] | PrimaryColor[]; +} From bbdedb134c9f8612fe24033dc5e8afab0b405dc2 Mon Sep 17 00:00:00 2001 From: rtcoder Date: Wed, 20 May 2026 20:00:48 +0200 Subject: [PATCH 4/9] Add pack smoke test and CI workflow for build and test validation --- .github/workflows/ci.yml | 38 +++++++++++++++ package.json | 1 + scripts/pack-smoke-test.mjs | 97 +++++++++++++++++++++++++++++++++++++ 3 files changed, 136 insertions(+) create mode 100644 .github/workflows/ci.yml create mode 100644 scripts/pack-smoke-test.mjs diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..217a3f6 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,38 @@ +name: CI + +on: + push: + branches: + - main + - master + pull_request: + +jobs: + test: + name: Build and test + runs-on: ubuntu-latest + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: 20 + cache: npm + + - name: Install dependencies + run: npm ci + + - name: Build + run: npm run build + + - name: Lint + run: npm run lint + + - name: Test + run: npm test + + - name: Pack smoke test + run: npm run test:pack diff --git a/package.json b/package.json index 94836b6..1d6cefb 100644 --- a/package.json +++ b/package.json @@ -18,6 +18,7 @@ "scripts": { "build": "tsc", "test": "jest --config jestconfig.json", + "test:pack": "node scripts/pack-smoke-test.mjs", "format": "prettier --write \"src/**/*.ts\"", "lint": "tslint -p tsconfig.json", "prepare": "npm run build", diff --git a/scripts/pack-smoke-test.mjs b/scripts/pack-smoke-test.mjs new file mode 100644 index 0000000..167905f --- /dev/null +++ b/scripts/pack-smoke-test.mjs @@ -0,0 +1,97 @@ +import { execFileSync } from 'node:child_process'; +import { mkdtempSync, rmSync, writeFileSync } from 'node:fs'; +import { tmpdir } from 'node:os'; +import { join } from 'node:path'; + +const rootDir = new URL('..', import.meta.url).pathname; +const tempDir = mkdtempSync(join(tmpdir(), 'dominant-color-pack-')); +const cacheDir = join(tempDir, 'npm-cache'); +const packageDir = join(tempDir, 'package-consumer'); + +function run(command, args, options = {}) { + execFileSync(command, args, { + cwd: rootDir, + env: { + ...process.env, + npm_config_cache: cacheDir, + }, + stdio: 'inherit', + ...options, + }); +} + +function runWithOutput(command, args, options = {}) { + return execFileSync(command, args, { + cwd: rootDir, + encoding: 'utf8', + env: { + ...process.env, + npm_config_cache: cacheDir, + }, + ...options, + }); +} + +try { + const packOutput = runWithOutput('npm', ['pack', '--json', '--pack-destination', tempDir]); + const [{ filename }] = JSON.parse(packOutput); + const tarballPath = join(tempDir, filename); + + run('npm', ['init', '-y'], { cwd: tempDir }); + run('npm', ['install', '--ignore-scripts', '--no-audit', '--no-fund', tarballPath], { cwd: tempDir }); + + writeFileSync( + join(tempDir, 'runtime-smoke.mjs'), + [ + "import { getDominantColor, getDominantColorAsync } from '@rtcoder/dominant-color';", + "if (typeof getDominantColor !== 'function') throw new Error('getDominantColor is not exported');", + "if (typeof getDominantColorAsync !== 'function') throw new Error('getDominantColorAsync is not exported');", + "console.log('runtime import smoke passed');", + '', + ].join('\n'), + ); + run('node', [join(tempDir, 'runtime-smoke.mjs')], { cwd: tempDir }); + + writeFileSync( + join(tempDir, 'type-smoke.ts'), + [ + "import { getDominantColorAsync } from '@rtcoder/dominant-color';", + "import type { DominantColorOptions, DominantColorResult } from '@rtcoder/dominant-color';", + '', + "const options: Partial = {", + " colorFormat: 'hex',", + " colorQuantization: 'bucket',", + '};', + '', + "async function run(img: HTMLImageElement): Promise {", + ' return getDominantColorAsync(img, options);', + '}', + '', + 'void run;', + '', + ].join('\n'), + ); + writeFileSync( + join(tempDir, 'tsconfig.json'), + JSON.stringify( + { + compilerOptions: { + lib: ['dom', 'es2020'], + module: 'esnext', + moduleResolution: 'node', + noEmit: true, + strict: true, + target: 'es2020', + }, + include: ['type-smoke.ts'], + }, + null, + 2, + ), + ); + + run('node', [join(rootDir, 'node_modules/typescript/bin/tsc'), '-p', join(tempDir, 'tsconfig.json')], { cwd: tempDir }); + console.log('pack smoke test passed'); +} finally { + rmSync(tempDir, { force: true, recursive: true }); +} From a0ad477c3192c9145c2d521909c2768ea7bcefca Mon Sep 17 00:00:00 2001 From: rtcoder Date: Wed, 20 May 2026 20:04:31 +0200 Subject: [PATCH 5/9] Convert build to ES module and restructure dominant color library --- dist/cjs/dominant-color.js | 245 +++++++++++++++++++++++++++++ dist/cjs/dominant-color.js.map | 1 + dist/cjs/interface.js | 3 + dist/{ => cjs}/interface.js.map | 2 +- dist/cjs/package.json | 3 + dist/dominant-color.js.map | 1 - dist/{ => esm}/dominant-color.d.ts | 0 dist/{ => esm}/dominant-color.js | 0 dist/esm/dominant-color.js.map | 1 + dist/{ => esm}/interface.d.ts | 0 dist/{ => esm}/interface.js | 0 dist/esm/interface.js.map | 1 + examples/music-app/js/index.js | 3 +- examples/palette/js/index.js | 2 +- js/index.js | 2 +- package.json | 18 ++- scripts/clean-dist.mjs | 3 + scripts/pack-smoke-test.mjs | 13 +- scripts/write-cjs-package.mjs | 6 + tsconfig.cjs.json | 8 + tsconfig.esm.json | 8 + 21 files changed, 306 insertions(+), 14 deletions(-) create mode 100644 dist/cjs/dominant-color.js create mode 100644 dist/cjs/dominant-color.js.map create mode 100644 dist/cjs/interface.js rename dist/{ => cjs}/interface.js.map (56%) create mode 100644 dist/cjs/package.json delete mode 100644 dist/dominant-color.js.map rename dist/{ => esm}/dominant-color.d.ts (100%) rename dist/{ => esm}/dominant-color.js (100%) create mode 100644 dist/esm/dominant-color.js.map rename dist/{ => esm}/interface.d.ts (100%) rename dist/{ => esm}/interface.js (100%) create mode 100644 dist/esm/interface.js.map create mode 100644 scripts/clean-dist.mjs create mode 100644 scripts/write-cjs-package.mjs create mode 100644 tsconfig.cjs.json create mode 100644 tsconfig.esm.json diff --git a/dist/cjs/dominant-color.js b/dist/cjs/dominant-color.js new file mode 100644 index 0000000..a1f4cab --- /dev/null +++ b/dist/cjs/dominant-color.js @@ -0,0 +1,245 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.getDominantColorAsync = exports.getDominantColor = void 0; +function rgbToHex(rgb) { + const [_r, _g, _b] = getRgbValues(rgb).map((val) => val.toString(16).padStart(2, '0')); + return `#${_r}${_g}${_b}`; +} +function rgbToHsl(rgb) { + const [_r, _g, _b] = getRgbValues(rgb); + const r = _r / 255; + const g = _g / 255; + const b = _b / 255; + const cMin = Math.min(r, g, b); + const cMax = Math.max(r, g, b); + const delta = cMax - cMin; + let h = 0; + if (delta !== 0) { + if (cMax === r) { + h = ((g - b) / delta) % 6; + } + else if (cMax === g) { + h = (b - r) / delta + 2; + } + else { + h = (r - g) / delta + 4; + } + } + h = Math.round(h * 60); + if (h < 0) { + h += 360; + } + const l = (cMax + cMin) / 2; + const s = delta === 0 ? 0 : delta / (1 - Math.abs(2 * l - 1)); + return `hsl(${h},${(s * 100).toFixed(1)}%,${(l * 100).toFixed(1)}%)`; +} +function getRgbValues(rgb) { + const values = rgb.match(/\d+/g); + if (!values || values.length < 3) { + throw new Error(`Invalid RGB color: ${rgb}`); + } + return values.slice(0, 3).map(Number); +} +function toRgbKey(r, g, b) { + return `${Math.round(r)},${Math.round(g)},${Math.round(b)}`; +} +function quantizeColor(color, bucketSize) { + const [r, g, b] = getRgbValues(color); + const maxColorValue = 255; + return toRgbKey(Math.min(maxColorValue, Math.floor(r / bucketSize) * bucketSize + bucketSize / 2), Math.min(maxColorValue, Math.floor(g / bucketSize) * bucketSize + bucketSize / 2), Math.min(maxColorValue, Math.floor(b / bucketSize) * bucketSize + bucketSize / 2)); +} +function quantizeColors(colors, config) { + if (config.colorQuantization === 'exact') { + return colors; + } + return Object.keys(colors).reduce((quantizedColors, color) => { + const quantizedColor = quantizeColor(color, config.colorBucketSize); + quantizedColors[quantizedColor] = (quantizedColors[quantizedColor] || 0) + colors[color]; + return quantizedColors; + }, {}); +} +function getColorDistanceSquared(r1, g1, b1, r2, g2, b2) { + return (r1 - r2) ** 2 + (g1 - g2) ** 2 + (b1 - b2) ** 2; +} +function groupColors(colors, threshold) { + if (threshold === 0) { + return colors; + } + const groups = []; + const thresholdSquared = threshold ** 2; + Object.keys(colors).forEach((color) => { + const [r, g, b] = getRgbValues(color); + const group = groups.find((item) => getColorDistanceSquared(item.r, item.g, item.b, r, g, b) <= thresholdSquared); + if (!group) { + groups.push({ r, g, b, count: colors[color] }); + return; + } + const totalCount = group.count + colors[color]; + group.r = (group.r * group.count + r * colors[color]) / totalCount; + group.g = (group.g * group.count + g * colors[color]) / totalCount; + group.b = (group.b * group.count + b * colors[color]) / totalCount; + group.count = totalCount; + }); + return groups.reduce((groupedColors, group) => { + const color = toRgbKey(group.r, group.g, group.b); + groupedColors[color] = (groupedColors[color] || 0) + group.count; + return groupedColors; + }, {}); +} +function detectColor(imageData, config) { + const { data } = imageData; + const colors = {}; + let primaryColor = ''; + let maxCount = 0; + for (let px = 0; px < data.length; px += (config.skipPixels + 1) * 4) { + if (data[px + 3] < 255) { + continue; // Ignore transparent pixels + } + const rgb = `${data[px]},${data[px + 1]},${data[px + 2]}`; + colors[rgb] = (colors[rgb] || 0) + 1; + if (colors[rgb] > maxCount) { + primaryColor = rgb; + maxCount = colors[rgb]; + } + } + const quantizedColors = quantizeColors(colors, config); + const groupedColors = groupColors(quantizedColors, config.colorGroupingThreshold); + primaryColor = ''; + maxCount = 0; + Object.keys(groupedColors).forEach((color) => { + if (groupedColors[color] > maxCount) { + primaryColor = color; + maxCount = groupedColors[color]; + } + }); + return [{ color: primaryColor, count: maxCount }, groupedColors]; +} +function getImageData(img, downScaleFactor = 1) { + const canvas = document.createElement('canvas'); + const context = canvas.getContext('2d'); + const scaledWidth = Math.max(1, Math.floor(img.width / downScaleFactor)); + const scaledHeight = Math.max(1, Math.floor(img.height / downScaleFactor)); + if (!context) { + throw new Error('Canvas 2D context is not available'); + } + canvas.width = scaledWidth; + canvas.height = scaledHeight; + context.drawImage(img, 0, 0, scaledWidth, scaledHeight); + return context.getImageData(0, 0, scaledWidth, scaledHeight); +} +function sortColors(colors, withOccurrences = false) { + const sorted = Object.keys(colors).sort((a, b) => colors[b] - colors[a]); + return withOccurrences + ? sorted.map((color) => ({ + color, + count: colors[color], + })) + : sorted; +} +function formatPalette(colorsPalette, format) { + if (!colorsPalette.length || typeof colorsPalette[0] === 'string') { + return colorsPalette.map((color) => getColorByFormat(color, format)); + } + return colorsPalette.map((item) => (Object.assign(Object.assign({}, item), { color: getColorByFormat(item.color, format) }))); +} +function getColorByFormat(color, format) { + switch (format) { + case 'rgb': + color = `rgb(${color})`; + break; + case 'hsl': + color = rgbToHsl(`rgb(${color})`); + break; + case 'hex': + color = rgbToHex(`rgb(${color})`); + break; + } + return color; +} +function validateOptions(config) { + if (!Number.isFinite(config.downScaleFactor) || config.downScaleFactor < 1) { + throw new Error('downScaleFactor must be equal to 1 or greater'); + } + if (!Number.isInteger(config.skipPixels) || config.skipPixels < 0) { + throw new Error('skipPixels must be a non-negative integer'); + } + if (!Number.isInteger(config.colorsPaletteLength) || config.colorsPaletteLength < 0) { + throw new Error('colorsPaletteLength must be a non-negative integer'); + } + if (!Number.isInteger(config.colorBucketSize) || config.colorBucketSize < 1 || config.colorBucketSize > 256) { + throw new Error('colorBucketSize must be an integer between 1 and 256'); + } + if (!Number.isFinite(config.colorGroupingThreshold) || config.colorGroupingThreshold < 0) { + throw new Error('colorGroupingThreshold must be a non-negative number'); + } + if (!['exact', 'bucket'].includes(config.colorQuantization)) { + throw new Error('colorQuantization must be "exact" or "bucket"'); + } +} +const defaultOptions = { + downScaleFactor: 1, + skipPixels: 0, + colorsPaletteLength: 5, + colorBucketSize: 24, + colorGroupingThreshold: 0, + colorQuantization: 'exact', + paletteWithCountOfOccurrences: false, + colorFormat: 'rgb', + callback: () => { + // callback + }, + errorCallback: () => { + // error callback + }, +}; +function getDominantColorConfig(options) { + const config = Object.assign(Object.assign({}, defaultOptions), options); + validateOptions(config); + return config; +} +function getDominantColor(element, options = {}) { + const config = getDominantColorConfig(options); + processDominantColor(element, config); +} +exports.getDominantColor = getDominantColor; +function getDominantColorAsync(element, options = {}) { + return new Promise((resolve, reject) => { + const config = getDominantColorConfig(Object.assign(Object.assign({}, options), { callback: (dominant, colorsPalette) => { + resolve({ dominant, colorsPalette }); + }, errorCallback: reject })); + processDominantColor(element, config); + }); +} +exports.getDominantColorAsync = getDominantColorAsync; +function processDominantColor(element, config) { + const source = element.currentSrc || element.src; + if (!source) { + config.errorCallback(new Error('Image source is empty')); + return; + } + const img = new Image(); + img.crossOrigin = 'Anonymous'; + img.onload = () => { + try { + const imageData = getImageData(img, config.downScaleFactor); + const [primaryColor, colors] = detectColor(imageData, config); + const colorsPalette = config.colorsPaletteLength + ? sortColors(colors, config.paletteWithCountOfOccurrences).slice(0, config.colorsPaletteLength) + : []; + if (!primaryColor.color) { + config.callback('', []); + return; + } + const dominant = getColorByFormat(primaryColor.color, config.colorFormat); + config.callback(dominant, formatPalette(colorsPalette, config.colorFormat)); + } + catch (error) { + config.errorCallback(error instanceof Error ? error : new Error(String(error))); + } + }; + img.onerror = () => { + config.errorCallback(new Error(`Unable to load image: ${source}`)); + }; + img.src = source; +} +//# sourceMappingURL=dominant-color.js.map \ No newline at end of file diff --git a/dist/cjs/dominant-color.js.map b/dist/cjs/dominant-color.js.map new file mode 100644 index 0000000..0d6e67f --- /dev/null +++ b/dist/cjs/dominant-color.js.map @@ -0,0 +1 @@ +{"version":3,"file":"dominant-color.js","sourceRoot":"","sources":["../../src/dominant-color.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/dist/cjs/interface.js b/dist/cjs/interface.js new file mode 100644 index 0000000..d549d1f --- /dev/null +++ b/dist/cjs/interface.js @@ -0,0 +1,3 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +//# sourceMappingURL=interface.js.map \ No newline at end of file diff --git a/dist/interface.js.map b/dist/cjs/interface.js.map similarity index 56% rename from dist/interface.js.map rename to dist/cjs/interface.js.map index d4b226c..199ce6a 100644 --- a/dist/interface.js.map +++ b/dist/cjs/interface.js.map @@ -1 +1 @@ -{"version":3,"file":"interface.js","sourceRoot":"","sources":["../src/interface.ts"],"names":[],"mappings":""} \ No newline at end of file +{"version":3,"file":"interface.js","sourceRoot":"","sources":["../../src/interface.ts"],"names":[],"mappings":""} \ No newline at end of file diff --git a/dist/cjs/package.json b/dist/cjs/package.json new file mode 100644 index 0000000..5bbefff --- /dev/null +++ b/dist/cjs/package.json @@ -0,0 +1,3 @@ +{ + "type": "commonjs" +} diff --git a/dist/dominant-color.js.map b/dist/dominant-color.js.map deleted file mode 100644 index bd123d4..0000000 --- a/dist/dominant-color.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"dominant-color.js","sourceRoot":"","sources":["../src/dominant-color.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/dist/dominant-color.d.ts b/dist/esm/dominant-color.d.ts similarity index 100% rename from dist/dominant-color.d.ts rename to dist/esm/dominant-color.d.ts diff --git a/dist/dominant-color.js b/dist/esm/dominant-color.js similarity index 100% rename from dist/dominant-color.js rename to dist/esm/dominant-color.js diff --git a/dist/esm/dominant-color.js.map b/dist/esm/dominant-color.js.map new file mode 100644 index 0000000..56048a8 --- /dev/null +++ b/dist/esm/dominant-color.js.map @@ -0,0 +1 @@ +{"version":3,"file":"dominant-color.js","sourceRoot":"","sources":["../../src/dominant-color.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/dist/interface.d.ts b/dist/esm/interface.d.ts similarity index 100% rename from dist/interface.d.ts rename to dist/esm/interface.d.ts diff --git a/dist/interface.js b/dist/esm/interface.js similarity index 100% rename from dist/interface.js rename to dist/esm/interface.js diff --git a/dist/esm/interface.js.map b/dist/esm/interface.js.map new file mode 100644 index 0000000..199ce6a --- /dev/null +++ b/dist/esm/interface.js.map @@ -0,0 +1 @@ +{"version":3,"file":"interface.js","sourceRoot":"","sources":["../../src/interface.ts"],"names":[],"mappings":""} \ No newline at end of file diff --git a/examples/music-app/js/index.js b/examples/music-app/js/index.js index a51e52c..ea6fca4 100644 --- a/examples/music-app/js/index.js +++ b/examples/music-app/js/index.js @@ -1,4 +1,4 @@ -import { getDominantColor } from '../../../dist/dominant-color.js'; +import { getDominantColor } from '../../../dist/esm/dominant-color.js'; let currentVolume = 1; const songs = []; @@ -493,4 +493,3 @@ fetch('./json/tracks.json') }); }); }); - diff --git a/examples/palette/js/index.js b/examples/palette/js/index.js index eb25fd9..14c563c 100644 --- a/examples/palette/js/index.js +++ b/examples/palette/js/index.js @@ -1,4 +1,4 @@ -import { getDominantColor } from '../../../dist/dominant-color.js'; +import { getDominantColor } from '../../../dist/esm/dominant-color.js'; function shift_color([r, g, b], val, percent) { return '#' + diff --git a/js/index.js b/js/index.js index 524d329..baf1e16 100644 --- a/js/index.js +++ b/js/index.js @@ -1,4 +1,4 @@ -import { getDominantColor } from '../dist/dominant-color.js'; +import { getDominantColor } from '../dist/esm/dominant-color.js'; const dropArea = document.getElementById('drop-area'); diff --git a/package.json b/package.json index 1d6cefb..e48d638 100644 --- a/package.json +++ b/package.json @@ -3,20 +3,24 @@ "version": "0.1.4", "description": "Get dominant color and palette of colors from an image", "type": "module", - "main": "dist/dominant-color.js", - "module": "dist/dominant-color.js", - "types": "dist/dominant-color.d.ts", + "main": "dist/cjs/dominant-color.js", + "module": "dist/esm/dominant-color.js", + "types": "dist/esm/dominant-color.d.ts", "exports": { ".": { - "types": "./dist/dominant-color.d.ts", - "import": "./dist/dominant-color.js", - "default": "./dist/dominant-color.js" + "types": "./dist/esm/dominant-color.d.ts", + "import": "./dist/esm/dominant-color.js", + "require": "./dist/cjs/dominant-color.js", + "default": "./dist/esm/dominant-color.js" }, "./package.json": "./package.json" }, "sideEffects": false, "scripts": { - "build": "tsc", + "build": "npm run clean && npm run build:esm && npm run build:cjs", + "build:cjs": "tsc -p tsconfig.cjs.json && node scripts/write-cjs-package.mjs", + "build:esm": "tsc -p tsconfig.esm.json", + "clean": "node scripts/clean-dist.mjs", "test": "jest --config jestconfig.json", "test:pack": "node scripts/pack-smoke-test.mjs", "format": "prettier --write \"src/**/*.ts\"", diff --git a/scripts/clean-dist.mjs b/scripts/clean-dist.mjs new file mode 100644 index 0000000..089e0ee --- /dev/null +++ b/scripts/clean-dist.mjs @@ -0,0 +1,3 @@ +import { rmSync } from 'node:fs'; + +rmSync(new URL('../dist', import.meta.url), { force: true, recursive: true }); diff --git a/scripts/pack-smoke-test.mjs b/scripts/pack-smoke-test.mjs index 167905f..b0f2a69 100644 --- a/scripts/pack-smoke-test.mjs +++ b/scripts/pack-smoke-test.mjs @@ -6,7 +6,6 @@ import { join } from 'node:path'; const rootDir = new URL('..', import.meta.url).pathname; const tempDir = mkdtempSync(join(tmpdir(), 'dominant-color-pack-')); const cacheDir = join(tempDir, 'npm-cache'); -const packageDir = join(tempDir, 'package-consumer'); function run(command, args, options = {}) { execFileSync(command, args, { @@ -52,6 +51,18 @@ try { ); run('node', [join(tempDir, 'runtime-smoke.mjs')], { cwd: tempDir }); + writeFileSync( + join(tempDir, 'runtime-smoke.cjs'), + [ + "const { getDominantColor, getDominantColorAsync } = require('@rtcoder/dominant-color');", + "if (typeof getDominantColor !== 'function') throw new Error('getDominantColor is not exported');", + "if (typeof getDominantColorAsync !== 'function') throw new Error('getDominantColorAsync is not exported');", + "console.log('runtime require smoke passed');", + '', + ].join('\n'), + ); + run('node', [join(tempDir, 'runtime-smoke.cjs')], { cwd: tempDir }); + writeFileSync( join(tempDir, 'type-smoke.ts'), [ diff --git a/scripts/write-cjs-package.mjs b/scripts/write-cjs-package.mjs new file mode 100644 index 0000000..aeaba25 --- /dev/null +++ b/scripts/write-cjs-package.mjs @@ -0,0 +1,6 @@ +import { mkdirSync, writeFileSync } from 'node:fs'; + +const cjsDir = new URL('../dist/cjs/', import.meta.url); + +mkdirSync(cjsDir, { recursive: true }); +writeFileSync(new URL('package.json', cjsDir), `${JSON.stringify({ type: 'commonjs' }, null, 2)}\n`); diff --git a/tsconfig.cjs.json b/tsconfig.cjs.json new file mode 100644 index 0000000..47e0364 --- /dev/null +++ b/tsconfig.cjs.json @@ -0,0 +1,8 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "declaration": false, + "module": "commonjs", + "outDir": "./dist/cjs" + } +} diff --git a/tsconfig.esm.json b/tsconfig.esm.json new file mode 100644 index 0000000..49c7c29 --- /dev/null +++ b/tsconfig.esm.json @@ -0,0 +1,8 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "declaration": true, + "module": "esnext", + "outDir": "./dist/esm" + } +} From f0d337077bcfe4d6d9c5728d6096c589c99afed5 Mon Sep 17 00:00:00 2001 From: rtcoder Date: Wed, 20 May 2026 20:10:24 +0200 Subject: [PATCH 6/9] Extend dominant color API to support multiple input sources and median-cut quantization --- README.md | 15 ++- dist/cjs/dominant-color.js | 172 ++++++++++++++++++++++----- dist/cjs/dominant-color.js.map | 2 +- dist/esm/dominant-color.d.ts | 8 +- dist/esm/dominant-color.js | 172 ++++++++++++++++++++++----- dist/esm/dominant-color.js.map | 2 +- dist/esm/interface.d.ts | 3 +- scripts/pack-smoke-test.mjs | 8 +- src/dominant-color.spec.ts | 83 ++++++++++++- src/dominant-color.ts | 209 +++++++++++++++++++++++++++------ src/interface.ts | 3 +- 11 files changed, 561 insertions(+), 116 deletions(-) diff --git a/README.md b/README.md index ebde751..6a8d32b 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ Import the `getDominantColor` or `getDominantColorAsync` function from `@rtcoder import { getDominantColor, getDominantColorAsync } from "@rtcoder/dominant-color"; ``` -Select an image element from your HTML: +Select an image source: ```javascript const img = document.querySelector('img'); @@ -50,10 +50,12 @@ You can also use the Promise-based API: ```javascript const { dominant, colorsPalette } = await getDominantColorAsync(img, { colorFormat: 'hex', - colorQuantization: 'bucket' + colorQuantization: 'median-cut' }); ``` +Image sources can be an `HTMLImageElement`, `HTMLCanvasElement`, `ImageBitmap`, image URL string, `Blob`, or `File`. + ## Configuration Options The `getDominantColor` and `getDominantColorAsync` functions accept the following configuration options: @@ -65,7 +67,7 @@ The `getDominantColor` and `getDominantColorAsync` functions accept the followin | `colorsPaletteLength` | number | 5 | Length of the returned color palette. | | `colorBucketSize` | number | 24 | RGB bucket size used when `colorQuantization` is `'bucket'`. Smaller values keep more detail; larger values merge more colors. | | `colorGroupingThreshold` | number | 0 | Groups similar RGB colors before sorting. Use `0` for exact pixel matching, or a larger value such as `10`-`30` for photos. | -| `colorQuantization` | string | `'exact'` | Defines the color counting algorithm. Use `'exact'` for exact RGB matching or `'bucket'` for more stable photo palettes. | +| `colorQuantization` | string | `'exact'` | Defines the color counting algorithm. Use `'exact'` for exact RGB matching, `'bucket'` for fast grouped palettes, or `'median-cut'` for more balanced photo palettes. | | `paletteWithCountOfOccurrences` | boolean | false | Determines whether to return colors with the number of occurrences. | | `colorFormat` | string | `'rgb'` | Defines the format of the returned dominant color and palette colors. Available values are `'rgb'`, `'hsl'`, and `'hex'`. | | `callback` | function | [empty function] | Callback function that receives the dominant color and the colors palette. | @@ -77,7 +79,8 @@ The library provides the following interfaces for type checking: ```typescript type ColorFormat = 'rgb' | 'hsl' | 'hex'; -type ColorQuantization = 'exact' | 'bucket'; +type ColorQuantization = 'exact' | 'bucket' | 'median-cut'; +type DominantColorSource = HTMLImageElement | HTMLCanvasElement | ImageBitmap | string | Blob; interface PrimaryColor { color: string; @@ -105,8 +108,8 @@ interface DominantColorResult { colorsPalette: string[] | PrimaryColor[]; } -function getDominantColor(element: HTMLImageElement, options?: Partial): void; -function getDominantColorAsync(element: HTMLImageElement, options?: Partial): Promise; +function getDominantColor(source: DominantColorSource, options?: Partial): void; +function getDominantColorAsync(source: DominantColorSource, options?: Partial): Promise; ``` Feel free to explore and utilize these interfaces for better code development. diff --git a/dist/cjs/dominant-color.js b/dist/cjs/dominant-color.js index a1f4cab..8d6ab30 100644 --- a/dist/cjs/dominant-color.js +++ b/dist/cjs/dominant-color.js @@ -49,7 +49,7 @@ function quantizeColor(color, bucketSize) { return toRgbKey(Math.min(maxColorValue, Math.floor(r / bucketSize) * bucketSize + bucketSize / 2), Math.min(maxColorValue, Math.floor(g / bucketSize) * bucketSize + bucketSize / 2), Math.min(maxColorValue, Math.floor(b / bucketSize) * bucketSize + bucketSize / 2)); } function quantizeColors(colors, config) { - if (config.colorQuantization === 'exact') { + if (config.colorQuantization !== 'bucket') { return colors; } return Object.keys(colors).reduce((quantizedColors, color) => { @@ -58,6 +58,76 @@ function quantizeColors(colors, config) { return quantizedColors; }, {}); } +function getMedianCutRange(colors, channel) { + return Math.max(...colors.map((color) => color[channel])) - Math.min(...colors.map((color) => color[channel])); +} +function getMedianCutChannel(colors) { + const ranges = { + b: getMedianCutRange(colors, 'b'), + g: getMedianCutRange(colors, 'g'), + r: getMedianCutRange(colors, 'r'), + }; + return Object.keys(ranges).sort((a, b) => ranges[b] - ranges[a])[0]; +} +function splitMedianCutBox(colors) { + if (colors.length <= 1) { + return [colors]; + } + const channel = getMedianCutChannel(colors); + const sorted = [...colors].sort((a, b) => a[channel] - b[channel]); + const totalCount = sorted.reduce((sum, color) => sum + color.count, 0); + let runningCount = 0; + let splitIndex = 1; + for (let index = 0; index < sorted.length - 1; index++) { + runningCount += sorted[index].count; + if (runningCount >= totalCount / 2) { + splitIndex = index + 1; + break; + } + } + return [sorted.slice(0, splitIndex), sorted.slice(splitIndex)]; +} +function averageMedianCutBox(colors) { + const totalCount = colors.reduce((sum, color) => sum + color.count, 0); + const weighted = colors.reduce((sum, color) => ({ + b: sum.b + color.b * color.count, + g: sum.g + color.g * color.count, + r: sum.r + color.r * color.count, + }), { b: 0, g: 0, r: 0 }); + return { + color: toRgbKey(weighted.r / totalCount, weighted.g / totalCount, weighted.b / totalCount), + count: totalCount, + }; +} +function medianCutColors(colors, paletteLength) { + if (paletteLength === 0) { + return {}; + } + let boxes = [ + Object.keys(colors).map((color) => { + const [r, g, b] = getRgbValues(color); + return { r, g, b, count: colors[color] }; + }), + ]; + while (boxes.length < paletteLength) { + const sortedBoxes = [...boxes].sort((a, b) => { + const aRange = Math.max(getMedianCutRange(a, 'r'), getMedianCutRange(a, 'g'), getMedianCutRange(a, 'b')); + const bRange = Math.max(getMedianCutRange(b, 'r'), getMedianCutRange(b, 'g'), getMedianCutRange(b, 'b')); + return bRange * b.reduce((sum, color) => sum + color.count, 0) - aRange * a.reduce((sum, color) => sum + color.count, 0); + }); + const boxToSplit = sortedBoxes.find((box) => box.length > 1); + if (!boxToSplit) { + break; + } + const splitBoxes = splitMedianCutBox(boxToSplit).filter((box) => box.length); + boxes = boxes.filter((box) => box !== boxToSplit).concat(splitBoxes); + } + return boxes.reduce((palette, box) => { + const color = averageMedianCutBox(box); + palette[color.color] = (palette[color.color] || 0) + color.count; + return palette; + }, {}); +} function getColorDistanceSquared(r1, g1, b1, r2, g2, b2) { return (r1 - r2) ** 2 + (g1 - g2) ** 2 + (b1 - b2) ** 2; } @@ -104,27 +174,34 @@ function detectColor(imageData, config) { } const quantizedColors = quantizeColors(colors, config); const groupedColors = groupColors(quantizedColors, config.colorGroupingThreshold); + const paletteColors = config.colorQuantization === 'median-cut' ? medianCutColors(groupedColors, config.colorsPaletteLength || 1) : groupedColors; primaryColor = ''; maxCount = 0; - Object.keys(groupedColors).forEach((color) => { - if (groupedColors[color] > maxCount) { + Object.keys(paletteColors).forEach((color) => { + if (paletteColors[color] > maxCount) { primaryColor = color; - maxCount = groupedColors[color]; + maxCount = paletteColors[color]; } }); - return [{ color: primaryColor, count: maxCount }, groupedColors]; + return [{ color: primaryColor, count: maxCount }, paletteColors]; +} +function getSourceWidth(source) { + return source.width; +} +function getSourceHeight(source) { + return source.height; } -function getImageData(img, downScaleFactor = 1) { +function getImageData(source, downScaleFactor = 1) { const canvas = document.createElement('canvas'); const context = canvas.getContext('2d'); - const scaledWidth = Math.max(1, Math.floor(img.width / downScaleFactor)); - const scaledHeight = Math.max(1, Math.floor(img.height / downScaleFactor)); + const scaledWidth = Math.max(1, Math.floor(getSourceWidth(source) / downScaleFactor)); + const scaledHeight = Math.max(1, Math.floor(getSourceHeight(source) / downScaleFactor)); if (!context) { throw new Error('Canvas 2D context is not available'); } canvas.width = scaledWidth; canvas.height = scaledHeight; - context.drawImage(img, 0, 0, scaledWidth, scaledHeight); + context.drawImage(source, 0, 0, scaledWidth, scaledHeight); return context.getImageData(0, 0, scaledWidth, scaledHeight); } function sortColors(colors, withOccurrences = false) { @@ -172,8 +249,8 @@ function validateOptions(config) { if (!Number.isFinite(config.colorGroupingThreshold) || config.colorGroupingThreshold < 0) { throw new Error('colorGroupingThreshold must be a non-negative number'); } - if (!['exact', 'bucket'].includes(config.colorQuantization)) { - throw new Error('colorQuantization must be "exact" or "bucket"'); + if (!['exact', 'bucket', 'median-cut'].includes(config.colorQuantization)) { + throw new Error('colorQuantization must be "exact", "bucket", or "median-cut"'); } } const defaultOptions = { @@ -197,49 +274,82 @@ function getDominantColorConfig(options) { validateOptions(config); return config; } -function getDominantColor(element, options = {}) { +function getDominantColor(source, options = {}) { const config = getDominantColorConfig(options); - processDominantColor(element, config); + processDominantColor(source, config); } exports.getDominantColor = getDominantColor; -function getDominantColorAsync(element, options = {}) { +function getDominantColorAsync(source, options = {}) { return new Promise((resolve, reject) => { const config = getDominantColorConfig(Object.assign(Object.assign({}, options), { callback: (dominant, colorsPalette) => { resolve({ dominant, colorsPalette }); }, errorCallback: reject })); - processDominantColor(element, config); + processDominantColor(source, config); }); } exports.getDominantColorAsync = getDominantColorAsync; -function processDominantColor(element, config) { - const source = element.currentSrc || element.src; - if (!source) { +function handleImageData(imageData, config) { + const [primaryColor, colors] = detectColor(imageData, config); + const colorsPalette = config.colorsPaletteLength + ? sortColors(colors, config.paletteWithCountOfOccurrences).slice(0, config.colorsPaletteLength) + : []; + if (!primaryColor.color) { + config.callback('', []); + return; + } + const dominant = getColorByFormat(primaryColor.color, config.colorFormat); + config.callback(dominant, formatPalette(colorsPalette, config.colorFormat)); +} +function isCanvasSource(source) { + return typeof source !== 'string' && typeof Blob !== 'undefined' && !(source instanceof Blob) && !('src' in source); +} +function getImageSource(source) { + if (typeof source === 'string') { + return source; + } + if (typeof Blob !== 'undefined' && source instanceof Blob) { + return URL.createObjectURL(source); + } + const element = source; + return element.currentSrc || element.src; +} +function processDominantColor(source, config) { + if (isCanvasSource(source)) { + try { + handleImageData(getImageData(source, config.downScaleFactor), config); + } + catch (error) { + config.errorCallback(error instanceof Error ? error : new Error(String(error))); + } + return; + } + const imageSource = getImageSource(source); + if (!imageSource) { config.errorCallback(new Error('Image source is empty')); return; } + const shouldRevokeObjectUrl = typeof Blob !== 'undefined' && source instanceof Blob; const img = new Image(); img.crossOrigin = 'Anonymous'; img.onload = () => { try { - const imageData = getImageData(img, config.downScaleFactor); - const [primaryColor, colors] = detectColor(imageData, config); - const colorsPalette = config.colorsPaletteLength - ? sortColors(colors, config.paletteWithCountOfOccurrences).slice(0, config.colorsPaletteLength) - : []; - if (!primaryColor.color) { - config.callback('', []); - return; - } - const dominant = getColorByFormat(primaryColor.color, config.colorFormat); - config.callback(dominant, formatPalette(colorsPalette, config.colorFormat)); + handleImageData(getImageData(img, config.downScaleFactor), config); } catch (error) { config.errorCallback(error instanceof Error ? error : new Error(String(error))); } + finally { + if (shouldRevokeObjectUrl) { + URL.revokeObjectURL(imageSource); + } + } }; img.onerror = () => { - config.errorCallback(new Error(`Unable to load image: ${source}`)); + if (shouldRevokeObjectUrl) { + URL.revokeObjectURL(imageSource); + } + config.errorCallback(new Error(`Unable to load image: ${imageSource}`)); }; - img.src = source; + img.src = imageSource; } //# sourceMappingURL=dominant-color.js.map \ No newline at end of file diff --git a/dist/cjs/dominant-color.js.map b/dist/cjs/dominant-color.js.map index 0d6e67f..0645f06 100644 --- a/dist/cjs/dominant-color.js.map +++ b/dist/cjs/dominant-color.js.map @@ -1 +1 @@ -{"version":3,"file":"dominant-color.js","sourceRoot":"","sources":["../../src/dominant-color.ts"],"names":[],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"dominant-color.js","sourceRoot":"","sources":["../../src/dominant-color.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/dist/esm/dominant-color.d.ts b/dist/esm/dominant-color.d.ts index 67ec6e8..e6339de 100644 --- a/dist/esm/dominant-color.d.ts +++ b/dist/esm/dominant-color.d.ts @@ -1,4 +1,4 @@ -import { DominantColorOptions, DominantColorResult } from './interface'; -export type { ColorFormat, ColorQuantization, Colors, DominantColorCallback, DominantColorErrorCallback, DominantColorOptions, DominantColorResult, PrimaryColor, } from './interface'; -export declare function getDominantColor(element: HTMLImageElement, options?: Partial): void; -export declare function getDominantColorAsync(element: HTMLImageElement, options?: Partial): Promise; +import { DominantColorOptions, DominantColorResult, DominantColorSource } from './interface'; +export type { ColorFormat, ColorQuantization, Colors, DominantColorCallback, DominantColorErrorCallback, DominantColorOptions, DominantColorResult, DominantColorSource, PrimaryColor, } from './interface'; +export declare function getDominantColor(source: DominantColorSource, options?: Partial): void; +export declare function getDominantColorAsync(source: DominantColorSource, options?: Partial): Promise; diff --git a/dist/esm/dominant-color.js b/dist/esm/dominant-color.js index 921a5ed..d5a6177 100644 --- a/dist/esm/dominant-color.js +++ b/dist/esm/dominant-color.js @@ -46,7 +46,7 @@ function quantizeColor(color, bucketSize) { return toRgbKey(Math.min(maxColorValue, Math.floor(r / bucketSize) * bucketSize + bucketSize / 2), Math.min(maxColorValue, Math.floor(g / bucketSize) * bucketSize + bucketSize / 2), Math.min(maxColorValue, Math.floor(b / bucketSize) * bucketSize + bucketSize / 2)); } function quantizeColors(colors, config) { - if (config.colorQuantization === 'exact') { + if (config.colorQuantization !== 'bucket') { return colors; } return Object.keys(colors).reduce((quantizedColors, color) => { @@ -55,6 +55,76 @@ function quantizeColors(colors, config) { return quantizedColors; }, {}); } +function getMedianCutRange(colors, channel) { + return Math.max(...colors.map((color) => color[channel])) - Math.min(...colors.map((color) => color[channel])); +} +function getMedianCutChannel(colors) { + const ranges = { + b: getMedianCutRange(colors, 'b'), + g: getMedianCutRange(colors, 'g'), + r: getMedianCutRange(colors, 'r'), + }; + return Object.keys(ranges).sort((a, b) => ranges[b] - ranges[a])[0]; +} +function splitMedianCutBox(colors) { + if (colors.length <= 1) { + return [colors]; + } + const channel = getMedianCutChannel(colors); + const sorted = [...colors].sort((a, b) => a[channel] - b[channel]); + const totalCount = sorted.reduce((sum, color) => sum + color.count, 0); + let runningCount = 0; + let splitIndex = 1; + for (let index = 0; index < sorted.length - 1; index++) { + runningCount += sorted[index].count; + if (runningCount >= totalCount / 2) { + splitIndex = index + 1; + break; + } + } + return [sorted.slice(0, splitIndex), sorted.slice(splitIndex)]; +} +function averageMedianCutBox(colors) { + const totalCount = colors.reduce((sum, color) => sum + color.count, 0); + const weighted = colors.reduce((sum, color) => ({ + b: sum.b + color.b * color.count, + g: sum.g + color.g * color.count, + r: sum.r + color.r * color.count, + }), { b: 0, g: 0, r: 0 }); + return { + color: toRgbKey(weighted.r / totalCount, weighted.g / totalCount, weighted.b / totalCount), + count: totalCount, + }; +} +function medianCutColors(colors, paletteLength) { + if (paletteLength === 0) { + return {}; + } + let boxes = [ + Object.keys(colors).map((color) => { + const [r, g, b] = getRgbValues(color); + return { r, g, b, count: colors[color] }; + }), + ]; + while (boxes.length < paletteLength) { + const sortedBoxes = [...boxes].sort((a, b) => { + const aRange = Math.max(getMedianCutRange(a, 'r'), getMedianCutRange(a, 'g'), getMedianCutRange(a, 'b')); + const bRange = Math.max(getMedianCutRange(b, 'r'), getMedianCutRange(b, 'g'), getMedianCutRange(b, 'b')); + return bRange * b.reduce((sum, color) => sum + color.count, 0) - aRange * a.reduce((sum, color) => sum + color.count, 0); + }); + const boxToSplit = sortedBoxes.find((box) => box.length > 1); + if (!boxToSplit) { + break; + } + const splitBoxes = splitMedianCutBox(boxToSplit).filter((box) => box.length); + boxes = boxes.filter((box) => box !== boxToSplit).concat(splitBoxes); + } + return boxes.reduce((palette, box) => { + const color = averageMedianCutBox(box); + palette[color.color] = (palette[color.color] || 0) + color.count; + return palette; + }, {}); +} function getColorDistanceSquared(r1, g1, b1, r2, g2, b2) { return (r1 - r2) ** 2 + (g1 - g2) ** 2 + (b1 - b2) ** 2; } @@ -101,27 +171,34 @@ function detectColor(imageData, config) { } const quantizedColors = quantizeColors(colors, config); const groupedColors = groupColors(quantizedColors, config.colorGroupingThreshold); + const paletteColors = config.colorQuantization === 'median-cut' ? medianCutColors(groupedColors, config.colorsPaletteLength || 1) : groupedColors; primaryColor = ''; maxCount = 0; - Object.keys(groupedColors).forEach((color) => { - if (groupedColors[color] > maxCount) { + Object.keys(paletteColors).forEach((color) => { + if (paletteColors[color] > maxCount) { primaryColor = color; - maxCount = groupedColors[color]; + maxCount = paletteColors[color]; } }); - return [{ color: primaryColor, count: maxCount }, groupedColors]; + return [{ color: primaryColor, count: maxCount }, paletteColors]; +} +function getSourceWidth(source) { + return source.width; +} +function getSourceHeight(source) { + return source.height; } -function getImageData(img, downScaleFactor = 1) { +function getImageData(source, downScaleFactor = 1) { const canvas = document.createElement('canvas'); const context = canvas.getContext('2d'); - const scaledWidth = Math.max(1, Math.floor(img.width / downScaleFactor)); - const scaledHeight = Math.max(1, Math.floor(img.height / downScaleFactor)); + const scaledWidth = Math.max(1, Math.floor(getSourceWidth(source) / downScaleFactor)); + const scaledHeight = Math.max(1, Math.floor(getSourceHeight(source) / downScaleFactor)); if (!context) { throw new Error('Canvas 2D context is not available'); } canvas.width = scaledWidth; canvas.height = scaledHeight; - context.drawImage(img, 0, 0, scaledWidth, scaledHeight); + context.drawImage(source, 0, 0, scaledWidth, scaledHeight); return context.getImageData(0, 0, scaledWidth, scaledHeight); } function sortColors(colors, withOccurrences = false) { @@ -169,8 +246,8 @@ function validateOptions(config) { if (!Number.isFinite(config.colorGroupingThreshold) || config.colorGroupingThreshold < 0) { throw new Error('colorGroupingThreshold must be a non-negative number'); } - if (!['exact', 'bucket'].includes(config.colorQuantization)) { - throw new Error('colorQuantization must be "exact" or "bucket"'); + if (!['exact', 'bucket', 'median-cut'].includes(config.colorQuantization)) { + throw new Error('colorQuantization must be "exact", "bucket", or "median-cut"'); } } const defaultOptions = { @@ -194,47 +271,80 @@ function getDominantColorConfig(options) { validateOptions(config); return config; } -export function getDominantColor(element, options = {}) { +export function getDominantColor(source, options = {}) { const config = getDominantColorConfig(options); - processDominantColor(element, config); + processDominantColor(source, config); } -export function getDominantColorAsync(element, options = {}) { +export function getDominantColorAsync(source, options = {}) { return new Promise((resolve, reject) => { const config = getDominantColorConfig(Object.assign(Object.assign({}, options), { callback: (dominant, colorsPalette) => { resolve({ dominant, colorsPalette }); }, errorCallback: reject })); - processDominantColor(element, config); + processDominantColor(source, config); }); } -function processDominantColor(element, config) { - const source = element.currentSrc || element.src; - if (!source) { +function handleImageData(imageData, config) { + const [primaryColor, colors] = detectColor(imageData, config); + const colorsPalette = config.colorsPaletteLength + ? sortColors(colors, config.paletteWithCountOfOccurrences).slice(0, config.colorsPaletteLength) + : []; + if (!primaryColor.color) { + config.callback('', []); + return; + } + const dominant = getColorByFormat(primaryColor.color, config.colorFormat); + config.callback(dominant, formatPalette(colorsPalette, config.colorFormat)); +} +function isCanvasSource(source) { + return typeof source !== 'string' && typeof Blob !== 'undefined' && !(source instanceof Blob) && !('src' in source); +} +function getImageSource(source) { + if (typeof source === 'string') { + return source; + } + if (typeof Blob !== 'undefined' && source instanceof Blob) { + return URL.createObjectURL(source); + } + const element = source; + return element.currentSrc || element.src; +} +function processDominantColor(source, config) { + if (isCanvasSource(source)) { + try { + handleImageData(getImageData(source, config.downScaleFactor), config); + } + catch (error) { + config.errorCallback(error instanceof Error ? error : new Error(String(error))); + } + return; + } + const imageSource = getImageSource(source); + if (!imageSource) { config.errorCallback(new Error('Image source is empty')); return; } + const shouldRevokeObjectUrl = typeof Blob !== 'undefined' && source instanceof Blob; const img = new Image(); img.crossOrigin = 'Anonymous'; img.onload = () => { try { - const imageData = getImageData(img, config.downScaleFactor); - const [primaryColor, colors] = detectColor(imageData, config); - const colorsPalette = config.colorsPaletteLength - ? sortColors(colors, config.paletteWithCountOfOccurrences).slice(0, config.colorsPaletteLength) - : []; - if (!primaryColor.color) { - config.callback('', []); - return; - } - const dominant = getColorByFormat(primaryColor.color, config.colorFormat); - config.callback(dominant, formatPalette(colorsPalette, config.colorFormat)); + handleImageData(getImageData(img, config.downScaleFactor), config); } catch (error) { config.errorCallback(error instanceof Error ? error : new Error(String(error))); } + finally { + if (shouldRevokeObjectUrl) { + URL.revokeObjectURL(imageSource); + } + } }; img.onerror = () => { - config.errorCallback(new Error(`Unable to load image: ${source}`)); + if (shouldRevokeObjectUrl) { + URL.revokeObjectURL(imageSource); + } + config.errorCallback(new Error(`Unable to load image: ${imageSource}`)); }; - img.src = source; + img.src = imageSource; } //# sourceMappingURL=dominant-color.js.map \ No newline at end of file diff --git a/dist/esm/dominant-color.js.map b/dist/esm/dominant-color.js.map index 56048a8..e18cb99 100644 --- a/dist/esm/dominant-color.js.map +++ b/dist/esm/dominant-color.js.map @@ -1 +1 @@ -{"version":3,"file":"dominant-color.js","sourceRoot":"","sources":["../../src/dominant-color.ts"],"names":[],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"dominant-color.js","sourceRoot":"","sources":["../../src/dominant-color.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/dist/esm/interface.d.ts b/dist/esm/interface.d.ts index 57fb4d0..4c0db2f 100644 --- a/dist/esm/interface.d.ts +++ b/dist/esm/interface.d.ts @@ -1,5 +1,6 @@ export declare type ColorFormat = 'rgb' | 'hsl' | 'hex'; -export declare type ColorQuantization = 'exact' | 'bucket'; +export declare type ColorQuantization = 'exact' | 'bucket' | 'median-cut'; +export declare type DominantColorSource = HTMLImageElement | HTMLCanvasElement | ImageBitmap | string | Blob; export interface PrimaryColor { color: string; count: number; diff --git a/scripts/pack-smoke-test.mjs b/scripts/pack-smoke-test.mjs index b0f2a69..257720f 100644 --- a/scripts/pack-smoke-test.mjs +++ b/scripts/pack-smoke-test.mjs @@ -67,15 +67,15 @@ try { join(tempDir, 'type-smoke.ts'), [ "import { getDominantColorAsync } from '@rtcoder/dominant-color';", - "import type { DominantColorOptions, DominantColorResult } from '@rtcoder/dominant-color';", + "import type { DominantColorOptions, DominantColorResult, DominantColorSource } from '@rtcoder/dominant-color';", '', "const options: Partial = {", " colorFormat: 'hex',", - " colorQuantization: 'bucket',", + " colorQuantization: 'median-cut',", '};', '', - "async function run(img: HTMLImageElement): Promise {", - ' return getDominantColorAsync(img, options);', + "async function run(source: DominantColorSource): Promise {", + ' return getDominantColorAsync(source, options);', '}', '', 'void run;', diff --git a/src/dominant-color.spec.ts b/src/dominant-color.spec.ts index 6e41de2..f4f5d18 100644 --- a/src/dominant-color.spec.ts +++ b/src/dominant-color.spec.ts @@ -2,6 +2,8 @@ import { getDominantColor, getDominantColorAsync } from './dominant-color'; let pixels: Uint8ClampedArray; let shouldFailImageLoad = false; +let createObjectURL: jest.Mock; +let revokeObjectURL: jest.Mock; class MockImage { public crossOrigin = ''; @@ -69,6 +71,13 @@ beforeEach(() => { ]); mockCanvas(); (global as any).Image = MockImage; + createObjectURL = jest.fn(() => 'blob:image'); + revokeObjectURL = jest.fn(); + (global as any).URL = { + createObjectURL, + revokeObjectURL, + }; + (global as any).Blob = class MockBlob {}; }); it('returns dominant color and palette in the requested format', () => { @@ -83,6 +92,45 @@ it('returns dominant color and palette in the requested format', () => { expect(callback).toHaveBeenCalledWith('#ff0000', ['#ff0000', '#0000ff']); }); +it('accepts a string image source', () => { + const callback = jest.fn(); + + getDominantColor('image.jpg', { + callback, + colorFormat: 'hex', + colorsPaletteLength: 1, + }); + + expect(callback).toHaveBeenCalledWith('#ff0000', ['#ff0000']); +}); + +it('accepts canvas-like sources without loading a new image', () => { + const callback = jest.fn(); + const canvas = { height: 2, width: 2 } as HTMLCanvasElement; + + getDominantColor(canvas, { + callback, + colorFormat: 'hex', + colorsPaletteLength: 1, + }); + + expect(callback).toHaveBeenCalledWith('#ff0000', ['#ff0000']); +}); + +it('accepts blob sources and revokes generated object URLs', () => { + const callback = jest.fn(); + const blob = new Blob(); + + getDominantColor(blob, { + callback, + colorsPaletteLength: 1, + }); + + expect(createObjectURL).toHaveBeenCalledWith(blob); + expect(revokeObjectURL).toHaveBeenCalledWith('blob:image'); + expect(callback).toHaveBeenCalledWith('rgb(255,0,0)', ['rgb(255,0,0)']); +}); + it('uses default options when they are not provided', () => { const callback = jest.fn(); @@ -164,6 +212,37 @@ it('quantizes colors into buckets when bucket quantization is enabled', () => { expect(callback).toHaveBeenCalledWith('#fc0c0c', ['#fc0c0c', '#0c0cfc']); }); +it('uses median-cut quantization for a balanced photo-like palette', () => { + pixels = new Uint8ClampedArray([ + 240, + 10, + 10, + 255, + 220, + 30, + 20, + 255, + 10, + 20, + 240, + 255, + 20, + 30, + 220, + 255, + ]); + const callback = jest.fn(); + + getDominantColor('image.jpg', { + callback, + colorFormat: 'hex', + colorQuantization: 'median-cut', + colorsPaletteLength: 2, + }); + + expect(callback).toHaveBeenCalledWith('#e6140f', ['#e6140f', '#0f19e6']); +}); + it('returns a promise result from getDominantColorAsync', async () => { await expect( getDominantColorAsync({ src: 'image.jpg' } as HTMLImageElement, { @@ -213,9 +292,9 @@ it('throws for invalid colorGroupingThreshold values before loading the image', it('throws for invalid colorQuantization values before loading the image', () => { expect(() => getDominantColor({ src: 'image.jpg' } as HTMLImageElement, { - colorQuantization: 'median-cut' as any, + colorQuantization: 'octree' as any, }), - ).toThrow('colorQuantization must be "exact" or "bucket"'); + ).toThrow('colorQuantization must be "exact", "bucket", or "median-cut"'); }); it('reports image load errors through errorCallback', () => { diff --git a/src/dominant-color.ts b/src/dominant-color.ts index dc5946d..dbed7f6 100644 --- a/src/dominant-color.ts +++ b/src/dominant-color.ts @@ -1,4 +1,4 @@ -import { ColorFormat, Colors, DominantColorOptions, DominantColorResult, PrimaryColor } from './interface'; +import { ColorFormat, Colors, DominantColorOptions, DominantColorResult, DominantColorSource, PrimaryColor } from './interface'; export type { ColorFormat, @@ -8,6 +8,7 @@ export type { DominantColorErrorCallback, DominantColorOptions, DominantColorResult, + DominantColorSource, PrimaryColor, } from './interface'; @@ -18,6 +19,15 @@ interface ColorGroup { r: number; } +interface MedianCutColor { + b: number; + count: number; + g: number; + r: number; +} + +type DrawableDominantColorSource = HTMLImageElement | HTMLCanvasElement | ImageBitmap; + function rgbToHex(rgb: string): string { const [_r, _g, _b] = getRgbValues(rgb).map((val) => val.toString(16).padStart(2, '0')); return `#${_r}${_g}${_b}`; @@ -77,7 +87,7 @@ function quantizeColor(color: string, bucketSize: number): string { } function quantizeColors(colors: Colors, config: DominantColorOptions): Colors { - if (config.colorQuantization === 'exact') { + if (config.colorQuantization !== 'bucket') { return colors; } @@ -88,6 +98,92 @@ function quantizeColors(colors: Colors, config: DominantColorOptions): Colors { }, {} as Colors); } +function getMedianCutRange(colors: MedianCutColor[], channel: 'r' | 'g' | 'b'): number { + return Math.max(...colors.map((color) => color[channel])) - Math.min(...colors.map((color) => color[channel])); +} + +function getMedianCutChannel(colors: MedianCutColor[]): 'r' | 'g' | 'b' { + const ranges = { + b: getMedianCutRange(colors, 'b'), + g: getMedianCutRange(colors, 'g'), + r: getMedianCutRange(colors, 'r'), + }; + return Object.keys(ranges).sort((a, b) => ranges[b as 'r' | 'g' | 'b'] - ranges[a as 'r' | 'g' | 'b'])[0] as 'r' | 'g' | 'b'; +} + +function splitMedianCutBox(colors: MedianCutColor[]): MedianCutColor[][] { + if (colors.length <= 1) { + return [colors]; + } + + const channel = getMedianCutChannel(colors); + const sorted = [...colors].sort((a, b) => a[channel] - b[channel]); + const totalCount = sorted.reduce((sum, color) => sum + color.count, 0); + let runningCount = 0; + let splitIndex = 1; + + for (let index = 0; index < sorted.length - 1; index++) { + runningCount += sorted[index].count; + if (runningCount >= totalCount / 2) { + splitIndex = index + 1; + break; + } + } + + return [sorted.slice(0, splitIndex), sorted.slice(splitIndex)]; +} + +function averageMedianCutBox(colors: MedianCutColor[]): PrimaryColor { + const totalCount = colors.reduce((sum, color) => sum + color.count, 0); + const weighted = colors.reduce( + (sum, color) => ({ + b: sum.b + color.b * color.count, + g: sum.g + color.g * color.count, + r: sum.r + color.r * color.count, + }), + { b: 0, g: 0, r: 0 }, + ); + + return { + color: toRgbKey(weighted.r / totalCount, weighted.g / totalCount, weighted.b / totalCount), + count: totalCount, + }; +} + +function medianCutColors(colors: Colors, paletteLength: number): Colors { + if (paletteLength === 0) { + return {}; + } + + let boxes = [ + Object.keys(colors).map((color) => { + const [r, g, b] = getRgbValues(color); + return { r, g, b, count: colors[color] }; + }), + ]; + + while (boxes.length < paletteLength) { + const sortedBoxes = [...boxes].sort((a, b) => { + const aRange = Math.max(getMedianCutRange(a, 'r'), getMedianCutRange(a, 'g'), getMedianCutRange(a, 'b')); + const bRange = Math.max(getMedianCutRange(b, 'r'), getMedianCutRange(b, 'g'), getMedianCutRange(b, 'b')); + return bRange * b.reduce((sum, color) => sum + color.count, 0) - aRange * a.reduce((sum, color) => sum + color.count, 0); + }); + const boxToSplit = sortedBoxes.find((box) => box.length > 1); + if (!boxToSplit) { + break; + } + + const splitBoxes = splitMedianCutBox(boxToSplit).filter((box) => box.length); + boxes = boxes.filter((box) => box !== boxToSplit).concat(splitBoxes); + } + + return boxes.reduce((palette, box) => { + const color = averageMedianCutBox(box); + palette[color.color] = (palette[color.color] || 0) + color.count; + return palette; + }, {} as Colors); +} + function getColorDistanceSquared(r1: number, g1: number, b1: number, r2: number, g2: number, b2: number): number { return (r1 - r2) ** 2 + (g1 - g2) ** 2 + (b1 - b2) ** 2; } @@ -143,23 +239,33 @@ function detectColor(imageData: ImageData, config: DominantColorOptions): [Prima const quantizedColors = quantizeColors(colors, config); const groupedColors = groupColors(quantizedColors, config.colorGroupingThreshold); + const paletteColors = + config.colorQuantization === 'median-cut' ? medianCutColors(groupedColors, config.colorsPaletteLength || 1) : groupedColors; primaryColor = ''; maxCount = 0; - Object.keys(groupedColors).forEach((color) => { - if (groupedColors[color] > maxCount) { + Object.keys(paletteColors).forEach((color) => { + if (paletteColors[color] > maxCount) { primaryColor = color; - maxCount = groupedColors[color]; + maxCount = paletteColors[color]; } }); - return [{ color: primaryColor, count: maxCount }, groupedColors]; + return [{ color: primaryColor, count: maxCount }, paletteColors]; +} + +function getSourceWidth(source: DrawableDominantColorSource): number { + return source.width; +} + +function getSourceHeight(source: DrawableDominantColorSource): number { + return source.height; } -function getImageData(img: HTMLImageElement, downScaleFactor = 1): ImageData { +function getImageData(source: DrawableDominantColorSource, downScaleFactor = 1): ImageData { const canvas = document.createElement('canvas') as HTMLCanvasElement; const context = canvas.getContext('2d'); - const scaledWidth = Math.max(1, Math.floor(img.width / downScaleFactor)); - const scaledHeight = Math.max(1, Math.floor(img.height / downScaleFactor)); + const scaledWidth = Math.max(1, Math.floor(getSourceWidth(source) / downScaleFactor)); + const scaledHeight = Math.max(1, Math.floor(getSourceHeight(source) / downScaleFactor)); if (!context) { throw new Error('Canvas 2D context is not available'); @@ -167,7 +273,7 @@ function getImageData(img: HTMLImageElement, downScaleFactor = 1): ImageData { canvas.width = scaledWidth; canvas.height = scaledHeight; - context.drawImage(img, 0, 0, scaledWidth, scaledHeight); + context.drawImage(source, 0, 0, scaledWidth, scaledHeight); return context.getImageData(0, 0, scaledWidth, scaledHeight); } @@ -222,8 +328,8 @@ function validateOptions(config: DominantColorOptions): void { if (!Number.isFinite(config.colorGroupingThreshold) || config.colorGroupingThreshold < 0) { throw new Error('colorGroupingThreshold must be a non-negative number'); } - if (!['exact', 'bucket'].includes(config.colorQuantization)) { - throw new Error('colorQuantization must be "exact" or "bucket"'); + if (!['exact', 'bucket', 'median-cut'].includes(config.colorQuantization)) { + throw new Error('colorQuantization must be "exact", "bucket", or "median-cut"'); } } @@ -250,13 +356,13 @@ function getDominantColorConfig(options: Partial): Dominan return config; } -export function getDominantColor(element: HTMLImageElement, options: Partial = {}): void { +export function getDominantColor(source: DominantColorSource, options: Partial = {}): void { const config = getDominantColorConfig(options); - processDominantColor(element, config); + processDominantColor(source, config); } export function getDominantColorAsync( - element: HTMLImageElement, + source: DominantColorSource, options: Partial = {}, ): Promise { return new Promise((resolve, reject) => { @@ -268,41 +374,76 @@ export function getDominantColorAsync( errorCallback: reject, }); - processDominantColor(element, config); + processDominantColor(source, config); }); } -function processDominantColor(element: HTMLImageElement, config: DominantColorOptions): void { - const source = element.currentSrc || element.src; - if (!source) { +function handleImageData(imageData: ImageData, config: DominantColorOptions): void { + const [primaryColor, colors] = detectColor(imageData, config); + const colorsPalette = config.colorsPaletteLength + ? sortColors(colors, config.paletteWithCountOfOccurrences).slice(0, config.colorsPaletteLength) + : []; + + if (!primaryColor.color) { + config.callback('', []); + return; + } + + const dominant = getColorByFormat(primaryColor.color, config.colorFormat); + config.callback(dominant, formatPalette(colorsPalette, config.colorFormat)); +} + +function isCanvasSource(source: DominantColorSource): source is HTMLCanvasElement | ImageBitmap { + return typeof source !== 'string' && typeof Blob !== 'undefined' && !(source instanceof Blob) && !('src' in source); +} + +function getImageSource(source: HTMLImageElement | string | Blob): string { + if (typeof source === 'string') { + return source; + } + if (typeof Blob !== 'undefined' && source instanceof Blob) { + return URL.createObjectURL(source); + } + const element = source as HTMLImageElement; + return element.currentSrc || element.src; +} + +function processDominantColor(source: DominantColorSource, config: DominantColorOptions): void { + if (isCanvasSource(source)) { + try { + handleImageData(getImageData(source, config.downScaleFactor), config); + } catch (error) { + config.errorCallback(error instanceof Error ? error : new Error(String(error))); + } + return; + } + + const imageSource = getImageSource(source); + if (!imageSource) { config.errorCallback(new Error('Image source is empty')); return; } + const shouldRevokeObjectUrl = typeof Blob !== 'undefined' && source instanceof Blob; const img = new Image(); img.crossOrigin = 'Anonymous'; img.onload = () => { try { - const imageData = getImageData(img, config.downScaleFactor); - const [primaryColor, colors] = detectColor(imageData, config); - const colorsPalette = config.colorsPaletteLength - ? sortColors(colors, config.paletteWithCountOfOccurrences).slice(0, config.colorsPaletteLength) - : []; - - if (!primaryColor.color) { - config.callback('', []); - return; - } - - const dominant = getColorByFormat(primaryColor.color, config.colorFormat); - config.callback(dominant, formatPalette(colorsPalette, config.colorFormat)); + handleImageData(getImageData(img, config.downScaleFactor), config); } catch (error) { config.errorCallback(error instanceof Error ? error : new Error(String(error))); + } finally { + if (shouldRevokeObjectUrl) { + URL.revokeObjectURL(imageSource); + } } }; img.onerror = () => { - config.errorCallback(new Error(`Unable to load image: ${source}`)); + if (shouldRevokeObjectUrl) { + URL.revokeObjectURL(imageSource); + } + config.errorCallback(new Error(`Unable to load image: ${imageSource}`)); }; - img.src = source; + img.src = imageSource; } diff --git a/src/interface.ts b/src/interface.ts index ff1af0d..0ff347e 100644 --- a/src/interface.ts +++ b/src/interface.ts @@ -1,5 +1,6 @@ export type ColorFormat = 'rgb' | 'hsl' | 'hex'; -export type ColorQuantization = 'exact' | 'bucket'; +export type ColorQuantization = 'exact' | 'bucket' | 'median-cut'; +export type DominantColorSource = HTMLImageElement | HTMLCanvasElement | ImageBitmap | string | Blob; export interface PrimaryColor { color: string; From 2aacaa279f4255f420548b1481bc643ff6cb0100 Mon Sep 17 00:00:00 2001 From: rtcoder Date: Wed, 20 May 2026 20:54:45 +0200 Subject: [PATCH 7/9] Refactor examples and documentation, update visual styles, and improve accessibility across components --- css/index.css | 97 ++++--- css/style.css | 481 +++++++++++++++++++++++++++---- documentation.html | 386 +++++++++++++------------ examples/music-app/css/style.css | 28 +- examples/music-app/index.html | 46 ++- examples/palette/css/style.css | 70 ++--- examples/palette/index.html | 46 ++- examples/palette/js/index.js | 2 +- index.html | 134 +++++++-- 9 files changed, 895 insertions(+), 395 deletions(-) diff --git a/css/index.css b/css/index.css index 5da9745..12057fb 100644 --- a/css/index.css +++ b/css/index.css @@ -1,81 +1,96 @@ @import 'style.css'; +.uploader-section { + padding-bottom: 1.25rem; + padding-top: 1.5rem; +} + +.uploader-section .page-title { + padding: 2rem 0 1.25rem; +} + #drop-area { - border: 2px dashed #ccc; - border-radius: 20px; - max-width: 480px; - width: 100%; - font-family: sans-serif; - margin: 20px auto; + align-items: center; + background: var(--surface); + border: 2px dashed #9bb7b5; + border-radius: 8px; + color: var(--brand-dark); + cursor: pointer; display: flex; - height: 200px; + font-size: clamp(1.1rem, 3vw, 1.8rem); + font-weight: 800; justify-content: center; - align-items: center; - font-size: 30px; + margin: 0 auto; + max-width: 720px; + min-height: 160px; + padding: 1.5rem; text-align: center; + transition: border-color 0.2s ease, background-color 0.2s ease; user-select: none; - cursor: pointer; + width: 100%; } #drop-area.highlight { - background: #09d url(../img/img-placeholder.png) center no-repeat; - background-size: contain; - border-color: #036193; + background: #dcefed url(../img/img-placeholder.png) center no-repeat; + background-size: 140px; + border-color: var(--brand); color: transparent; } #drop-area:hover { - border-color: #036193; + border-color: var(--brand); + background-color: #eef7f5; } #gallery { - margin: 10px auto; - display: flex; - flex-wrap: wrap; - justify-content: space-evenly; - max-width: 500px; + display: grid; + gap: 1rem; + grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); + margin: 1.5rem auto 0; + max-width: 980px; +} + +.uploader-section + .section-tight { + padding-top: 1.25rem; } .img-container { - width: 100%; + --dominant-color: transparent; + background: var(--surface); + border: 1px solid var(--line); + border-radius: 8px; + box-shadow: 0 16px 40px rgba(23, 32, 38, 0.1); display: flex; - margin: 10px; - justify-content: center; - align-items: center; flex-direction: column; - border: 1px solid #ccc; - border-radius: 20px; overflow: hidden; - --dominant-color: transparent; - box-shadow: 0 0 5px 0 var(--dominant-color); } .img-color-container { - width: 100%; - padding: 10px; - display: flex; - justify-content: space-evenly; align-items: center; - font-size: 20px; + display: flex; + gap: 1rem; + justify-content: space-between; + padding: 1rem; } .img-color-container .circle { - width: 100px; - height: 100px; - border-radius: 100px; - border: 1px solid rgba(0, 0, 0, 0.5); background-color: var(--dominant-color); + border: 1px solid rgba(23, 32, 38, 0.2); + border-radius: 50%; + flex: 0 0 auto; + height: 72px; + width: 72px; } .image { background: url(../img/transparent.png) repeat; } -input { - display: none; +.image img { + height: auto; + width: 100%; } -img { - object-fit: unset; - border-bottom: 1px solid #ddd; +input[type='file'] { + display: none; } diff --git a/css/style.css b/css/style.css index b9af47a..3bab495 100644 --- a/css/style.css +++ b/css/style.css @@ -1,106 +1,471 @@ -@import 'https://fonts.googleapis.com/css2?family=Lato:ital,wght@0,100;0,300;0,400;0,700;0,900;1,100;1,300;1,400;1,700;1,900&display=swap'; +@import 'https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&display=swap'; + +:root { + --bg: #f7f4ef; + --surface: #ffffff; + --surface-soft: #f0ece4; + --ink: #172026; + --muted: #65717a; + --line: #ddd5c9; + --brand: #006d77; + --brand-dark: #034e55; + --accent: #d95f39; + --green: #4f7d5f; + --shadow: 0 18px 50px rgba(23, 32, 38, 0.12); +} * { + box-sizing: border-box; margin: 0; padding: 0; - box-sizing: border-box; } -ul { - list-style: none; +html { + scroll-behavior: smooth; +} + +body { + background: var(--bg); + color: var(--ink); + font-family: Inter, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; + line-height: 1.6; +} + +body::before { + background: + linear-gradient(90deg, rgba(23, 32, 38, 0.04) 1px, transparent 1px), + linear-gradient(rgba(23, 32, 38, 0.04) 1px, transparent 1px); + background-size: 44px 44px; + content: ""; + inset: 0; + pointer-events: none; + position: fixed; + z-index: -1; } a { - color: #0099bb; + color: var(--brand); text-decoration: none; - position: relative; } -html { - scroll-behavior: smooth; +a:hover { + color: var(--brand-dark); } -body { - background: #fefefe; - font-family: Lato, sans-serif; +img { + display: block; + max-width: 100%; + user-select: none; } -header { +code { + background: rgba(0, 109, 119, 0.1); + border-radius: 5px; + color: var(--brand-dark); + font-family: "SFMono-Regular", Consolas, "Liberation Mono", monospace; + font-size: 0.92em; + padding: 0.1rem 0.35rem; +} + +pre { + background: #172026; + border-radius: 8px; + color: #f8f4ea; + line-height: 1.55; + margin: 1rem 0; + overflow-x: auto; + padding: 1rem; +} + +pre code { + background: transparent; + color: inherit; + padding: 0; +} + +table { + border-collapse: collapse; width: 100%; - top: 0; +} + +th, +td { + border-bottom: 1px solid var(--line); + padding: 0.9rem; + text-align: left; + vertical-align: top; +} + +th { + color: var(--ink); + font-size: 0.8rem; + letter-spacing: 0.04em; + text-transform: uppercase; +} + +.site-header { + background: rgba(247, 244, 239, 0.92); + border-bottom: 1px solid rgba(221, 213, 201, 0.9); + backdrop-filter: blur(14px); position: sticky; - user-select: none; - box-shadow: 0 1px 2px 1px #ddd; + top: 0; + z-index: 10; } -header ul { +.nav { + align-items: center; display: flex; - flex-direction: row; + gap: 1rem; + justify-content: space-between; + margin: 0 auto; + max-width: 1180px; + min-height: 72px; + padding: 0 1.25rem; +} + +.brand { align-items: center; - height: 40px; - background: #fff; - justify-content: center; - border-radius: 5px; + color: var(--ink); + display: inline-flex; + font-weight: 800; + gap: 0.75rem; + letter-spacing: -0.01em; } -header ul li { - margin: 5px; - padding: 5px; - position: relative; - border-radius: 5px; - border: 1px solid transparent; +.brand-mark { + background: conic-gradient(from 35deg, #006d77, #d95f39, #f6bd60, #4f7d5f, #006d77); + border: 2px solid #fff; + border-radius: 50%; + box-shadow: 0 6px 18px rgba(23, 32, 38, 0.18); + height: 34px; + width: 34px; } -header ul li.active { - background-color: #09c; +.nav-links { + align-items: center; + display: flex; + gap: 0.35rem; + list-style: none; } -header ul li:hover { - border: 1px solid #09c; +.nav-links a { + border-radius: 999px; + color: var(--ink); + display: inline-flex; + font-size: 0.95rem; + font-weight: 600; + padding: 0.55rem 0.85rem; } -header ul li.active > a { +.nav-links a:hover, +.nav-links .active > a { + background: var(--ink); color: #fff; - pointer-events: none; } -header ul li ul { - height: auto; - max-height: 0; - transition: all 0.5s ease-in-out; +.nav-links li { + position: relative; +} + +.nav-links ul { + background: var(--surface); + border: 1px solid var(--line); + border-radius: 8px; + box-shadow: var(--shadow); + display: none; + left: 0; + list-style: none; + min-width: 180px; + padding: 0.35rem; position: absolute; - flex-direction: column; - align-items: flex-start; - overflow: hidden; - box-shadow: 0 0 0 0 #000; - min-width: 100px; - border-radius: 5px; + top: 100%; } -header ul li:hover ul { - max-height: 500px; - box-shadow: 0 1px 3px 0 #000; +.nav-links li:hover ul, +.nav-links li:focus-within ul { + display: block; } -img { - width: 100%; +.container { + margin: 0 auto; + max-width: 1180px; + padding: 0 1.25rem; +} + +.section { + padding: 4.5rem 0; +} + +.section-tight { + padding: 2.5rem 0; +} + +.hero { + display: grid; + gap: 2.5rem; + grid-template-columns: minmax(0, 1.05fr) minmax(320px, 0.95fr); + min-height: calc(100vh - 72px); + padding: 4rem 0 2.5rem; +} + +.hero-content { + align-self: center; +} + +.eyebrow { + color: var(--accent); + font-size: 0.78rem; + font-weight: 800; + letter-spacing: 0.14em; + margin-bottom: 1rem; + text-transform: uppercase; +} + +.hero h1, +.page-title h1 { + font-size: clamp(2.6rem, 7vw, 5.8rem); + letter-spacing: 0; + line-height: 0.95; + max-width: 780px; +} + +.lead { + color: var(--muted); + font-size: clamp(1.05rem, 2vw, 1.28rem); + margin-top: 1.35rem; + max-width: 680px; +} + +.actions { + display: flex; + flex-wrap: wrap; + gap: 0.8rem; + margin-top: 2rem; +} + +.button { + align-items: center; + background: var(--ink); + border: 1px solid var(--ink); + border-radius: 999px; + color: #fff; + display: inline-flex; + font-weight: 800; + min-height: 44px; + padding: 0.65rem 1rem; +} + +.button:hover { + background: var(--brand); + border-color: var(--brand); + color: #fff; +} + +.button-secondary { + background: transparent; + color: var(--ink); +} + +.button-secondary:hover { + background: var(--surface); + color: var(--brand-dark); +} + +.hero-visual { + align-self: end; + background: var(--surface); + border: 1px solid var(--line); + border-radius: 8px; + box-shadow: var(--shadow); + overflow: hidden; +} + +.hero-visual img { + aspect-ratio: 4 / 3; height: 100%; object-fit: cover; - user-select: none; - pointer-events: none; + width: 100%; } -.container { - padding: 0 15px; +.color-strip { + display: grid; + grid-template-columns: repeat(5, 1fr); + min-height: 72px; +} + +.color-strip span:nth-child(1) { background: #006d77; } +.color-strip span:nth-child(2) { background: #83c5be; } +.color-strip span:nth-child(3) { background: #f6bd60; } +.color-strip span:nth-child(4) { background: #d95f39; } +.color-strip span:nth-child(5) { background: #172026; } + +.panel { + background: var(--surface); + border: 1px solid var(--line); + border-radius: 8px; + box-shadow: 0 12px 30px rgba(23, 32, 38, 0.08); + padding: 1.25rem; +} + +.grid { + display: grid; + gap: 1rem; +} + +.grid-3 { + grid-template-columns: repeat(3, minmax(0, 1fr)); +} + +.grid-2 { + grid-template-columns: repeat(2, minmax(0, 1fr)); +} + +.feature h3, +.demo-card h3 { + font-size: 1.1rem; + line-height: 1.25; +} + +.feature p, +.demo-card p { + color: var(--muted); + margin-top: 0.55rem; +} + +.demo-card { + overflow: hidden; + padding: 0; +} + +.demo-card img { + aspect-ratio: 16 / 10; + object-fit: cover; + width: 100%; +} + +.demo-card-content { + display: block; + padding: 1.25rem 1.5rem 1.45rem; +} + +.page-title { + padding: 4rem 0 2rem; +} + +.doc-layout { + display: grid; + gap: 2rem; + grid-template-columns: 220px minmax(0, 1fr); +} + +.toc { + align-self: start; + background: var(--surface); + border: 1px solid var(--line); + border-radius: 8px; + padding: 1rem; + position: sticky; + top: 92px; +} + +.toc a { + color: var(--muted); + display: block; + font-weight: 700; + padding: 0.35rem 0; +} + +.toc a:hover { + color: var(--brand); +} + +.docs-content { + min-width: 0; +} + +.docs-content h2 { + font-size: 1.8rem; + margin: 2.5rem 0 1rem; +} + +.docs-content h2:first-child { + margin-top: 0; +} + +.table-wrap { + background: var(--surface); + border: 1px solid var(--line); + border-radius: 8px; + overflow-x: auto; +} + +.demo-heading { + align-items: end; display: flex; - flex-direction: column; + gap: 1rem; + justify-content: space-between; + padding: 3.5rem 0 1.5rem; +} + +.demo-heading h1 { + font-size: clamp(2.2rem, 5vw, 4.4rem); + line-height: 1; +} + +.demo-heading p { + color: var(--muted); + margin-top: 0.65rem; + max-width: 620px; } -h2 { - padding: 30px 0 20px; - text-align: center; +.demo-heading .button { + flex: 0 0 auto; + justify-content: center; + min-width: 136px; + white-space: nowrap; +} + +.site-footer { + border-top: 1px solid var(--line); + color: var(--muted); + margin-top: 4rem; + padding: 2rem 0; } -p { - text-align: center; +@media (max-width: 820px) { + .nav { + align-items: flex-start; + flex-direction: column; + padding-bottom: 0.8rem; + padding-top: 0.8rem; + } + + .nav-links { + flex-wrap: wrap; + } + + .nav-links ul { + position: static; + } + + .hero, + .grid-2, + .grid-3, + .doc-layout { + grid-template-columns: 1fr; + } + + .hero { + min-height: auto; + padding-top: 3rem; + } + + .toc { + position: static; + } + + .demo-heading { + align-items: flex-start; + flex-direction: column; + } } diff --git a/documentation.html b/documentation.html index b81e633..f2e9697 100644 --- a/documentation.html +++ b/documentation.html @@ -1,206 +1,216 @@ - + - - - - Get dominant color - - + + + + Dominant Color - Documentation + + -
- + -
- -

Dominant color

-

Get dominant color from images using only JavaScript

-

Installation

-
npm i @rtcoder/dominant-color
-
-

Usage

-
import {getDominantColor} from "@rtcoder/dominant-color";
-
-const img = document.querySelector('img');
-
-getDominantColor(img, {
-    downScaleFactor: 1,
-    skipPixels: 0,
-    colorsPaletteLength: 5,
-    paletteWithCountOfOccurrences: false,
-    colorFormat: 'rgb',
-    callback: (color, palette) => {
-       // your code here
-    }
+
+
+

Documentation

+

Use color extraction where images already live.

+

+ The library accepts DOM image sources, canvas output, object URLs, blobs, and files. It ships ESM and CJS builds with TypeScript declarations. +

+
+ +
+ + +
+
+

Installation

+
npm i @rtcoder/dominant-color
+
+ +
+

Imports

+

Use ESM in modern apps:

+
import { getDominantColor, getDominantColorAsync } from '@rtcoder/dominant-color';
+

CommonJS consumers can use require:

+
const { getDominantColor } = require('@rtcoder/dominant-color');
+
+ +
+

Usage

+

Promise-based API:

+
const img = document.querySelector('img');
+
+const result = await getDominantColorAsync(img, {
+  colorFormat: 'hex',
+  colorQuantization: 'median-cut',
+  colorsPaletteLength: 6,
 });
-
-

Config options

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDefault valueDescription
downScaleFactornumber1factor of scale down of image, recommended to use for many large images
skipPixelsnumber0when larger than 0, skips every n pixels of while determine dominant color, recommended to use for large - images -
colorsPaletteLengthnumber5length of returned palette of colors
paletteWithCountOfOccurrencesbooleanfalsedetermines whether to return colors with the number of occurrences
colorFormatstring‘rgb’defines the format of the returned colors, available values are ‘rgb’, ‘hsl’ and ‘hex’
callbackfunction[empty function]callback function
-

Interfaces

-
type ColorFormat = 'rgb' | 'hsl' | 'hex';
+console.log(result.dominant, result.colorsPalette);
+

Callback API:

+
getDominantColor(img, {
+  colorFormat: 'rgb',
+  callback: (dominant, colorsPalette) => {
+    console.log(dominant, colorsPalette);
+  },
+  errorCallback: (error) => {
+    console.error(error);
+  },
+});
+
+ +
+

Image sources

+
+
+

DOM and canvas

+

HTMLImageElement, HTMLCanvasElement, and ImageBitmap can be passed directly.

+
+
+

Files and URLs

+

Use URL strings, Blob, or File. Blob object URLs are created and revoked internally.

+
+
+
+ +
+

Options

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDefaultDescription
downScaleFactornumber1Scales the source down before sampling. Useful for large images.
skipPixelsnumber0Skips every n pixels while reading image data.
colorsPaletteLengthnumber5Maximum number of colors returned in the palette.
colorQuantization'exact' | 'bucket' | 'median-cut''exact'Controls palette extraction. median-cut is best for balanced photo palettes.
colorBucketSizenumber24Bucket size used by colorQuantization: 'bucket'.
colorGroupingThresholdnumber0Groups nearby RGB values after counting or quantization.
paletteWithCountOfOccurrencesbooleanfalseReturns palette entries as { color, count }.
colorFormat'rgb' | 'hsl' | 'hex''rgb'Formats the dominant color and palette colors.
callbackfunctionempty functionReceives dominant and colorsPalette.
errorCallbackfunctionempty functionReceives image loading, canvas, and processing errors.
+
+
+ +
+

Types

+
type ColorFormat = 'rgb' | 'hsl' | 'hex';
+type ColorQuantization = 'exact' | 'bucket' | 'median-cut';
+type DominantColorSource = HTMLImageElement | HTMLCanvasElement | ImageBitmap | string | Blob;
 
 interface PrimaryColor {
   color: string;
   count: number;
 }
 
-interface DominantColorOptions {
-  downScaleFactor: number;
-  skipPixels: number;
-  colorsPaletteLength: number;
-  paletteWithCountOfOccurrences: boolean;
-  colorFormat: ColorFormat;
-  callback: DominantColorCallback;
+interface DominantColorResult {
+  dominant: string;
+  colorsPalette: string[] | PrimaryColor[];
 }
 
-type DominantColorCallback = (dominant: string, colorsPalette: (string[]) | (PrimaryColor[])) => void;
-
-function getDominantColor(element: HTMLImageElement, options: Partial<DominantColorOptions>): void
-
- -
- +function getDominantColor( + source: DominantColorSource, + options?: Partial<DominantColorOptions> +): void; + +function getDominantColorAsync( + source: DominantColorSource, + options?: Partial<DominantColorOptions> +): Promise<DominantColorResult>;
+ + +
+ + +
+
Documentation for @rtcoder/dominant-color.
+
diff --git a/examples/music-app/css/style.css b/examples/music-app/css/style.css index 1a44965..4177c70 100644 --- a/examples/music-app/css/style.css +++ b/examples/music-app/css/style.css @@ -3,6 +3,7 @@ .music-app-example { display: flex; justify-content: center; + padding-bottom: 4rem; } .music-app-example .phone-container { @@ -14,12 +15,13 @@ width: 300px; height: 600px; display: flex; - border: 2px solid rgba(0, 0, 0, 0.3); + border: 8px solid #172026; padding: 10px; - border-radius: 30px; + border-radius: 34px; overflow: hidden; user-select: none; background: var(--app-dominant-color); + box-shadow: 0 22px 60px rgba(23, 32, 38, 0.24); transition: background 0.4s ease-in-out; } @@ -29,7 +31,7 @@ display: flex; border-radius: 20px; overflow: hidden; - box-shadow: 5px 5px 10px rgba(255, 255, 255, .2), -5px -5px 10px rgba(255, 255, 255, .2); + box-shadow: inset 0 0 0 1px rgba(255, 255, 255, .24); } .music-app-example .app .title { @@ -57,7 +59,7 @@ .music-app-example .slides-container { width: 100%; display: flex; - padding: 40px 0 10px; + padding: 26px 0 8px; } .music-app-example .slides { @@ -88,6 +90,12 @@ box-shadow: var(--shadow); } +.music-app-example .slides .slide img { + height: 100%; + object-fit: cover; + width: 100%; +} + .music-app-example .title, .music-app-example .author { width: 100%; @@ -109,7 +117,7 @@ width: 100%; display: flex; flex-direction: column; - padding: 25px 10px 20px; + padding: 18px 10px 14px; } .music-app-example .controls .progress { @@ -183,7 +191,7 @@ flex-direction: row; justify-content: space-around; align-items: flex-start; - margin-top: 50px; + margin-top: 42px; } .music-app-example .controls .buttons .play-pause, @@ -213,7 +221,8 @@ display: flex; flex-direction: row; justify-content: space-between; - padding: 0 10px; + margin-top: auto; + padding: 0 10px 12px; } .music-app-example .app-footer .repeat, @@ -234,6 +243,11 @@ transition: color 0.4s ease-in-out; } +.music-app-example .material-icons { + font-size: 24px; + line-height: 1; +} + .music-app-example .app-header .back-button:active, .music-app-example .app-header .more:active, .music-app-example .app-footer .repeat:active, diff --git a/examples/music-app/index.html b/examples/music-app/index.html index 2d77ebf..25476f2 100644 --- a/examples/music-app/index.html +++ b/examples/music-app/index.html @@ -2,31 +2,43 @@ - + - Get dominant color - Music app + Dominant Color - Music app example -
-
    -
  • Home
  • -
  • Documentation
  • -
  • - Examples + -
    -

    Music app example

    +
    +
    +
    +

    Adaptive UI demo

    +

    Album art drives the interface.

    +

    The player extracts colors from cover images and applies the palette to the controls and background.

    +
    + Palette demo +
    @@ -93,7 +105,11 @@

    Music app example

    - + + +
    +
    Music app example using dynamic colors from album art.
    +
    diff --git a/examples/palette/css/style.css b/examples/palette/css/style.css index 0959680..705c24a 100644 --- a/examples/palette/css/style.css +++ b/examples/palette/css/style.css @@ -1,68 +1,58 @@ @import '../../../css/style.css'; .palette-example { - display: flex; - flex-direction: row; - justify-content: center; - align-items: center; - flex-wrap: wrap; + display: grid; + gap: 1.25rem; + grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); + padding-bottom: 4rem; } .palette-example .image-palette { - --dominant-color: ''; - width: 350px; - display: flex; - flex-direction: row; - margin: 5px; - padding: 5px; - border: 1px solid var(--dominant-color); - border-radius: 10px; + --dominant-color: transparent; + background: var(--surface); + border: 1px solid var(--line); + border-radius: 8px; + box-shadow: 0 14px 32px rgba(23, 32, 38, 0.1); + display: grid; + grid-template-columns: minmax(0, 1fr) 58px; overflow: hidden; - transition: background-color 0.2s ease-in-out; -} - - -.palette-example .image-palette:hover { - background-color: var(--dominant-color); -} - -.palette-example .image-palette:hover .image { - overflow: visible; } .palette-example .image { - width: 300px; - height: 300px; - display: flex; - overflow: hidden; - border-radius: 10px; - padding: 10px; background-color: var(--dominant-color); + min-height: 300px; + padding: 0.75rem; + transition: background-color 0.2s ease-in-out; } .palette-example .img-container { - display: flex; + border-radius: 8px; + height: 100%; overflow: hidden; - border-radius: 300px; width: 100%; +} + +.palette-example img { height: 100%; + object-fit: cover; + width: 100%; } .palette-example .palette { - height: 100%; - width: 50px; + align-items: center; + background: #f4efe7; display: flex; flex-direction: column; - align-items: center; - justify-content: space-between; + gap: 0.4rem; + justify-content: center; + padding: 0.7rem 0.45rem; } .palette-example .palette > div { - width: 40px; - height: 40px; - display: flex; background-image: url(../img/leather.png); background-position: center; - border-radius: 40px; - margin-bottom: 3px; + border-radius: 50%; + box-shadow: 0 4px 10px rgba(23, 32, 38, 0.14); + height: 38px; + width: 38px; } diff --git a/examples/palette/index.html b/examples/palette/index.html index 66961c5..431b4ae 100644 --- a/examples/palette/index.html +++ b/examples/palette/index.html @@ -2,31 +2,43 @@ - + - Get dominant color - examples + Dominant Color - Palette example -
    -
      -
    • Home
    • -
    • Documentation
    • -
    • - Examples + -
      -

      Palette example

      +
      +
      +
      +

      Palette demo

      +

      Images with extracted palettes.

      +

      Each card reads the image, detects a dominant color, and renders a compact palette beside the source.

      +
      + View API +
      @@ -65,7 +77,11 @@

      Palette example

      -
      + + +
      +
      Palette extraction example using the browser build.
      +
      diff --git a/examples/palette/js/index.js b/examples/palette/js/index.js index 14c563c..f289d75 100644 --- a/examples/palette/js/index.js +++ b/examples/palette/js/index.js @@ -66,7 +66,7 @@ function callbackAfterGetColor(imgNode) { imgNode.parentNode.parentNode.parentNode.querySelector('.palette').innerHTML = colors.map(c => { const v = lightOrDark(c) === 'light' ? 0 : 255; - const dotStyle = `background-color:rgb(${c}); border: 1px solid rgba(${v},${v},${v},0.45)`; + const dotStyle = `background-color:${c}; border: 1px solid rgba(${v},${v},${v},0.45)`; return `
      `; }).join(''); }; diff --git a/index.html b/index.html index adaa401..916ecfc 100644 --- a/index.html +++ b/index.html @@ -1,43 +1,117 @@ - + - - - - Get dominant color - + + + + Dominant Color - JavaScript image color extraction + + -
      - + -
      +
      +
      +
      +

      Tiny image intelligence for the browser

      +

      Extract colors from real images.

      +

      + Get a dominant color and palette from images, canvases, blobs, URLs, or image elements with callback and Promise APIs. +

      + +
      +
      + Sample landscape used to demonstrate palette extraction + +
      +
      -

      Get dominant color of image

      -

      Upload image below and check the dominant color of image

      +
      +
      +
      +

      Modern input support

      +

      Use image elements, canvas, ImageBitmap, URL strings, Blob, or File objects.

      +
      +
      +

      Callback or Promise

      +

      Keep existing callback code or use the async API in modern application flows.

      +
      +
      +

      Photo-ready palettes

      +

      Choose exact RGB counting, fast buckets, or median-cut quantization for balanced palettes.

      +
      +
      +
      - - +
      +
      +
      +

      Interactive demo

      +

      Drop an image and inspect its color.

      +

      The uploader runs locally in your browser and shows the detected dominant color for each image.

      +
      -
      + + +
      + - +
      + +
      + +
      +
      Built for browser image workflows with TypeScript declarations, ESM, and CJS builds.
      +
      + + From 145b7de1d2c8612a3dbbf2a310760805e453b88d Mon Sep 17 00:00:00 2001 From: rtcoder Date: Wed, 20 May 2026 21:00:19 +0200 Subject: [PATCH 8/9] Bump version to 0.2.0 for API changes and feature updates --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 50d062b..cc5c322 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@rtcoder/dominant-color", - "version": "0.1.4", + "version": "0.2.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@rtcoder/dominant-color", - "version": "0.1.4", + "version": "0.2.0", "license": "ISC", "devDependencies": { "@types/jest": "^27.0.2", diff --git a/package.json b/package.json index e48d638..9c74f04 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@rtcoder/dominant-color", - "version": "0.1.4", + "version": "0.2.0", "description": "Get dominant color and palette of colors from an image", "type": "module", "main": "dist/cjs/dominant-color.js", From 96056adff350ff2cbaca977fb4982bb85e808e4b Mon Sep 17 00:00:00 2001 From: rtcoder Date: Wed, 20 May 2026 21:04:09 +0200 Subject: [PATCH 9/9] Update CI workflow to use latest actions and Node.js version --- .github/workflows/ci.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 217a3f6..ed21913 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -14,12 +14,12 @@ jobs: steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@v6 - name: Setup Node.js - uses: actions/setup-node@v4 + uses: actions/setup-node@v6 with: - node-version: 20 + node-version: 24 cache: npm - name: Install dependencies