Something went wrong. Try again.
Monorepo for Aesthetic.Computer aesthetic.computer
Something went wrong. Try again.
JavaScript
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263// png in, png out, plus the one number we judge a round trip by.
import { readFileSync, writeFileSync } from "node:fs";import { PNG } from "pngjs";
const { log10, round, min, max, sqrt } = Math;
export function load(path) { const png = PNG.sync.read(readFileSync(path)); return { width: png.width, height: png.height, data: png.data };}
export function save(path, img) { const png = new PNG({ width: img.width, height: img.height }); png.data = Buffer.from(img.data); writeFileSync(path, PNG.sync.write(png));}
export function psnr(a, b) { let sum = 0, n = 0; for (let i = 0; i < a.data.length; i += 4) for (let c = 0; c < 3; c += 1) { const d = a.data[i + c] - b.data[i + c]; sum += d * d; n += 1; } const mse = sum / n; return mse === 0 ? Infinity : 10 * log10((255 * 255) / mse);}
// grayscale test card: ramps to see banding, wedges to see how fine a detail// survives, flats to see noise, edges to see ringing.export function testcard(w = 256, h = 256) { const data = new Uint8Array(w * h * 4).fill(255); const set = (x, y, v) => { const i = (y * w + x) * 4; data[i] = data[i + 1] = data[i + 2] = min(255, max(0, round(v))); }; for (let y = 0; y < h; y += 1) for (let x = 0; x < w; x += 1) { const u = x / w, v = y / h; let g; if (v < 0.25) g = u * 255; // horizontal ramp else if (v < 0.5) { const period = 2 + round((1 - u) * 14); // wedge, fine on the right g = x % period < period / 2 ? 235 : 20; } else if (v < 0.75) { const step = round(u * 7) / 7; // stair steps g = step * 255; } else { const c = (x >> 3) + (y >> 3); // checker with a diagonal through it g = c % 2 ? 200 : 40; if (abs2(x - y) < 2) g = 255; } set(x, y, g); } return { width: w, height: h, data };}
const abs2 = (n) => (n < 0 ? -n : n);