You can edit the below JavaScript code to customize the image tool.
Apply Changes
function processImage(originalImg, levels = 5, noiseAmount = 20, edgeDarkening = 0.3, edgeThreshold = 30) {
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
const W = originalImg.naturalWidth || originalImg.width;
const H = originalImg.naturalHeight || originalImg.height;
canvas.width = W;
canvas.height = H;
// Parameter validation and normalization
let numLevels = parseInt(String(levels), 10);
if (isNaN(numLevels) || numLevels < 2) {
numLevels = 2;
}
let currentNoiseAmount = parseFloat(String(noiseAmount));
if (isNaN(currentNoiseAmount) || currentNoiseAmount < 0) {
currentNoiseAmount = 0;
}
let currentEdgeDarkening = parseFloat(String(edgeDarkening));
if (isNaN(currentEdgeDarkening)) {
currentEdgeDarkening = 0.3;
}
currentEdgeDarkening = Math.max(0, Math.min(1, currentEdgeDarkening));
let currentEdgeThreshold = parseFloat(String(edgeThreshold));
if (isNaN(currentEdgeThreshold) || currentEdgeThreshold < 0) {
currentEdgeThreshold = 0;
}
ctx.drawImage(originalImg, 0, 0, W, H);
const imageData = ctx.getImageData(0, 0, W, H);
const data = imageData.data;
// Create a copy of the original pixel data for accurate edge detection
const originalPixelData = new Uint8ClampedArray(imageData.data);
const levelStep = 255 / (numLevels - 1);
for (let y = 0; y < H; y++) {
for (let x = 0; x < W; x++) {
const i = (y * W + x) * 4;
// Get original color values for processing
let rOrig = originalPixelData[i];
let gOrig = originalPixelData[i + 1];
let bOrig = originalPixelData[i + 2];
// 1. Posterization
// Apply to r, g, b which will be modified
let r = Math.round(rOrig / levelStep) * levelStep;
let g = Math.round(gOrig / levelStep) * levelStep;
let b = Math.round(bOrig / levelStep) * levelStep;
// 2. Add Noise
if (currentNoiseAmount > 0) {
const noise = (Math.random() * 2 - 1) * currentNoiseAmount; // Centered noise
r += noise;
g += noise;
b += noise;
}
// 3. Simple Edge Darkening
if (currentEdgeDarkening > 0 && currentEdgeThreshold >= 0) {
const currentLuminance = (originalPixelData[i] * 0.299 +
originalPixelData[i + 1] * 0.587 +
originalPixelData[i + 2] * 0.114);
let maxDiff = 0;
const neighborsOffsets = [
[-1, 0], [1, 0], [0, -1], [0, 1] // 4-connectivity
// For 8-connectivity, add: [-1, -1], [1, -1], [-1, 1], [1, 1]
];
for (const [dx, dy] of neighborsOffsets) {
const nx = x + dx;
const ny = y + dy;
if (nx >= 0 && nx < W && ny >= 0 && ny < H) {
const ni = (ny * W + nx) * 4;
const neighborLuminance = (originalPixelData[ni] * 0.299 +
originalPixelData[ni + 1] * 0.587 +
originalPixelData[ni + 2] * 0.114);
maxDiff = Math.max(maxDiff, Math.abs(currentLuminance - neighborLuminance));
}
}
if (maxDiff > currentEdgeThreshold) {
const factor = 1.0 - currentEdgeDarkening;
r *= factor;
g *= factor;
b *= factor;
}
}
// Clamp values and apply to image data
data[i] = Math.max(0, Math.min(255, r));
data[i + 1] = Math.max(0, Math.min(255, g));
data[i + 2] = Math.max(0, Math.min(255, b));
// Alpha (data[i + 3]) remains unchanged from original
}
}
ctx.putImageData(imageData, 0, 0);
return canvas;
}
Apply Changes