wip
This commit is contained in:
parent
23e60ae668
commit
0dcfa88c29
1 changed files with 44 additions and 41 deletions
|
@ -28,6 +28,17 @@ function fromLinear(val) {
|
|||
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 {
|
||||
constructor(r, g, b) {
|
||||
this.r = r;
|
||||
|
@ -46,41 +57,32 @@ class RGB {
|
|||
return new RGB(r,g,b);
|
||||
}
|
||||
|
||||
toLinear() {
|
||||
map(callback) {
|
||||
return new RGB(
|
||||
toLinear(this.r),
|
||||
toLinear(this.g),
|
||||
toLinear(this.b)
|
||||
callback(this.r),
|
||||
callback(this.g),
|
||||
callback(this.b)
|
||||
);
|
||||
}
|
||||
|
||||
toLinear() {
|
||||
return this.map(toLinear);
|
||||
}
|
||||
|
||||
fromLinear() {
|
||||
return new RGB(
|
||||
fromLinear(this.r),
|
||||
fromLinear(this.g),
|
||||
fromLinear(this.b)
|
||||
);
|
||||
return this.map(fromLinear);
|
||||
}
|
||||
|
||||
cap() {
|
||||
if (this.r < 0) {
|
||||
this.r = 0;
|
||||
}
|
||||
if (this.g < 0) {
|
||||
this.g = 0;
|
||||
}
|
||||
if (this.b < 0) {
|
||||
this.b = 0;
|
||||
}
|
||||
if (this.r > 255) {
|
||||
this.r = 255;
|
||||
}
|
||||
if (this.g > 255) {
|
||||
this.g = 255;
|
||||
}
|
||||
if (this.b > 255) {
|
||||
this.b = 255;
|
||||
}
|
||||
toSRGB() {
|
||||
return this.map(toSRGB);
|
||||
}
|
||||
|
||||
clamp() {
|
||||
return this.map((val) => {
|
||||
if (val < 0) return 0;
|
||||
if (val > 255) return 255;
|
||||
return val;
|
||||
});
|
||||
}
|
||||
|
||||
inc(other) {
|
||||
|
@ -90,11 +92,11 @@ class RGB {
|
|||
return this;
|
||||
}
|
||||
|
||||
static add(a, b) {
|
||||
add(other) {
|
||||
return new RGB(
|
||||
a.r + b.r,
|
||||
a.g + b.g,
|
||||
a.b + b.b
|
||||
this.r + other.r,
|
||||
this.g + other.g,
|
||||
this.b + other.b
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -399,6 +401,7 @@ let atariRGB = [
|
|||
0xfffa84,
|
||||
0xffff99,
|
||||
].map((hex) => RGB.fromHex(hex).toLinear());
|
||||
//].map((hex) => RGB.fromHex(hex));
|
||||
|
||||
/**
|
||||
* Dither RGB input data with a target palette size.
|
||||
|
@ -430,10 +433,9 @@ function decimate(input, palette, n) {
|
|||
let inputPixel = (x, error) => {
|
||||
let rgb = input[x].clone();
|
||||
if (error) {
|
||||
rgb.inc(error.cur[x]);
|
||||
rgb = rgb.add(error.cur[x]);
|
||||
}
|
||||
rgb.cap();
|
||||
return rgb;
|
||||
return rgb.clamp();
|
||||
};
|
||||
|
||||
// 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 brightest = Math.max(...lumas);
|
||||
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);
|
||||
if (y > 0) {
|
||||
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);
|
||||
lines.push(line);
|
||||
|
@ -897,11 +899,12 @@ async function saveImage(width, height, lines, dest) {
|
|||
if (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 + 1] = fromLinear(rgb.g);
|
||||
rgba[y * stride + x * 4 + 2] = fromLinear(rgb.b);
|
||||
rgba[y * stride + x * 4 + 0] = rgb.r;
|
||||
rgba[y * stride + x * 4 + 1] = rgb.g;
|
||||
rgba[y * stride + x * 4 + 2] = rgb.b;
|
||||
rgba[y * stride + x * 4 + 3] = 255;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue