You can edit the below JavaScript code to customize the image tool.
Apply Changes
function processImage(originalImg, blockSize = 8, desaturationLevel = 0.3, tintColorStr = "", tintIntensity = 0.1) {
// Sanitize and validate parameters
blockSize = Math.max(1, Math.floor(blockSize)); // Ensure blockSize is at least 1 and an integer
desaturationLevel = Math.max(0, Math.min(1, desaturationLevel)); // Clamp desaturationLevel between 0 and 1
tintIntensity = Math.max(0, Math.min(1, tintIntensity)); // Clamp tintIntensity between 0 and 1
let tintR = 0, tintG = 0, tintB = 0;
let applyTint = false;
// Parse tintColorStr if provided (e.g., "255,0,0" for red)
if (typeof tintColorStr === 'string' && tintColorStr.trim() !== "") {
const parts = tintColorStr.split(',').map(s => parseInt(s.trim(), 10));
if (parts.length === 3 && parts.every(p => !isNaN(p) && p >= 0 && p <= 255)) {
[tintR, tintG, tintB] = parts;
applyTint = true;
} else {
console.warn("Invalid tintColorStr format. Expected 'r,g,b' with values 0-255. Tint will not be applied. Received:", tintColorStr);
}
}
// Create a canvas element
const canvas = document.createElement('canvas');
// Use willReadFrequently hint for potential performance optimization by the browser
const ctx = canvas.getContext('2d', { willReadFrequently: true });
// Get image dimensions
const imgWidth = originalImg.naturalWidth || originalImg.width;
const imgHeight = originalImg.naturalHeight || originalImg.height;
// Set canvas dimensions
canvas.width = imgWidth;
canvas.height = imgHeight;
// If the image has no dimensions, return the empty canvas
if (imgWidth === 0 || imgHeight === 0) {
return canvas;
}
// Draw the original image onto the canvas
ctx.drawImage(originalImg, 0, 0, imgWidth, imgHeight);
// Get the pixel data from the canvas
const imageData = ctx.getImageData(0, 0, imgWidth, imgHeight);
const data = imageData.data; // This is a Uint8ClampedArray: [r,g,b,a, r,g,b,a, ...]
// Iterate over the image in blocks defined by blockSize
for (let y = 0; y < imgHeight; y += blockSize) {
for (let x = 0; x < imgWidth; x += blockSize) {
let sumR = 0, sumG = 0, sumB = 0, sumA = 0;
let numPixelsInBlock = 0;
// Determine the actual dimensions of the current block (handles edges of the image)
const currentBlockHeight = Math.min(blockSize, imgHeight - y);
const currentBlockWidth = Math.min(blockSize, imgWidth - x);
// Calculate the average color and alpha for the current block
for (let blockY = 0; blockY < currentBlockHeight; blockY++) {
for (let blockX = 0; blockX < currentBlockWidth; blockX++) {
const pixelX = x + blockX;
const pixelY = y + blockY;
const index = (pixelY * imgWidth + pixelX) * 4; // Each pixel has 4 components (R,G,B,A)
sumR += data[index];
sumG += data[index + 1];
sumB += data[index + 2];
sumA += data[index + 3];
numPixelsInBlock++;
}
}
// Should not happen with valid dimensions (width/height > 0) and blockSize >= 1
if (numPixelsInBlock === 0) continue;
// Calculate average R, G, B, A values for the block
let avgR = sumR / numPixelsInBlock;
let avgG = sumG / numPixelsInBlock;
let avgB = sumB / numPixelsInBlock;
const avgA = sumA / numPixelsInBlock; // Preserve average alpha
// Apply desaturation effect
if (desaturationLevel > 0) {
// Standard luminosity formula for grayscale conversion
const gray = 0.299 * avgR + 0.587 * avgG + 0.114 * avgB;
// Interpolate between original color and gray
avgR = avgR * (1 - desaturationLevel) + gray * desaturationLevel;
avgG = avgG * (1 - desaturationLevel) + gray * desaturationLevel;
avgB = avgB * (1 - desaturationLevel) + gray * desaturationLevel;
}
// Apply tint effect
if (applyTint && tintIntensity > 0) {
// Interpolate between current color and tint color
avgR = avgR * (1 - tintIntensity) + tintR * tintIntensity;
avgG = avgG * (1 - tintIntensity) + tintG * tintIntensity;
avgB = avgB * (1 - tintIntensity) + tintB * tintIntensity;
}
// Fill the entire block in the imageData with the new calculated color
// Uint8ClampedArray automatically clamps values to the 0-255 range upon assignment.
for (let blockY = 0; blockY < currentBlockHeight; blockY++) {
for (let blockX = 0; blockX < currentBlockWidth; blockX++) {
const pixelX = x + blockX;
const pixelY = y + blockY;
const index = (pixelY * imgWidth + pixelX) * 4;
data[index] = avgR;
data[index + 1] = avgG;
data[index + 2] = avgB;
data[index + 3] = avgA; // Apply the averaged alpha
}
}
}
}
// Put the modified image data back onto the canvas
ctx.putImageData(imageData, 0, 0);
// Return the canvas element with the processed image
return canvas;
}
Apply Changes