blob: 7bfdc13a4eb9231901e2132cc0794d137fc9df42 (
plain) (
tree)
|
|
const upload = document.getElementById('upload');
const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');
upload.addEventListener('change', function (e) {
const file = e.target.files[0];
const reader = new FileReader();
reader.onload = function (event) {
const img = new Image();
img.onload = function () {
canvas.width = img.width;
canvas.height = img.height;
ctx.drawImage(img, 0, 0);
applyDithering();
};
img.src = event.target.result;
};
reader.readAsDataURL(file);
});
// TIL how to do this!
document.getElementById('download').addEventListener('click', function() {
const dataUrl = canvas.toDataURL('image/png'); // Convert the canvas to a data URL
const a = document.createElement('a'); // Create an anchor element
a.href = dataUrl; // Set the href of the anchor to the data URL
a.download = 'dithered-image.png'; // Set the download attribute to the desired file name
a.setAttribute('rel', 'noopener noreferrer');
a.setAttribute('target', '_blank');
document.body.appendChild(a); // Append the anchor to the body
a.click(); // Trigger a click on the anchor to start the download
document.body.removeChild(a); // Remove the anchor from the body
});
function applyDithering() {
const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
const data = imageData.data;
const width = canvas.width;
const height = canvas.height;
// Find the gray value of a pixel
const getGrayValue = (r, g, b) => 0.299 * r + 0.587 * g + 0.114 * b;
// Set the pixel value
const setPixel = (x, y, value) => {
const index = (y * width + x) * 4;
const gray = value < 128 ? 0 : 255;
data[index] = gray;
data[index + 1] = gray;
data[index + 2] = gray;
data[index + 3] = 255;
};
// https://en.wikipedia.org/wiki/Floyd–Steinberg_dithering
// Loop through each pixel in the image
for (let y = 0; y < height; y++) {
for (let x = 0; x < width; x++) {
const index = (y * width + x) * 4;
const oldR = data[index];
const oldG = data[index + 1];
const oldB = data[index + 2];
const oldGray = getGrayValue(oldR, oldG, oldB);
const newGray = oldGray < 128 ? 0 : 255;
const error = oldGray - newGray;
setPixel(x, y, oldGray);
// Spread error to neighboring pixels
if (x + 1 < width) {
data[(y * width + x + 1) * 4] += error * 7 / 16;
data[(y * width + x + 1) * 4 + 1] += error * 7 / 16;
data[(y * width + x + 1) * 4 + 2] += error * 7 / 16;
}
if (y + 1 < height) {
if (x - 1 >= 0) {
data[((y + 1) * width + x - 1) * 4] += error * 3 / 16;
data[((y + 1) * width + x - 1) * 4 + 1] += error * 3 / 16;
data[((y + 1) * width + x - 1) * 4 + 2] += error * 3 / 16;
}
data[((y + 1) * width + x) * 4] += error * 5 / 16;
data[((y + 1) * width + x) * 4 + 1] += error * 5 / 16;
data[((y + 1) * width + x) * 4 + 2] += error * 5 / 16;
if (x + 1 < width) {
data[((y + 1) * width + x + 1) * 4] += error * 1 / 16;
data[((y + 1) * width + x + 1) * 4 + 1] += error * 1 / 16;
data[((y + 1) * width + x + 1) * 4 + 2] += error * 1 / 16;
}
}
}
}
ctx.putImageData(imageData, 0, 0);
}
|