@thi.ng/pixel-dominant-colors 1.1.49 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +15 -1
- package/README.md +14 -10
- package/api.d.ts +34 -0
- package/api.js +0 -0
- package/index.d.ts +3 -52
- package/index.js +3 -20
- package/kmeans.d.ts +20 -0
- package/kmeans.js +15 -0
- package/mean-cut.d.ts +6 -0
- package/mean-cut.js +19 -0
- package/package.json +20 -4
- package/utils.d.ts +4 -0
- package/utils.js +12 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Change Log
|
|
2
2
|
|
|
3
|
-
- **Last updated**: 2025-06-
|
|
3
|
+
- **Last updated**: 2025-06-24T21:39:38Z
|
|
4
4
|
- **Generator**: [thi.ng/monopub](https://thi.ng/monopub)
|
|
5
5
|
|
|
6
6
|
All notable changes to this project will be documented in this file.
|
|
@@ -11,6 +11,20 @@ See [Conventional Commits](https://conventionalcommits.org/) for commit guidelin
|
|
|
11
11
|
**Note:** Unlisted _patch_ versions only involve non-code or otherwise excluded changes
|
|
12
12
|
and/or version bumps of transitive dependencies.
|
|
13
13
|
|
|
14
|
+
# [2.0.0](https://github.com/thi-ng/umbrella/tree/@thi.ng/pixel-dominant-colors@2.0.0) (2025-06-24)
|
|
15
|
+
|
|
16
|
+
#### 🛑 Breaking changes
|
|
17
|
+
|
|
18
|
+
- update dominantColors() ([9cf7a48](https://github.com/thi-ng/umbrella/commit/9cf7a48))
|
|
19
|
+
- BREAKING CHANGE: rename `dominantColors()` => `dominantColorsKmeans()`, remove `dominantColorsArray()`
|
|
20
|
+
- merge `dominantColors()` & `dominantColorsArray()` => `dominantColorsKmeans()`
|
|
21
|
+
- add `DominantColor` result type
|
|
22
|
+
- add filterSamples helper
|
|
23
|
+
|
|
24
|
+
#### 🚀 Features
|
|
25
|
+
|
|
26
|
+
- add dominantColorsMeanCut()/dominantColorsMedianCut() ([2ab48c7](https://github.com/thi-ng/umbrella/commit/2ab48c7))
|
|
27
|
+
|
|
14
28
|
### [1.1.2](https://github.com/thi-ng/umbrella/tree/@thi.ng/pixel-dominant-colors@1.1.2) (2024-07-25)
|
|
15
29
|
|
|
16
30
|
#### ♻️ Refactoring
|
package/README.md
CHANGED
|
@@ -33,15 +33,18 @@ extracted from the [@thi.ng/pixel](https://thi.ng/pixel) package.
|
|
|
33
33
|
|
|
34
34
|
### Dominant color extraction
|
|
35
35
|
|
|
36
|
-
The
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
clustering](https://github.com/thi-ng/umbrella/tree/develop/packages/k-means)
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
36
|
+
The package provides several methods to extract the dominant colors from a given image:
|
|
37
|
+
|
|
38
|
+
- [`dominantColorsKmeans()`](https://docs.thi.ng/umbrella/pixel/functions/dominantColorsKmeans.html)
|
|
39
|
+
uses [k-means clustering](https://github.com/thi-ng/umbrella/tree/develop/packages/k-means)
|
|
40
|
+
- [`dominantColorsMeanCut()`](https://docs.thi.ng/umbrella/pixel/functions/dominantColorsMeanCut.html)
|
|
41
|
+
- [`dominantColorsMedianCut()`](https://docs.thi.ng/umbrella/pixel/functions/dominantColorsMedianCut.html)
|
|
42
|
+
|
|
43
|
+
In all cases the clustering can be configured. The functions return an array of
|
|
44
|
+
`{ color, area }` objects (sorted by descending area), where `color` is a
|
|
45
|
+
cluster's dominant color (in the format of the source image) and `area` the
|
|
46
|
+
normalized cluster size (number of selected pixels over total number of pixels
|
|
47
|
+
in the image).
|
|
45
48
|
|
|
46
49
|
Also see the [dominant colors example project & online
|
|
47
50
|
tool](https://demo.thi.ng/umbrella/dominant-colors/) based on this function.
|
|
@@ -123,13 +126,14 @@ For Node.js REPL:
|
|
|
123
126
|
const pdc = await import("@thi.ng/pixel-dominant-colors");
|
|
124
127
|
```
|
|
125
128
|
|
|
126
|
-
Package sizes (brotli'd, pre-treeshake): ESM:
|
|
129
|
+
Package sizes (brotli'd, pre-treeshake): ESM: 381 bytes
|
|
127
130
|
|
|
128
131
|
## Dependencies
|
|
129
132
|
|
|
130
133
|
- [@thi.ng/api](https://github.com/thi-ng/umbrella/tree/develop/packages/api)
|
|
131
134
|
- [@thi.ng/k-means](https://github.com/thi-ng/umbrella/tree/develop/packages/k-means)
|
|
132
135
|
- [@thi.ng/pixel](https://github.com/thi-ng/umbrella/tree/develop/packages/pixel)
|
|
136
|
+
- [@thi.ng/vectors](https://github.com/thi-ng/umbrella/tree/develop/packages/vectors)
|
|
133
137
|
|
|
134
138
|
Note: @thi.ng/api is in _most_ cases a type-only import (not used at runtime)
|
|
135
139
|
|
package/api.d.ts
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type { Fn2, NumericArray } from "@thi.ng/api";
|
|
2
|
+
/**
|
|
3
|
+
* Options for {@link dominantColors}, an extension of
|
|
4
|
+
* [KMeansOpts](https://docs.thi.ng/umbrella/k-means/interfaces/KMeansOpts.html).
|
|
5
|
+
*/
|
|
6
|
+
export interface DominantColorOpts {
|
|
7
|
+
/**
|
|
8
|
+
* Predicate used to only include pixels in the analysis for which the
|
|
9
|
+
* filter returns truthy result. E.g. to pre-exclude weakly saturated or
|
|
10
|
+
* dark colors etc. The second arg is the index of the pixel in the image's
|
|
11
|
+
* pixel buffer.
|
|
12
|
+
*
|
|
13
|
+
* If omitted, all pixels will be included (default).
|
|
14
|
+
*/
|
|
15
|
+
filter: Fn2<NumericArray, number, boolean>;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Result type for dominant color extraction functions
|
|
19
|
+
*/
|
|
20
|
+
export interface DominantColor {
|
|
21
|
+
/**
|
|
22
|
+
* RGB tuple
|
|
23
|
+
*/
|
|
24
|
+
color: number[];
|
|
25
|
+
/**
|
|
26
|
+
* Normalized area (based on number of samples)
|
|
27
|
+
*/
|
|
28
|
+
area: number;
|
|
29
|
+
/**
|
|
30
|
+
* Sample IDs (indices) belonging to this cluster.
|
|
31
|
+
*/
|
|
32
|
+
items?: number[];
|
|
33
|
+
}
|
|
34
|
+
//# sourceMappingURL=api.d.ts.map
|
package/api.js
ADDED
|
File without changes
|
package/index.d.ts
CHANGED
|
@@ -1,53 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* Options for {@link dominantColors}, an extension of
|
|
6
|
-
* [KMeansOpts](https://docs.thi.ng/umbrella/k-means/interfaces/KMeansOpts.html).
|
|
7
|
-
*/
|
|
8
|
-
export interface DominantColorOpts extends KMeansOpts {
|
|
9
|
-
/**
|
|
10
|
-
* Predicate used to only include pixels in the analysis for which the
|
|
11
|
-
* filter returns truthy result. E.g. to pre-exclude weakly saturated or
|
|
12
|
-
* dark colors etc. The second arg is the index of the pixel in the image's
|
|
13
|
-
* pixel buffer.
|
|
14
|
-
*
|
|
15
|
-
* If omitted, all pixels will be included (default).
|
|
16
|
-
*/
|
|
17
|
-
filter: Fn2<Float32Array, number, boolean>;
|
|
18
|
-
}
|
|
19
|
-
/**
|
|
20
|
-
* Takes a {@link FloatBuffer} and applies k-means clustering to extract the
|
|
21
|
-
* `num` dominant colors from the given image. The clustering can be configured
|
|
22
|
-
* via optionally provided `opts`. Returns array of `{ color, area }` objects
|
|
23
|
-
* (sorted by descending area), where `color` is a cluster's dominant color and
|
|
24
|
-
* `area` the normalized cluster size.
|
|
25
|
-
*
|
|
26
|
-
* @remarks
|
|
27
|
-
* This function is syntax sugar for {@link dominantColorsArray}.
|
|
28
|
-
*
|
|
29
|
-
* See thi.ng/k-means for details about clustering implementation & options.
|
|
30
|
-
*
|
|
31
|
-
* @param img -
|
|
32
|
-
* @param num -
|
|
33
|
-
* @param opts -
|
|
34
|
-
*/
|
|
35
|
-
export declare const dominantColors: (img: FloatBuffer, num: number, opts?: Partial<DominantColorOpts>) => {
|
|
36
|
-
color: number[];
|
|
37
|
-
area: number;
|
|
38
|
-
ids: number[];
|
|
39
|
-
}[];
|
|
40
|
-
/**
|
|
41
|
-
* Similar to {@link dominantColors}, but accepting an array of color samples
|
|
42
|
-
* instead of a `FloatBuffer` image.
|
|
43
|
-
*
|
|
44
|
-
* @param num
|
|
45
|
-
* @param samples
|
|
46
|
-
* @param opts
|
|
47
|
-
*/
|
|
48
|
-
export declare const dominantColorsArray: (num: number, samples: NumericArray[], opts?: Partial<KMeansOpts>) => {
|
|
49
|
-
color: number[];
|
|
50
|
-
area: number;
|
|
51
|
-
ids: number[];
|
|
52
|
-
}[];
|
|
1
|
+
export * from "./api.js";
|
|
2
|
+
export * from "./kmeans.js";
|
|
3
|
+
export * from "./mean-cut.js";
|
|
53
4
|
//# sourceMappingURL=index.d.ts.map
|
package/index.js
CHANGED
|
@@ -1,20 +1,3 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
const filter = opts?.filter || (() => true);
|
|
5
|
-
let i = 0;
|
|
6
|
-
for (let p of img) {
|
|
7
|
-
if (filter(p, i)) samples.push(p);
|
|
8
|
-
i++;
|
|
9
|
-
}
|
|
10
|
-
return samples.length ? dominantColorsArray(num, samples, opts) : [];
|
|
11
|
-
};
|
|
12
|
-
const dominantColorsArray = (num, samples, opts) => kmeans(Math.min(num, samples.length), samples, opts).sort((a, b) => b.items.length - a.items.length).map((c) => ({
|
|
13
|
-
color: [...c.centroid],
|
|
14
|
-
area: c.items.length / samples.length,
|
|
15
|
-
ids: c.items
|
|
16
|
-
}));
|
|
17
|
-
export {
|
|
18
|
-
dominantColors,
|
|
19
|
-
dominantColorsArray
|
|
20
|
-
};
|
|
1
|
+
export * from "./api.js";
|
|
2
|
+
export * from "./kmeans.js";
|
|
3
|
+
export * from "./mean-cut.js";
|
package/kmeans.d.ts
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { NumericArray } from "@thi.ng/api";
|
|
2
|
+
import type { KMeansOpts } from "@thi.ng/k-means";
|
|
3
|
+
import type { FloatBuffer } from "@thi.ng/pixel/float";
|
|
4
|
+
import type { DominantColor, DominantColorOpts } from "./api.js";
|
|
5
|
+
/**
|
|
6
|
+
* Takes a {@link FloatBuffer} and applies k-means clustering to extract the
|
|
7
|
+
* `num` dominant colors from the given image. The clustering can be configured
|
|
8
|
+
* via optionally provided `opts`. Returns array of `{ color, area }` objects
|
|
9
|
+
* (sorted by descending area), where `color` is a cluster's dominant color and
|
|
10
|
+
* `area` the normalized cluster size.
|
|
11
|
+
*
|
|
12
|
+
* @remarks
|
|
13
|
+
* See thi.ng/k-means for details about clustering implementation & options.
|
|
14
|
+
*
|
|
15
|
+
* @param img -
|
|
16
|
+
* @param num -
|
|
17
|
+
* @param opts -
|
|
18
|
+
*/
|
|
19
|
+
export declare const dominantColorsKmeans: (img: FloatBuffer | NumericArray[], num: number, opts?: Partial<DominantColorOpts & KMeansOpts>) => DominantColor[];
|
|
20
|
+
//# sourceMappingURL=kmeans.d.ts.map
|
package/kmeans.js
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { kmeans } from "@thi.ng/k-means/kmeans";
|
|
2
|
+
import { filterSamples } from "./utils.js";
|
|
3
|
+
const dominantColorsKmeans = (img, num, opts) => {
|
|
4
|
+
const samples = opts?.filter ? filterSamples(opts.filter, img) : Array.isArray(img) ? img : [...img];
|
|
5
|
+
return samples.length ? kmeans(Math.min(num, samples.length), samples, opts).sort((a, b) => b.items.length - a.items.length).map(
|
|
6
|
+
(c) => ({
|
|
7
|
+
color: [...c.centroid],
|
|
8
|
+
area: c.items.length / samples.length,
|
|
9
|
+
ids: c.items
|
|
10
|
+
})
|
|
11
|
+
) : [];
|
|
12
|
+
};
|
|
13
|
+
export {
|
|
14
|
+
dominantColorsKmeans
|
|
15
|
+
};
|
package/mean-cut.d.ts
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { NumericArray } from "@thi.ng/api";
|
|
2
|
+
import type { FloatBuffer } from "@thi.ng/pixel/float";
|
|
3
|
+
import type { DominantColor, DominantColorOpts } from "./api.js";
|
|
4
|
+
export declare const dominantColorsMeanCut: (img: FloatBuffer | NumericArray[], num: number, opts?: Partial<DominantColorOpts>) => DominantColor[];
|
|
5
|
+
export declare const dominantColorsMedianCut: (img: FloatBuffer | NumericArray[], num: number, opts?: Partial<DominantColorOpts>) => DominantColor[];
|
|
6
|
+
//# sourceMappingURL=mean-cut.d.ts.map
|
package/mean-cut.js
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { computeCutWith } from "@thi.ng/k-means/mean-cut";
|
|
2
|
+
import { mean, vmean } from "@thi.ng/vectors/mean";
|
|
3
|
+
import { vmedian } from "@thi.ng/vectors/median";
|
|
4
|
+
import { filterSamples } from "./utils.js";
|
|
5
|
+
const dominantColorsMeanCut = (img, num, opts) => __dominantColors(vmean, img, num, opts);
|
|
6
|
+
const dominantColorsMedianCut = (img, num, opts) => __dominantColors(vmedian, img, num, opts);
|
|
7
|
+
const __dominantColors = (cut, img, num, opts) => {
|
|
8
|
+
const samples = opts?.filter ? filterSamples(opts.filter, img) : [...img];
|
|
9
|
+
return samples.length ? computeCutWith(cut, samples, samples[0].length, num).sort((a, b) => b.length - a.length).map(
|
|
10
|
+
(bin) => ({
|
|
11
|
+
color: mean([], bin),
|
|
12
|
+
area: bin.length / samples.length
|
|
13
|
+
})
|
|
14
|
+
) : [];
|
|
15
|
+
};
|
|
16
|
+
export {
|
|
17
|
+
dominantColorsMeanCut,
|
|
18
|
+
dominantColorsMedianCut
|
|
19
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@thi.ng/pixel-dominant-colors",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.0",
|
|
4
4
|
"description": "k-means based dominant color extraction from images/pixel buffers",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"module": "./index.js",
|
|
@@ -40,8 +40,9 @@
|
|
|
40
40
|
},
|
|
41
41
|
"dependencies": {
|
|
42
42
|
"@thi.ng/api": "^8.11.29",
|
|
43
|
-
"@thi.ng/k-means": "^
|
|
44
|
-
"@thi.ng/pixel": "^7.5.1"
|
|
43
|
+
"@thi.ng/k-means": "^2.0.0",
|
|
44
|
+
"@thi.ng/pixel": "^7.5.1",
|
|
45
|
+
"@thi.ng/vectors": "^8.3.1"
|
|
45
46
|
},
|
|
46
47
|
"devDependencies": {
|
|
47
48
|
"esbuild": "^0.25.5",
|
|
@@ -55,7 +56,10 @@
|
|
|
55
56
|
"dominant",
|
|
56
57
|
"image",
|
|
57
58
|
"k-means",
|
|
59
|
+
"mean",
|
|
60
|
+
"median",
|
|
58
61
|
"palette",
|
|
62
|
+
"quantize",
|
|
59
63
|
"typescript"
|
|
60
64
|
],
|
|
61
65
|
"publishConfig": {
|
|
@@ -75,6 +79,18 @@
|
|
|
75
79
|
"exports": {
|
|
76
80
|
".": {
|
|
77
81
|
"default": "./index.js"
|
|
82
|
+
},
|
|
83
|
+
"./api": {
|
|
84
|
+
"default": "./api.js"
|
|
85
|
+
},
|
|
86
|
+
"./kmeans": {
|
|
87
|
+
"default": "./kmeans.js"
|
|
88
|
+
},
|
|
89
|
+
"./mean-cut": {
|
|
90
|
+
"default": "./mean-cut.js"
|
|
91
|
+
},
|
|
92
|
+
"./utils": {
|
|
93
|
+
"default": "./utils.js"
|
|
78
94
|
}
|
|
79
95
|
},
|
|
80
96
|
"thi.ng": {
|
|
@@ -82,5 +98,5 @@
|
|
|
82
98
|
"year": 2021,
|
|
83
99
|
"screenshot": "pixel/dominant-colors-01.jpg"
|
|
84
100
|
},
|
|
85
|
-
"gitHead": "
|
|
101
|
+
"gitHead": "45e91ee75236e39fc87ea10fbabac1272bef62e3\n"
|
|
86
102
|
}
|
package/utils.d.ts
ADDED