some oldbits
This commit is contained in:
parent
9a93e7341f
commit
9826a90e02
1 changed files with 60 additions and 11 deletions
|
@ -426,7 +426,7 @@ function decimate(input, palette, n, inputError, y) {
|
||||||
|
|
||||||
// Apply dithering with given palette and collect color usage stats
|
// Apply dithering with given palette and collect color usage stats
|
||||||
let dither = (palette) => {
|
let dither = (palette) => {
|
||||||
let fitness = new Float64Array(palette.length);
|
let fitness = new Float64Array(width);
|
||||||
let error = {
|
let error = {
|
||||||
cur: [],
|
cur: [],
|
||||||
next: [],
|
next: [],
|
||||||
|
@ -476,10 +476,12 @@ function decimate(input, palette, n, inputError, y) {
|
||||||
|
|
||||||
let mag = nextError.magnitude();
|
let mag = nextError.magnitude();
|
||||||
fitness[x] = maxDist / mag;
|
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));
|
||||||
|
|
||||||
// just store the distance2
|
|
||||||
let mag2 = nextError.magnitude2();
|
let mag2 = nextError.magnitude2();
|
||||||
//fitness[x] = mag2;
|
|
||||||
distance2 += mag2;
|
distance2 += mag2;
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
|
@ -509,11 +511,12 @@ function decimate(input, palette, n, inputError, y) {
|
||||||
//reserved = [0, 5, 10, 15]; // grayscale
|
//reserved = [0, 5, 10, 15]; // grayscale
|
||||||
//reserved = [0, 0x48, 0x78, 15]; // vaporwave
|
//reserved = [0, 0x48, 0x78, 15]; // vaporwave
|
||||||
//reserved = [0, 0x3c, 0x78, 15]; // red/blue/white
|
//reserved = [0, 0x3c, 0x78, 15]; // red/blue/white
|
||||||
|
|
||||||
/*
|
/*
|
||||||
if (( y & 1 ) === 0) {
|
if (( y & 1 ) === 0) {
|
||||||
reserved = [0, 0x3c, 0x1a, 15]; // red/yellow/white
|
reserved = [0, 0x3c, 0x1e, 15]; // red/yellow/white
|
||||||
} else {
|
} else {
|
||||||
reserved = [0, 0x76, 0x9a, 15]; // blue/cyan/white
|
reserved = [0, 0x76, 0x9e, 0xb8]; // blue/cyan/green
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@ -553,7 +556,8 @@ function decimate(input, palette, n, inputError, y) {
|
||||||
a = a.sort((a, b) => b.count - a.count);
|
a = a.sort((a, b) => b.count - a.count);
|
||||||
a = a.map(({hue}) => hue);
|
a = a.map(({hue}) => hue);
|
||||||
a = a.filter((color) => !keepers[color]);
|
a = a.filter((color) => !keepers[color]);
|
||||||
a = a.slice(0, n - reserved.length);
|
//a = a.slice(0, n - reserved.length);
|
||||||
|
a = a.slice(0, decimated.length - 1 - reserved.length);
|
||||||
a = a.map((hue) => (hue << 4) | lumas[hue]);
|
a = a.map((hue) => (hue << 4) | lumas[hue]);
|
||||||
a = a.sort((a, b) => a - b);
|
a = a.sort((a, b) => a - b);
|
||||||
|
|
||||||
|
@ -564,19 +568,63 @@ function decimate(input, palette, n, inputError, y) {
|
||||||
|
|
||||||
// popularity? not really working right
|
// popularity? not really working right
|
||||||
// first, dither to the total atari palette
|
// first, dither to the total atari palette
|
||||||
|
/*
|
||||||
while (decimated.length > n) {
|
while (decimated.length > n) {
|
||||||
let {popularity, fitness} = dither(decimated);
|
|
||||||
// temporarily strip the reserved items
|
|
||||||
//console.log(y);
|
//console.log(y);
|
||||||
|
let {popularity} = dither(decimated);
|
||||||
let a = decimated;
|
let a = decimated;
|
||||||
|
// temporarily strip the reserved items
|
||||||
a = a.filter((color) => !keepers[color]);
|
a = a.filter((color) => !keepers[color]);
|
||||||
a = a.sort((a, b) => popularity[b] - popularity[a]);
|
a = a.sort((a, b) => popularity[b] - popularity[a]);
|
||||||
//a = a.slice(0, n - reserved.length);
|
|
||||||
a = reserved.concat(a);
|
a = reserved.concat(a);
|
||||||
decimated = a.slice(0, decimated.length - 1);
|
decimated = a.slice(0, n);
|
||||||
//console.log(decimated);
|
//console.log(decimated);
|
||||||
}
|
}
|
||||||
//console.log('end', decimated);
|
//console.log('end', decimated);
|
||||||
|
*/
|
||||||
|
|
||||||
|
while (decimated.length > n) {
|
||||||
|
let {popularity, fitness, output} = dither(decimated);
|
||||||
|
|
||||||
|
// Try dropping least used color on each iteration
|
||||||
|
let least = Infinity;
|
||||||
|
let pick = -1;
|
||||||
|
for (let i = 1; i < decimated.length; i++) {
|
||||||
|
|
||||||
|
//let coolFactor = popularity[i];
|
||||||
|
|
||||||
|
let coolFactor = 0;
|
||||||
|
if (popularity[i]) {
|
||||||
|
for (let x = 0; x < width; x++) {
|
||||||
|
if (output[x] == i) {
|
||||||
|
// Scale up the scoring for close matches to prioritize
|
||||||
|
// color accuracy over raw linear usage.
|
||||||
|
//coolFactor += (fitness[x] ** 2);
|
||||||
|
coolFactor += (fitness[x] ** 4);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (coolFactor < least) {
|
||||||
|
pick = i;
|
||||||
|
least = coolFactor;
|
||||||
|
}
|
||||||
|
decimated = decimated.filter((color, i) => {
|
||||||
|
if (i == 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (i == pick) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// Also drop any non-black unused colors to save trouble.
|
||||||
|
// However -- this may change dither results.
|
||||||
|
// Try this with/without later.
|
||||||
|
if (popularity[i] == 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Palette fits
|
// Palette fits
|
||||||
return dither(decimated);
|
return dither(decimated);
|
||||||
|
@ -845,6 +893,7 @@ async function saveImage(width, height, lines, dest) {
|
||||||
resolve(image);
|
resolve(image);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
await image.resize(Math.round(width2 * 2 / 1.2), height * 2);
|
||||||
await image.writeAsync(dest);
|
await image.writeAsync(dest);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue