You can edit the below JavaScript code to customize the image tool.
async function processImage(originalImg, sharpenStrength = 1.0, saturationBoost = 0.2) {
// Ensure parameters are valid numbers, falling back to defaults if not.
let sStrength = parseFloat(sharpenStrength);
if (isNaN(sStrength)) {
console.warn(`Invalid sharpenStrength value "${sharpenStrength}", using default 1.0.`);
sStrength = 1.0;
}
let sBoost = parseFloat(saturationBoost);
if (isNaN(sBoost)) {
console.warn(`Invalid saturationBoost value "${saturationBoost}", using default 0.2.`);
sBoost = 0.2;
}
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d', { willReadFrequently: true }); // Optimization hint
// Use naturalWidth/Height for pristine dimensions, fallback to width/height
canvas.width = originalImg.naturalWidth || originalImg.width;
canvas.height = originalImg.naturalHeight || originalImg.height;
// Handle cases of invalid image or dimensions
if (canvas.width === 0 || canvas.height === 0) {
console.warn("Image has zero width or height.");
return canvas; // Return empty (0x0) canvas
}
ctx.drawImage(originalImg, 0, 0, canvas.width, canvas.height);
let imageData;
try {
imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
} catch (e) {
console.error("Could not get ImageData (e.g., tainted canvas for cross-origin image). Filter cannot be applied.", e);
// Return canvas with the original image drawn, as pixel manipulation is not possible.
return canvas;
}
const data = imageData.data;
const imgWidth = canvas.width;
const imgHeight = canvas.height;
// Create a copy of the pixel data. This is essential for convolution (sharpening)
// to ensure calculations use original pixel values, not ones already modified in this pass.
const PcopyData = new Uint8ClampedArray(data);
// 1. Apply Sharpening
// Sharpening is applied only if strength is positive and image is large enough for a 3x3 kernel.
if (sStrength > 0 && imgWidth >= 3 && imgHeight >= 3) {
// Define the sharpening kernel.
// The sum of kernel weights is 1 ( (1 + 4*sStrength) - 4*sStrength = 1 ),
// which helps maintain overall image brightness.
const kernel = [
[0, -sStrength, 0],
[-sStrength, 1 + 4 * sStrength, -sStrength],
[0, -sStrength, 0]
];
// Iterate over each pixel (excluding 1-pixel border)
for (let y = 1; y < imgHeight - 1; y++) {
for (let x = 1; x < imgWidth - 1; x++) {
let sumR = 0, sumG = 0, sumB = 0;
// Apply the 3x3 kernel to the current pixel
for (let ky = -1; ky <= 1; ky++) { // Kernel y-offset (-1, 0, 1)
for (let kx = -1; kx <= 1; kx++) { // Kernel x-offset (-1, 0, 1)
// Get coordinates of the neighboring pixel in the source data
const Px = x + kx;
const Py = y + ky;
// Calculate the index of the neighboring pixel in the 1D PcopyData array
const Pidx = (Py * imgWidth + Px) * 4;
// Get the_weight from the kernel matrix
const Pweight = kernel[ky + 1][kx + 1]; // kernel indices are 0,1,2
// Accumulate weighted R, G, B values from source data (PcopyData)
sumR += PcopyData[Pidx] * Pweight;
sumG += PcopyData[Pidx + 1] * Pweight;
sumB += PcopyData[Pidx + 2] * Pweight;
// Alpha channel (PcopyData[Pidx + 3]) is not typically part of sharpening
}
}
// Calculate the index of the current pixel in the destination data array
const idx = (y * imgWidth + x) * 4;
// Set the new R, G, B values, clamped to [0, 255]
data[idx] = Math.max(0, Math.min(255, sumR));
data[idx + 1] = Math.max(0, Math.min(255, sumG));
data[idx + 2] = Math.max(0, Math.min(255, sumB));
// Alpha channel (data[idx + 3]) is preserved from the original image unchanged by sharpening
}
}
} // If sStrength is 0 or image is too small, sharpening is skipped. Border pixels also remain unsharpened.
// 2. Apply Saturation Boost
// This operates on the pixel data (which may have been sharpened in the previous step).
if (sBoost !== 0) { // Allow sBoost = 0 for no change, negative for desaturation.
const satFactor = 1.0 + sBoost;
// satFactor = 0 for grayscale (sBoost = -1.0)
// satFactor = 1 for no change (sBoost = 0)
// satFactor > 1 for increased saturation
for (let i = 0; i < data.length; i += 4) {
const r = data[i];
const g = data[i + 1];
const b = data[i + 2];
// Calculate luminance (brightness) using standard Rec. 601/709 coefficients
const L = 0.299 * r + 0.587 * g + 0.114 * b;
// Adjust R, G, B towards/away from L based on saturation factor
data[i] = Math.max(0, Math.min(255, L + satFactor * (r - L)));
data[i + 1] = Math.max(0, Math.min(255, L + satFactor * (g - L)));
data[i + 2] = Math.max(0, Math.min(255, L + satFactor * (b - L)));
// Alpha channel (data[i + 3]) remains unchanged by saturation adjustment
}
} // If sBoost is 0, saturation adjustment is skipped.
// Write the modified pixel data back to the canvas
ctx.putImageData(imageData, 0, 0);
return canvas;
}
Free Image Tool Creator
Can't find the image tool you're looking for? Create one based on your own needs now!
The Image Macro Filter is a web tool designed to enhance images by applying sharpening and saturation adjustments. Users can upload an image and adjust the sharpening strength to make details more pronounced, while also boosting the color saturation to make the image more vibrant. This tool is useful for photographers looking to enhance their images before sharing, for graphic designers who need to improve visual quality, or for anyone wanting to enhance their pictures for social media or personal use.