Optimise dither
This commit is contained in:
+3
-17
@@ -1,7 +1,7 @@
|
|||||||
|
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { ImportOutput, MuralOld, RGB } from "../interfaces";
|
import { ImportOutput, MuralOld, RGB } from "../interfaces";
|
||||||
import { canvasToImageData, convertOldMuralToNewMural, createMuralExtended, getColorScore, getExtension,
|
import { canvasToImageData, convertOldMuralToNewMural, createClosestIndexColor, createMuralExtended, getColorScore, getExtension,
|
||||||
imageDataToPaletteIndices, imageToCanvas, loadImageSource, processNumberEvent,
|
imageDataToPaletteIndices, imageToCanvas, loadImageSource, processNumberEvent,
|
||||||
readAsArrayBuffer,
|
readAsArrayBuffer,
|
||||||
readAsDataUrl, readAsString, resize, rgb } from "../lib/utils";
|
readAsDataUrl, readAsString, resize, rgb } from "../lib/utils";
|
||||||
@@ -440,13 +440,13 @@ function quantizeImage(
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function flatQuantizeImageData(imageData: ImageData, palette: Palette) {
|
export function flatQuantizeImageData(imageData: ImageData, palette: Palette) {
|
||||||
|
const indexColor = createClosestIndexColor(palette.palette);
|
||||||
for (let i = 0; i < imageData.data.length; i += 4) {
|
for (let i = 0; i < imageData.data.length; i += 4) {
|
||||||
const r = imageData.data[i + 0] ?? 0;
|
const r = imageData.data[i + 0] ?? 0;
|
||||||
const g = imageData.data[i + 1] ?? 0;
|
const g = imageData.data[i + 1] ?? 0;
|
||||||
const b = imageData.data[i + 2] ?? 0;
|
const b = imageData.data[i + 2] ?? 0;
|
||||||
const a = imageData.data[i + 3] ?? 0;
|
const a = imageData.data[i + 3] ?? 0;
|
||||||
const obj = rgb(r, g, b);
|
const index = indexColor(r, g, b);
|
||||||
const index = findClosestIndexColor(obj, palette);
|
|
||||||
const color = palette.palette[index];
|
const color = palette.palette[index];
|
||||||
if (!color) throw new Error(`Unknown color index ${index}`);
|
if (!color) throw new Error(`Unknown color index ${index}`);
|
||||||
imageData.data[i + 0] = color.r;
|
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) {
|
export function imageDataToCanvas(imageData: ImageData) {
|
||||||
const canvas = document.createElement("canvas");
|
const canvas = document.createElement("canvas");
|
||||||
const ctx = canvas.getContext("2d")!;
|
const ctx = canvas.getContext("2d")!;
|
||||||
|
|||||||
+22
-3
@@ -224,13 +224,13 @@ export function canvasToImageData(canvas: HTMLCanvasElement) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function flatQuantizeImageData(imageData: ImageData, palette: RGB[]) {
|
export function flatQuantizeImageData(imageData: ImageData, palette: RGB[]) {
|
||||||
|
const indexColor = createClosestIndexColor(palette);
|
||||||
for (let i = 0; i < imageData.data.length; i += 4) {
|
for (let i = 0; i < imageData.data.length; i += 4) {
|
||||||
const r = imageData.data[i + 0] ?? 0;
|
const r = imageData.data[i + 0] ?? 0;
|
||||||
const g = imageData.data[i + 1] ?? 0;
|
const g = imageData.data[i + 1] ?? 0;
|
||||||
const b = imageData.data[i + 2] ?? 0;
|
const b = imageData.data[i + 2] ?? 0;
|
||||||
const a = imageData.data[i + 3] ?? 0;
|
const a = imageData.data[i + 3] ?? 0;
|
||||||
const obj = rgb(r, g, b);
|
const index = indexColor(r, g, b);
|
||||||
const index = findClosestIndexColor(obj, palette);
|
|
||||||
const color = palette[index];
|
const color = palette[index];
|
||||||
if (!color) throw new Error(`Unknown color index ${index}`);
|
if (!color) throw new Error(`Unknown color index ${index}`);
|
||||||
imageData.data[i + 0] = color.r;
|
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[]) {
|
export function imageDataToPaletteIndices(imageData: ImageData, palette: RGB[]) {
|
||||||
const { height, width } = imageData;
|
const { height, width } = imageData;
|
||||||
let k = 0;
|
let k = 0;
|
||||||
|
const indexColor = createClosestIndexColor(palette);
|
||||||
const pixels = new Int8Array(height * width);
|
const pixels = new Int8Array(height * width);
|
||||||
for (let i = 0; i < imageData.data.length; i += 4) {
|
for (let i = 0; i < imageData.data.length; i += 4) {
|
||||||
const r = imageData.data[i + 0] ?? 0;
|
const r = imageData.data[i + 0] ?? 0;
|
||||||
@@ -282,7 +283,7 @@ export function imageDataToPaletteIndices(imageData: ImageData, palette: RGB[])
|
|||||||
if (a < 25) {
|
if (a < 25) {
|
||||||
pixels[k++] = -1;
|
pixels[k++] = -1;
|
||||||
} else {
|
} else {
|
||||||
const index = findClosestFormArray(rgb(r, g, b), palette);
|
const index = indexColor(r, g, b);
|
||||||
pixels[k++] = index;
|
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;
|
let numberFormatter: Intl.NumberFormat;
|
||||||
try {
|
try {
|
||||||
const userLocale = navigator.language || (navigator as any).userLanguage;
|
const userLocale = navigator.language || (navigator as any).userLanguage;
|
||||||
|
|||||||
Reference in New Issue
Block a user