mirror of
https://github.com/publiclab/image-sequencer.git
synced 2025-12-13 11:50:02 +01:00
77 lines
2.4 KiB
JavaScript
77 lines
2.4 KiB
JavaScript
module.exports = function Dither(pixels, type) {
|
||
type = type;
|
||
let bayerThresholdMap = [
|
||
[15, 135, 45, 165],
|
||
[195, 75, 225, 105],
|
||
[60, 180, 30, 150],
|
||
[240, 120, 210, 90]
|
||
];
|
||
|
||
let lumR = [];
|
||
let lumG = [];
|
||
let lumB = [];
|
||
for (let i = 0; i < 256; i++) {
|
||
lumR[i] = i * 0.299;
|
||
lumG[i] = i * 0.587;
|
||
lumB[i] = i * 0.114;
|
||
}
|
||
let threshold = 129;
|
||
let imageDataLength = pixels.data.length; //imageData.data.length;
|
||
|
||
// Greyscale luminance (sets r pixels to luminance of rgb)
|
||
for (let i = 0; i <= imageDataLength; i++) {
|
||
pixels.data[i] = Math.floor(lumR[pixels.data[i++]] + lumG[pixels.data[i++]] + lumB[pixels.data[i++]]);
|
||
}
|
||
|
||
let w = pixels.shape[0];
|
||
let newPixel, err;
|
||
|
||
for (let currentPixel = 0; currentPixel <= imageDataLength; currentPixel += 4) {
|
||
|
||
if (type === 'none') {
|
||
// No dithering
|
||
pixels.data[currentPixel] = pixels.data[currentPixel] < threshold ? 0 : 255;
|
||
|
||
} else if (type === 'bayer') {
|
||
|
||
// 4x4 Bayer ordered dithering algorithm
|
||
let x = currentPixel / 4 % w;
|
||
let y = Math.floor(currentPixel / 4 / w);
|
||
let map = Math.floor((pixels.data[currentPixel] + bayerThresholdMap[x % 4][y % 4]) / 2);
|
||
pixels.data[currentPixel] = (map < threshold) ? 0 : 255;
|
||
|
||
} else if (type === 'floydsteinberg') {
|
||
|
||
// Floyd–Steinberg dithering algorithm
|
||
newPixel = pixels.data[currentPixel] < 129 ? 0 : 255;
|
||
err = Math.floor((pixels.data[currentPixel] - newPixel) / 16);
|
||
pixels.data[currentPixel] = newPixel;
|
||
|
||
pixels.data[currentPixel + 4] += err * 7;
|
||
pixels.data[currentPixel + 4 * w - 4] += err * 3;
|
||
pixels.data[currentPixel + 4 * w] += err * 5;
|
||
pixels.data[currentPixel + 4 * w + 4] += err * 1;
|
||
|
||
} else {
|
||
|
||
// Bill Atkinson's dithering algorithm
|
||
newPixel = pixels.data[currentPixel] < threshold ? 0 : 255;
|
||
err = Math.floor((pixels.data[currentPixel] - newPixel) / 8);
|
||
pixels.data[currentPixel] = newPixel;
|
||
|
||
pixels.data[currentPixel + 4] += err;
|
||
pixels.data[currentPixel + 8] += err;
|
||
pixels.data[currentPixel + 4 * w - 4] += err;
|
||
pixels.data[currentPixel + 4 * w] += err;
|
||
pixels.data[currentPixel + 4 * w + 4] += err;
|
||
pixels.data[currentPixel + 8 * w] += err;
|
||
|
||
}
|
||
|
||
// Set g and b pixels equal to r
|
||
pixels.data[currentPixel + 1] = pixels.data[currentPixel + 2] = pixels.data[currentPixel];
|
||
}
|
||
return pixels;
|
||
|
||
};
|