This commit is contained in:
Brooke Vibber 2023-03-22 23:24:11 -07:00
parent 23e60ae668
commit 0dcfa88c29

View file

@ -28,6 +28,17 @@ function fromLinear(val) {
return unit * 255; return unit * 255;
} }
function toSRGB(val) {
val /= 255;
if (val <= 0.0031308) {
val *= 12.92;
} else {
val = (val * 1.055) ** (1.0 / 2.4) - 0.055;
}
val *= 255;
return val;
}
class RGB { class RGB {
constructor(r, g, b) { constructor(r, g, b) {
this.r = r; this.r = r;
@ -46,41 +57,32 @@ class RGB {
return new RGB(r,g,b); return new RGB(r,g,b);
} }
toLinear() { map(callback) {
return new RGB( return new RGB(
toLinear(this.r), callback(this.r),
toLinear(this.g), callback(this.g),
toLinear(this.b) callback(this.b)
); );
} }
toLinear() {
return this.map(toLinear);
}
fromLinear() { fromLinear() {
return new RGB( return this.map(fromLinear);
fromLinear(this.r),
fromLinear(this.g),
fromLinear(this.b)
);
} }
cap() { toSRGB() {
if (this.r < 0) { return this.map(toSRGB);
this.r = 0; }
}
if (this.g < 0) { clamp() {
this.g = 0; return this.map((val) => {
} if (val < 0) return 0;
if (this.b < 0) { if (val > 255) return 255;
this.b = 0; return val;
} });
if (this.r > 255) {
this.r = 255;
}
if (this.g > 255) {
this.g = 255;
}
if (this.b > 255) {
this.b = 255;
}
} }
inc(other) { inc(other) {
@ -90,11 +92,11 @@ class RGB {
return this; return this;
} }
static add(a, b) { add(other) {
return new RGB( return new RGB(
a.r + b.r, this.r + other.r,
a.g + b.g, this.g + other.g,
a.b + b.b this.b + other.b
); );
} }
@ -399,6 +401,7 @@ let atariRGB = [
0xfffa84, 0xfffa84,
0xffff99, 0xffff99,
].map((hex) => RGB.fromHex(hex).toLinear()); ].map((hex) => RGB.fromHex(hex).toLinear());
//].map((hex) => RGB.fromHex(hex));
/** /**
* Dither RGB input data with a target palette size. * Dither RGB input data with a target palette size.
@ -430,10 +433,9 @@ function decimate(input, palette, n) {
let inputPixel = (x, error) => { let inputPixel = (x, error) => {
let rgb = input[x].clone(); let rgb = input[x].clone();
if (error) { if (error) {
rgb.inc(error.cur[x]); rgb = rgb.add(error.cur[x]);
} }
rgb.cap(); return rgb.clamp();
return rgb;
}; };
// Apply dithering with given palette and collect color usage stats // Apply dithering with given palette and collect color usage stats
@ -585,7 +587,7 @@ function decimate(input, palette, n) {
let lumas = bucket.map((rgb) => rgb.luma()); let lumas = bucket.map((rgb) => rgb.luma());
let brightest = Math.max(...lumas); let brightest = Math.max(...lumas);
if (avg_luma > 0) { if (avg_luma > 0) {
rgb = rgb.multiply(brightest / avg_luma); rgb = rgb.multiply(brightest / avg_luma).clamp();
} }
@ -740,7 +742,7 @@ async function convert(source) {
.slice(y * width, (y + 1) * width); .slice(y * width, (y + 1) * width);
if (y > 0) { if (y > 0) {
let error = lines[y - 1].error; let error = lines[y - 1].error;
inputLine = inputLine.map((rgb, x) => RGB.add(rgb, error[x])); inputLine = inputLine.map((rgb, x) => rgb.add(error[x]));
} }
let line = decimate(inputLine, allColors, 4, y); let line = decimate(inputLine, allColors, 4, y);
lines.push(line); lines.push(line);
@ -897,11 +899,12 @@ async function saveImage(width, height, lines, dest) {
if (i >= width) { if (i >= width) {
throw new Error('i >= width'); throw new Error('i >= width');
} }
let rgb = atariRGB[palette[output[i]]]; //let rgb = atariRGB[palette[output[i]]].fromLinear();
let rgb = atariRGB[palette[output[i]]].toSRGB();
rgba[y * stride + x * 4 + 0] = fromLinear(rgb.r); rgba[y * stride + x * 4 + 0] = rgb.r;
rgba[y * stride + x * 4 + 1] = fromLinear(rgb.g); rgba[y * stride + x * 4 + 1] = rgb.g;
rgba[y * stride + x * 4 + 2] = fromLinear(rgb.b); rgba[y * stride + x * 4 + 2] = rgb.b;
rgba[y * stride + x * 4 + 3] = 255; rgba[y * stride + x * 4 + 3] = 255;
} }
} }