Optimise dither

This commit is contained in:
2025-02-13 17:24:22 +01:00
parent 75994c110d
commit f2e59cfda3
2 changed files with 25 additions and 20 deletions
+3 -17
View File
@@ -1,7 +1,7 @@
import React from "react";
import { ImportOutput, MuralOld, RGB } from "../interfaces";
import { canvasToImageData, convertOldMuralToNewMural, createMuralExtended, getColorScore, getExtension,
import { canvasToImageData, convertOldMuralToNewMural, createClosestIndexColor, createMuralExtended, getColorScore, getExtension,
imageDataToPaletteIndices, imageToCanvas, loadImageSource, processNumberEvent,
readAsArrayBuffer,
readAsDataUrl, readAsString, resize, rgb } from "../lib/utils";
@@ -440,13 +440,13 @@ function quantizeImage(
}
export function flatQuantizeImageData(imageData: ImageData, palette: Palette) {
const indexColor = createClosestIndexColor(palette.palette);
for (let i = 0; i < imageData.data.length; i += 4) {
const r = imageData.data[i + 0] ?? 0;
const g = imageData.data[i + 1] ?? 0;
const b = imageData.data[i + 2] ?? 0;
const a = imageData.data[i + 3] ?? 0;
const obj = rgb(r, g, b);
const index = findClosestIndexColor(obj, palette);
const index = indexColor(r, g, b);
const color = palette.palette[index];
if (!color) throw new Error(`Unknown color index ${index}`);
imageData.data[i + 0] = color.r;
@@ -456,20 +456,6 @@ export function flatQuantizeImageData(imageData: ImageData, palette: Palette) {
}
}
export function findClosestIndexColor(rgbO: RGB, palette: Palette) {
const scores: number[] = [];
for (const rgb of palette.palette) {
const r = getColorScore(rgbO.r, rgb.r);
const g = getColorScore(rgbO.g, rgb.g);
const b = getColorScore(rgbO.b, rgb.b);
scores.push(r + g + b);
}
const lowest = Math.min(...scores);
const index = scores.indexOf(lowest);
return index;
}
export function imageDataToCanvas(imageData: ImageData) {
const canvas = document.createElement("canvas");
const ctx = canvas.getContext("2d")!;
+22 -3
View File
@@ -224,13 +224,13 @@ export function canvasToImageData(canvas: HTMLCanvasElement) {
}
export function flatQuantizeImageData(imageData: ImageData, palette: RGB[]) {
const indexColor = createClosestIndexColor(palette);
for (let i = 0; i < imageData.data.length; i += 4) {
const r = imageData.data[i + 0] ?? 0;
const g = imageData.data[i + 1] ?? 0;
const b = imageData.data[i + 2] ?? 0;
const a = imageData.data[i + 3] ?? 0;
const obj = rgb(r, g, b);
const index = findClosestIndexColor(obj, palette);
const index = indexColor(r, g, b);
const color = palette[index];
if (!color) throw new Error(`Unknown color index ${index}`);
imageData.data[i + 0] = color.r;
@@ -273,6 +273,7 @@ export async function getPixelStatusMural(mural: Mural, palette: RGB[]): Promise
export function imageDataToPaletteIndices(imageData: ImageData, palette: RGB[]) {
const { height, width } = imageData;
let k = 0;
const indexColor = createClosestIndexColor(palette);
const pixels = new Int8Array(height * width);
for (let i = 0; i < imageData.data.length; i += 4) {
const r = imageData.data[i + 0] ?? 0;
@@ -282,7 +283,7 @@ export function imageDataToPaletteIndices(imageData: ImageData, palette: RGB[])
if (a < 25) {
pixels[k++] = -1;
} else {
const index = findClosestFormArray(rgb(r, g, b), palette);
const index = indexColor(r, g, b);
pixels[k++] = index;
}
}
@@ -381,6 +382,24 @@ export function createMuralExtended(mural: Mural, palette: string[]): MuralEx {
};
}
export function createClosestIndexColor(palette: RGB[]) {
const scores = new Uint16Array(palette.length);
let lowest = Number.MAX_SAFE_INTEGER;
return (r: number, g: number, b: number) => {
lowest = Number.MAX_SAFE_INTEGER;
for (let i = 0; i < palette.length; i++) {
const rgb = palette[i];
const rr = getColorScore(r, rgb.r);
const gg = getColorScore(g, rgb.g);
const bb = getColorScore(b, rgb.b);
const value = rr + gg + bb;
lowest = lowest < value ? lowest : value;
scores[i] = value;
}
return scores.indexOf(lowest);
};
}
let numberFormatter: Intl.NumberFormat;
try {
const userLocale = navigator.language || (navigator as any).userLanguage;