Please bookmark this page to avoid losing your image tool!

Image Mehndi Pattern Filter Effect 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.
function processImage(originalImg, mehndiColorStr = "101,67,33", backgroundColorStr = "255,235,205", edgeThreshold = 50) {
    const canvas = document.createElement('canvas');
    const ctx = canvas.getContext('2d');

    const imgWidth = originalImg.naturalWidth;
    const imgHeight = originalImg.naturalHeight;

    // Ensure canvas has at least 1x1 dimension, even if original image is 0x0
    canvas.width = Math.max(1, imgWidth);
    canvas.height = Math.max(1, imgHeight);

    // Parse color strings into RGB components
    const [mR, mG, mB] = mehndiColorStr.split(',').map(Number);
    const [bR, bG, bB] = backgroundColorStr.split(',').map(Number);

    // If the image is too small for the Sobel kernel (needs at least 3x3 area)
    // or if original dimensions were 0, fill with background color.
    if (imgWidth < 3 || imgHeight < 3) {
        ctx.fillStyle = `rgb(${bR},${bG},${bB})`;
        ctx.fillRect(0, 0, canvas.width, canvas.height);
        return canvas;
    }

    // Draw the original image onto the canvas to access its pixel data
    ctx.drawImage(originalImg, 0, 0, imgWidth, imgHeight);
    const imageData = ctx.getImageData(0, 0, imgWidth, imgHeight);
    const data = imageData.data; // Pixel data: R,G,B,A, R,G,B,A, ...

    // Step 1: Convert the image to grayscale
    // Store grayscale values in a 1D array
    const grayData = new Uint8ClampedArray(imgWidth * imgHeight);
    for (let i = 0; i < data.length; i += 4) {
        const r = data[i];
        const g = data[i + 1];
        const b = data[i + 2];
        // Standard luminance calculation
        grayData[i / 4] = Math.round(0.299 * r + 0.587 * g + 0.114 * b);
    }

    // Step 2: Apply Sobel operator to detect edges
    // edgeMagnitudeData will store the calculated magnitude for each non-border pixel
    const edgeMagnitudeData = new Float32Array(imgWidth * imgHeight);
    let maxMagnitude = 0; // To normalize magnitudes later

    // Iterate over interior pixels (Sobel kernel is 3x3)
    for (let y = 1; y < imgHeight - 1; y++) {
        for (let x = 1; x < imgWidth - 1; x++) {
            const i = y * imgWidth + x; // Index for the current pixel in grayData

            // Gx (horizontal gradient)
            const Gx = (
                -grayData[(y - 1) * imgWidth + (x - 1)] + grayData[(y - 1) * imgWidth + (x + 1)] +
                -2 * grayData[y * imgWidth + (x - 1)]   + 2 * grayData[y * imgWidth + (x + 1)] +
                -grayData[(y + 1) * imgWidth + (x - 1)] + grayData[(y + 1) * imgWidth + (x + 1)]
            );

            // Gy (vertical gradient)
            const Gy = (
                -grayData[(y - 1) * imgWidth + (x - 1)] - 2 * grayData[(y - 1) * imgWidth + x] - grayData[(y - 1) * imgWidth + (x + 1)] +
                 grayData[(y + 1) * imgWidth + (x - 1)] + 2 * grayData[(y + 1) * imgWidth + x] + grayData[(y + 1) * imgWidth + (x + 1)]
            );

            const magnitude = Math.sqrt(Gx * Gx + Gy * Gy);
            edgeMagnitudeData[i] = magnitude;
            if (magnitude > maxMagnitude) {
                maxMagnitude = magnitude;
            }
        }
    }
    
    // Step 3: Normalize edge magnitudes to a 0-255 range
    const normalizedEdgeData = new Uint8ClampedArray(imgWidth * imgHeight);
    if (maxMagnitude > 0) {
        for (let i = 0; i < imgWidth * imgHeight; i++) {
            // Pixels on the border were not processed by Sobel, their edgeMagnitudeData[i] is 0.
            // Normalizing 0 gives 0, which is correct (no edge detected).
            normalizedEdgeData[i] = Math.round((edgeMagnitudeData[i] / maxMagnitude) * 255);
        }
    }
    // If maxMagnitude is 0 (e.g., for a completely flat image), normalizedEdgeData will be all zeros.

    // Step 4: Colorize the output image based on normalized edge magnitudes
    // Iterate through all pixel positions (0 to width*height - 1)
    for (let i = 0; i < grayData.length; i++) {
        const dataIdx = i * 4; // Base index for R channel in imageData.data
        const x = i % imgWidth;
        const y = Math.floor(i / imgWidth);

        // Color border pixels with the background color
        if (x === 0 || x === imgWidth - 1 || y === 0 || y === imgHeight - 1) {
            data[dataIdx]     = bR;
            data[dataIdx + 1] = bG;
            data[dataIdx + 2] = bB;
        } else {
            // For non-border pixels, use their normalized edge magnitude
            const normMagnitude = normalizedEdgeData[i];
            if (normMagnitude > edgeThreshold) { // If edge is strong enough
                data[dataIdx]     = mR;         // Use mehndi color for the pattern
                data[dataIdx + 1] = mG;
                data[dataIdx + 2] = mB;
            } else {                             // Otherwise, use background color
                data[dataIdx]     = bR;
                data[dataIdx + 1] = bG;
                data[dataIdx + 2] = bB;
            }
        }
        data[dataIdx + 3] = 255; // Set alpha to fully opaque
    }

    // Put the modified pixel data back onto 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 Mehndi Pattern Filter Effect Tool allows users to apply a unique mehndi (henna) pattern effect to their images. By processing the original image, it transforms it into a design that highlights edges with the chosen mehndi color, while filling the background with a specified color. This tool is ideal for artists, designers, and anyone looking to create visually appealing images for invitations, social media posts, or personal projects, adding a creative twist reminiscent of traditional henna designs.

Leave a Reply

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