huebrew 0.1.0 → 0.2.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/README.md +37 -2
- package/dist/chunk-ZGA67ZO4.js +7 -0
- package/dist/chunk-ZGA67ZO4.js.map +1 -0
- package/dist/cli.cjs +40 -0
- package/dist/cli.cjs.map +1 -0
- package/dist/cli.js +36 -0
- package/dist/cli.js.map +1 -0
- package/dist/index.js +1 -6
- package/dist/index.js.map +1 -1
- package/package.json +7 -2
package/README.md
CHANGED
|
@@ -48,13 +48,48 @@ screenshot), **marketers** (brand colors from a logo), **content creators**
|
|
|
48
48
|
|
|
49
49
|
**No install —** just open the **[web studio](https://didrod205.github.io/huebrew/)**.
|
|
50
50
|
|
|
51
|
-
|
|
51
|
+
**Command line** (brew a palette from a PNG, right in your terminal):
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
npx huebrew logo.png --css # CSS variables, straight to stdout
|
|
55
|
+
npx huebrew hero.png --tailwind # a Tailwind colors config with OKLab ramps
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
**Library:**
|
|
52
59
|
|
|
53
60
|
```bash
|
|
54
61
|
npm install huebrew
|
|
55
62
|
```
|
|
56
63
|
|
|
57
|
-
Zero dependencies. Ships ESM + CJS + TypeScript types. Works in the browser, Node, Deno and Bun.
|
|
64
|
+
Zero runtime dependencies. Ships ESM + CJS + TypeScript types. Works in the browser, Node, Deno and Bun.
|
|
65
|
+
|
|
66
|
+
## CLI
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
huebrew <image.png> [options]
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
```text
|
|
73
|
+
$ huebrew sunset.png -n 5
|
|
74
|
+
████ #1B3A5F hsl(210, 56%, 24%)
|
|
75
|
+
████ #E8743B hsl(18, 80%, 57%)
|
|
76
|
+
████ #F4C95D hsl(42, 87%, 66%)
|
|
77
|
+
████ #7A1E2B hsl(351, 61%, 30%)
|
|
78
|
+
████ #C9D6DF hsl(205, 24%, 83%)
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
| Option | Description |
|
|
82
|
+
| ------ | ----------- |
|
|
83
|
+
| `-n, --colors <n>` | Number of colors (default 6) |
|
|
84
|
+
| `--hex` / `--css` / `--scss` / `--json` | Output in that format |
|
|
85
|
+
| `--tailwind` | Tailwind colors config with **OKLab 50–950 ramps** |
|
|
86
|
+
| `--svg [file]` | An SVG swatch strip (stdout or a file) |
|
|
87
|
+
| `--names a,b,c` | Names for `--tailwind` colors |
|
|
88
|
+
| `-o, --out <file>` | Write to a file instead of stdout |
|
|
89
|
+
|
|
90
|
+
The CLI decodes **PNG** natively using Node's built-in `zlib` — so it stays
|
|
91
|
+
**zero-dependency**. For JPEG/WebP, decode to RGBA and use the library API
|
|
92
|
+
(below). Nothing is uploaded; all processing is local.
|
|
58
93
|
|
|
59
94
|
## Usage
|
|
60
95
|
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
var T=(t,r,n)=>t<r?r:t>n?n:t;function B([t,r,n]){let e=o=>T(Math.round(o),0,255).toString(16).padStart(2,"0");return `#${e(t)}${e(r)}${e(n)}`}function C(t){let r=t.replace(/^#/,"");r.length===3&&(r=r.split("").map(e=>e+e).join(""));let n=parseInt(r,16);return [n>>16&255,n>>8&255,n&255]}function I([t,r,n]){t/=255,r/=255,n/=255;let e=Math.max(t,r,n),o=Math.min(t,r,n),u=(e+o)/2;if(e===o)return {h:0,s:0,l:Math.round(u*100)};let i=e-o,s=u>.5?i/(2-e-o):i/(e+o),a;return e===t?a=(r-n)/i+(r<n?6:0):e===r?a=(n-t)/i+2:a=(t-r)/i+4,{h:Math.round(a*60),s:Math.round(s*100),l:Math.round(u*100)}}var R=t=>t<=.04045?t/12.92:((t+.055)/1.055)**2.4,x=t=>t<=.0031308?12.92*t:1.055*t**(1/2.4)-.055;function M([t,r,n]){return .2126*R(t/255)+.7152*R(r/255)+.0722*R(n/255)}function F(t,r){let n=M(t),e=M(r),[o,u]=n>=e?[n,e]:[e,n];return (o+.05)/(u+.05)}function w(t){return M(t)>=.179?"#000000":"#ffffff"}var O=t=>M(t)>=.179;function z([t,r,n]){let e=R(t/255),o=R(r/255),u=R(n/255),i=Math.cbrt(.4122214708*e+.5363325363*o+.0514459929*u),s=Math.cbrt(.2119034982*e+.6806995451*o+.1073969566*u),a=Math.cbrt(.0883024619*e+.2817188376*o+.6299787005*u);return {L:.2104542553*i+.793617785*s-.0040720468*a,a:1.9779984951*i-2.428592205*s+.4505937099*a,b:.0259040371*i+.7827717662*s-.808675766*a}}function j({L:t,a:r,b:n}){let e=(t+.3963377774*r+.2158037573*n)**3,o=(t-.1055613458*r-.0638541728*n)**3,u=(t-.0894841775*r-1.291485548*n)**3,i=4.0767416621*e-3.3077115913*o+.2309699292*u,s=-1.2684380046*e+2.6097574011*o-.3413193965*u,a=-0.0041960863*e-.7034186147*o+1.707614701*u;return [T(x(i),0,1)*255,T(x(s),0,1)*255,T(x(a),0,1)*255]}var G=[50,100,200,300,400,500,600,700,800,900,950],q=[.971,.936,.885,.808,.704,.602,.515,.43,.366,.317,.235];function $(t){let{a:r,b:n}=z(t);return q.map(e=>B(j({L:e,a:r,b:n})))}var g=(t,r,n)=>(t<<10)+(r<<5)+n,A=class t{constructor(r,n,e,o,u,i,s){this.r1=r;this.r2=n;this.g1=e;this.g2=o;this.b1=u;this.b2=i;this.histo=s;}r1;r2;g1;g2;b1;b2;histo;_count=-1;_avg=null;volume(){return (this.r2-this.r1+1)*(this.g2-this.g1+1)*(this.b2-this.b1+1)}count(){if(this._count>=0)return this._count;let r=0;for(let n=this.r1;n<=this.r2;n++)for(let e=this.g1;e<=this.g2;e++)for(let o=this.b1;o<=this.b2;o++)r+=this.histo[g(n,e,o)];return this._count=r,r}average(){if(this._avg)return this._avg;let r=0,n=0,e=0,o=0,u=8;for(let i=this.r1;i<=this.r2;i++)for(let s=this.g1;s<=this.g2;s++)for(let a=this.b1;a<=this.b2;a++){let c=this.histo[g(i,s,a)];r+=c,n+=c*(i+.5)*u,e+=c*(s+.5)*u,o+=c*(a+.5)*u;}return this._avg=r?[Math.round(n/r),Math.round(e/r),Math.round(o/r)]:[Math.round(u*(this.r1+this.r2+1)/2),Math.round(u*(this.g1+this.g2+1)/2),Math.round(u*(this.b1+this.b2+1)/2)],this._avg}clone(r,n,e,o,u,i){return new t(r,n,e,o,u,i,this.histo)}};function V(t,r){let n=new Int32Array(32768);for(let e=0;e<t.length;e+=4*r){let o=t[e+3];if(o!==void 0&&o<125)continue;let u=t[e]>>3,i=t[e+1]>>3,s=t[e+2]>>3,a=g(u,i,s);n[a]=n[a]+1;}return n}function E(t){let r=31,n=0,e=31,o=0,u=31,i=0;for(let s=0;s<32;s++)for(let a=0;a<32;a++)for(let c=0;c<32;c++)t[g(s,a,c)]>0&&(r=Math.min(r,s),n=Math.max(n,s),e=Math.min(e,a),o=Math.max(o,a),u=Math.min(u,c),i=Math.max(i,c));return new A(r,n,e,o,u,i,t)}function N(t){let r=t.count();if(r===0)return [t];let n=t.r2-t.r1+1,e=t.g2-t.g1+1,o=t.b2-t.b1+1,u=Math.max(n,e,o)===n?"r":Math.max(e,o)===e?"g":"b",i=[],s=0,{histo:a}=t,c=(p,k)=>{for(let S=p;S<=k;S++){let d=0;if(u==="r")for(let m=t.g1;m<=t.g2;m++)for(let h=t.b1;h<=t.b2;h++)d+=a[g(S,m,h)];else if(u==="g")for(let m=t.r1;m<=t.r2;m++)for(let h=t.b1;h<=t.b2;h++)d+=a[g(m,S,h)];else for(let m=t.r1;m<=t.r2;m++)for(let h=t.g1;h<=t.g2;h++)d+=a[g(m,h,S)];s+=d,i[S]=s;}},b=u==="r"?t.r1:u==="g"?t.g1:t.b1,f=u==="r"?t.r2:u==="g"?t.g2:t.b2;if(c(b,f),b===f)return [t];let l=b;for(let p=b;p<=f;p++)if(i[p]>r/2){l=Math.max(b,Math.min(f-1,p));break}let L=t.clone(t.r1,u==="r"?l:t.r2,t.g1,u==="g"?l:t.g2,t.b1,u==="b"?l:t.b2),H=t.clone(u==="r"?l+1:t.r1,t.r2,u==="g"?l+1:t.g1,t.g2,u==="b"?l+1:t.b1,t.b2);return [L,H]}function P(t,r,n){let e=V(t,Math.max(1,n)),o=[E(e)];if(o[0].count()===0)return [];let u=(i,s)=>{let a=0;for(;a++<1e3&&o.length<i;){o.sort((f,l)=>s?f.count()*f.volume()-l.count()*l.volume():f.count()-l.count());let c=o.pop();if(!c||c.count()===0){c&&o.push(c);break}let b=N(c);if(b.length===1){o.push(b[0]);break}o.push(b[0],b[1]);}};return u(Math.max(1,Math.floor(.75*r)),false),u(r,true),o.filter(i=>i.count()>0).sort((i,s)=>s.count()-i.count()).slice(0,r)}function U(t,r=6,n=1){return r<1?[]:P(t,r,n).map(e=>e.average())}function y(t,r=6,n=1){return r<1?[]:P(t,r,n).map(e=>({rgb:e.average(),population:e.count()}))}var _=(t,r)=>`${r}-${t+1}`;function Q(t){return t.map(r=>r.hex)}function v(t,r="color"){return `:root {
|
|
2
|
+
${t.map((e,o)=>` --${_(o,r)}: ${e.hex};`).join(`
|
|
3
|
+
`)}
|
|
4
|
+
}`}function tt(t,r="color"){return t.map((n,e)=>`$${_(e,r)}: ${n.hex};`).join(`
|
|
5
|
+
`)}function rt(t){return JSON.stringify(t.map(r=>({hex:r.hex,rgb:r.rgb,hsl:r.hsl,population:r.population})),null,2)}function nt(t,r={}){let n=r.size??80,e=n*t.length,o=t.map((u,i)=>{let s=i*n,a=u.hex.toUpperCase();return `<rect x="${s}" y="0" width="${n}" height="${n}" fill="${u.hex}"/><text x="${s+n/2}" y="${n-8}" font-family="monospace" font-size="10" text-anchor="middle" fill="${u.textColor}">${a}</text>`}).join("");return `<svg xmlns="http://www.w3.org/2000/svg" width="${e}" height="${n}" viewBox="0 0 ${e} ${n}">${o}</svg>`}function et(t,r=[]){let n={};return t.forEach((e,o)=>{let u=r[o]??`palette-${o+1}`,i=$(e.rgb),s={};G.forEach((a,c)=>{s[a]=i[c];}),n[u]=s;}),n}function K(t){return typeof t=="object"&&t!==null&&"data"in t?t.data:t}function W(t){return Math.max(1,Math.round(Math.sqrt(t/2e4)))}function J(t,r){return {rgb:t,hex:B(t),hsl:I(t),population:r,isLight:O(t),textColor:w(t)}}function X(t,r={}){let n=K(t),e=r.colors??6,o=r.step??W(n.length/4);return y(n,e,o).map(({rgb:u,population:i})=>J(u,i))}function at(t,r={}){return X(t,{...r,colors:Math.max(r.colors??5,5)})[0]??null}
|
|
6
|
+
export{B as a,C as b,I as c,M as d,F as e,w as f,G as g,$ as h,U as i,y as j,Q as k,v as l,tt as m,rt as n,nt as o,et as p,X as q,at as r};//# sourceMappingURL=chunk-ZGA67ZO4.js.map
|
|
7
|
+
//# sourceMappingURL=chunk-ZGA67ZO4.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/color.ts","../src/quantize.ts","../src/format.ts","../src/index.ts"],"names":["clamp","n","lo","hi","rgbToHex","r","g","b","h","hexToRgb","hex","c","rgbToHsl","max","min","l","d","srgbToLinear","linearToSrgb","luminance","contrast","a","la","lb","textColorFor","bg","isLight","rgb","rgbToOklab","lr","lg","m","s","oklabToRgb","L","RAMP_STOPS","RAMP_L","ramp","base","colorIndex","VBox","_VBox","r1","r2","g1","g2","b1","b2","histo","total","rs","gs","bs","mult","buildHisto","pixels","step","i","idx","vboxFromHisto","medianCut","vbox","rw","gw","bw","axis","partial","sum","accumulate","outer1","outer2","slice","splitPoint","run","maxColors","boxes","splitUntil","target","byVolume","iterations","x","y","biggest","parts","box","quantize","quantizeWithCounts","slug","prefix","toArray","swatches","toCSS","toSCSS","toJSON","toSVG","options","size","w","rects","label","toTailwind","names","out","name","stops","obj","stop","j","toPixels","source","autoStep","pixelCount","makeSwatch","population","palette","colors","dominant"],"mappings":"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","file":"chunk-ZGA67ZO4.js","sourcesContent":["/**\n * Color math for huebrew: hex/rgb/hsl conversion, WCAG luminance, and an\n * OKLab-based lightness ramp (perceptually even tints/shades).\n */\n\nexport type RGB = [number, number, number];\n\nconst clamp = (n: number, lo: number, hi: number): number => (n < lo ? lo : n > hi ? hi : n);\n\nexport function rgbToHex([r, g, b]: RGB): string {\n const h = (n: number) => clamp(Math.round(n), 0, 255).toString(16).padStart(2, \"0\");\n return `#${h(r)}${h(g)}${h(b)}`;\n}\n\nexport function hexToRgb(hex: string): RGB {\n let h = hex.replace(/^#/, \"\");\n if (h.length === 3) h = h.split(\"\").map((c) => c + c).join(\"\");\n const n = parseInt(h, 16);\n return [(n >> 16) & 255, (n >> 8) & 255, n & 255];\n}\n\nexport function rgbToHsl([r, g, b]: RGB): { h: number; s: number; l: number } {\n r /= 255;\n g /= 255;\n b /= 255;\n const max = Math.max(r, g, b);\n const min = Math.min(r, g, b);\n const l = (max + min) / 2;\n if (max === min) return { h: 0, s: 0, l: Math.round(l * 100) };\n const d = max - min;\n const s = l > 0.5 ? d / (2 - max - min) : d / (max + min);\n let h: number;\n if (max === r) h = (g - b) / d + (g < b ? 6 : 0);\n else if (max === g) h = (b - r) / d + 2;\n else h = (r - g) / d + 4;\n return { h: Math.round(h * 60), s: Math.round(s * 100), l: Math.round(l * 100) };\n}\n\nconst srgbToLinear = (c: number): number =>\n c <= 0.04045 ? c / 12.92 : ((c + 0.055) / 1.055) ** 2.4;\nconst linearToSrgb = (c: number): number =>\n c <= 0.0031308 ? 12.92 * c : 1.055 * c ** (1 / 2.4) - 0.055;\n\n/** WCAG relative luminance (0–1). */\nexport function luminance([r, g, b]: RGB): number {\n return 0.2126 * srgbToLinear(r / 255) + 0.7152 * srgbToLinear(g / 255) + 0.0722 * srgbToLinear(b / 255);\n}\n\n/** WCAG contrast ratio between two colors (1–21). */\nexport function contrast(a: RGB, b: RGB): number {\n const la = luminance(a);\n const lb = luminance(b);\n const [hi, lo] = la >= lb ? [la, lb] : [lb, la];\n return (hi + 0.05) / (lo + 0.05);\n}\n\n/** Black or white — whichever is more readable on `bg`. */\nexport function textColorFor(bg: RGB): \"#000000\" | \"#ffffff\" {\n return luminance(bg) >= 0.179 ? \"#000000\" : \"#ffffff\";\n}\n\nexport const isLight = (rgb: RGB): boolean => luminance(rgb) >= 0.179;\n\n// --- OKLab ---\ninterface OKLab {\n L: number;\n a: number;\n b: number;\n}\n\nfunction rgbToOklab([r, g, b]: RGB): OKLab {\n const lr = srgbToLinear(r / 255);\n const lg = srgbToLinear(g / 255);\n const lb = srgbToLinear(b / 255);\n const l = Math.cbrt(0.4122214708 * lr + 0.5363325363 * lg + 0.0514459929 * lb);\n const m = Math.cbrt(0.2119034982 * lr + 0.6806995451 * lg + 0.1073969566 * lb);\n const s = Math.cbrt(0.0883024619 * lr + 0.2817188376 * lg + 0.6299787005 * lb);\n return {\n L: 0.2104542553 * l + 0.793617785 * m - 0.0040720468 * s,\n a: 1.9779984951 * l - 2.428592205 * m + 0.4505937099 * s,\n b: 0.0259040371 * l + 0.7827717662 * m - 0.808675766 * s,\n };\n}\n\nfunction oklabToRgb({ L, a, b }: OKLab): RGB {\n const l = (L + 0.3963377774 * a + 0.2158037573 * b) ** 3;\n const m = (L - 0.1055613458 * a - 0.0638541728 * b) ** 3;\n const s = (L - 0.0894841775 * a - 1.291485548 * b) ** 3;\n const lr = 4.0767416621 * l - 3.3077115913 * m + 0.2309699292 * s;\n const lg = -1.2684380046 * l + 2.6097574011 * m - 0.3413193965 * s;\n const lb = -0.0041960863 * l - 0.7034186147 * m + 1.707614701 * s;\n return [\n clamp(linearToSrgb(lr), 0, 1) * 255,\n clamp(linearToSrgb(lg), 0, 1) * 255,\n clamp(linearToSrgb(lb), 0, 1) * 255,\n ];\n}\n\n/** Tailwind-style ramp stops and their target OKLab lightness. */\nexport const RAMP_STOPS = [50, 100, 200, 300, 400, 500, 600, 700, 800, 900, 950] as const;\nconst RAMP_L = [0.971, 0.936, 0.885, 0.808, 0.704, 0.602, 0.515, 0.43, 0.366, 0.317, 0.235];\n\n/**\n * Generate a perceptually-even tint/shade ramp from a base color by holding its\n * OKLab hue & chroma and walking lightness through Tailwind-like stops.\n * Returns hex strings, light → dark, one per {@link RAMP_STOPS} entry.\n */\nexport function ramp(base: RGB): string[] {\n const { a, b } = rgbToOklab(base);\n return RAMP_L.map((L) => rgbToHex(oklabToRgb({ L, a, b })));\n}\n","/**\n * Modified Median Cut Quantization (MMCQ) — extract a small, representative\n * palette from a large set of pixels, deterministically and dependency-free.\n *\n * The classic approach: bucket colors into a 3D histogram, then repeatedly\n * split the box containing the most pixels along its longest axis at the\n * population median, prioritizing first by population and then by population×volume.\n */\n\nimport type { RGB } from \"./color.js\";\n\nconst SIGBITS = 5;\nconst RSHIFT = 8 - SIGBITS;\nconst HISTO_SIZE = 1 << (3 * SIGBITS);\nconst FRACT_BY_POPULATION = 0.75;\nconst MAX_ITERATIONS = 1000;\n\nconst colorIndex = (r: number, g: number, b: number): number =>\n (r << (2 * SIGBITS)) + (g << SIGBITS) + b;\n\nclass VBox {\n constructor(\n public r1: number,\n public r2: number,\n public g1: number,\n public g2: number,\n public b1: number,\n public b2: number,\n public readonly histo: Int32Array,\n ) {}\n\n private _count = -1;\n private _avg: RGB | null = null;\n\n volume(): number {\n return (this.r2 - this.r1 + 1) * (this.g2 - this.g1 + 1) * (this.b2 - this.b1 + 1);\n }\n\n count(): number {\n if (this._count >= 0) return this._count;\n let n = 0;\n for (let r = this.r1; r <= this.r2; r++)\n for (let g = this.g1; g <= this.g2; g++)\n for (let b = this.b1; b <= this.b2; b++) n += this.histo[colorIndex(r, g, b)] as number;\n this._count = n;\n return n;\n }\n\n average(): RGB {\n if (this._avg) return this._avg;\n let total = 0;\n let rs = 0;\n let gs = 0;\n let bs = 0;\n const mult = 1 << RSHIFT;\n for (let r = this.r1; r <= this.r2; r++)\n for (let g = this.g1; g <= this.g2; g++)\n for (let b = this.b1; b <= this.b2; b++) {\n const h = this.histo[colorIndex(r, g, b)] as number;\n total += h;\n rs += h * (r + 0.5) * mult;\n gs += h * (g + 0.5) * mult;\n bs += h * (b + 0.5) * mult;\n }\n this._avg = total\n ? [Math.round(rs / total), Math.round(gs / total), Math.round(bs / total)]\n : [\n Math.round((mult * (this.r1 + this.r2 + 1)) / 2),\n Math.round((mult * (this.g1 + this.g2 + 1)) / 2),\n Math.round((mult * (this.b1 + this.b2 + 1)) / 2),\n ];\n return this._avg;\n }\n\n clone(r1: number, r2: number, g1: number, g2: number, b1: number, b2: number): VBox {\n return new VBox(r1, r2, g1, g2, b1, b2, this.histo);\n }\n}\n\nfunction buildHisto(pixels: ArrayLike<number>, step: number): Int32Array {\n const histo = new Int32Array(HISTO_SIZE);\n for (let i = 0; i < pixels.length; i += 4 * step) {\n const a = pixels[i + 3];\n if (a !== undefined && a < 125) continue; // skip mostly-transparent pixels\n const r = (pixels[i] as number) >> RSHIFT;\n const g = (pixels[i + 1] as number) >> RSHIFT;\n const b = (pixels[i + 2] as number) >> RSHIFT;\n const idx = colorIndex(r, g, b);\n histo[idx] = (histo[idx] as number) + 1;\n }\n return histo;\n}\n\nfunction vboxFromHisto(histo: Int32Array): VBox {\n let r1 = 31, r2 = 0, g1 = 31, g2 = 0, b1 = 31, b2 = 0;\n for (let r = 0; r < 32; r++)\n for (let g = 0; g < 32; g++)\n for (let b = 0; b < 32; b++) {\n if ((histo[colorIndex(r, g, b)] as number) > 0) {\n r1 = Math.min(r1, r); r2 = Math.max(r2, r);\n g1 = Math.min(g1, g); g2 = Math.max(g2, g);\n b1 = Math.min(b1, b); b2 = Math.max(b2, b);\n }\n }\n return new VBox(r1, r2, g1, g2, b1, b2, histo);\n}\n\nfunction medianCut(vbox: VBox): [VBox, VBox] | [VBox] {\n const total = vbox.count();\n if (total === 0) return [vbox];\n\n const rw = vbox.r2 - vbox.r1 + 1;\n const gw = vbox.g2 - vbox.g1 + 1;\n const bw = vbox.b2 - vbox.b1 + 1;\n const axis = Math.max(rw, gw, bw) === rw ? \"r\" : Math.max(gw, bw) === gw ? \"g\" : \"b\";\n\n const partial: number[] = [];\n let sum = 0;\n const { histo } = vbox;\n\n const accumulate = (outer1: number, outer2: number) => {\n for (let i = outer1; i <= outer2; i++) {\n let slice = 0;\n if (axis === \"r\") {\n for (let g = vbox.g1; g <= vbox.g2; g++)\n for (let b = vbox.b1; b <= vbox.b2; b++) slice += histo[colorIndex(i, g, b)] as number;\n } else if (axis === \"g\") {\n for (let r = vbox.r1; r <= vbox.r2; r++)\n for (let b = vbox.b1; b <= vbox.b2; b++) slice += histo[colorIndex(r, i, b)] as number;\n } else {\n for (let r = vbox.r1; r <= vbox.r2; r++)\n for (let g = vbox.g1; g <= vbox.g2; g++) slice += histo[colorIndex(r, g, i)] as number;\n }\n sum += slice;\n partial[i] = sum;\n }\n };\n\n const lo = axis === \"r\" ? vbox.r1 : axis === \"g\" ? vbox.g1 : vbox.b1;\n const hi = axis === \"r\" ? vbox.r2 : axis === \"g\" ? vbox.g2 : vbox.b2;\n accumulate(lo, hi);\n\n if (lo === hi) return [vbox]; // can't split a single slice\n\n let splitPoint = lo;\n for (let i = lo; i <= hi; i++) {\n if ((partial[i] as number) > total / 2) {\n splitPoint = Math.max(lo, Math.min(hi - 1, i));\n break;\n }\n }\n\n const a = vbox.clone(\n vbox.r1, axis === \"r\" ? splitPoint : vbox.r2,\n vbox.g1, axis === \"g\" ? splitPoint : vbox.g2,\n vbox.b1, axis === \"b\" ? splitPoint : vbox.b2,\n );\n const b = vbox.clone(\n axis === \"r\" ? splitPoint + 1 : vbox.r1, vbox.r2,\n axis === \"g\" ? splitPoint + 1 : vbox.g1, vbox.g2,\n axis === \"b\" ? splitPoint + 1 : vbox.b1, vbox.b2,\n );\n return [a, b];\n}\n\nfunction run(pixels: ArrayLike<number>, maxColors: number, step: number): VBox[] {\n const histo = buildHisto(pixels, Math.max(1, step));\n const boxes = [vboxFromHisto(histo)];\n if (boxes[0]!.count() === 0) return [];\n\n const splitUntil = (target: number, byVolume: boolean) => {\n let iterations = 0;\n while (iterations++ < MAX_ITERATIONS && boxes.length < target) {\n boxes.sort((x, y) =>\n byVolume ? x.count() * x.volume() - y.count() * y.volume() : x.count() - y.count(),\n );\n const biggest = boxes.pop();\n if (!biggest || biggest.count() === 0) {\n if (biggest) boxes.push(biggest);\n break;\n }\n const parts = medianCut(biggest);\n if (parts.length === 1) {\n boxes.push(parts[0]); // unsplittable; leave it and stop trying\n break;\n }\n boxes.push(parts[0], parts[1]);\n }\n };\n\n splitUntil(Math.max(1, Math.floor(FRACT_BY_POPULATION * maxColors)), false);\n splitUntil(maxColors, true);\n\n return boxes\n .filter((box) => box.count() > 0)\n .sort((x, y) => y.count() - x.count())\n .slice(0, maxColors);\n}\n\n/**\n * Quantize `pixels` (a flat RGBA array) down to at most `maxColors` colors.\n * `step` samples every Nth pixel for speed. Returns RGB triplets ordered by\n * population (most common first).\n */\nexport function quantize(pixels: ArrayLike<number>, maxColors = 6, step = 1): RGB[] {\n if (maxColors < 1) return [];\n return run(pixels, maxColors, step).map((box) => box.average());\n}\n\n/** Like {@link quantize}, but each color carries its pixel population (sampled). */\nexport function quantizeWithCounts(\n pixels: ArrayLike<number>,\n maxColors = 6,\n step = 1,\n): { rgb: RGB; population: number }[] {\n if (maxColors < 1) return [];\n return run(pixels, maxColors, step).map((box) => ({ rgb: box.average(), population: box.count() }));\n}\n","/**\n * Export a palette into developer-ready formats: hex array, CSS variables,\n * SCSS, JSON, an SVG preview strip, and a Tailwind color config (with\n * perceptual ramps).\n */\n\nimport { ramp, RAMP_STOPS } from \"./color.js\";\nimport type { Swatch } from \"./index.js\";\n\nconst slug = (i: number, prefix: string): string => `${prefix}-${i + 1}`;\n\n/** Just the hex strings, in palette order. */\nexport function toArray(swatches: Swatch[]): string[] {\n return swatches.map((s) => s.hex);\n}\n\n/** `:root { --color-1: #...; ... }` */\nexport function toCSS(swatches: Swatch[], prefix = \"color\"): string {\n const lines = swatches.map((s, i) => ` --${slug(i, prefix)}: ${s.hex};`);\n return `:root {\\n${lines.join(\"\\n\")}\\n}`;\n}\n\n/** `$color-1: #...;` SCSS variables. */\nexport function toSCSS(swatches: Swatch[], prefix = \"color\"): string {\n return swatches.map((s, i) => `$${slug(i, prefix)}: ${s.hex};`).join(\"\\n\");\n}\n\n/** Pretty JSON of the palette (hex, rgb, hsl, population). */\nexport function toJSON(swatches: Swatch[]): string {\n return JSON.stringify(\n swatches.map((s) => ({ hex: s.hex, rgb: s.rgb, hsl: s.hsl, population: s.population })),\n null,\n 2,\n );\n}\n\n/** A standalone SVG strip of swatches — great for READMEs and previews. */\nexport function toSVG(swatches: Swatch[], options: { size?: number } = {}): string {\n const size = options.size ?? 80;\n const w = size * swatches.length;\n const rects = swatches\n .map((s, i) => {\n const x = i * size;\n const label = s.hex.toUpperCase();\n return (\n `<rect x=\"${x}\" y=\"0\" width=\"${size}\" height=\"${size}\" fill=\"${s.hex}\"/>` +\n `<text x=\"${x + size / 2}\" y=\"${size - 8}\" font-family=\"monospace\" font-size=\"10\" ` +\n `text-anchor=\"middle\" fill=\"${s.textColor}\">${label}</text>`\n );\n })\n .join(\"\");\n return `<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"${w}\" height=\"${size}\" viewBox=\"0 0 ${w} ${size}\">${rects}</svg>`;\n}\n\n/**\n * A Tailwind `theme.extend.colors` object. Each swatch becomes a named color\n * with a full 50–950 perceptual ramp (great for dropping into a config).\n *\n * ```ts\n * toTailwind(palette(img), [\"brand\", \"accent\"]);\n * // { brand: { 50: \"#...\", ..., 950: \"#...\" }, accent: { ... }, ... }\n * ```\n */\nexport function toTailwind(\n swatches: Swatch[],\n names: string[] = [],\n): Record<string, Record<string, string>> {\n const out: Record<string, Record<string, string>> = {};\n swatches.forEach((s, i) => {\n const name = names[i] ?? `palette-${i + 1}`;\n const stops = ramp(s.rgb);\n const obj: Record<string, string> = {};\n RAMP_STOPS.forEach((stop, j) => {\n obj[stop] = stops[j] as string;\n });\n out[name] = obj;\n });\n return out;\n}\n","/**\n * huebrew — brew a usable color palette & theme tokens from any image.\n *\n * Zero dependencies. The core works on raw RGBA pixels, so it runs in the\n * browser (via canvas `ImageData`), in Node (via any decoder you already use),\n * Deno or Bun — and never makes a network call.\n */\n\nimport { isLight, rgbToHex, rgbToHsl, textColorFor, type RGB } from \"./color.js\";\nimport { quantize, quantizeWithCounts } from \"./quantize.js\";\n\nexport type { RGB } from \"./color.js\";\nexport { rgbToHex, hexToRgb, rgbToHsl, ramp, contrast, luminance, textColorFor, RAMP_STOPS } from \"./color.js\";\nexport { quantize, quantizeWithCounts } from \"./quantize.js\";\nexport * from \"./format.js\";\n\nexport interface Swatch {\n rgb: RGB;\n hex: string;\n hsl: { h: number; s: number; l: number };\n /** Sampled pixel population for this color (higher = more dominant). */\n population: number;\n isLight: boolean;\n /** `\"#000000\"` or `\"#ffffff\"` — whichever is readable on this swatch (WCAG). */\n textColor: string;\n}\n\n/** An RGBA pixel buffer, or anything `ImageData`-shaped (`{ data, width, height }`). */\nexport type PixelSource = ArrayLike<number> | { data: ArrayLike<number>; width?: number; height?: number };\n\nexport interface PaletteOptions {\n /** How many colors to extract. Default `6`. */\n colors?: number;\n /** Sample every Nth pixel. Default: auto (targets ~20k samples for speed). */\n step?: number;\n}\n\nfunction toPixels(source: PixelSource): ArrayLike<number> {\n if (typeof source === \"object\" && source !== null && \"data\" in source) return source.data;\n return source;\n}\n\nfunction autoStep(pixelCount: number): number {\n return Math.max(1, Math.round(Math.sqrt(pixelCount / 20000)));\n}\n\nfunction makeSwatch(rgb: RGB, population: number): Swatch {\n return {\n rgb,\n hex: rgbToHex(rgb),\n hsl: rgbToHsl(rgb),\n population,\n isLight: isLight(rgb),\n textColor: textColorFor(rgb),\n };\n}\n\n/**\n * Extract a palette from an image's pixels, most-dominant first.\n *\n * ```ts\n * // Browser\n * const ctx = canvas.getContext(\"2d\")!;\n * const swatches = palette(ctx.getImageData(0, 0, canvas.width, canvas.height), { colors: 6 });\n * swatches[0].hex; // dominant color\n * ```\n */\nexport function palette(source: PixelSource, options: PaletteOptions = {}): Swatch[] {\n const pixels = toPixels(source);\n const colors = options.colors ?? 6;\n const step = options.step ?? autoStep(pixels.length / 4);\n return quantizeWithCounts(pixels, colors, step).map(({ rgb, population }) =>\n makeSwatch(rgb, population),\n );\n}\n\n/** The single most dominant color, or `null` for an empty/transparent image. */\nexport function dominant(source: PixelSource, options: PaletteOptions = {}): Swatch | null {\n return palette(source, { ...options, colors: Math.max(options.colors ?? 5, 5) })[0] ?? null;\n}\n"]}
|
package/dist/cli.cjs
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
'use strict';var fs=require('fs'),zlib=require('zlib');var v=[137,80,78,71,13,10,26,10];function D(t){return v.every((e,r)=>t[r]===e)}function J(t,e,r){let n=t+e-r,o=Math.abs(n-t),s=Math.abs(n-e),i=Math.abs(n-r);return o<=s&&o<=i?t:s<=i?e:r}function T(t){if(!D(t))throw new Error("not a PNG file");let e=new DataView(t.buffer,t.byteOffset,t.byteLength),r=0,n=0,o=0,s=0,i=0,u=[],a=null,c=null,l=8;for(;l+8<=t.length;){let d=e.getUint32(l),p=String.fromCharCode(t[l+4],t[l+5],t[l+6],t[l+7]),f=l+8;if(f+d>t.length)break;if(p==="IHDR")r=e.getUint32(f),n=e.getUint32(f+4),o=t[f+8],s=t[f+9],i=t[f+12];else if(p==="PLTE")a=t.subarray(f,f+d);else if(p==="tRNS")c=t.subarray(f,f+d);else if(p==="IDAT")u.push(t.subarray(f,f+d));else if(p==="IEND")break;l=f+d+4;}if(r===0||n===0)throw new Error("invalid PNG: missing IHDR");if(i!==0)throw new Error("interlaced PNG is not supported");if(o!==8&&o!==16&&!(s===3&&o<=8))throw new Error(`unsupported PNG bit depth ${o}`);let h=u.reduce((d,p)=>d+p.length,0),m=new Uint8Array(h),S=0;for(let d of u)m.set(d,S),S+=d.length;let w=new Uint8Array(zlib.inflateSync(m)),b=K(s),y=o===16?2:1,g=new Uint8Array(r*n*4);return s===3?Z(w,r,n,o,a,c,g):Y(w,r,n,b,y,s,c,g),{width:r,height:n,data:g}}function K(t){switch(t){case 0:return 1;case 2:return 3;case 3:return 1;case 4:return 2;case 6:return 4;default:throw new Error(`unsupported PNG color type ${t}`)}}function $(t,e,r,n){let o=e*n,s=new Uint8Array(r*o),i=0;for(let u=0;u<r;u++){let a=t[i++],c=u*o;for(let l=0;l<o;l++){let h=t[i++],m=l>=n?s[c+l-n]:0,S=u>0?s[c-o+l]:0,w=u>0&&l>=n?s[c-o+l-n]:0,b;switch(a){case 0:b=h;break;case 1:b=h+m;break;case 2:b=h+S;break;case 3:b=h+(m+S>>1);break;case 4:b=h+J(m,S,w);break;default:throw new Error(`unsupported PNG filter ${a}`)}s[c+l]=b&255;}}return s}function Y(t,e,r,n,o,s,i,u){let a=n*o,c=$(t,e,r,a),l=e*a;for(let h=0;h<r;h++)for(let m=0;m<e;m++){let S=h*l+m*a,w=(h*e+m)*4,b=f=>c[S+f*o],y,g,d,p=255;s===0||s===4?(y=g=d=b(0),s===4&&(p=b(1))):(y=b(0),g=b(1),d=b(2),s===6&&(p=b(3))),u[w]=y,u[w+1]=g,u[w+2]=d,u[w+3]=p;}}function Z(t,e,r,n,o,s,i){if(!o)throw new Error("indexed PNG missing PLTE");let u=Math.ceil(e*n/8),a=$(t,u,r,1);for(let c=0;c<r;c++)for(let l=0;l<e;l++){let h=X(a,c*u,l,n),m=(c*e+l)*4;i[m]=o[h*3]??0,i[m+1]=o[h*3+1]??0,i[m+2]=o[h*3+2]??0,i[m+3]=s&&h<s.length?s[h]:255;}}function X(t,e,r,n){if(n===8)return t[e+r];let o=8/n,s=t[e+Math.floor(r/o)],i=(o-1-r%o)*n,u=(1<<n)-1;return s>>i&u}var R=(t,e,r)=>t<e?e:t>r?r:t;function G([t,e,r]){let n=o=>R(Math.round(o),0,255).toString(16).padStart(2,"0");return `#${n(t)}${n(e)}${n(r)}`}function P([t,e,r]){t/=255,e/=255,r/=255;let n=Math.max(t,e,r),o=Math.min(t,e,r),s=(n+o)/2;if(n===o)return {h:0,s:0,l:Math.round(s*100)};let i=n-o,u=s>.5?i/(2-n-o):i/(n+o),a;return n===t?a=(e-r)/i+(e<r?6:0):n===e?a=(r-t)/i+2:a=(t-e)/i+4,{h:Math.round(a*60),s:Math.round(u*100),l:Math.round(s*100)}}var A=t=>t<=.04045?t/12.92:((t+.055)/1.055)**2.4,M=t=>t<=.0031308?12.92*t:1.055*t**(1/2.4)-.055;function O([t,e,r]){return .2126*A(t/255)+.7152*A(e/255)+.0722*A(r/255)}function B(t){return O(t)>=.179?"#000000":"#ffffff"}var U=t=>O(t)>=.179;function Q([t,e,r]){let n=A(t/255),o=A(e/255),s=A(r/255),i=Math.cbrt(.4122214708*n+.5363325363*o+.0514459929*s),u=Math.cbrt(.2119034982*n+.6806995451*o+.1073969566*s),a=Math.cbrt(.0883024619*n+.2817188376*o+.6299787005*s);return {L:.2104542553*i+.793617785*u-.0040720468*a,a:1.9779984951*i-2.428592205*u+.4505937099*a,b:.0259040371*i+.7827717662*u-.808675766*a}}function tt({L:t,a:e,b:r}){let n=(t+.3963377774*e+.2158037573*r)**3,o=(t-.1055613458*e-.0638541728*r)**3,s=(t-.0894841775*e-1.291485548*r)**3,i=4.0767416621*n-3.3077115913*o+.2309699292*s,u=-1.2684380046*n+2.6097574011*o-.3413193965*s,a=-0.0041960863*n-.7034186147*o+1.707614701*s;return [R(M(i),0,1)*255,R(M(u),0,1)*255,R(M(a),0,1)*255]}var N=[50,100,200,300,400,500,600,700,800,900,950],et=[.971,.936,.885,.808,.704,.602,.515,.43,.366,.317,.235];function k(t){let{a:e,b:r}=Q(t);return et.map(n=>G(tt({L:n,a:e,b:r})))}var x=(t,e,r)=>(t<<10)+(e<<5)+r,I=class t{constructor(e,r,n,o,s,i,u){this.r1=e;this.r2=r;this.g1=n;this.g2=o;this.b1=s;this.b2=i;this.histo=u;}r1;r2;g1;g2;b1;b2;histo;_count=-1;_avg=null;volume(){return (this.r2-this.r1+1)*(this.g2-this.g1+1)*(this.b2-this.b1+1)}count(){if(this._count>=0)return this._count;let e=0;for(let r=this.r1;r<=this.r2;r++)for(let n=this.g1;n<=this.g2;n++)for(let o=this.b1;o<=this.b2;o++)e+=this.histo[x(r,n,o)];return this._count=e,e}average(){if(this._avg)return this._avg;let e=0,r=0,n=0,o=0,s=8;for(let i=this.r1;i<=this.r2;i++)for(let u=this.g1;u<=this.g2;u++)for(let a=this.b1;a<=this.b2;a++){let c=this.histo[x(i,u,a)];e+=c,r+=c*(i+.5)*s,n+=c*(u+.5)*s,o+=c*(a+.5)*s;}return this._avg=e?[Math.round(r/e),Math.round(n/e),Math.round(o/e)]:[Math.round(s*(this.r1+this.r2+1)/2),Math.round(s*(this.g1+this.g2+1)/2),Math.round(s*(this.b1+this.b2+1)/2)],this._avg}clone(e,r,n,o,s,i){return new t(e,r,n,o,s,i,this.histo)}};function rt(t,e){let r=new Int32Array(32768);for(let n=0;n<t.length;n+=4*e){let o=t[n+3];if(o!==void 0&&o<125)continue;let s=t[n]>>3,i=t[n+1]>>3,u=t[n+2]>>3,a=x(s,i,u);r[a]=r[a]+1;}return r}function nt(t){let e=31,r=0,n=31,o=0,s=31,i=0;for(let u=0;u<32;u++)for(let a=0;a<32;a++)for(let c=0;c<32;c++)t[x(u,a,c)]>0&&(e=Math.min(e,u),r=Math.max(r,u),n=Math.min(n,a),o=Math.max(o,a),s=Math.min(s,c),i=Math.max(i,c));return new I(e,r,n,o,s,i,t)}function ot(t){let e=t.count();if(e===0)return [t];let r=t.r2-t.r1+1,n=t.g2-t.g1+1,o=t.b2-t.b1+1,s=Math.max(r,n,o)===r?"r":Math.max(n,o)===n?"g":"b",i=[],u=0,{histo:a}=t,c=(b,y)=>{for(let g=b;g<=y;g++){let d=0;if(s==="r")for(let p=t.g1;p<=t.g2;p++)for(let f=t.b1;f<=t.b2;f++)d+=a[x(g,p,f)];else if(s==="g")for(let p=t.r1;p<=t.r2;p++)for(let f=t.b1;f<=t.b2;f++)d+=a[x(p,g,f)];else for(let p=t.r1;p<=t.r2;p++)for(let f=t.g1;f<=t.g2;f++)d+=a[x(p,f,g)];u+=d,i[g]=u;}},l=s==="r"?t.r1:s==="g"?t.g1:t.b1,h=s==="r"?t.r2:s==="g"?t.g2:t.b2;if(c(l,h),l===h)return [t];let m=l;for(let b=l;b<=h;b++)if(i[b]>e/2){m=Math.max(l,Math.min(h-1,b));break}let S=t.clone(t.r1,s==="r"?m:t.r2,t.g1,s==="g"?m:t.g2,t.b1,s==="b"?m:t.b2),w=t.clone(s==="r"?m+1:t.r1,t.r2,s==="g"?m+1:t.g1,t.g2,s==="b"?m+1:t.b1,t.b2);return [S,w]}function st(t,e,r){let n=rt(t,Math.max(1,r)),o=[nt(n)];if(o[0].count()===0)return [];let s=(i,u)=>{let a=0;for(;a++<1e3&&o.length<i;){o.sort((h,m)=>u?h.count()*h.volume()-m.count()*m.volume():h.count()-m.count());let c=o.pop();if(!c||c.count()===0){c&&o.push(c);break}let l=ot(c);if(l.length===1){o.push(l[0]);break}o.push(l[0],l[1]);}};return s(Math.max(1,Math.floor(.75*e)),false),s(e,true),o.filter(i=>i.count()>0).sort((i,u)=>u.count()-i.count()).slice(0,e)}function C(t,e=6,r=1){return e<1?[]:st(t,e,r).map(n=>({rgb:n.average(),population:n.count()}))}var L=(t,e)=>`${e}-${t+1}`;function E(t){return t.map(e=>e.hex)}function j(t,e="color"){return `:root {
|
|
3
|
+
${t.map((n,o)=>` --${L(o,e)}: ${n.hex};`).join(`
|
|
4
|
+
`)}
|
|
5
|
+
}`}function _(t,e="color"){return t.map((r,n)=>`$${L(n,e)}: ${r.hex};`).join(`
|
|
6
|
+
`)}function H(t){return JSON.stringify(t.map(e=>({hex:e.hex,rgb:e.rgb,hsl:e.hsl,population:e.population})),null,2)}function F(t,e={}){let r=e.size??80,n=r*t.length,o=t.map((s,i)=>{let u=i*r,a=s.hex.toUpperCase();return `<rect x="${u}" y="0" width="${r}" height="${r}" fill="${s.hex}"/><text x="${u+r/2}" y="${r-8}" font-family="monospace" font-size="10" text-anchor="middle" fill="${s.textColor}">${a}</text>`}).join("");return `<svg xmlns="http://www.w3.org/2000/svg" width="${n}" height="${r}" viewBox="0 0 ${n} ${r}">${o}</svg>`}function z(t,e=[]){let r={};return t.forEach((n,o)=>{let s=e[o]??`palette-${o+1}`,i=k(n.rgb),u={};N.forEach((a,c)=>{u[a]=i[c];}),r[s]=u;}),r}function it(t){return typeof t=="object"&&t!==null&&"data"in t?t.data:t}function ut(t){return Math.max(1,Math.round(Math.sqrt(t/2e4)))}function at(t,e){return {rgb:t,hex:G(t),hsl:P(t),population:e,isLight:U(t),textColor:B(t)}}function V(t,e={}){let r=it(t),n=e.colors??6,o=e.step??ut(r.length/4);return C(r,n,o).map(({rgb:s,population:i})=>at(s,i))}var q={version:"0.2.0"};function ht(t){let e={file:null,colors:6,format:"swatches",out:null,names:[],noColor:false};for(let r=0;r<t.length;r++){let n=t[r];if(n==="-n"||n==="--colors")e.colors=Math.max(1,Number(t[++r])||6);else if(n==="--hex")e.format="hex";else if(n==="--css")e.format="css";else if(n==="--scss")e.format="scss";else if(n==="--json")e.format="json";else if(n==="--tailwind")e.format="tailwind";else if(n==="--svg"){e.format="svg";let o=t[r+1];o&&!o.startsWith("-")&&(e.out=t[++r]);}else n==="-o"||n==="--out"?e.out=t[++r]??null:n==="--names"?e.names=(t[++r]??"").split(",").map(o=>o.trim()):n==="--no-color"?e.noColor=true:n.startsWith("-")||(e.file=n);}return e}function ft(t,e){let[r,n,o]=t.rgb;return `${e?`\x1B[48;2;${r};${n};${o}m \x1B[0m`:" \u2588\u2588"} ${t.hex.toUpperCase()} ${pt(`hsl(${t.hsl.h}, ${t.hsl.s}%, ${t.hsl.l}%)`,22)}`}function pt(t,e){return t.length>=e?t:t+" ".repeat(e-t.length)}var bt=`huebrew \u2014 brew a color palette from an image (PNG), 100% locally.
|
|
7
|
+
|
|
8
|
+
Usage:
|
|
9
|
+
huebrew <image.png> [options]
|
|
10
|
+
|
|
11
|
+
Options:
|
|
12
|
+
-n, --colors <n> Number of colors to extract (default 6)
|
|
13
|
+
--hex Output a plain hex list
|
|
14
|
+
--css Output CSS custom properties (:root { --color-1: \u2026 })
|
|
15
|
+
--scss Output SCSS variables
|
|
16
|
+
--json Output JSON (hex, rgb, hsl, population)
|
|
17
|
+
--tailwind Output a Tailwind colors config with OKLab 50\u2013950 ramps
|
|
18
|
+
--svg [file] Output an SVG swatch strip (to stdout or a file)
|
|
19
|
+
--names a,b,c Names for --tailwind colors
|
|
20
|
+
-o, --out <file> Write output to a file instead of stdout
|
|
21
|
+
--no-color Disable ANSI color in the swatch view
|
|
22
|
+
-h, --help Show this help
|
|
23
|
+
-v, --version Show version
|
|
24
|
+
|
|
25
|
+
Only PNG is decoded natively (zero dependencies). For JPEG/WebP, decode to RGBA
|
|
26
|
+
and use the library API. Nothing is uploaded \u2014 all processing is local.`;function dt(t,e){switch(e.format){case "hex":return E(t).join(`
|
|
27
|
+
`);case "css":return j(t);case "scss":return _(t);case "json":return H(t);case "svg":return F(t);case "tailwind":{let r=z(t,e.names);return `// tailwind.config \u2014 theme.extend.colors
|
|
28
|
+
${JSON.stringify(r,null,2)}`}default:{let r=!e.noColor&&process.stdout.isTTY===true;return t.map(o=>ft(o,r)).join(`
|
|
29
|
+
`)}}}function gt(){let t=process.argv.slice(2);if(t.includes("-h")||t.includes("--help"))return process.stdout.write(bt+`
|
|
30
|
+
`),0;if(t.includes("-v")||t.includes("--version"))return process.stdout.write(`huebrew ${q.version}
|
|
31
|
+
`),0;let e=ht(t);if(!e.file)return process.stderr.write("huebrew: provide a PNG image. See `huebrew --help`.\n"),2;let r;try{r=fs.readFileSync(e.file);}catch{return process.stderr.write(`huebrew: cannot read ${e.file}
|
|
32
|
+
`),2}let n;try{n=T(r);}catch(i){return process.stderr.write(`huebrew: ${i.message}
|
|
33
|
+
`),/not a PNG/.test(i.message)||process.stderr.write(`huebrew: only PNG is supported by the CLI today.
|
|
34
|
+
`),2}let o=V(n,{colors:e.colors});if(o.length===0)return process.stderr.write(`huebrew: no colors found (empty or fully transparent image).
|
|
35
|
+
`),1;let s=dt(o,e);return e.out?(fs.writeFileSync(e.out,s.endsWith(`
|
|
36
|
+
`)?s:s+`
|
|
37
|
+
`),process.stderr.write(`\u2713 wrote ${e.out}
|
|
38
|
+
`)):process.stdout.write(s+`
|
|
39
|
+
`),0}process.exit(gt());//# sourceMappingURL=cli.cjs.map
|
|
40
|
+
//# sourceMappingURL=cli.cjs.map
|
package/dist/cli.cjs.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/png.ts","../src/color.ts","../src/quantize.ts","../src/format.ts","../src/index.ts","../package.json","../src/cli.ts"],"names":["SIGNATURE","isPng","b","v","i","paeth","a","c","p","pa","pb","pc","decodePng","buf","dv","width","height","bitDepth","colorType","interlace","idat","palette","trns","pos","len","type","dataStart","total","n","compressed","off","raw","inflateSync","channels","colorTypeChannels","sampleBytes","out","decodeIndexed","decodeDirect","unfilter","bpp","stride","rawPos","y","filter","rowStart","x","value","rows","src","dst","sample","ch","r","idx","readIndex","perByte","byte","shift","mask","clamp","lo","hi","rgbToHex","g","h","rgbToHsl","max","min","l","d","s","srgbToLinear","linearToSrgb","luminance","textColorFor","bg","isLight","rgb","rgbToOklab","lr","lg","lb","m","oklabToRgb","L","RAMP_STOPS","RAMP_L","ramp","base","colorIndex","VBox","_VBox","r1","r2","g1","g2","b1","b2","histo","rs","gs","bs","mult","buildHisto","pixels","step","vboxFromHisto","medianCut","vbox","rw","gw","bw","axis","partial","sum","accumulate","outer1","outer2","slice","splitPoint","run","maxColors","boxes","splitUntil","target","byVolume","iterations","biggest","parts","box","quantizeWithCounts","slug","prefix","toArray","swatches","toCSS","toSCSS","toJSON","toSVG","options","size","w","rects","label","toTailwind","names","name","stops","obj","stop","j","toPixels","source","autoStep","pixelCount","makeSwatch","population","colors","package_default","parseArgs","argv","o","next","block","useColor","pad","HELP","render","config","main","bytes","readFileSync","image","e","output","writeFileSync"],"mappings":"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","file":"cli.cjs","sourcesContent":["/**\n * Minimal PNG decoder → RGBA pixels, using only Node's built-in `zlib`.\n *\n * Supports the common cases huebrew needs for palette extraction: 8-bit\n * truecolor (type 2), truecolor+alpha (type 6), grayscale (0), grayscale+alpha\n * (4) and palette/indexed (3), with all five scanline filters. 16-bit samples\n * are down-sampled to 8-bit. Interlaced PNGs are rejected with a clear error.\n *\n * This keeps huebrew dependency-free at runtime — `node:zlib` is part of the\n * standard library, not an npm package.\n */\n\nimport { inflateSync } from \"node:zlib\";\n\nexport interface DecodedImage {\n width: number;\n height: number;\n /** RGBA, 4 bytes per pixel, row-major. */\n data: Uint8Array;\n}\n\nconst SIGNATURE = [0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a];\n\nexport function isPng(b: Uint8Array): boolean {\n return SIGNATURE.every((v, i) => b[i] === v);\n}\n\nfunction paeth(a: number, b: number, c: number): number {\n const p = a + b - c;\n const pa = Math.abs(p - a);\n const pb = Math.abs(p - b);\n const pc = Math.abs(p - c);\n if (pa <= pb && pa <= pc) return a;\n if (pb <= pc) return b;\n return c;\n}\n\n/** Decode a PNG buffer into RGBA pixels. Throws on unsupported variants. */\nexport function decodePng(buf: Uint8Array): DecodedImage {\n if (!isPng(buf)) throw new Error(\"not a PNG file\");\n const dv = new DataView(buf.buffer, buf.byteOffset, buf.byteLength);\n\n let width = 0;\n let height = 0;\n let bitDepth = 0;\n let colorType = 0;\n let interlace = 0;\n const idat: Uint8Array[] = [];\n let palette: Uint8Array | null = null;\n let trns: Uint8Array | null = null;\n\n let pos = 8;\n while (pos + 8 <= buf.length) {\n const len = dv.getUint32(pos);\n const type = String.fromCharCode(buf[pos + 4]!, buf[pos + 5]!, buf[pos + 6]!, buf[pos + 7]!);\n const dataStart = pos + 8;\n if (dataStart + len > buf.length) break;\n if (type === \"IHDR\") {\n width = dv.getUint32(dataStart);\n height = dv.getUint32(dataStart + 4);\n bitDepth = buf[dataStart + 8]!;\n colorType = buf[dataStart + 9]!;\n interlace = buf[dataStart + 12]!;\n } else if (type === \"PLTE\") {\n palette = buf.subarray(dataStart, dataStart + len);\n } else if (type === \"tRNS\") {\n trns = buf.subarray(dataStart, dataStart + len);\n } else if (type === \"IDAT\") {\n idat.push(buf.subarray(dataStart, dataStart + len));\n } else if (type === \"IEND\") {\n break;\n }\n pos = dataStart + len + 4; // + CRC\n }\n\n if (width === 0 || height === 0) throw new Error(\"invalid PNG: missing IHDR\");\n if (interlace !== 0) throw new Error(\"interlaced PNG is not supported\");\n if (bitDepth !== 8 && bitDepth !== 16 && !(colorType === 3 && bitDepth <= 8)) {\n throw new Error(`unsupported PNG bit depth ${bitDepth}`);\n }\n\n // Concatenate IDAT and inflate.\n const total = idat.reduce((n, c) => n + c.length, 0);\n const compressed = new Uint8Array(total);\n let off = 0;\n for (const c of idat) {\n compressed.set(c, off);\n off += c.length;\n }\n const raw = new Uint8Array(inflateSync(compressed));\n\n const channels = colorTypeChannels(colorType);\n const sampleBytes = bitDepth === 16 ? 2 : 1;\n const out = new Uint8Array(width * height * 4);\n\n if (colorType === 3) {\n decodeIndexed(raw, width, height, bitDepth, palette, trns, out);\n } else {\n decodeDirect(raw, width, height, channels, sampleBytes, colorType, trns, out);\n }\n return { width, height, data: out };\n}\n\nfunction colorTypeChannels(colorType: number): number {\n switch (colorType) {\n case 0: return 1; // grayscale\n case 2: return 3; // truecolor\n case 3: return 1; // indexed\n case 4: return 2; // grayscale + alpha\n case 6: return 4; // truecolor + alpha\n default: throw new Error(`unsupported PNG color type ${colorType}`);\n }\n}\n\n/** Reverse PNG scanline filters in place, returning the unfiltered row bytes. */\nfunction unfilter(raw: Uint8Array, width: number, height: number, bpp: number): Uint8Array {\n const stride = width * bpp;\n const out = new Uint8Array(height * stride);\n let rawPos = 0;\n for (let y = 0; y < height; y++) {\n const filter = raw[rawPos++]!;\n const rowStart = y * stride;\n for (let x = 0; x < stride; x++) {\n const value = raw[rawPos++]!;\n const a = x >= bpp ? out[rowStart + x - bpp]! : 0;\n const b = y > 0 ? out[rowStart - stride + x]! : 0;\n const c = y > 0 && x >= bpp ? out[rowStart - stride + x - bpp]! : 0;\n let v: number;\n switch (filter) {\n case 0: v = value; break;\n case 1: v = value + a; break;\n case 2: v = value + b; break;\n case 3: v = value + ((a + b) >> 1); break;\n case 4: v = value + paeth(a, b, c); break;\n default: throw new Error(`unsupported PNG filter ${filter}`);\n }\n out[rowStart + x] = v & 0xff;\n }\n }\n return out;\n}\n\nfunction decodeDirect(\n raw: Uint8Array,\n width: number,\n height: number,\n channels: number,\n sampleBytes: number,\n colorType: number,\n trns: Uint8Array | null,\n out: Uint8Array,\n): void {\n const bpp = channels * sampleBytes;\n const rows = unfilter(raw, width, height, bpp);\n const stride = width * bpp;\n\n for (let y = 0; y < height; y++) {\n for (let x = 0; x < width; x++) {\n const src = y * stride + x * bpp;\n const dst = (y * width + x) * 4;\n // Read each channel's high byte (handles 8- and 16-bit).\n const sample = (ch: number): number => rows[src + ch * sampleBytes]!;\n let r: number, g: number, b: number, a = 255;\n if (colorType === 0 || colorType === 4) {\n r = g = b = sample(0);\n if (colorType === 4) a = sample(1);\n } else {\n r = sample(0);\n g = sample(1);\n b = sample(2);\n if (colorType === 6) a = sample(3);\n }\n out[dst] = r;\n out[dst + 1] = g;\n out[dst + 2] = b;\n out[dst + 3] = a;\n }\n void trns;\n }\n}\n\nfunction decodeIndexed(\n raw: Uint8Array,\n width: number,\n height: number,\n bitDepth: number,\n palette: Uint8Array | null,\n trns: Uint8Array | null,\n out: Uint8Array,\n): void {\n if (!palette) throw new Error(\"indexed PNG missing PLTE\");\n // Indexed images store packed indices; unfilter with 1 byte-per-pixel stride\n // computed from the bit depth.\n const stride = Math.ceil((width * bitDepth) / 8);\n const rows = unfilter(raw, stride, height, 1);\n\n for (let y = 0; y < height; y++) {\n for (let x = 0; x < width; x++) {\n const idx = readIndex(rows, y * stride, x, bitDepth);\n const dst = (y * width + x) * 4;\n out[dst] = palette[idx * 3] ?? 0;\n out[dst + 1] = palette[idx * 3 + 1] ?? 0;\n out[dst + 2] = palette[idx * 3 + 2] ?? 0;\n out[dst + 3] = trns && idx < trns.length ? trns[idx]! : 255;\n }\n }\n}\n\nfunction readIndex(rows: Uint8Array, rowStart: number, x: number, bitDepth: number): number {\n if (bitDepth === 8) return rows[rowStart + x]!;\n const perByte = 8 / bitDepth;\n const byte = rows[rowStart + Math.floor(x / perByte)]!;\n const shift = (perByte - 1 - (x % perByte)) * bitDepth;\n const mask = (1 << bitDepth) - 1;\n return (byte >> shift) & mask;\n}\n","/**\n * Color math for huebrew: hex/rgb/hsl conversion, WCAG luminance, and an\n * OKLab-based lightness ramp (perceptually even tints/shades).\n */\n\nexport type RGB = [number, number, number];\n\nconst clamp = (n: number, lo: number, hi: number): number => (n < lo ? lo : n > hi ? hi : n);\n\nexport function rgbToHex([r, g, b]: RGB): string {\n const h = (n: number) => clamp(Math.round(n), 0, 255).toString(16).padStart(2, \"0\");\n return `#${h(r)}${h(g)}${h(b)}`;\n}\n\nexport function hexToRgb(hex: string): RGB {\n let h = hex.replace(/^#/, \"\");\n if (h.length === 3) h = h.split(\"\").map((c) => c + c).join(\"\");\n const n = parseInt(h, 16);\n return [(n >> 16) & 255, (n >> 8) & 255, n & 255];\n}\n\nexport function rgbToHsl([r, g, b]: RGB): { h: number; s: number; l: number } {\n r /= 255;\n g /= 255;\n b /= 255;\n const max = Math.max(r, g, b);\n const min = Math.min(r, g, b);\n const l = (max + min) / 2;\n if (max === min) return { h: 0, s: 0, l: Math.round(l * 100) };\n const d = max - min;\n const s = l > 0.5 ? d / (2 - max - min) : d / (max + min);\n let h: number;\n if (max === r) h = (g - b) / d + (g < b ? 6 : 0);\n else if (max === g) h = (b - r) / d + 2;\n else h = (r - g) / d + 4;\n return { h: Math.round(h * 60), s: Math.round(s * 100), l: Math.round(l * 100) };\n}\n\nconst srgbToLinear = (c: number): number =>\n c <= 0.04045 ? c / 12.92 : ((c + 0.055) / 1.055) ** 2.4;\nconst linearToSrgb = (c: number): number =>\n c <= 0.0031308 ? 12.92 * c : 1.055 * c ** (1 / 2.4) - 0.055;\n\n/** WCAG relative luminance (0–1). */\nexport function luminance([r, g, b]: RGB): number {\n return 0.2126 * srgbToLinear(r / 255) + 0.7152 * srgbToLinear(g / 255) + 0.0722 * srgbToLinear(b / 255);\n}\n\n/** WCAG contrast ratio between two colors (1–21). */\nexport function contrast(a: RGB, b: RGB): number {\n const la = luminance(a);\n const lb = luminance(b);\n const [hi, lo] = la >= lb ? [la, lb] : [lb, la];\n return (hi + 0.05) / (lo + 0.05);\n}\n\n/** Black or white — whichever is more readable on `bg`. */\nexport function textColorFor(bg: RGB): \"#000000\" | \"#ffffff\" {\n return luminance(bg) >= 0.179 ? \"#000000\" : \"#ffffff\";\n}\n\nexport const isLight = (rgb: RGB): boolean => luminance(rgb) >= 0.179;\n\n// --- OKLab ---\ninterface OKLab {\n L: number;\n a: number;\n b: number;\n}\n\nfunction rgbToOklab([r, g, b]: RGB): OKLab {\n const lr = srgbToLinear(r / 255);\n const lg = srgbToLinear(g / 255);\n const lb = srgbToLinear(b / 255);\n const l = Math.cbrt(0.4122214708 * lr + 0.5363325363 * lg + 0.0514459929 * lb);\n const m = Math.cbrt(0.2119034982 * lr + 0.6806995451 * lg + 0.1073969566 * lb);\n const s = Math.cbrt(0.0883024619 * lr + 0.2817188376 * lg + 0.6299787005 * lb);\n return {\n L: 0.2104542553 * l + 0.793617785 * m - 0.0040720468 * s,\n a: 1.9779984951 * l - 2.428592205 * m + 0.4505937099 * s,\n b: 0.0259040371 * l + 0.7827717662 * m - 0.808675766 * s,\n };\n}\n\nfunction oklabToRgb({ L, a, b }: OKLab): RGB {\n const l = (L + 0.3963377774 * a + 0.2158037573 * b) ** 3;\n const m = (L - 0.1055613458 * a - 0.0638541728 * b) ** 3;\n const s = (L - 0.0894841775 * a - 1.291485548 * b) ** 3;\n const lr = 4.0767416621 * l - 3.3077115913 * m + 0.2309699292 * s;\n const lg = -1.2684380046 * l + 2.6097574011 * m - 0.3413193965 * s;\n const lb = -0.0041960863 * l - 0.7034186147 * m + 1.707614701 * s;\n return [\n clamp(linearToSrgb(lr), 0, 1) * 255,\n clamp(linearToSrgb(lg), 0, 1) * 255,\n clamp(linearToSrgb(lb), 0, 1) * 255,\n ];\n}\n\n/** Tailwind-style ramp stops and their target OKLab lightness. */\nexport const RAMP_STOPS = [50, 100, 200, 300, 400, 500, 600, 700, 800, 900, 950] as const;\nconst RAMP_L = [0.971, 0.936, 0.885, 0.808, 0.704, 0.602, 0.515, 0.43, 0.366, 0.317, 0.235];\n\n/**\n * Generate a perceptually-even tint/shade ramp from a base color by holding its\n * OKLab hue & chroma and walking lightness through Tailwind-like stops.\n * Returns hex strings, light → dark, one per {@link RAMP_STOPS} entry.\n */\nexport function ramp(base: RGB): string[] {\n const { a, b } = rgbToOklab(base);\n return RAMP_L.map((L) => rgbToHex(oklabToRgb({ L, a, b })));\n}\n","/**\n * Modified Median Cut Quantization (MMCQ) — extract a small, representative\n * palette from a large set of pixels, deterministically and dependency-free.\n *\n * The classic approach: bucket colors into a 3D histogram, then repeatedly\n * split the box containing the most pixels along its longest axis at the\n * population median, prioritizing first by population and then by population×volume.\n */\n\nimport type { RGB } from \"./color.js\";\n\nconst SIGBITS = 5;\nconst RSHIFT = 8 - SIGBITS;\nconst HISTO_SIZE = 1 << (3 * SIGBITS);\nconst FRACT_BY_POPULATION = 0.75;\nconst MAX_ITERATIONS = 1000;\n\nconst colorIndex = (r: number, g: number, b: number): number =>\n (r << (2 * SIGBITS)) + (g << SIGBITS) + b;\n\nclass VBox {\n constructor(\n public r1: number,\n public r2: number,\n public g1: number,\n public g2: number,\n public b1: number,\n public b2: number,\n public readonly histo: Int32Array,\n ) {}\n\n private _count = -1;\n private _avg: RGB | null = null;\n\n volume(): number {\n return (this.r2 - this.r1 + 1) * (this.g2 - this.g1 + 1) * (this.b2 - this.b1 + 1);\n }\n\n count(): number {\n if (this._count >= 0) return this._count;\n let n = 0;\n for (let r = this.r1; r <= this.r2; r++)\n for (let g = this.g1; g <= this.g2; g++)\n for (let b = this.b1; b <= this.b2; b++) n += this.histo[colorIndex(r, g, b)] as number;\n this._count = n;\n return n;\n }\n\n average(): RGB {\n if (this._avg) return this._avg;\n let total = 0;\n let rs = 0;\n let gs = 0;\n let bs = 0;\n const mult = 1 << RSHIFT;\n for (let r = this.r1; r <= this.r2; r++)\n for (let g = this.g1; g <= this.g2; g++)\n for (let b = this.b1; b <= this.b2; b++) {\n const h = this.histo[colorIndex(r, g, b)] as number;\n total += h;\n rs += h * (r + 0.5) * mult;\n gs += h * (g + 0.5) * mult;\n bs += h * (b + 0.5) * mult;\n }\n this._avg = total\n ? [Math.round(rs / total), Math.round(gs / total), Math.round(bs / total)]\n : [\n Math.round((mult * (this.r1 + this.r2 + 1)) / 2),\n Math.round((mult * (this.g1 + this.g2 + 1)) / 2),\n Math.round((mult * (this.b1 + this.b2 + 1)) / 2),\n ];\n return this._avg;\n }\n\n clone(r1: number, r2: number, g1: number, g2: number, b1: number, b2: number): VBox {\n return new VBox(r1, r2, g1, g2, b1, b2, this.histo);\n }\n}\n\nfunction buildHisto(pixels: ArrayLike<number>, step: number): Int32Array {\n const histo = new Int32Array(HISTO_SIZE);\n for (let i = 0; i < pixels.length; i += 4 * step) {\n const a = pixels[i + 3];\n if (a !== undefined && a < 125) continue; // skip mostly-transparent pixels\n const r = (pixels[i] as number) >> RSHIFT;\n const g = (pixels[i + 1] as number) >> RSHIFT;\n const b = (pixels[i + 2] as number) >> RSHIFT;\n const idx = colorIndex(r, g, b);\n histo[idx] = (histo[idx] as number) + 1;\n }\n return histo;\n}\n\nfunction vboxFromHisto(histo: Int32Array): VBox {\n let r1 = 31, r2 = 0, g1 = 31, g2 = 0, b1 = 31, b2 = 0;\n for (let r = 0; r < 32; r++)\n for (let g = 0; g < 32; g++)\n for (let b = 0; b < 32; b++) {\n if ((histo[colorIndex(r, g, b)] as number) > 0) {\n r1 = Math.min(r1, r); r2 = Math.max(r2, r);\n g1 = Math.min(g1, g); g2 = Math.max(g2, g);\n b1 = Math.min(b1, b); b2 = Math.max(b2, b);\n }\n }\n return new VBox(r1, r2, g1, g2, b1, b2, histo);\n}\n\nfunction medianCut(vbox: VBox): [VBox, VBox] | [VBox] {\n const total = vbox.count();\n if (total === 0) return [vbox];\n\n const rw = vbox.r2 - vbox.r1 + 1;\n const gw = vbox.g2 - vbox.g1 + 1;\n const bw = vbox.b2 - vbox.b1 + 1;\n const axis = Math.max(rw, gw, bw) === rw ? \"r\" : Math.max(gw, bw) === gw ? \"g\" : \"b\";\n\n const partial: number[] = [];\n let sum = 0;\n const { histo } = vbox;\n\n const accumulate = (outer1: number, outer2: number) => {\n for (let i = outer1; i <= outer2; i++) {\n let slice = 0;\n if (axis === \"r\") {\n for (let g = vbox.g1; g <= vbox.g2; g++)\n for (let b = vbox.b1; b <= vbox.b2; b++) slice += histo[colorIndex(i, g, b)] as number;\n } else if (axis === \"g\") {\n for (let r = vbox.r1; r <= vbox.r2; r++)\n for (let b = vbox.b1; b <= vbox.b2; b++) slice += histo[colorIndex(r, i, b)] as number;\n } else {\n for (let r = vbox.r1; r <= vbox.r2; r++)\n for (let g = vbox.g1; g <= vbox.g2; g++) slice += histo[colorIndex(r, g, i)] as number;\n }\n sum += slice;\n partial[i] = sum;\n }\n };\n\n const lo = axis === \"r\" ? vbox.r1 : axis === \"g\" ? vbox.g1 : vbox.b1;\n const hi = axis === \"r\" ? vbox.r2 : axis === \"g\" ? vbox.g2 : vbox.b2;\n accumulate(lo, hi);\n\n if (lo === hi) return [vbox]; // can't split a single slice\n\n let splitPoint = lo;\n for (let i = lo; i <= hi; i++) {\n if ((partial[i] as number) > total / 2) {\n splitPoint = Math.max(lo, Math.min(hi - 1, i));\n break;\n }\n }\n\n const a = vbox.clone(\n vbox.r1, axis === \"r\" ? splitPoint : vbox.r2,\n vbox.g1, axis === \"g\" ? splitPoint : vbox.g2,\n vbox.b1, axis === \"b\" ? splitPoint : vbox.b2,\n );\n const b = vbox.clone(\n axis === \"r\" ? splitPoint + 1 : vbox.r1, vbox.r2,\n axis === \"g\" ? splitPoint + 1 : vbox.g1, vbox.g2,\n axis === \"b\" ? splitPoint + 1 : vbox.b1, vbox.b2,\n );\n return [a, b];\n}\n\nfunction run(pixels: ArrayLike<number>, maxColors: number, step: number): VBox[] {\n const histo = buildHisto(pixels, Math.max(1, step));\n const boxes = [vboxFromHisto(histo)];\n if (boxes[0]!.count() === 0) return [];\n\n const splitUntil = (target: number, byVolume: boolean) => {\n let iterations = 0;\n while (iterations++ < MAX_ITERATIONS && boxes.length < target) {\n boxes.sort((x, y) =>\n byVolume ? x.count() * x.volume() - y.count() * y.volume() : x.count() - y.count(),\n );\n const biggest = boxes.pop();\n if (!biggest || biggest.count() === 0) {\n if (biggest) boxes.push(biggest);\n break;\n }\n const parts = medianCut(biggest);\n if (parts.length === 1) {\n boxes.push(parts[0]); // unsplittable; leave it and stop trying\n break;\n }\n boxes.push(parts[0], parts[1]);\n }\n };\n\n splitUntil(Math.max(1, Math.floor(FRACT_BY_POPULATION * maxColors)), false);\n splitUntil(maxColors, true);\n\n return boxes\n .filter((box) => box.count() > 0)\n .sort((x, y) => y.count() - x.count())\n .slice(0, maxColors);\n}\n\n/**\n * Quantize `pixels` (a flat RGBA array) down to at most `maxColors` colors.\n * `step` samples every Nth pixel for speed. Returns RGB triplets ordered by\n * population (most common first).\n */\nexport function quantize(pixels: ArrayLike<number>, maxColors = 6, step = 1): RGB[] {\n if (maxColors < 1) return [];\n return run(pixels, maxColors, step).map((box) => box.average());\n}\n\n/** Like {@link quantize}, but each color carries its pixel population (sampled). */\nexport function quantizeWithCounts(\n pixels: ArrayLike<number>,\n maxColors = 6,\n step = 1,\n): { rgb: RGB; population: number }[] {\n if (maxColors < 1) return [];\n return run(pixels, maxColors, step).map((box) => ({ rgb: box.average(), population: box.count() }));\n}\n","/**\n * Export a palette into developer-ready formats: hex array, CSS variables,\n * SCSS, JSON, an SVG preview strip, and a Tailwind color config (with\n * perceptual ramps).\n */\n\nimport { ramp, RAMP_STOPS } from \"./color.js\";\nimport type { Swatch } from \"./index.js\";\n\nconst slug = (i: number, prefix: string): string => `${prefix}-${i + 1}`;\n\n/** Just the hex strings, in palette order. */\nexport function toArray(swatches: Swatch[]): string[] {\n return swatches.map((s) => s.hex);\n}\n\n/** `:root { --color-1: #...; ... }` */\nexport function toCSS(swatches: Swatch[], prefix = \"color\"): string {\n const lines = swatches.map((s, i) => ` --${slug(i, prefix)}: ${s.hex};`);\n return `:root {\\n${lines.join(\"\\n\")}\\n}`;\n}\n\n/** `$color-1: #...;` SCSS variables. */\nexport function toSCSS(swatches: Swatch[], prefix = \"color\"): string {\n return swatches.map((s, i) => `$${slug(i, prefix)}: ${s.hex};`).join(\"\\n\");\n}\n\n/** Pretty JSON of the palette (hex, rgb, hsl, population). */\nexport function toJSON(swatches: Swatch[]): string {\n return JSON.stringify(\n swatches.map((s) => ({ hex: s.hex, rgb: s.rgb, hsl: s.hsl, population: s.population })),\n null,\n 2,\n );\n}\n\n/** A standalone SVG strip of swatches — great for READMEs and previews. */\nexport function toSVG(swatches: Swatch[], options: { size?: number } = {}): string {\n const size = options.size ?? 80;\n const w = size * swatches.length;\n const rects = swatches\n .map((s, i) => {\n const x = i * size;\n const label = s.hex.toUpperCase();\n return (\n `<rect x=\"${x}\" y=\"0\" width=\"${size}\" height=\"${size}\" fill=\"${s.hex}\"/>` +\n `<text x=\"${x + size / 2}\" y=\"${size - 8}\" font-family=\"monospace\" font-size=\"10\" ` +\n `text-anchor=\"middle\" fill=\"${s.textColor}\">${label}</text>`\n );\n })\n .join(\"\");\n return `<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"${w}\" height=\"${size}\" viewBox=\"0 0 ${w} ${size}\">${rects}</svg>`;\n}\n\n/**\n * A Tailwind `theme.extend.colors` object. Each swatch becomes a named color\n * with a full 50–950 perceptual ramp (great for dropping into a config).\n *\n * ```ts\n * toTailwind(palette(img), [\"brand\", \"accent\"]);\n * // { brand: { 50: \"#...\", ..., 950: \"#...\" }, accent: { ... }, ... }\n * ```\n */\nexport function toTailwind(\n swatches: Swatch[],\n names: string[] = [],\n): Record<string, Record<string, string>> {\n const out: Record<string, Record<string, string>> = {};\n swatches.forEach((s, i) => {\n const name = names[i] ?? `palette-${i + 1}`;\n const stops = ramp(s.rgb);\n const obj: Record<string, string> = {};\n RAMP_STOPS.forEach((stop, j) => {\n obj[stop] = stops[j] as string;\n });\n out[name] = obj;\n });\n return out;\n}\n","/**\n * huebrew — brew a usable color palette & theme tokens from any image.\n *\n * Zero dependencies. The core works on raw RGBA pixels, so it runs in the\n * browser (via canvas `ImageData`), in Node (via any decoder you already use),\n * Deno or Bun — and never makes a network call.\n */\n\nimport { isLight, rgbToHex, rgbToHsl, textColorFor, type RGB } from \"./color.js\";\nimport { quantize, quantizeWithCounts } from \"./quantize.js\";\n\nexport type { RGB } from \"./color.js\";\nexport { rgbToHex, hexToRgb, rgbToHsl, ramp, contrast, luminance, textColorFor, RAMP_STOPS } from \"./color.js\";\nexport { quantize, quantizeWithCounts } from \"./quantize.js\";\nexport * from \"./format.js\";\n\nexport interface Swatch {\n rgb: RGB;\n hex: string;\n hsl: { h: number; s: number; l: number };\n /** Sampled pixel population for this color (higher = more dominant). */\n population: number;\n isLight: boolean;\n /** `\"#000000\"` or `\"#ffffff\"` — whichever is readable on this swatch (WCAG). */\n textColor: string;\n}\n\n/** An RGBA pixel buffer, or anything `ImageData`-shaped (`{ data, width, height }`). */\nexport type PixelSource = ArrayLike<number> | { data: ArrayLike<number>; width?: number; height?: number };\n\nexport interface PaletteOptions {\n /** How many colors to extract. Default `6`. */\n colors?: number;\n /** Sample every Nth pixel. Default: auto (targets ~20k samples for speed). */\n step?: number;\n}\n\nfunction toPixels(source: PixelSource): ArrayLike<number> {\n if (typeof source === \"object\" && source !== null && \"data\" in source) return source.data;\n return source;\n}\n\nfunction autoStep(pixelCount: number): number {\n return Math.max(1, Math.round(Math.sqrt(pixelCount / 20000)));\n}\n\nfunction makeSwatch(rgb: RGB, population: number): Swatch {\n return {\n rgb,\n hex: rgbToHex(rgb),\n hsl: rgbToHsl(rgb),\n population,\n isLight: isLight(rgb),\n textColor: textColorFor(rgb),\n };\n}\n\n/**\n * Extract a palette from an image's pixels, most-dominant first.\n *\n * ```ts\n * // Browser\n * const ctx = canvas.getContext(\"2d\")!;\n * const swatches = palette(ctx.getImageData(0, 0, canvas.width, canvas.height), { colors: 6 });\n * swatches[0].hex; // dominant color\n * ```\n */\nexport function palette(source: PixelSource, options: PaletteOptions = {}): Swatch[] {\n const pixels = toPixels(source);\n const colors = options.colors ?? 6;\n const step = options.step ?? autoStep(pixels.length / 4);\n return quantizeWithCounts(pixels, colors, step).map(({ rgb, population }) =>\n makeSwatch(rgb, population),\n );\n}\n\n/** The single most dominant color, or `null` for an empty/transparent image. */\nexport function dominant(source: PixelSource, options: PaletteOptions = {}): Swatch | null {\n return palette(source, { ...options, colors: Math.max(options.colors ?? 5, 5) })[0] ?? null;\n}\n","{\n \"name\": \"huebrew\",\n \"version\": \"0.2.0\",\n \"description\": \"Brew a color palette & ready-to-use theme tokens from any image — dominant colors via median-cut, perceptual OKLab ramps, and CSS/SCSS/Tailwind/JSON/SVG export. CLI + library + web app. Zero dependencies, 100% local.\",\n \"type\": \"module\",\n \"main\": \"./dist/index.js\",\n \"module\": \"./dist/index.js\",\n \"types\": \"./dist/index.d.ts\",\n \"exports\": {\n \".\": {\n \"types\": \"./dist/index.d.ts\",\n \"import\": \"./dist/index.js\",\n \"require\": \"./dist/index.cjs\"\n }\n },\n \"bin\": {\n \"huebrew\": \"./dist/cli.js\"\n },\n \"files\": [\n \"dist\"\n ],\n \"sideEffects\": false,\n \"engines\": {\n \"node\": \">=18\"\n },\n \"scripts\": {\n \"build\": \"tsup\",\n \"build:web\": \"vite build\",\n \"dev\": \"vite\",\n \"test\": \"vitest run\",\n \"test:watch\": \"vitest\",\n \"typecheck\": \"tsc --noEmit\",\n \"lint\": \"tsc --noEmit\",\n \"prepublishOnly\": \"npm run build\"\n },\n \"keywords\": [\n \"color-palette\",\n \"palette-extractor\",\n \"image-colors\",\n \"dominant-color\",\n \"color-thief\",\n \"median-cut\",\n \"oklch\",\n \"tailwind-colors\",\n \"design-tokens\",\n \"color-scheme\",\n \"theme-generator\",\n \"cli\",\n \"zero-dependency\"\n ],\n \"author\": \"didrod205 (https://github.com/didrod205)\",\n \"license\": \"MIT\",\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"git+https://github.com/didrod205/huebrew.git\"\n },\n \"bugs\": {\n \"url\": \"https://github.com/didrod205/huebrew/issues\"\n },\n \"homepage\": \"https://didrod205.github.io/huebrew/\",\n \"devDependencies\": {\n \"@types/node\": \"^22.19.19\",\n \"tsup\": \"^8.3.5\",\n \"typescript\": \"^5.7.2\",\n \"vite\": \"^6.0.0\",\n \"vitest\": \"^2.1.8\"\n }\n}\n","#!/usr/bin/env node\n/**\n * huebrew CLI — brew a color palette from a PNG image, zero-dependency.\n *\n * huebrew photo.png # print the palette (swatches + hex)\n * huebrew photo.png -n 8 # 8 colors\n * huebrew photo.png --css # CSS variables\n * huebrew photo.png --tailwind # Tailwind color config (OKLab ramps)\n * huebrew photo.png --svg palette.svg # write an SVG strip\n *\n * Only PNG is decoded natively (via Node's built-in zlib — still no deps). For\n * other formats, decode to RGBA yourself and use the library API.\n */\n\nimport { readFileSync, writeFileSync } from \"node:fs\";\nimport { decodePng } from \"./png.js\";\nimport { palette, type Swatch } from \"./index.js\";\nimport { toArray, toCSS, toSCSS, toJSON, toSVG, toTailwind } from \"./format.js\";\nimport pkg from \"../package.json\";\n\ninterface Options {\n file: string | null;\n colors: number;\n format: \"swatches\" | \"hex\" | \"css\" | \"scss\" | \"json\" | \"svg\" | \"tailwind\";\n out: string | null;\n names: string[];\n noColor: boolean;\n}\n\nfunction parseArgs(argv: string[]): Options {\n const o: Options = {\n file: null,\n colors: 6,\n format: \"swatches\",\n out: null,\n names: [],\n noColor: false,\n };\n for (let i = 0; i < argv.length; i++) {\n const a = argv[i]!;\n if (a === \"-n\" || a === \"--colors\") o.colors = Math.max(1, Number(argv[++i]) || 6);\n else if (a === \"--hex\") o.format = \"hex\";\n else if (a === \"--css\") o.format = \"css\";\n else if (a === \"--scss\") o.format = \"scss\";\n else if (a === \"--json\") o.format = \"json\";\n else if (a === \"--tailwind\") o.format = \"tailwind\";\n else if (a === \"--svg\") {\n o.format = \"svg\";\n const next = argv[i + 1];\n if (next && !next.startsWith(\"-\")) o.out = argv[++i]!;\n } else if (a === \"-o\" || a === \"--out\") o.out = argv[++i] ?? null;\n else if (a === \"--names\") o.names = (argv[++i] ?? \"\").split(\",\").map((s) => s.trim());\n else if (a === \"--no-color\") o.noColor = true;\n else if (!a.startsWith(\"-\")) o.file = a;\n }\n return o;\n}\n\n/** Print a swatch as a colored block using a truecolor ANSI background. */\nfunction block(s: Swatch, useColor: boolean): string {\n const [r, g, b] = s.rgb;\n const swatch = useColor ? `\\x1b[48;2;${r};${g};${b}m \\x1b[0m` : \" ██\";\n const pct = \"\";\n return `${swatch} ${s.hex.toUpperCase()} ${pad(`hsl(${s.hsl.h}, ${s.hsl.s}%, ${s.hsl.l}%)`, 22)}${pct}`;\n}\n\nfunction pad(s: string, n: number): string {\n return s.length >= n ? s : s + \" \".repeat(n - s.length);\n}\n\nconst HELP = `huebrew — brew a color palette from an image (PNG), 100% locally.\n\nUsage:\n huebrew <image.png> [options]\n\nOptions:\n -n, --colors <n> Number of colors to extract (default 6)\n --hex Output a plain hex list\n --css Output CSS custom properties (:root { --color-1: … })\n --scss Output SCSS variables\n --json Output JSON (hex, rgb, hsl, population)\n --tailwind Output a Tailwind colors config with OKLab 50–950 ramps\n --svg [file] Output an SVG swatch strip (to stdout or a file)\n --names a,b,c Names for --tailwind colors\n -o, --out <file> Write output to a file instead of stdout\n --no-color Disable ANSI color in the swatch view\n -h, --help Show this help\n -v, --version Show version\n\nOnly PNG is decoded natively (zero dependencies). For JPEG/WebP, decode to RGBA\nand use the library API. Nothing is uploaded — all processing is local.`;\n\nfunction render(swatches: Swatch[], o: Options): string {\n switch (o.format) {\n case \"hex\": return toArray(swatches).join(\"\\n\");\n case \"css\": return toCSS(swatches);\n case \"scss\": return toSCSS(swatches);\n case \"json\": return toJSON(swatches);\n case \"svg\": return toSVG(swatches);\n case \"tailwind\": {\n const config = toTailwind(swatches, o.names);\n return `// tailwind.config — theme.extend.colors\\n${JSON.stringify(config, null, 2)}`;\n }\n default: {\n const useColor = !o.noColor && process.stdout.isTTY === true;\n const lines = swatches.map((s) => block(s, useColor));\n return lines.join(\"\\n\");\n }\n }\n}\n\nfunction main(): number {\n const argv = process.argv.slice(2);\n if (argv.includes(\"-h\") || argv.includes(\"--help\")) {\n process.stdout.write(HELP + \"\\n\");\n return 0;\n }\n if (argv.includes(\"-v\") || argv.includes(\"--version\")) {\n process.stdout.write(`huebrew ${pkg.version}\\n`);\n return 0;\n }\n\n const o = parseArgs(argv);\n if (!o.file) {\n process.stderr.write(\"huebrew: provide a PNG image. See `huebrew --help`.\\n\");\n return 2;\n }\n\n let bytes: Uint8Array;\n try {\n bytes = readFileSync(o.file);\n } catch {\n process.stderr.write(`huebrew: cannot read ${o.file}\\n`);\n return 2;\n }\n\n let image;\n try {\n image = decodePng(bytes);\n } catch (e) {\n process.stderr.write(`huebrew: ${(e as Error).message}\\n`);\n if (!/not a PNG/.test((e as Error).message)) {\n process.stderr.write(\"huebrew: only PNG is supported by the CLI today.\\n\");\n }\n return 2;\n }\n\n const swatches = palette(image, { colors: o.colors });\n if (swatches.length === 0) {\n process.stderr.write(\"huebrew: no colors found (empty or fully transparent image).\\n\");\n return 1;\n }\n\n const output = render(swatches, o);\n if (o.out) {\n writeFileSync(o.out, output.endsWith(\"\\n\") ? output : output + \"\\n\");\n process.stderr.write(`✓ wrote ${o.out}\\n`);\n } else {\n process.stdout.write(output + \"\\n\");\n }\n return 0;\n}\n\nprocess.exit(main());\n"]}
|
package/dist/cli.js
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {q,p,o,n,m,l,k as k$1}from'./chunk-ZGA67ZO4.js';import {readFileSync,writeFileSync}from'fs';import {inflateSync}from'zlib';var k=[137,80,78,71,13,10,26,10];function I(e){return k.every((t,n)=>e[n]===t)}function j(e,t,n){let r=e+t-n,o=Math.abs(r-e),s=Math.abs(r-t),l=Math.abs(r-n);return o<=s&&o<=l?e:s<=l?t:n}function E(e){if(!I(e))throw new Error("not a PNG file");let t=new DataView(e.buffer,e.byteOffset,e.byteLength),n=0,r=0,o=0,s=0,l=0,a=[],h=null,d=null,i=8;for(;i+8<=e.length;){let f=t.getUint32(i),b=String.fromCharCode(e[i+4],e[i+5],e[i+6],e[i+7]),p=i+8;if(p+f>e.length)break;if(b==="IHDR")n=t.getUint32(p),r=t.getUint32(p+4),o=e[p+8],s=e[p+9],l=e[p+12];else if(b==="PLTE")h=e.subarray(p,p+f);else if(b==="tRNS")d=e.subarray(p,p+f);else if(b==="IDAT")a.push(e.subarray(p,p+f));else if(b==="IEND")break;i=p+f+4;}if(n===0||r===0)throw new Error("invalid PNG: missing IHDR");if(l!==0)throw new Error("interlaced PNG is not supported");if(o!==8&&o!==16&&!(s===3&&o<=8))throw new Error(`unsupported PNG bit depth ${o}`);let c=a.reduce((f,b)=>f+b.length,0),u=new Uint8Array(c),g=0;for(let f of a)u.set(f,g),g+=f.length;let w=new Uint8Array(inflateSync(u)),m=L(s),x=o===16?2:1,y=new Uint8Array(n*r*4);return s===3?D(w,n,r,o,h,d,y):T(w,n,r,m,x,s,d,y),{width:n,height:r,data:y}}function L(e){switch(e){case 0:return 1;case 2:return 3;case 3:return 1;case 4:return 2;case 6:return 4;default:throw new Error(`unsupported PNG color type ${e}`)}}function G(e,t,n,r){let o=t*r,s=new Uint8Array(n*o),l=0;for(let a=0;a<n;a++){let h=e[l++],d=a*o;for(let i=0;i<o;i++){let c=e[l++],u=i>=r?s[d+i-r]:0,g=a>0?s[d-o+i]:0,w=a>0&&i>=r?s[d-o+i-r]:0,m;switch(h){case 0:m=c;break;case 1:m=c+u;break;case 2:m=c+g;break;case 3:m=c+(u+g>>1);break;case 4:m=c+j(u,g,w);break;default:throw new Error(`unsupported PNG filter ${h}`)}s[d+i]=m&255;}}return s}function T(e,t,n,r,o,s,l,a){let h=r*o,d=G(e,t,n,h),i=t*h;for(let c=0;c<n;c++)for(let u=0;u<t;u++){let g=c*i+u*h,w=(c*t+u)*4,m=p=>d[g+p*o],x,y,f,b=255;s===0||s===4?(x=y=f=m(0),s===4&&(b=m(1))):(x=m(0),y=m(1),f=m(2),s===6&&(b=m(3))),a[w]=x,a[w+1]=y,a[w+2]=f,a[w+3]=b;}}function D(e,t,n,r,o,s,l){if(!o)throw new Error("indexed PNG missing PLTE");let a=Math.ceil(t*r/8),h=G(e,a,n,1);for(let d=0;d<n;d++)for(let i=0;i<t;i++){let c=M(h,d*a,i,r),u=(d*t+i)*4;l[u]=o[c*3]??0,l[u+1]=o[c*3+1]??0,l[u+2]=o[c*3+2]??0,l[u+3]=s&&c<s.length?s[c]:255;}}function M(e,t,n,r){if(r===8)return e[t+n];let o=8/r,s=e[t+Math.floor(n/o)],l=(o-1-n%o)*r,a=(1<<r)-1;return s>>l&a}var $={version:"0.2.0"};function V(e){let t={file:null,colors:6,format:"swatches",out:null,names:[],noColor:false};for(let n=0;n<e.length;n++){let r=e[n];if(r==="-n"||r==="--colors")t.colors=Math.max(1,Number(e[++n])||6);else if(r==="--hex")t.format="hex";else if(r==="--css")t.format="css";else if(r==="--scss")t.format="scss";else if(r==="--json")t.format="json";else if(r==="--tailwind")t.format="tailwind";else if(r==="--svg"){t.format="svg";let o=e[n+1];o&&!o.startsWith("-")&&(t.out=e[++n]);}else r==="-o"||r==="--out"?t.out=e[++n]??null:r==="--names"?t.names=(e[++n]??"").split(",").map(o=>o.trim()):r==="--no-color"?t.noColor=true:r.startsWith("-")||(t.file=r);}return t}function B(e,t){let[n,r,o]=e.rgb;return `${t?`\x1B[48;2;${n};${r};${o}m \x1B[0m`:" \u2588\u2588"} ${e.hex.toUpperCase()} ${F(`hsl(${e.hsl.h}, ${e.hsl.s}%, ${e.hsl.l}%)`,22)}`}function F(e,t){return e.length>=t?e:e+" ".repeat(t-e.length)}var H=`huebrew \u2014 brew a color palette from an image (PNG), 100% locally.
|
|
3
|
+
|
|
4
|
+
Usage:
|
|
5
|
+
huebrew <image.png> [options]
|
|
6
|
+
|
|
7
|
+
Options:
|
|
8
|
+
-n, --colors <n> Number of colors to extract (default 6)
|
|
9
|
+
--hex Output a plain hex list
|
|
10
|
+
--css Output CSS custom properties (:root { --color-1: \u2026 })
|
|
11
|
+
--scss Output SCSS variables
|
|
12
|
+
--json Output JSON (hex, rgb, hsl, population)
|
|
13
|
+
--tailwind Output a Tailwind colors config with OKLab 50\u2013950 ramps
|
|
14
|
+
--svg [file] Output an SVG swatch strip (to stdout or a file)
|
|
15
|
+
--names a,b,c Names for --tailwind colors
|
|
16
|
+
-o, --out <file> Write output to a file instead of stdout
|
|
17
|
+
--no-color Disable ANSI color in the swatch view
|
|
18
|
+
-h, --help Show this help
|
|
19
|
+
-v, --version Show version
|
|
20
|
+
|
|
21
|
+
Only PNG is decoded natively (zero dependencies). For JPEG/WebP, decode to RGBA
|
|
22
|
+
and use the library API. Nothing is uploaded \u2014 all processing is local.`;function z(e,t){switch(t.format){case "hex":return k$1(e).join(`
|
|
23
|
+
`);case "css":return l(e);case "scss":return m(e);case "json":return n(e);case "svg":return o(e);case "tailwind":{let n=p(e,t.names);return `// tailwind.config \u2014 theme.extend.colors
|
|
24
|
+
${JSON.stringify(n,null,2)}`}default:{let n=!t.noColor&&process.stdout.isTTY===true;return e.map(o=>B(o,n)).join(`
|
|
25
|
+
`)}}}function K(){let e=process.argv.slice(2);if(e.includes("-h")||e.includes("--help"))return process.stdout.write(H+`
|
|
26
|
+
`),0;if(e.includes("-v")||e.includes("--version"))return process.stdout.write(`huebrew ${$.version}
|
|
27
|
+
`),0;let t=V(e);if(!t.file)return process.stderr.write("huebrew: provide a PNG image. See `huebrew --help`.\n"),2;let n;try{n=readFileSync(t.file);}catch{return process.stderr.write(`huebrew: cannot read ${t.file}
|
|
28
|
+
`),2}let r;try{r=E(n);}catch(l){return process.stderr.write(`huebrew: ${l.message}
|
|
29
|
+
`),/not a PNG/.test(l.message)||process.stderr.write(`huebrew: only PNG is supported by the CLI today.
|
|
30
|
+
`),2}let o=q(r,{colors:t.colors});if(o.length===0)return process.stderr.write(`huebrew: no colors found (empty or fully transparent image).
|
|
31
|
+
`),1;let s=z(o,t);return t.out?(writeFileSync(t.out,s.endsWith(`
|
|
32
|
+
`)?s:s+`
|
|
33
|
+
`),process.stderr.write(`\u2713 wrote ${t.out}
|
|
34
|
+
`)):process.stdout.write(s+`
|
|
35
|
+
`),0}process.exit(K());//# sourceMappingURL=cli.js.map
|
|
36
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/png.ts","../package.json","../src/cli.ts"],"names":["SIGNATURE","isPng","b","v","i","paeth","a","c","p","pa","pb","pc","decodePng","buf","dv","width","height","bitDepth","colorType","interlace","idat","palette","trns","pos","len","type","dataStart","total","n","compressed","off","raw","inflateSync","channels","colorTypeChannels","sampleBytes","out","decodeIndexed","decodeDirect","unfilter","bpp","stride","rawPos","y","filter","rowStart","x","value","rows","src","dst","sample","ch","r","g","idx","readIndex","perByte","byte","shift","mask","package_default","parseArgs","argv","o","next","s","block","useColor","pad","HELP","render","swatches","toArray","toCSS","toSCSS","toJSON","toSVG","config","toTailwind","main","bytes","readFileSync","image","e","output","writeFileSync"],"mappings":"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","file":"cli.js","sourcesContent":["/**\n * Minimal PNG decoder → RGBA pixels, using only Node's built-in `zlib`.\n *\n * Supports the common cases huebrew needs for palette extraction: 8-bit\n * truecolor (type 2), truecolor+alpha (type 6), grayscale (0), grayscale+alpha\n * (4) and palette/indexed (3), with all five scanline filters. 16-bit samples\n * are down-sampled to 8-bit. Interlaced PNGs are rejected with a clear error.\n *\n * This keeps huebrew dependency-free at runtime — `node:zlib` is part of the\n * standard library, not an npm package.\n */\n\nimport { inflateSync } from \"node:zlib\";\n\nexport interface DecodedImage {\n width: number;\n height: number;\n /** RGBA, 4 bytes per pixel, row-major. */\n data: Uint8Array;\n}\n\nconst SIGNATURE = [0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a];\n\nexport function isPng(b: Uint8Array): boolean {\n return SIGNATURE.every((v, i) => b[i] === v);\n}\n\nfunction paeth(a: number, b: number, c: number): number {\n const p = a + b - c;\n const pa = Math.abs(p - a);\n const pb = Math.abs(p - b);\n const pc = Math.abs(p - c);\n if (pa <= pb && pa <= pc) return a;\n if (pb <= pc) return b;\n return c;\n}\n\n/** Decode a PNG buffer into RGBA pixels. Throws on unsupported variants. */\nexport function decodePng(buf: Uint8Array): DecodedImage {\n if (!isPng(buf)) throw new Error(\"not a PNG file\");\n const dv = new DataView(buf.buffer, buf.byteOffset, buf.byteLength);\n\n let width = 0;\n let height = 0;\n let bitDepth = 0;\n let colorType = 0;\n let interlace = 0;\n const idat: Uint8Array[] = [];\n let palette: Uint8Array | null = null;\n let trns: Uint8Array | null = null;\n\n let pos = 8;\n while (pos + 8 <= buf.length) {\n const len = dv.getUint32(pos);\n const type = String.fromCharCode(buf[pos + 4]!, buf[pos + 5]!, buf[pos + 6]!, buf[pos + 7]!);\n const dataStart = pos + 8;\n if (dataStart + len > buf.length) break;\n if (type === \"IHDR\") {\n width = dv.getUint32(dataStart);\n height = dv.getUint32(dataStart + 4);\n bitDepth = buf[dataStart + 8]!;\n colorType = buf[dataStart + 9]!;\n interlace = buf[dataStart + 12]!;\n } else if (type === \"PLTE\") {\n palette = buf.subarray(dataStart, dataStart + len);\n } else if (type === \"tRNS\") {\n trns = buf.subarray(dataStart, dataStart + len);\n } else if (type === \"IDAT\") {\n idat.push(buf.subarray(dataStart, dataStart + len));\n } else if (type === \"IEND\") {\n break;\n }\n pos = dataStart + len + 4; // + CRC\n }\n\n if (width === 0 || height === 0) throw new Error(\"invalid PNG: missing IHDR\");\n if (interlace !== 0) throw new Error(\"interlaced PNG is not supported\");\n if (bitDepth !== 8 && bitDepth !== 16 && !(colorType === 3 && bitDepth <= 8)) {\n throw new Error(`unsupported PNG bit depth ${bitDepth}`);\n }\n\n // Concatenate IDAT and inflate.\n const total = idat.reduce((n, c) => n + c.length, 0);\n const compressed = new Uint8Array(total);\n let off = 0;\n for (const c of idat) {\n compressed.set(c, off);\n off += c.length;\n }\n const raw = new Uint8Array(inflateSync(compressed));\n\n const channels = colorTypeChannels(colorType);\n const sampleBytes = bitDepth === 16 ? 2 : 1;\n const out = new Uint8Array(width * height * 4);\n\n if (colorType === 3) {\n decodeIndexed(raw, width, height, bitDepth, palette, trns, out);\n } else {\n decodeDirect(raw, width, height, channels, sampleBytes, colorType, trns, out);\n }\n return { width, height, data: out };\n}\n\nfunction colorTypeChannels(colorType: number): number {\n switch (colorType) {\n case 0: return 1; // grayscale\n case 2: return 3; // truecolor\n case 3: return 1; // indexed\n case 4: return 2; // grayscale + alpha\n case 6: return 4; // truecolor + alpha\n default: throw new Error(`unsupported PNG color type ${colorType}`);\n }\n}\n\n/** Reverse PNG scanline filters in place, returning the unfiltered row bytes. */\nfunction unfilter(raw: Uint8Array, width: number, height: number, bpp: number): Uint8Array {\n const stride = width * bpp;\n const out = new Uint8Array(height * stride);\n let rawPos = 0;\n for (let y = 0; y < height; y++) {\n const filter = raw[rawPos++]!;\n const rowStart = y * stride;\n for (let x = 0; x < stride; x++) {\n const value = raw[rawPos++]!;\n const a = x >= bpp ? out[rowStart + x - bpp]! : 0;\n const b = y > 0 ? out[rowStart - stride + x]! : 0;\n const c = y > 0 && x >= bpp ? out[rowStart - stride + x - bpp]! : 0;\n let v: number;\n switch (filter) {\n case 0: v = value; break;\n case 1: v = value + a; break;\n case 2: v = value + b; break;\n case 3: v = value + ((a + b) >> 1); break;\n case 4: v = value + paeth(a, b, c); break;\n default: throw new Error(`unsupported PNG filter ${filter}`);\n }\n out[rowStart + x] = v & 0xff;\n }\n }\n return out;\n}\n\nfunction decodeDirect(\n raw: Uint8Array,\n width: number,\n height: number,\n channels: number,\n sampleBytes: number,\n colorType: number,\n trns: Uint8Array | null,\n out: Uint8Array,\n): void {\n const bpp = channels * sampleBytes;\n const rows = unfilter(raw, width, height, bpp);\n const stride = width * bpp;\n\n for (let y = 0; y < height; y++) {\n for (let x = 0; x < width; x++) {\n const src = y * stride + x * bpp;\n const dst = (y * width + x) * 4;\n // Read each channel's high byte (handles 8- and 16-bit).\n const sample = (ch: number): number => rows[src + ch * sampleBytes]!;\n let r: number, g: number, b: number, a = 255;\n if (colorType === 0 || colorType === 4) {\n r = g = b = sample(0);\n if (colorType === 4) a = sample(1);\n } else {\n r = sample(0);\n g = sample(1);\n b = sample(2);\n if (colorType === 6) a = sample(3);\n }\n out[dst] = r;\n out[dst + 1] = g;\n out[dst + 2] = b;\n out[dst + 3] = a;\n }\n void trns;\n }\n}\n\nfunction decodeIndexed(\n raw: Uint8Array,\n width: number,\n height: number,\n bitDepth: number,\n palette: Uint8Array | null,\n trns: Uint8Array | null,\n out: Uint8Array,\n): void {\n if (!palette) throw new Error(\"indexed PNG missing PLTE\");\n // Indexed images store packed indices; unfilter with 1 byte-per-pixel stride\n // computed from the bit depth.\n const stride = Math.ceil((width * bitDepth) / 8);\n const rows = unfilter(raw, stride, height, 1);\n\n for (let y = 0; y < height; y++) {\n for (let x = 0; x < width; x++) {\n const idx = readIndex(rows, y * stride, x, bitDepth);\n const dst = (y * width + x) * 4;\n out[dst] = palette[idx * 3] ?? 0;\n out[dst + 1] = palette[idx * 3 + 1] ?? 0;\n out[dst + 2] = palette[idx * 3 + 2] ?? 0;\n out[dst + 3] = trns && idx < trns.length ? trns[idx]! : 255;\n }\n }\n}\n\nfunction readIndex(rows: Uint8Array, rowStart: number, x: number, bitDepth: number): number {\n if (bitDepth === 8) return rows[rowStart + x]!;\n const perByte = 8 / bitDepth;\n const byte = rows[rowStart + Math.floor(x / perByte)]!;\n const shift = (perByte - 1 - (x % perByte)) * bitDepth;\n const mask = (1 << bitDepth) - 1;\n return (byte >> shift) & mask;\n}\n","{\n \"name\": \"huebrew\",\n \"version\": \"0.2.0\",\n \"description\": \"Brew a color palette & ready-to-use theme tokens from any image — dominant colors via median-cut, perceptual OKLab ramps, and CSS/SCSS/Tailwind/JSON/SVG export. CLI + library + web app. Zero dependencies, 100% local.\",\n \"type\": \"module\",\n \"main\": \"./dist/index.js\",\n \"module\": \"./dist/index.js\",\n \"types\": \"./dist/index.d.ts\",\n \"exports\": {\n \".\": {\n \"types\": \"./dist/index.d.ts\",\n \"import\": \"./dist/index.js\",\n \"require\": \"./dist/index.cjs\"\n }\n },\n \"bin\": {\n \"huebrew\": \"./dist/cli.js\"\n },\n \"files\": [\n \"dist\"\n ],\n \"sideEffects\": false,\n \"engines\": {\n \"node\": \">=18\"\n },\n \"scripts\": {\n \"build\": \"tsup\",\n \"build:web\": \"vite build\",\n \"dev\": \"vite\",\n \"test\": \"vitest run\",\n \"test:watch\": \"vitest\",\n \"typecheck\": \"tsc --noEmit\",\n \"lint\": \"tsc --noEmit\",\n \"prepublishOnly\": \"npm run build\"\n },\n \"keywords\": [\n \"color-palette\",\n \"palette-extractor\",\n \"image-colors\",\n \"dominant-color\",\n \"color-thief\",\n \"median-cut\",\n \"oklch\",\n \"tailwind-colors\",\n \"design-tokens\",\n \"color-scheme\",\n \"theme-generator\",\n \"cli\",\n \"zero-dependency\"\n ],\n \"author\": \"didrod205 (https://github.com/didrod205)\",\n \"license\": \"MIT\",\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"git+https://github.com/didrod205/huebrew.git\"\n },\n \"bugs\": {\n \"url\": \"https://github.com/didrod205/huebrew/issues\"\n },\n \"homepage\": \"https://didrod205.github.io/huebrew/\",\n \"devDependencies\": {\n \"@types/node\": \"^22.19.19\",\n \"tsup\": \"^8.3.5\",\n \"typescript\": \"^5.7.2\",\n \"vite\": \"^6.0.0\",\n \"vitest\": \"^2.1.8\"\n }\n}\n","#!/usr/bin/env node\n/**\n * huebrew CLI — brew a color palette from a PNG image, zero-dependency.\n *\n * huebrew photo.png # print the palette (swatches + hex)\n * huebrew photo.png -n 8 # 8 colors\n * huebrew photo.png --css # CSS variables\n * huebrew photo.png --tailwind # Tailwind color config (OKLab ramps)\n * huebrew photo.png --svg palette.svg # write an SVG strip\n *\n * Only PNG is decoded natively (via Node's built-in zlib — still no deps). For\n * other formats, decode to RGBA yourself and use the library API.\n */\n\nimport { readFileSync, writeFileSync } from \"node:fs\";\nimport { decodePng } from \"./png.js\";\nimport { palette, type Swatch } from \"./index.js\";\nimport { toArray, toCSS, toSCSS, toJSON, toSVG, toTailwind } from \"./format.js\";\nimport pkg from \"../package.json\";\n\ninterface Options {\n file: string | null;\n colors: number;\n format: \"swatches\" | \"hex\" | \"css\" | \"scss\" | \"json\" | \"svg\" | \"tailwind\";\n out: string | null;\n names: string[];\n noColor: boolean;\n}\n\nfunction parseArgs(argv: string[]): Options {\n const o: Options = {\n file: null,\n colors: 6,\n format: \"swatches\",\n out: null,\n names: [],\n noColor: false,\n };\n for (let i = 0; i < argv.length; i++) {\n const a = argv[i]!;\n if (a === \"-n\" || a === \"--colors\") o.colors = Math.max(1, Number(argv[++i]) || 6);\n else if (a === \"--hex\") o.format = \"hex\";\n else if (a === \"--css\") o.format = \"css\";\n else if (a === \"--scss\") o.format = \"scss\";\n else if (a === \"--json\") o.format = \"json\";\n else if (a === \"--tailwind\") o.format = \"tailwind\";\n else if (a === \"--svg\") {\n o.format = \"svg\";\n const next = argv[i + 1];\n if (next && !next.startsWith(\"-\")) o.out = argv[++i]!;\n } else if (a === \"-o\" || a === \"--out\") o.out = argv[++i] ?? null;\n else if (a === \"--names\") o.names = (argv[++i] ?? \"\").split(\",\").map((s) => s.trim());\n else if (a === \"--no-color\") o.noColor = true;\n else if (!a.startsWith(\"-\")) o.file = a;\n }\n return o;\n}\n\n/** Print a swatch as a colored block using a truecolor ANSI background. */\nfunction block(s: Swatch, useColor: boolean): string {\n const [r, g, b] = s.rgb;\n const swatch = useColor ? `\\x1b[48;2;${r};${g};${b}m \\x1b[0m` : \" ██\";\n const pct = \"\";\n return `${swatch} ${s.hex.toUpperCase()} ${pad(`hsl(${s.hsl.h}, ${s.hsl.s}%, ${s.hsl.l}%)`, 22)}${pct}`;\n}\n\nfunction pad(s: string, n: number): string {\n return s.length >= n ? s : s + \" \".repeat(n - s.length);\n}\n\nconst HELP = `huebrew — brew a color palette from an image (PNG), 100% locally.\n\nUsage:\n huebrew <image.png> [options]\n\nOptions:\n -n, --colors <n> Number of colors to extract (default 6)\n --hex Output a plain hex list\n --css Output CSS custom properties (:root { --color-1: … })\n --scss Output SCSS variables\n --json Output JSON (hex, rgb, hsl, population)\n --tailwind Output a Tailwind colors config with OKLab 50–950 ramps\n --svg [file] Output an SVG swatch strip (to stdout or a file)\n --names a,b,c Names for --tailwind colors\n -o, --out <file> Write output to a file instead of stdout\n --no-color Disable ANSI color in the swatch view\n -h, --help Show this help\n -v, --version Show version\n\nOnly PNG is decoded natively (zero dependencies). For JPEG/WebP, decode to RGBA\nand use the library API. Nothing is uploaded — all processing is local.`;\n\nfunction render(swatches: Swatch[], o: Options): string {\n switch (o.format) {\n case \"hex\": return toArray(swatches).join(\"\\n\");\n case \"css\": return toCSS(swatches);\n case \"scss\": return toSCSS(swatches);\n case \"json\": return toJSON(swatches);\n case \"svg\": return toSVG(swatches);\n case \"tailwind\": {\n const config = toTailwind(swatches, o.names);\n return `// tailwind.config — theme.extend.colors\\n${JSON.stringify(config, null, 2)}`;\n }\n default: {\n const useColor = !o.noColor && process.stdout.isTTY === true;\n const lines = swatches.map((s) => block(s, useColor));\n return lines.join(\"\\n\");\n }\n }\n}\n\nfunction main(): number {\n const argv = process.argv.slice(2);\n if (argv.includes(\"-h\") || argv.includes(\"--help\")) {\n process.stdout.write(HELP + \"\\n\");\n return 0;\n }\n if (argv.includes(\"-v\") || argv.includes(\"--version\")) {\n process.stdout.write(`huebrew ${pkg.version}\\n`);\n return 0;\n }\n\n const o = parseArgs(argv);\n if (!o.file) {\n process.stderr.write(\"huebrew: provide a PNG image. See `huebrew --help`.\\n\");\n return 2;\n }\n\n let bytes: Uint8Array;\n try {\n bytes = readFileSync(o.file);\n } catch {\n process.stderr.write(`huebrew: cannot read ${o.file}\\n`);\n return 2;\n }\n\n let image;\n try {\n image = decodePng(bytes);\n } catch (e) {\n process.stderr.write(`huebrew: ${(e as Error).message}\\n`);\n if (!/not a PNG/.test((e as Error).message)) {\n process.stderr.write(\"huebrew: only PNG is supported by the CLI today.\\n\");\n }\n return 2;\n }\n\n const swatches = palette(image, { colors: o.colors });\n if (swatches.length === 0) {\n process.stderr.write(\"huebrew: no colors found (empty or fully transparent image).\\n\");\n return 1;\n }\n\n const output = render(swatches, o);\n if (o.out) {\n writeFileSync(o.out, output.endsWith(\"\\n\") ? output : output + \"\\n\");\n process.stderr.write(`✓ wrote ${o.out}\\n`);\n } else {\n process.stdout.write(output + \"\\n\");\n }\n return 0;\n}\n\nprocess.exit(main());\n"]}
|
package/dist/index.js
CHANGED
|
@@ -1,7 +1,2 @@
|
|
|
1
|
-
|
|
2
|
-
${t.map((e,o)=>` --${_(o,r)}: ${e.hex};`).join(`
|
|
3
|
-
`)}
|
|
4
|
-
}`}function tt(t,r="color"){return t.map((n,e)=>`$${_(e,r)}: ${n.hex};`).join(`
|
|
5
|
-
`)}function rt(t){return JSON.stringify(t.map(r=>({hex:r.hex,rgb:r.rgb,hsl:r.hsl,population:r.population})),null,2)}function nt(t,r={}){let n=r.size??80,e=n*t.length,o=t.map((u,i)=>{let s=i*n,a=u.hex.toUpperCase();return `<rect x="${s}" y="0" width="${n}" height="${n}" fill="${u.hex}"/><text x="${s+n/2}" y="${n-8}" font-family="monospace" font-size="10" text-anchor="middle" fill="${u.textColor}">${a}</text>`}).join("");return `<svg xmlns="http://www.w3.org/2000/svg" width="${e}" height="${n}" viewBox="0 0 ${e} ${n}">${o}</svg>`}function et(t,r=[]){let n={};return t.forEach((e,o)=>{let u=r[o]??`palette-${o+1}`,i=$(e.rgb),s={};G.forEach((a,c)=>{s[a]=i[c];}),n[u]=s;}),n}function K(t){return typeof t=="object"&&t!==null&&"data"in t?t.data:t}function W(t){return Math.max(1,Math.round(Math.sqrt(t/2e4)))}function J(t,r){return {rgb:t,hex:B(t),hsl:I(t),population:r,isLight:O(t),textColor:w(t)}}function X(t,r={}){let n=K(t),e=r.colors??6,o=r.step??W(n.length/4);return y(n,e,o).map(({rgb:u,population:i})=>J(u,i))}function at(t,r={}){return X(t,{...r,colors:Math.max(r.colors??5,5)})[0]??null}
|
|
6
|
-
export{G as RAMP_STOPS,F as contrast,at as dominant,C as hexToRgb,M as luminance,X as palette,U as quantize,y as quantizeWithCounts,$ as ramp,B as rgbToHex,I as rgbToHsl,w as textColorFor,Q as toArray,v as toCSS,rt as toJSON,tt as toSCSS,nt as toSVG,et as toTailwind};//# sourceMappingURL=index.js.map
|
|
1
|
+
export{g as RAMP_STOPS,e as contrast,r as dominant,b as hexToRgb,d as luminance,q as palette,i as quantize,j as quantizeWithCounts,h as ramp,a as rgbToHex,c as rgbToHsl,f as textColorFor,k as toArray,l as toCSS,n as toJSON,m as toSCSS,o as toSVG,p as toTailwind}from'./chunk-ZGA67ZO4.js';//# sourceMappingURL=index.js.map
|
|
7
2
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/color.ts","../src/quantize.ts","../src/format.ts","../src/index.ts"],"names":["clamp","n","lo","hi","rgbToHex","r","g","b","h","hexToRgb","hex","c","rgbToHsl","max","min","l","d","srgbToLinear","linearToSrgb","luminance","contrast","a","la","lb","textColorFor","bg","isLight","rgb","rgbToOklab","lr","lg","m","s","oklabToRgb","L","RAMP_STOPS","RAMP_L","ramp","base","colorIndex","VBox","_VBox","r1","r2","g1","g2","b1","b2","histo","total","rs","gs","bs","mult","buildHisto","pixels","step","i","idx","vboxFromHisto","medianCut","vbox","rw","gw","bw","axis","partial","sum","accumulate","outer1","outer2","slice","splitPoint","run","maxColors","boxes","splitUntil","target","byVolume","iterations","x","y","biggest","parts","box","quantize","quantizeWithCounts","slug","prefix","toArray","swatches","toCSS","toSCSS","toJSON","toSVG","options","size","w","rects","label","toTailwind","names","out","name","stops","obj","stop","j","toPixels","source","autoStep","pixelCount","makeSwatch","population","palette","colors","dominant"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Color math for huebrew: hex/rgb/hsl conversion, WCAG luminance, and an\n * OKLab-based lightness ramp (perceptually even tints/shades).\n */\n\nexport type RGB = [number, number, number];\n\nconst clamp = (n: number, lo: number, hi: number): number => (n < lo ? lo : n > hi ? hi : n);\n\nexport function rgbToHex([r, g, b]: RGB): string {\n const h = (n: number) => clamp(Math.round(n), 0, 255).toString(16).padStart(2, \"0\");\n return `#${h(r)}${h(g)}${h(b)}`;\n}\n\nexport function hexToRgb(hex: string): RGB {\n let h = hex.replace(/^#/, \"\");\n if (h.length === 3) h = h.split(\"\").map((c) => c + c).join(\"\");\n const n = parseInt(h, 16);\n return [(n >> 16) & 255, (n >> 8) & 255, n & 255];\n}\n\nexport function rgbToHsl([r, g, b]: RGB): { h: number; s: number; l: number } {\n r /= 255;\n g /= 255;\n b /= 255;\n const max = Math.max(r, g, b);\n const min = Math.min(r, g, b);\n const l = (max + min) / 2;\n if (max === min) return { h: 0, s: 0, l: Math.round(l * 100) };\n const d = max - min;\n const s = l > 0.5 ? d / (2 - max - min) : d / (max + min);\n let h: number;\n if (max === r) h = (g - b) / d + (g < b ? 6 : 0);\n else if (max === g) h = (b - r) / d + 2;\n else h = (r - g) / d + 4;\n return { h: Math.round(h * 60), s: Math.round(s * 100), l: Math.round(l * 100) };\n}\n\nconst srgbToLinear = (c: number): number =>\n c <= 0.04045 ? c / 12.92 : ((c + 0.055) / 1.055) ** 2.4;\nconst linearToSrgb = (c: number): number =>\n c <= 0.0031308 ? 12.92 * c : 1.055 * c ** (1 / 2.4) - 0.055;\n\n/** WCAG relative luminance (0–1). */\nexport function luminance([r, g, b]: RGB): number {\n return 0.2126 * srgbToLinear(r / 255) + 0.7152 * srgbToLinear(g / 255) + 0.0722 * srgbToLinear(b / 255);\n}\n\n/** WCAG contrast ratio between two colors (1–21). */\nexport function contrast(a: RGB, b: RGB): number {\n const la = luminance(a);\n const lb = luminance(b);\n const [hi, lo] = la >= lb ? [la, lb] : [lb, la];\n return (hi + 0.05) / (lo + 0.05);\n}\n\n/** Black or white — whichever is more readable on `bg`. */\nexport function textColorFor(bg: RGB): \"#000000\" | \"#ffffff\" {\n return luminance(bg) >= 0.179 ? \"#000000\" : \"#ffffff\";\n}\n\nexport const isLight = (rgb: RGB): boolean => luminance(rgb) >= 0.179;\n\n// --- OKLab ---\ninterface OKLab {\n L: number;\n a: number;\n b: number;\n}\n\nfunction rgbToOklab([r, g, b]: RGB): OKLab {\n const lr = srgbToLinear(r / 255);\n const lg = srgbToLinear(g / 255);\n const lb = srgbToLinear(b / 255);\n const l = Math.cbrt(0.4122214708 * lr + 0.5363325363 * lg + 0.0514459929 * lb);\n const m = Math.cbrt(0.2119034982 * lr + 0.6806995451 * lg + 0.1073969566 * lb);\n const s = Math.cbrt(0.0883024619 * lr + 0.2817188376 * lg + 0.6299787005 * lb);\n return {\n L: 0.2104542553 * l + 0.793617785 * m - 0.0040720468 * s,\n a: 1.9779984951 * l - 2.428592205 * m + 0.4505937099 * s,\n b: 0.0259040371 * l + 0.7827717662 * m - 0.808675766 * s,\n };\n}\n\nfunction oklabToRgb({ L, a, b }: OKLab): RGB {\n const l = (L + 0.3963377774 * a + 0.2158037573 * b) ** 3;\n const m = (L - 0.1055613458 * a - 0.0638541728 * b) ** 3;\n const s = (L - 0.0894841775 * a - 1.291485548 * b) ** 3;\n const lr = 4.0767416621 * l - 3.3077115913 * m + 0.2309699292 * s;\n const lg = -1.2684380046 * l + 2.6097574011 * m - 0.3413193965 * s;\n const lb = -0.0041960863 * l - 0.7034186147 * m + 1.707614701 * s;\n return [\n clamp(linearToSrgb(lr), 0, 1) * 255,\n clamp(linearToSrgb(lg), 0, 1) * 255,\n clamp(linearToSrgb(lb), 0, 1) * 255,\n ];\n}\n\n/** Tailwind-style ramp stops and their target OKLab lightness. */\nexport const RAMP_STOPS = [50, 100, 200, 300, 400, 500, 600, 700, 800, 900, 950] as const;\nconst RAMP_L = [0.971, 0.936, 0.885, 0.808, 0.704, 0.602, 0.515, 0.43, 0.366, 0.317, 0.235];\n\n/**\n * Generate a perceptually-even tint/shade ramp from a base color by holding its\n * OKLab hue & chroma and walking lightness through Tailwind-like stops.\n * Returns hex strings, light → dark, one per {@link RAMP_STOPS} entry.\n */\nexport function ramp(base: RGB): string[] {\n const { a, b } = rgbToOklab(base);\n return RAMP_L.map((L) => rgbToHex(oklabToRgb({ L, a, b })));\n}\n","/**\n * Modified Median Cut Quantization (MMCQ) — extract a small, representative\n * palette from a large set of pixels, deterministically and dependency-free.\n *\n * The classic approach: bucket colors into a 3D histogram, then repeatedly\n * split the box containing the most pixels along its longest axis at the\n * population median, prioritizing first by population and then by population×volume.\n */\n\nimport type { RGB } from \"./color.js\";\n\nconst SIGBITS = 5;\nconst RSHIFT = 8 - SIGBITS;\nconst HISTO_SIZE = 1 << (3 * SIGBITS);\nconst FRACT_BY_POPULATION = 0.75;\nconst MAX_ITERATIONS = 1000;\n\nconst colorIndex = (r: number, g: number, b: number): number =>\n (r << (2 * SIGBITS)) + (g << SIGBITS) + b;\n\nclass VBox {\n constructor(\n public r1: number,\n public r2: number,\n public g1: number,\n public g2: number,\n public b1: number,\n public b2: number,\n public readonly histo: Int32Array,\n ) {}\n\n private _count = -1;\n private _avg: RGB | null = null;\n\n volume(): number {\n return (this.r2 - this.r1 + 1) * (this.g2 - this.g1 + 1) * (this.b2 - this.b1 + 1);\n }\n\n count(): number {\n if (this._count >= 0) return this._count;\n let n = 0;\n for (let r = this.r1; r <= this.r2; r++)\n for (let g = this.g1; g <= this.g2; g++)\n for (let b = this.b1; b <= this.b2; b++) n += this.histo[colorIndex(r, g, b)] as number;\n this._count = n;\n return n;\n }\n\n average(): RGB {\n if (this._avg) return this._avg;\n let total = 0;\n let rs = 0;\n let gs = 0;\n let bs = 0;\n const mult = 1 << RSHIFT;\n for (let r = this.r1; r <= this.r2; r++)\n for (let g = this.g1; g <= this.g2; g++)\n for (let b = this.b1; b <= this.b2; b++) {\n const h = this.histo[colorIndex(r, g, b)] as number;\n total += h;\n rs += h * (r + 0.5) * mult;\n gs += h * (g + 0.5) * mult;\n bs += h * (b + 0.5) * mult;\n }\n this._avg = total\n ? [Math.round(rs / total), Math.round(gs / total), Math.round(bs / total)]\n : [\n Math.round((mult * (this.r1 + this.r2 + 1)) / 2),\n Math.round((mult * (this.g1 + this.g2 + 1)) / 2),\n Math.round((mult * (this.b1 + this.b2 + 1)) / 2),\n ];\n return this._avg;\n }\n\n clone(r1: number, r2: number, g1: number, g2: number, b1: number, b2: number): VBox {\n return new VBox(r1, r2, g1, g2, b1, b2, this.histo);\n }\n}\n\nfunction buildHisto(pixels: ArrayLike<number>, step: number): Int32Array {\n const histo = new Int32Array(HISTO_SIZE);\n for (let i = 0; i < pixels.length; i += 4 * step) {\n const a = pixels[i + 3];\n if (a !== undefined && a < 125) continue; // skip mostly-transparent pixels\n const r = (pixels[i] as number) >> RSHIFT;\n const g = (pixels[i + 1] as number) >> RSHIFT;\n const b = (pixels[i + 2] as number) >> RSHIFT;\n const idx = colorIndex(r, g, b);\n histo[idx] = (histo[idx] as number) + 1;\n }\n return histo;\n}\n\nfunction vboxFromHisto(histo: Int32Array): VBox {\n let r1 = 31, r2 = 0, g1 = 31, g2 = 0, b1 = 31, b2 = 0;\n for (let r = 0; r < 32; r++)\n for (let g = 0; g < 32; g++)\n for (let b = 0; b < 32; b++) {\n if ((histo[colorIndex(r, g, b)] as number) > 0) {\n r1 = Math.min(r1, r); r2 = Math.max(r2, r);\n g1 = Math.min(g1, g); g2 = Math.max(g2, g);\n b1 = Math.min(b1, b); b2 = Math.max(b2, b);\n }\n }\n return new VBox(r1, r2, g1, g2, b1, b2, histo);\n}\n\nfunction medianCut(vbox: VBox): [VBox, VBox] | [VBox] {\n const total = vbox.count();\n if (total === 0) return [vbox];\n\n const rw = vbox.r2 - vbox.r1 + 1;\n const gw = vbox.g2 - vbox.g1 + 1;\n const bw = vbox.b2 - vbox.b1 + 1;\n const axis = Math.max(rw, gw, bw) === rw ? \"r\" : Math.max(gw, bw) === gw ? \"g\" : \"b\";\n\n const partial: number[] = [];\n let sum = 0;\n const { histo } = vbox;\n\n const accumulate = (outer1: number, outer2: number) => {\n for (let i = outer1; i <= outer2; i++) {\n let slice = 0;\n if (axis === \"r\") {\n for (let g = vbox.g1; g <= vbox.g2; g++)\n for (let b = vbox.b1; b <= vbox.b2; b++) slice += histo[colorIndex(i, g, b)] as number;\n } else if (axis === \"g\") {\n for (let r = vbox.r1; r <= vbox.r2; r++)\n for (let b = vbox.b1; b <= vbox.b2; b++) slice += histo[colorIndex(r, i, b)] as number;\n } else {\n for (let r = vbox.r1; r <= vbox.r2; r++)\n for (let g = vbox.g1; g <= vbox.g2; g++) slice += histo[colorIndex(r, g, i)] as number;\n }\n sum += slice;\n partial[i] = sum;\n }\n };\n\n const lo = axis === \"r\" ? vbox.r1 : axis === \"g\" ? vbox.g1 : vbox.b1;\n const hi = axis === \"r\" ? vbox.r2 : axis === \"g\" ? vbox.g2 : vbox.b2;\n accumulate(lo, hi);\n\n if (lo === hi) return [vbox]; // can't split a single slice\n\n let splitPoint = lo;\n for (let i = lo; i <= hi; i++) {\n if ((partial[i] as number) > total / 2) {\n splitPoint = Math.max(lo, Math.min(hi - 1, i));\n break;\n }\n }\n\n const a = vbox.clone(\n vbox.r1, axis === \"r\" ? splitPoint : vbox.r2,\n vbox.g1, axis === \"g\" ? splitPoint : vbox.g2,\n vbox.b1, axis === \"b\" ? splitPoint : vbox.b2,\n );\n const b = vbox.clone(\n axis === \"r\" ? splitPoint + 1 : vbox.r1, vbox.r2,\n axis === \"g\" ? splitPoint + 1 : vbox.g1, vbox.g2,\n axis === \"b\" ? splitPoint + 1 : vbox.b1, vbox.b2,\n );\n return [a, b];\n}\n\nfunction run(pixels: ArrayLike<number>, maxColors: number, step: number): VBox[] {\n const histo = buildHisto(pixels, Math.max(1, step));\n const boxes = [vboxFromHisto(histo)];\n if (boxes[0]!.count() === 0) return [];\n\n const splitUntil = (target: number, byVolume: boolean) => {\n let iterations = 0;\n while (iterations++ < MAX_ITERATIONS && boxes.length < target) {\n boxes.sort((x, y) =>\n byVolume ? x.count() * x.volume() - y.count() * y.volume() : x.count() - y.count(),\n );\n const biggest = boxes.pop();\n if (!biggest || biggest.count() === 0) {\n if (biggest) boxes.push(biggest);\n break;\n }\n const parts = medianCut(biggest);\n if (parts.length === 1) {\n boxes.push(parts[0]); // unsplittable; leave it and stop trying\n break;\n }\n boxes.push(parts[0], parts[1]);\n }\n };\n\n splitUntil(Math.max(1, Math.floor(FRACT_BY_POPULATION * maxColors)), false);\n splitUntil(maxColors, true);\n\n return boxes\n .filter((box) => box.count() > 0)\n .sort((x, y) => y.count() - x.count())\n .slice(0, maxColors);\n}\n\n/**\n * Quantize `pixels` (a flat RGBA array) down to at most `maxColors` colors.\n * `step` samples every Nth pixel for speed. Returns RGB triplets ordered by\n * population (most common first).\n */\nexport function quantize(pixels: ArrayLike<number>, maxColors = 6, step = 1): RGB[] {\n if (maxColors < 1) return [];\n return run(pixels, maxColors, step).map((box) => box.average());\n}\n\n/** Like {@link quantize}, but each color carries its pixel population (sampled). */\nexport function quantizeWithCounts(\n pixels: ArrayLike<number>,\n maxColors = 6,\n step = 1,\n): { rgb: RGB; population: number }[] {\n if (maxColors < 1) return [];\n return run(pixels, maxColors, step).map((box) => ({ rgb: box.average(), population: box.count() }));\n}\n","/**\n * Export a palette into developer-ready formats: hex array, CSS variables,\n * SCSS, JSON, an SVG preview strip, and a Tailwind color config (with\n * perceptual ramps).\n */\n\nimport { ramp, RAMP_STOPS } from \"./color.js\";\nimport type { Swatch } from \"./index.js\";\n\nconst slug = (i: number, prefix: string): string => `${prefix}-${i + 1}`;\n\n/** Just the hex strings, in palette order. */\nexport function toArray(swatches: Swatch[]): string[] {\n return swatches.map((s) => s.hex);\n}\n\n/** `:root { --color-1: #...; ... }` */\nexport function toCSS(swatches: Swatch[], prefix = \"color\"): string {\n const lines = swatches.map((s, i) => ` --${slug(i, prefix)}: ${s.hex};`);\n return `:root {\\n${lines.join(\"\\n\")}\\n}`;\n}\n\n/** `$color-1: #...;` SCSS variables. */\nexport function toSCSS(swatches: Swatch[], prefix = \"color\"): string {\n return swatches.map((s, i) => `$${slug(i, prefix)}: ${s.hex};`).join(\"\\n\");\n}\n\n/** Pretty JSON of the palette (hex, rgb, hsl, population). */\nexport function toJSON(swatches: Swatch[]): string {\n return JSON.stringify(\n swatches.map((s) => ({ hex: s.hex, rgb: s.rgb, hsl: s.hsl, population: s.population })),\n null,\n 2,\n );\n}\n\n/** A standalone SVG strip of swatches — great for READMEs and previews. */\nexport function toSVG(swatches: Swatch[], options: { size?: number } = {}): string {\n const size = options.size ?? 80;\n const w = size * swatches.length;\n const rects = swatches\n .map((s, i) => {\n const x = i * size;\n const label = s.hex.toUpperCase();\n return (\n `<rect x=\"${x}\" y=\"0\" width=\"${size}\" height=\"${size}\" fill=\"${s.hex}\"/>` +\n `<text x=\"${x + size / 2}\" y=\"${size - 8}\" font-family=\"monospace\" font-size=\"10\" ` +\n `text-anchor=\"middle\" fill=\"${s.textColor}\">${label}</text>`\n );\n })\n .join(\"\");\n return `<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"${w}\" height=\"${size}\" viewBox=\"0 0 ${w} ${size}\">${rects}</svg>`;\n}\n\n/**\n * A Tailwind `theme.extend.colors` object. Each swatch becomes a named color\n * with a full 50–950 perceptual ramp (great for dropping into a config).\n *\n * ```ts\n * toTailwind(palette(img), [\"brand\", \"accent\"]);\n * // { brand: { 50: \"#...\", ..., 950: \"#...\" }, accent: { ... }, ... }\n * ```\n */\nexport function toTailwind(\n swatches: Swatch[],\n names: string[] = [],\n): Record<string, Record<string, string>> {\n const out: Record<string, Record<string, string>> = {};\n swatches.forEach((s, i) => {\n const name = names[i] ?? `palette-${i + 1}`;\n const stops = ramp(s.rgb);\n const obj: Record<string, string> = {};\n RAMP_STOPS.forEach((stop, j) => {\n obj[stop] = stops[j] as string;\n });\n out[name] = obj;\n });\n return out;\n}\n","/**\n * huebrew — brew a usable color palette & theme tokens from any image.\n *\n * Zero dependencies. The core works on raw RGBA pixels, so it runs in the\n * browser (via canvas `ImageData`), in Node (via any decoder you already use),\n * Deno or Bun — and never makes a network call.\n */\n\nimport { isLight, rgbToHex, rgbToHsl, textColorFor, type RGB } from \"./color.js\";\nimport { quantize, quantizeWithCounts } from \"./quantize.js\";\n\nexport type { RGB } from \"./color.js\";\nexport { rgbToHex, hexToRgb, rgbToHsl, ramp, contrast, luminance, textColorFor, RAMP_STOPS } from \"./color.js\";\nexport { quantize, quantizeWithCounts } from \"./quantize.js\";\nexport * from \"./format.js\";\n\nexport interface Swatch {\n rgb: RGB;\n hex: string;\n hsl: { h: number; s: number; l: number };\n /** Sampled pixel population for this color (higher = more dominant). */\n population: number;\n isLight: boolean;\n /** `\"#000000\"` or `\"#ffffff\"` — whichever is readable on this swatch (WCAG). */\n textColor: string;\n}\n\n/** An RGBA pixel buffer, or anything `ImageData`-shaped (`{ data, width, height }`). */\nexport type PixelSource = ArrayLike<number> | { data: ArrayLike<number>; width?: number; height?: number };\n\nexport interface PaletteOptions {\n /** How many colors to extract. Default `6`. */\n colors?: number;\n /** Sample every Nth pixel. Default: auto (targets ~20k samples for speed). */\n step?: number;\n}\n\nfunction toPixels(source: PixelSource): ArrayLike<number> {\n if (typeof source === \"object\" && source !== null && \"data\" in source) return source.data;\n return source;\n}\n\nfunction autoStep(pixelCount: number): number {\n return Math.max(1, Math.round(Math.sqrt(pixelCount / 20000)));\n}\n\nfunction makeSwatch(rgb: RGB, population: number): Swatch {\n return {\n rgb,\n hex: rgbToHex(rgb),\n hsl: rgbToHsl(rgb),\n population,\n isLight: isLight(rgb),\n textColor: textColorFor(rgb),\n };\n}\n\n/**\n * Extract a palette from an image's pixels, most-dominant first.\n *\n * ```ts\n * // Browser\n * const ctx = canvas.getContext(\"2d\")!;\n * const swatches = palette(ctx.getImageData(0, 0, canvas.width, canvas.height), { colors: 6 });\n * swatches[0].hex; // dominant color\n * ```\n */\nexport function palette(source: PixelSource, options: PaletteOptions = {}): Swatch[] {\n const pixels = toPixels(source);\n const colors = options.colors ?? 6;\n const step = options.step ?? autoStep(pixels.length / 4);\n return quantizeWithCounts(pixels, colors, step).map(({ rgb, population }) =>\n makeSwatch(rgb, population),\n );\n}\n\n/** The single most dominant color, or `null` for an empty/transparent image. */\nexport function dominant(source: PixelSource, options: PaletteOptions = {}): Swatch | null {\n return palette(source, { ...options, colors: Math.max(options.colors ?? 5, 5) })[0] ?? null;\n}\n"]}
|
|
1
|
+
{"version":3,"sources":[],"names":[],"mappings":"","file":"index.js"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "huebrew",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "Brew a color palette & ready-to-use theme tokens from any image — dominant colors via median-cut, perceptual OKLab ramps, and CSS/SCSS/Tailwind/JSON/SVG export. Zero dependencies, 100% local.",
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"description": "Brew a color palette & ready-to-use theme tokens from any image — dominant colors via median-cut, perceptual OKLab ramps, and CSS/SCSS/Tailwind/JSON/SVG export. CLI + library + web app. Zero dependencies, 100% local.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
7
7
|
"module": "./dist/index.js",
|
|
@@ -13,6 +13,9 @@
|
|
|
13
13
|
"require": "./dist/index.cjs"
|
|
14
14
|
}
|
|
15
15
|
},
|
|
16
|
+
"bin": {
|
|
17
|
+
"huebrew": "./dist/cli.js"
|
|
18
|
+
},
|
|
16
19
|
"files": [
|
|
17
20
|
"dist"
|
|
18
21
|
],
|
|
@@ -42,6 +45,7 @@
|
|
|
42
45
|
"design-tokens",
|
|
43
46
|
"color-scheme",
|
|
44
47
|
"theme-generator",
|
|
48
|
+
"cli",
|
|
45
49
|
"zero-dependency"
|
|
46
50
|
],
|
|
47
51
|
"author": "didrod205 (https://github.com/didrod205)",
|
|
@@ -55,6 +59,7 @@
|
|
|
55
59
|
},
|
|
56
60
|
"homepage": "https://didrod205.github.io/huebrew/",
|
|
57
61
|
"devDependencies": {
|
|
62
|
+
"@types/node": "^22.19.19",
|
|
58
63
|
"tsup": "^8.3.5",
|
|
59
64
|
"typescript": "^5.7.2",
|
|
60
65
|
"vite": "^6.0.0",
|