From 1d3712be5c89e3528d58da4d29514cbce7d9d030 Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Fri, 24 Mar 2023 00:23:59 -0700 Subject: [PATCH] wip --- dither-image.js | 43 ++++++++++++++----------------------------- 1 file changed, 14 insertions(+), 29 deletions(-) diff --git a/dither-image.js b/dither-image.js index f804df8..ee313d0 100644 --- a/dither-image.js +++ b/dither-image.js @@ -134,13 +134,23 @@ class RGB { this.b * this.b; } + sum() { + return this.r + this.g + this.b; + } + + lumaScale() { + return new RGB( + this.r * 0.299, + this.g * 0.586, + this.b * 0.114 + ); + } + luma() { - return this.r * 0.299 + this.g * 0.587 + this.b * 0.114; + return this.lumaScale().sum(); } } -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 = [ @@ -414,19 +424,6 @@ let atariRGB = [ * @returns {{output: number[], palette: number[], error: RGB[]}} */ function decimate(input, palette, n) { - // to brute-force, the possible palettes are: - // 255 * 254 * 253 = 16,386,810 - // - // we could brute force it but that's a lot :D - // but can do some bisection :D - // - // need a fitness metric. - // each pixel in the dithered line gives a distance - // sum/average them? median? maximum? - // summing evens out the ups/downs from dithering - // but doesn't distinguish between two close and two distant options - // consider median, 90th-percentile, and max of abs(distance) - // consider doing the distance for each channel? let width = input.length; @@ -440,7 +437,6 @@ function decimate(input, palette, n) { // Apply dithering with given palette and collect color usage stats let dither = (palette) => { - let fitness = zeroes(width); let error = { cur: [], next: [], @@ -467,7 +463,7 @@ function decimate(input, palette, n) { for (let i = 0; i < palette.length; i++) { let diff = rgb.difference(atariRGB[palette[i]]); - let dist = diff.magnitude2(); + let dist = diff.magnitude(); if (dist < shortest) { nextError = diff; shortest = dist; @@ -484,21 +480,10 @@ function decimate(input, palette, n) { error.next[x - 1]?.inc(share(3)); error.next[x ]?.inc(share(5)); error.next[x + 1]?.inc(share(1)); - - let mag = nextError.magnitude(); - fitness[x] = maxDist / mag; - // 442 is the 3d distance across the rgb cube - //fitness[x] = 442 - (nextError.magnitude()); - //fitness[x] = 442 / (442 - nextError.magnitude()); - fitness[x] = 255 / (256 - Math.max(0, nextError.r, nextError.g, nextError.b)); - - let mag2 = nextError.magnitude2(); - distance2 += mag2; } return { output, palette, - fitness, distance2, popularity, error: error.next