From 9a93e7341faf7b3d1973482d1d90d29fd0d7f050 Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Sun, 19 Mar 2023 16:56:18 -0700 Subject: [PATCH] wip almost --- dither-image.js | 35 ++++++++++++++++++++++++++++++++--- 1 file changed, 32 insertions(+), 3 deletions(-) diff --git a/dither-image.js b/dither-image.js index 0157f2b..3b0aec4 100644 --- a/dither-image.js +++ b/dither-image.js @@ -110,6 +110,10 @@ class RGB { ); } + magnitude() { + return Math.sqrt(this.magnitude2()); + } + magnitude2() { return this.r * this.r + this.g * this.g + @@ -117,6 +121,8 @@ class RGB { } } +const maxDist = (new RGB(255, 255, 255)).magnitude(); + // snarfed from https://lospec.com/palette-list/atari-8-bit-family-gtia // which was calculated with Retrospecs App's Atari 800 emulator let atariRGB = [ @@ -420,7 +426,7 @@ function decimate(input, palette, n, inputError, y) { // Apply dithering with given palette and collect color usage stats let dither = (palette) => { - let fitness = new Float64Array(width); + let fitness = new Float64Array(palette.length); let error = { cur: [], next: [], @@ -431,7 +437,7 @@ function decimate(input, palette, n, inputError, y) { } let output = new Uint8Array(width); - let popularity = new Int32Array(width); + let popularity = new Int32Array(palette.length); let distance2 = 0; let nextError = new RGB(0, 0, 0); @@ -468,9 +474,12 @@ function decimate(input, palette, n, inputError, y) { error.next[x]?.inc(double); error.next[x + 1]?.inc(double); + let mag = nextError.magnitude(); + fitness[x] = maxDist / mag; + // just store the distance2 let mag2 = nextError.magnitude2(); - fitness[x] = mag2; + //fitness[x] = mag2; distance2 += mag2; } return { @@ -521,6 +530,9 @@ function decimate(input, palette, n, inputError, y) { return arr; }; + // this takes the top hues, and uses the brightest of each hue + // needs tuning + /* // first, dither to the total atari palette while (decimated.length > n) { let {popularity} = dither(decimated); @@ -548,7 +560,24 @@ function decimate(input, palette, n, inputError, y) { decimated = reserved.concat(a); } console.log('end', decimated); + */ + // popularity? not really working right + // first, dither to the total atari palette + while (decimated.length > n) { + let {popularity, fitness} = dither(decimated); + // temporarily strip the reserved items + //console.log(y); + let a = decimated; + a = a.filter((color) => !keepers[color]); + a = a.sort((a, b) => popularity[b] - popularity[a]); + //a = a.slice(0, n - reserved.length); + a = reserved.concat(a); + decimated = a.slice(0, decimated.length - 1); + //console.log(decimated); + } + //console.log('end', decimated); + // Palette fits return dither(decimated); }