Please bookmark this page to avoid losing your image tool!

Image Dialogue Removal And Repair 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.
async function processImage(originalImg, removeX = 0, removeY = 0, removeWidth = 0, removeHeight = 0, patchSize = 11, searchBorder = 20) {
    const width = originalImg.naturalWidth;
    const height = originalImg.naturalHeight;

    // 1. --- Input Validation and Setup ---
    if (removeWidth <= 0 || removeHeight <= 0 || width === 0 || height === 0) {
        const canvas = document.createElement('canvas');
        canvas.width = width || 1;
        canvas.height = height || 1;
        const ctx = canvas.getContext('2d');
        if (width > 0 && height > 0) {
            ctx.drawImage(originalImg, 0, 0);
        }
        return canvas;
    }

    if (patchSize % 2 === 0) {
        patchSize++; // Ensure patch size is odd for a clear center pixel.
    }
    const patchRadius = Math.floor(patchSize / 2);

    // 2. --- Canvas and Image Data Setup ---
    const canvas = document.createElement('canvas');
    canvas.width = width;
    canvas.height = height;
    const ctx = canvas.getContext('2d', { willReadFrequently: true });
    ctx.drawImage(originalImg, 0, 0);

    const finalImageData = ctx.getImageData(0, 0, width, height);
    const data = finalImageData.data;
    const originalHoleMask = new Uint8Array(width * height).fill(0);

    // 3. --- Define Hole, Source Region, and Pixels to Fill ---
    const pixelsToFill = [];

    const rX = Math.max(0, removeX);
    const rY = Math.max(0, removeY);
    const rW = Math.min(width - rX, removeWidth);
    const rH = Math.min(height - rY, removeHeight);

    for (let y = rY; y < rY + rH; y++) {
        for (let x = rX; x < rX + rW; x++) {
            const index = y * width + x;
            originalHoleMask[index] = 1;
            pixelsToFill.push({ x, y });
        }
    }

    if (pixelsToFill.length === 0) {
        return canvas;
    }

    // Pre-calculate all valid source patch center locations.
    const sourcePatchLocations = [];
    const searchXMin = Math.max(patchRadius, rX - searchBorder);
    const searchYMin = Math.max(patchRadius, rY - searchBorder);
    const searchXMax = Math.min(width - patchRadius - 1, rX + rW + searchBorder);
    const searchYMax = Math.min(height - patchRadius - 1, rY + rH + searchBorder);
   
    for (let y = searchYMin; y <= searchYMax; y++) {
        for (let x = searchXMin; x <= searchXMax; x++) {
            let isPatchValid = true;
            checkPatch:
            for (let dy = -patchRadius; dy <= patchRadius; dy++) {
                for (let dx = -patchRadius; dx <= patchRadius; dx++) {
                    if (originalHoleMask[(y + dy) * width + (x + dx)]) {
                        isPatchValid = false;
                        break checkPatch;
                    }
                }
            }
            if (isPatchValid) {
                sourcePatchLocations.push({ x, y });
            }
        }
    }
   
    if (sourcePatchLocations.length === 0) {
        console.error("No source region found to sample from. Try increasing searchBorder or reducing patchSize.");
        return canvas;
    }
   
    // 4. --- Patch Matching and Filling ---
    const findBestMatch = (tx, ty, currentHoleMask) => {
        let bestMatch = { x: -1, y: -1, ssd: Infinity };
        // Randomly sample source patches for performance.
        const maxSamples = Math.min(sourcePatchLocations.length, 500);

        for (let i = 0; i < maxSamples; i++) {
            const source = sourcePatchLocations[Math.floor(Math.random() * sourcePatchLocations.length)];
            let { x: sx, y: sy } = source;
           
            let currentSsd = 0;
            let pixelsCompared = 0;

            for (let dy = -patchRadius; dy <= patchRadius; dy++) {
                for (let dx = -patchRadius; dx <= patchRadius; dx++) {
                    const currentTx = tx + dx;
                    const currentTy = ty + dy;

                    if (currentTx < 0 || currentTx >= width || currentTy < 0 || currentTy >= height) continue;
                   
                    if (currentHoleMask[currentTy * width + currentTx] === 0) { // If target pixel is known
                        const targetIdx = (currentTy * width + currentTx) * 4;
                        const sourceIdx = ((sy + dy) * width + (sx + dx)) * 4;

                        const dR = data[targetIdx] - data[sourceIdx];
                        const dG = data[targetIdx + 1] - data[sourceIdx + 1];
                        const dB = data[targetIdx + 2] - data[sourceIdx + 2];

                        currentSsd += dR * dR + dG * dG + dB * dB;
                        pixelsCompared++;
                    }
                }
            }

            if (pixelsCompared > 0) {
                const avgSsd = currentSsd / pixelsCompared;
                if (avgSsd < bestMatch.ssd) {
                    bestMatch = { x: sx, y: sy, ssd: avgSsd };
                }
            }
        }
        return bestMatch;
    };
   
    const fillPass = (pixels, currentHoleMask) => {
        for (const p of pixels) {
            const bestMatch = findBestMatch(p.x, p.y, currentHoleMask);
            if (bestMatch.x !== -1) {
                const sourceColorIdx = (bestMatch.y * width + bestMatch.x) * 4;
                const targetIdx = (p.y * width + p.x) * 4;
                data[targetIdx] = data[sourceColorIdx];
                data[targetIdx + 1] = data[sourceColorIdx + 1];
                data[targetIdx + 2] = data[sourceColorIdx + 2];
                // Mark this pixel as filled for subsequent pixels in this same pass
                currentHoleMask[p.y * width + p.x] = 0;
            }
        }
    };
    
    // A simple raster scan (top-left to bottom-right) propagates information
    // from the top and left of the hole.
    let pass1HoleMask = new Uint8Array(originalHoleMask);
    fillPass([...pixelsToFill], pass1HoleMask);
    
    // 5. --- Finalize and Return Canvas ---
    ctx.putImageData(finalImageData, 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 Dialogue Removal and Repair Tool is designed to help users remove unwanted areas from images and repair them seamlessly. It allows users to specify a rectangular region of an image to be removed, using advanced patch-matching algorithms to fill in the missing areas by sampling surrounding pixels. This tool can be particularly useful for photographers and graphic designers looking to clean up images by removing watermarks, text, or other distractions without leaving obvious traces. Additionally, it can be used in image restoration projects where damaged sections need to be replaced with visually coherent content.

Leave a Reply

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