Please bookmark this page to avoid losing your image tool!

Image Restoration Tool

(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.
/**
 * Image Restoration Tool - "Концерт спасён!" (Concert saved!)
 * Restores dark, muddy, and slightly blurry concert photos by intelligently 
 * recovering shadows, boosting dynamics (brightness/contrast/saturation), 
 * and applying an unsharp mask convolution to restore edges.
 */
async function processImage(
    originalImg,
    gamma = 1.3,
    brightness = 15,
    contrast = 15,
    saturation = 1.2,
    sharpenAmount = 0.8
) {
    // Coerce parameters to numbers gracefully
    gamma = Number(gamma) || 1;
    brightness = Number(brightness) || 0;
    contrast = Math.max(-255, Math.min(255, Number(contrast) || 0));
    saturation = Number(saturation) || 1;
    sharpenAmount = Number(sharpenAmount) || 0;

    const canvas = document.createElement('canvas');
    const width = originalImg.width;
    const height = originalImg.height;
    canvas.width = width;
    canvas.height = height;

    const ctx = canvas.getContext('2d');
    // Fill with black to prevent transparent issues
    ctx.fillStyle = "#000000";
    ctx.fillRect(0, 0, width, height);
    ctx.drawImage(originalImg, 0, 0);

    // If the image is too small to process, just return it
    if (width === 0 || height === 0) return canvas;

    const imageData = ctx.getImageData(0, 0, width, height);
    const data = imageData.data;

    // Yield control briefly to keep the UI thread responsive when processing large images
    await new Promise(r => setTimeout(r, 0));

    // 1. Build a Transformation Lookup Table (LUT) for Gamma, Brightness, and Contrast
    // Using Uint8ClampedArray handles Math.min(255, Math.max(0, val)) restrictions internally
    const lut = new Uint8ClampedArray(256);
    const gammaCorrection = 1 / gamma;
    const contrastFactor = (259 * (contrast + 255)) / (255 * (259 - contrast));

    for (let i = 0; i < 256; i++) {
        // Shadow recovery via inverse gamma
        let val = 255 * Math.pow(i / 255, gammaCorrection);
        // Base brightness augmentation
        val += brightness;
        // Contrast enhancement (anchored around mid-gray 128)
        val = contrastFactor * (val - 128) + 128;
        
        lut[i] = val;
    }

    // 2. Apply LUT and Color Saturation
    for (let i = 0; i < data.length; i += 4) {
        let r = lut[data[i]];
        let g = lut[data[i + 1]];
        let b = lut[data[i + 2]];

        if (saturation !== 1.0) {
            // Rec. 601 luma approximation map
            const luma = 0.299 * r + 0.587 * g + 0.114 * b;
            data[i] = luma + saturation * (r - luma);
            data[i + 1] = luma + saturation * (g - luma);
            data[i + 2] = luma + saturation * (b - luma);
        } else {
            data[i] = r;
            data[i + 1] = g;
            data[i + 2] = b;
        }
        // data[i + 3] (Alpha) is kept exactly as is
    }

    await new Promise(r => setTimeout(r, 0));

    // 3. Apply Unsharp Masking using Convolution Matrix
    if (sharpenAmount > 0 && width > 2 && height > 2) {
        // We read from the cloned snapshot, write to the live array
        const tempData = new Uint8ClampedArray(data);
        const w = width;
        const h = height;

        const center = 1 + 4 * sharpenAmount;
        const edge = -sharpenAmount;

        // Skip 1px edge boundary constraints to significantly heavily optimize the operation speed
        for (let y = 1; y < h - 1; y++) {
            let rowBase = y * w;
            let prevRowBase = (y - 1) * w;
            let nextRowBase = (y + 1) * w;

            for (let x = 1; x < w - 1; x++) {
                const idx = (rowBase + x) * 4;

                const idxN = (prevRowBase + x) * 4;
                const idxS = (nextRowBase + x) * 4;
                const idxW = idx - 4;
                const idxE = idx + 4;

                // Process R, G, B channels individually
                for (let c = 0; c < 3; c++) {
                    data[idx + c] =
                        tempData[idx + c] * center +
                        tempData[idxN + c] * edge +
                        tempData[idxS + c] * edge +
                        tempData[idxW + c] * edge +
                        tempData[idxE + c] * edge;
                }
            }
        }
    }

    // Paint updated pixels back onto the main 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 Restoration Tool is designed to enhance and improve the quality of low-light or poorly captured photographs. It functions by recovering details from shadows, adjusting brightness and contrast, and boosting color saturation to create more vibrant images. Additionally, it features an unsharp mask sharpening effect to help restore edge clarity and reduce slight blurriness. This tool is particularly useful for salvaging photos taken in challenging lighting conditions, such as concert photography, nighttime events, or indoor shots with heavy shadows.

Leave a Reply

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