diff options
author | elioat <elioat@tilde.institute> | 2025-03-29 23:08:33 -0400 |
---|---|---|
committer | elioat <elioat@tilde.institute> | 2025-03-29 23:08:33 -0400 |
commit | b3f0f9e478d450b9a1bf3a6278e1e3bdbe0f1f6f (patch) | |
tree | e14043b064d20d90a985cdc3b943ae08b785b869 | |
parent | f185a42a9f1f9431e6208bed6516737d92efefbd (diff) | |
download | tour-b3f0f9e478d450b9a1bf3a6278e1e3bdbe0f1f6f.tar.gz |
*
-rw-r--r-- | js/leibovitz/dither.js | 88 |
1 files changed, 74 insertions, 14 deletions
diff --git a/js/leibovitz/dither.js b/js/leibovitz/dither.js index 9e1ffb1..90d6325 100644 --- a/js/leibovitz/dither.js +++ b/js/leibovitz/dither.js @@ -68,6 +68,8 @@ const DitherManager = { return this._orderedDither(data, width, height); case 'atkinson': return this._atkinsonDither(data, width, height); + case 'bayer': + return this._bayerDither(data, width, height); default: return imageData; } @@ -275,6 +277,72 @@ const DitherManager = { } return new ImageData(newData, width, height); + }, + + // Add this as a method in DitherManager + _bayerDither(data, width, height) { + const newData = new Uint8ClampedArray(data); + const blockSize = this.currentBlockSize; + + // 4x4 Bayer matrix (simpler and more visible pattern than 8x8) + const bayerMatrix = [ + [ 0, 8, 2, 10], + [12, 4, 14, 6 ], + [ 3, 11, 1, 9 ], + [15, 7, 13, 5 ] + ]; + + // Scale factor to make the pattern more pronounced + const scaleFactor = 16; // Increase this value to make pattern more visible + + // Process in blocks + for (let y = 0; y < height; y += blockSize) { + for (let x = 0; x < width; x += blockSize) { + // Calculate block average + let blockSum = [0, 0, 0]; + let pixelCount = 0; + + for (let by = 0; by < blockSize && y + by < height; by++) { + for (let bx = 0; bx < blockSize && x + bx < width; bx++) { + const idx = ((y + by) * width + (x + bx)) * 4; + for (let c = 0; c < 3; c++) { + blockSum[c] += newData[idx + c]; + } + pixelCount++; + } + } + + // Calculate block average + const blockAvg = blockSum.map(sum => sum / pixelCount); + + // Get matrix value for this block position + const matrixX = Math.floor(x / blockSize) % 4; + const matrixY = Math.floor(y / blockSize) % 4; + const threshold = (bayerMatrix[matrixY][matrixX] * scaleFactor); + + // Apply dithering to the block + for (let c = 0; c < 3; c++) { + // Normalize pixel value and apply threshold + const normalizedPixel = blockAvg[c]; + const newPixel = normalizedPixel > threshold ? 255 : 0; + + // Fill the entire block with the new color + for (let by = 0; by < blockSize && y + by < height; by++) { + for (let bx = 0; bx < blockSize && x + bx < width; bx++) { + const idx = ((y + by) * width + (x + bx)) * 4; + newData[idx + c] = newPixel; + } + } + } + } + } + + // Preserve alpha channel + for (let i = 3; i < newData.length; i += 4) { + newData[i] = data[i]; + } + + return new ImageData(newData, width, height); } }; @@ -337,25 +405,17 @@ function bayerDither(imageData, width) { } } + // Preserve alpha channel + for (let i = 3; i < data.length; i += 4) { + data[i] = imageData.data[i]; + } + return data; } function applyDithering(imageData, width) { const method = document.getElementById('dither-select').value; - const blockSize = DitherManager.currentBlockSize; - - switch (method) { - case 'floyd-steinberg': - return DitherManager._floydSteinbergDither(imageData.data, width, imageData.height); - case 'bayer': - return bayerDither(imageData, width); - case 'atkinson': - return DitherManager._atkinsonDither(imageData.data, width, imageData.height); - case 'ordered': - return DitherManager._orderedDither(imageData.data, width, imageData.height); - default: - return new Uint8ClampedArray(imageData.data); - } + return DitherManager.applyDither(imageData, method); } function floydSteinbergDither(imageData, width, blockSize) { |