|
| 1 | +# swatchify |
| 2 | + |
| 3 | +Extract dominant colors from images using k-means clustering — browser-only, zero dependencies. |
| 4 | + |
| 5 | +## Install |
| 6 | + |
| 7 | +```bash |
| 8 | +npm install swatchify |
| 9 | +``` |
| 10 | + |
| 11 | +## Usage |
| 12 | + |
| 13 | +```ts |
| 14 | +import { extractColors, generatePaletteCanvas } from 'swatchify'; |
| 15 | + |
| 16 | +// From file input |
| 17 | +const file = document.querySelector('input[type="file"]').files[0]; |
| 18 | +const colors = await extractColors(file); |
| 19 | + |
| 20 | +console.log(colors); |
| 21 | +// [ |
| 22 | +// { hex: '#4A90D9', percentage: 32.5, rgb: { r: 74, g: 144, b: 217 } }, |
| 23 | +// { hex: '#2C3E50', percentage: 24.1, rgb: { r: 44, g: 62, b: 80 } }, |
| 24 | +// ... |
| 25 | +// ] |
| 26 | + |
| 27 | +// Generate a palette canvas |
| 28 | +const canvas = generatePaletteCanvas(colors, 500, 100); |
| 29 | +document.body.appendChild(canvas); |
| 30 | +``` |
| 31 | + |
| 32 | +## API |
| 33 | + |
| 34 | +### `extractColors(input, options?)` |
| 35 | + |
| 36 | +Extract dominant colors from an image. |
| 37 | + |
| 38 | +**Input types:** |
| 39 | +- `HTMLImageElement` |
| 40 | +- `HTMLCanvasElement` |
| 41 | +- `ImageData` |
| 42 | +- `File` or `Blob` |
| 43 | +- URL string (including data URLs) |
| 44 | + |
| 45 | +**Options:** |
| 46 | + |
| 47 | +| Option | Type | Default | Description | |
| 48 | +|--------|------|---------|-------------| |
| 49 | +| `numColors` | number | 5 | Number of colors to extract | |
| 50 | +| `quality` | number | 50 | Quality 0-100 (lower = faster) | |
| 51 | +| `excludeWhite` | boolean | false | Filter out near-white colors | |
| 52 | +| `excludeBlack` | boolean | false | Filter out near-black colors | |
| 53 | +| `minContrast` | number | 0 | Minimum distance between colors | |
| 54 | +| `colorThreshold` | number | 30 | Threshold for white/black detection | |
| 55 | + |
| 56 | +**Returns:** `Promise<ExtractedColor[]>` |
| 57 | + |
| 58 | +### `generatePaletteCanvas(colors, width?, height?)` |
| 59 | + |
| 60 | +Create a canvas element showing the color palette. |
| 61 | + |
| 62 | +```ts |
| 63 | +const canvas = generatePaletteCanvas(colors, 600, 120); |
| 64 | +``` |
| 65 | + |
| 66 | +### `generatePaletteDataURL(colors, width?, height?)` |
| 67 | + |
| 68 | +Get the palette as a PNG data URL. |
| 69 | + |
| 70 | +```ts |
| 71 | +const dataUrl = generatePaletteDataURL(colors); |
| 72 | +img.src = dataUrl; |
| 73 | +``` |
| 74 | + |
| 75 | +### `getContrastColor(rgb)` |
| 76 | + |
| 77 | +Get black or white text color for optimal contrast on a background. |
| 78 | + |
| 79 | +```ts |
| 80 | +import { getContrastColor } from 'swatchify'; |
| 81 | + |
| 82 | +const textColor = getContrastColor({ r: 74, g: 144, b: 217 }); |
| 83 | +// '#FFFFFF' |
| 84 | +``` |
| 85 | + |
| 86 | +## Types |
| 87 | + |
| 88 | +```ts |
| 89 | +interface ExtractedColor { |
| 90 | + hex: string; // e.g., "#4A90D9" |
| 91 | + percentage: number; // e.g., 32.5 |
| 92 | + rgb: { r: number; g: number; b: number }; |
| 93 | +} |
| 94 | + |
| 95 | +interface ExtractOptions { |
| 96 | + numColors?: number; |
| 97 | + quality?: number; |
| 98 | + excludeWhite?: boolean; |
| 99 | + excludeBlack?: boolean; |
| 100 | + minContrast?: number; |
| 101 | + colorThreshold?: number; |
| 102 | +} |
| 103 | +``` |
| 104 | + |
| 105 | +## Development |
| 106 | + |
| 107 | +```bash |
| 108 | +cd js |
| 109 | + |
| 110 | +# Install dependencies |
| 111 | +npm install |
| 112 | + |
| 113 | +# Run example dev server |
| 114 | +npm run dev |
| 115 | + |
| 116 | +# Build library |
| 117 | +npm run build |
| 118 | +``` |
| 119 | + |
| 120 | +## How it works |
| 121 | + |
| 122 | +1. Image is loaded and optionally downscaled based on quality setting |
| 123 | +2. Pixels are extracted via Canvas API |
| 124 | +3. K-means++ clustering finds dominant color clusters |
| 125 | +4. Colors are filtered (white/black exclusion, min contrast) |
| 126 | +5. Results sorted by dominance percentage |
| 127 | + |
| 128 | +## License |
| 129 | + |
| 130 | +MIT |
0 commit comments