Please bookmark this page to avoid losing your image tool!

Image Macro Filter

(Free & Supports Bulk Upload)

Drag & drop your images here or

The result will appear here...
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!

Description

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.

Leave a Reply

Your email address will not be published. Required fields are marked *