https://github.com/sheraff/palette
https://github.com/sheraff/palette
Last synced: 12 months ago
JSON representation
- Host: GitHub
- URL: https://github.com/sheraff/palette
- Owner: Sheraff
- Created: 2024-09-15T17:21:35.000Z (over 1 year ago)
- Default Branch: main
- Last Pushed: 2024-12-08T19:48:38.000Z (over 1 year ago)
- Last Synced: 2025-06-11T08:08:21.344Z (12 months ago)
- Language: TypeScript
- Size: 5.47 MB
- Stars: 0
- Watchers: 1
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
# Color palette extraction
> [!WARNING]
> This library is still in development and the API is subject to change.
> - The entry point is `extractColors.ts`
> - use `pnpm test` to launch the tests
> - use `pnpm serve` to get a visual preview of what is happening on `localhost:3000`
With an emphasis on
- **Accuracy**, using a clustering algorithm and saliency feature detection to find the most representative colors.
*Other libraries use a simple histogram and manual thresholding / quantization*
- **Usability**, by returning colors that are visually distinct and can be used in a design.
*Other libraries return "just the main colors", we also look for contrast and accents*
- **Speed**, by using worker threads and array buffers.
*Other libraries are synchronous and require a lot of memory to run*
```ts
const colors = await extractColors(buffer, 3, {
workers: true,
colorSpace: oklabSpace,
strategy: gapStatisticKmeans({ max: 10 }),
clamp: 0.005,
})
```
## How does it work
| image | step |
|-----|-----|
|  | original image (*here the original image is scrambled to avoid infringing on copyrights*) |
|
| main colors are extracted by [k-means](https://en.wikipedia.org/wiki/K-means_clustering) clustering |
|  | the **background** is picked from extracted colors by looking at the most prevalent colors outside of the masked center |
|  | the **foreground** is picked from the most salient features by [Itti-Koch filtering](https://en.wikipedia.org/wiki/Laurent_Itti) of the image |
|
| main colors are split into 2 pools depending on their proximity with either the background or the foreground |
|
|
- the **accent** is picked from the foreground pool based on its *chroma*, *prevalence*, and *distance* to the already picked colors.
- the **alternate background** is picked from the background pool based on its *prevalence* and *contrast* with the foreground colors.
## Sample of results

## Multi-threading
A lot of the work done by this library is CPU intensive, so if performance is *at all* a concern, you should enable multithreading by using the `workers: true` option. If [`piscina`](https://www.npmjs.com/package/piscina) is installed, it will be used to manage the worker pool, and the pool can be provided (`worker: pool`) to integrate with the rest of your application
## Unit-testing colors
Because changes on "color manipulation" algorithms can be chaotic, we need to be able to test our resulting colors with some form of *fuzzy matching*. Additionally, color codes don't immediately mentally map to actual colors, making tests hard to read.
For this we base our tests on "named colors" (taken from the CSS list):
```ts
t.diagnostic(`accent: ${hex(accent)} >> ${nameColor(accent)} (${simpleColor(accent)})`)
assert.strictEqual(nameColor(accent), 'lightcoral')
// will output: ℹ accent: #f85963 >> lightcoral (salmon)
```