Please bookmark this page to avoid losing your image tool!

Image Depth Of Field 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, focusXPercent = 50, focusYPercent = 50, focusRadiusPercent = 15, blurAmountPx = 5, transitionRangePercent = 20) {
    // Ensure parameters are numbers and have valid ranges
    focusXPercent = Number(focusXPercent);
    focusYPercent = Number(focusYPercent);
    focusRadiusPercent = Math.max(0, Number(focusRadiusPercent));
    blurAmountPx = Math.max(0, Number(blurAmountPx));
    transitionRangePercent = Math.max(0, Number(transitionRangePercent));

    const imgWidth = originalImg.naturalWidth || originalImg.width;
    const imgHeight = originalImg.naturalHeight || originalImg.height;

    const outputCanvas = document.createElement('canvas');

    if (imgWidth === 0 || imgHeight === 0) {
        console.warn("Input image has zero dimensions. Returning 1x1 blank canvas.");
        outputCanvas.width = 1;
        outputCanvas.height = 1;
        // Optionally, fill with a color or indicate error state on the canvas
        // const ctx = outputCanvas.getContext('2d');
        // ctx.fillStyle = 'rgba(0,0,0,0.1)'; // A very faint gray for example
        // ctx.fillRect(0,0,1,1);
        return outputCanvas;
    }

    outputCanvas.width = imgWidth;
    outputCanvas.height = imgHeight;
    // Optimization hint for context, useful for frequent getImageData/putImageData
    const outputCtx = outputCanvas.getContext('2d', { willReadFrequently: true });

    // 1. Prepare blurred version of the image
    const blurCanvas = document.createElement('canvas');
    blurCanvas.width = imgWidth;
    blurCanvas.height = imgHeight;
    const blurCtx = blurCanvas.getContext('2d', { willReadFrequently: true });

    if (blurAmountPx > 0) {
        blurCtx.filter = `blur(${blurAmountPx}px)`;
        blurCtx.drawImage(originalImg, 0, 0, imgWidth, imgHeight); // Blur is applied during this draw
        blurCtx.filter = 'none'; // Reset filter to ensure getImageData gets the filtered content correctly and doesn't affect future draws
    } else {
        // If no blur, blurred version is the same as original
        blurCtx.drawImage(originalImg, 0, 0, imgWidth, imgHeight);
    }
    // It's crucial that originalImg is loaded and not tainted (CORS) for getImageData to work.
    const blurImageData = blurCtx.getImageData(0, 0, imgWidth, imgHeight);

    // 2. Prepare sharp version of the image (for its ImageData)
    //    Could optimize by only creating this if needed (i.e., focus is not 0 everywhere)
    //    but for clarity, we'll always get it.
    const sharpCanvas = document.createElement('canvas');
    sharpCanvas.width = imgWidth;
    sharpCanvas.height = imgHeight;
    const sharpCtx = sharpCanvas.getContext('2d', { willReadFrequently: true });
    sharpCtx.drawImage(originalImg, 0, 0, imgWidth, imgHeight);
    const sharpImageData = sharpCtx.getImageData(0, 0, imgWidth, imgHeight);

    // Create ImageData for the output
    const outputImageData = outputCtx.createImageData(imgWidth, imgHeight);

    // Calculate actual metric values from percentage parameters
    const actualFocusX = imgWidth * focusXPercent / 100;
    const actualFocusY = imgHeight * focusYPercent / 100;
    
    const minDimension = Math.min(imgWidth, imgHeight); // Base radius on the smaller dimension for consistency
    const actualFocusRadius = minDimension * focusRadiusPercent / 100;
    const actualTransitionRange = minDimension * transitionRangePercent / 100;

    // 4. Pixel Loop for blending sharp and blurred images
    for (let y = 0; y < imgHeight; y++) {
        for (let x = 0; x < imgWidth; x++) {
            const distX = x - actualFocusX;
            const distY = y - actualFocusY;
            const distance = Math.sqrt(distX * distX + distY * distY);

            let sharpnessFactor = 0.0; // 1.0 means fully sharp, 0.0 means fully blurred
            
            if (distance <= actualFocusRadius) {
                sharpnessFactor = 1.0;
            } else if (actualTransitionRange <= 0) { // No transition zone (hard edge), and we are outside focusRadius
                sharpnessFactor = 0.0;
            } else if (distance >= actualFocusRadius + actualTransitionRange) { // Past transition zone
                sharpnessFactor = 0.0;
            } else { // Within transition zone
                sharpnessFactor = 1.0 - (distance - actualFocusRadius) / actualTransitionRange;
            }
            
            // Clamp sharpnessFactor to [0, 1] just in case of floating point nuances
            sharpnessFactor = Math.max(0, Math.min(1, sharpnessFactor));

            const idx = (y * imgWidth + x) * 4; // Index for the current pixel's R channel

            // Blend R, G, B, and Alpha channels
            // outputPixel = sharpPixel * factor + blurPixel * (1 - factor)
            if (sharpnessFactor === 1.0) { // Fully sharp
                outputImageData.data[idx]     = sharpImageData.data[idx];
                outputImageData.data[idx + 1] = sharpImageData.data[idx + 1];
                outputImageData.data[idx + 2] = sharpImageData.data[idx + 2];
                outputImageData.data[idx + 3] = sharpImageData.data[idx + 3];
            } else if (sharpnessFactor === 0.0) { // Fully blurred
                outputImageData.data[idx]     = blurImageData.data[idx];
                outputImageData.data[idx + 1] = blurImageData.data[idx + 1];
                outputImageData.data[idx + 2] = blurImageData.data[idx + 2];
                outputImageData.data[idx + 3] = blurImageData.data[idx + 3];
            } else { // In transition zone, blend
                outputImageData.data[idx]     = sharpImageData.data[idx]     * sharpnessFactor + blurImageData.data[idx]     * (1 - sharpnessFactor);
                outputImageData.data[idx + 1] = sharpImageData.data[idx + 1] * sharpnessFactor + blurImageData.data[idx + 1] * (1 - sharpnessFactor);
                outputImageData.data[idx + 2] = sharpImageData.data[idx + 2] * sharpnessFactor + blurImageData.data[idx + 2] * (1 - sharpnessFactor);
                outputImageData.data[idx + 3] = sharpImageData.data[idx + 3] * sharpnessFactor + blurImageData.data[idx + 3] * (1 - sharpnessFactor);
            }
        }
    }

    // 5. Draw the final composited image data to the output canvas
    outputCtx.putImageData(outputImageData, 0, 0);

    return outputCanvas;
}

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 Depth Of Field Filter is a tool designed to apply a depth of field effect to images, simulating professional photography techniques. Users can specify focal points and adjust the amount of blur to create a visually striking focus on specific areas of an image while softly blurring the surroundings. This tool is ideal for enhancing portrait photographs, emphasizing subjects within a scene, or adding artistic flair to landscape images. It allows customization through parameters such as focus position, focus radius, blur intensity, and transition range, making it versatile for various creative applications.

Leave a Reply

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