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;
|
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) {
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
clamp() {
|
||||||
|
return this.map((val) => {
|
||||||
|
if (val < 0) return 0;
|
||||||
|
if (val > 255) return 255;
|
||||||
|
return val;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue