Please bookmark this page to avoid losing your image tool!

Image Bokeh Filter Application

(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, 
    blurAmount = 10, 
    centerXPercent = 50, 
    centerYPercent = 50, 
    focusRadiusPercent = 25, 
    highlightThreshold = 220, 
    highlightSize = 15, 
    highlightShape = "circle"
) {
    // Helper function for drawing hexagon
    // Using arrow function syntax for brevity and consistent `this` (though not used here)
    const _drawHexagon = (context, x, y, radius) => {
        context.beginPath();
        for (let i = 0; i < 6; i++) {
            // Angle for flat top hexagon (common for aperture shapes)
            const angle = (Math.PI / 3) * i + Math.PI / 6; 
            const hx = x + radius * Math.cos(angle);
            const hy = y + radius * Math.sin(angle);
            if (i === 0) {
                context.moveTo(hx, hy);
            } else {
                context.lineTo(hx, hy);
            }
        }
        context.closePath();
        context.fill();
    };

    // --- Parameter Validation and Type Casting ---
    let numBlurAmount = Number(blurAmount);
    let numCenterXPercent = Number(centerXPercent);
    let numCenterYPercent = Number(centerYPercent);
    let numFocusRadiusPercent = Number(focusRadiusPercent);
    let numHighlightThreshold = Number(highlightThreshold);
    let numHighlightSize = Number(highlightSize);
    let strHighlightShape = String(highlightShape).toLowerCase();

    // Assign defaults if parsing failed or values are unreasonable
    if (isNaN(numBlurAmount) || numBlurAmount < 0) numBlurAmount = 10;
    if (isNaN(numCenterXPercent) || numCenterXPercent < 0 || numCenterXPercent > 100) numCenterXPercent = 50;
    if (isNaN(numCenterYPercent) || numCenterYPercent < 0 || numCenterYPercent > 100) numCenterYPercent = 50;
    if (isNaN(numFocusRadiusPercent) || numFocusRadiusPercent < 0 || numFocusRadiusPercent > 100) numFocusRadiusPercent = 25;
    if (isNaN(numHighlightThreshold) || numHighlightThreshold < 0 || numHighlightThreshold > 255) numHighlightThreshold = 220;
    if (isNaN(numHighlightSize) || numHighlightSize <= 0) numHighlightSize = 15;
    if (!['circle', 'hexagon'].includes(strHighlightShape)) strHighlightShape = 'circle';

    // --- Canvas Setup ---
    const outputCanvas = document.createElement('canvas');
    const ctx = outputCanvas.getContext('2d');

    const w = originalImg.naturalWidth || originalImg.width;
    const h = originalImg.naturalHeight || originalImg.height;

    if (w === 0 || h === 0) {
        console.warn("Image dimensions are zero. Returning empty canvas.");
        outputCanvas.width = 0;
        outputCanvas.height = 0;
        return outputCanvas;
    }

    outputCanvas.width = w;
    outputCanvas.height = h;

    // Calculate focus area parameters in pixels
    const focusX = (numCenterXPercent / 100) * w;
    const focusY = (numCenterYPercent / 100) * h;
    const minDimension = Math.min(w, h);
    // Radius percent is relative to half of the smaller dimension, so 100% makes diameter = minDimension
    const actualFocusRadius = (numFocusRadiusPercent / 100) * (minDimension / 2);

    let blurredImageCanvas = null; // To store the purely blurred version for highlight detection

    // --- Step 1: Draw Base Image (Blurred or Original) ---
    if (numBlurAmount > 0) {
        // Create a temporary canvas to hold the blurred image.
        // This is crucial because ctx.filter is a live effect, and for getImageData,
        // we need the explicit pixel values of the blurred image.
        blurredImageCanvas = document.createElement('canvas');
        blurredImageCanvas.width = w;
        blurredImageCanvas.height = h;
        const blurredCtx = blurredImageCanvas.getContext('2d');
        
        blurredCtx.filter = `blur(${numBlurAmount}px)`;
        blurredCtx.drawImage(originalImg, 0, 0, w, h);
        blurredCtx.filter = 'none'; // Important to remove filter after drawing
        
        // Draw this pre-blurred image onto the main output canvas
        ctx.drawImage(blurredImageCanvas, 0, 0, w, h);
    } else {
        // No blur, draw original image directly to output
        ctx.drawImage(originalImg, 0, 0, w, h);
    }

    // --- Step 2: Detect and Draw Bokeh Highlights ---
    // Highlights are drawn if blur is applied, size > 0, and threshold is in a usable range (<255 for denominator).
    if (numBlurAmount > 0 && blurredImageCanvas && numHighlightSize > 0 && numHighlightThreshold < 255) {
        let imageData;
        try {
            // Get image data from the canvas that contains the definitive blurred image
            const sourceCtx = blurredImageCanvas.getContext('2d');
            imageData = sourceCtx.getImageData(0, 0, w, h);
        } catch (e) {
            console.warn("Could not get image data for highlights (e.g., CORS issue). Highlights skipped.", e);
            imageData = null;
        }

        if (imageData) {
            const data = imageData.data;
            // Iterate with a step related to highlight size for performance and visual spacing
            const step = Math.max(1, Math.floor(numHighlightSize / 2) || 1); 

            for (let y = 0; y < h; y += step) {
                for (let x = 0; x < w; x += step) {
                    const i = (y * w + x) * 4; // Pixel index
                    const r = data[i];
                    const g = data[i + 1];
                    const b = data[i + 2];
                    // const a = data[i + 3]; // Alpha of source pixel, not used for brightness

                    const brightness = (r + g + b) / 3; // Simple average brightness

                    if (brightness > numHighlightThreshold) {
                        const dx = x - focusX;
                        const dy = y - focusY;
                        // Check if the highlight point is outside the focus circle
                        if (dx * dx + dy * dy > actualFocusRadius * actualFocusRadius) {
                            
                            // Factor based on how much brightness exceeds threshold, normalized
                            const excessBrightnessFactor = Math.min((brightness - numHighlightThreshold) / (255 - numHighlightThreshold), 1);
                            
                            // Modulate alpha of highlights: brighter points are more opaque
                            const baseAlpha = 0.15; 
                            const finalAlpha = Math.min(baseAlpha + excessBrightnessFactor * 0.4, 0.7); // Max alpha ~0.55, capped further by Math.min
                                                                                                     
                            ctx.fillStyle = `rgba(${r}, ${g}, ${b}, ${finalAlpha})`;

                            if (strHighlightShape === 'hexagon') {
                                _drawHexagon(ctx, x, y, numHighlightSize);
                            } else { // Default to circle
                                ctx.beginPath();
                                ctx.arc(x, y, numHighlightSize, 0, Math.PI * 2);
                                ctx.fill();
                            }
                        }
                    }
                }
            }
        }
    }

    // --- Step 3: Draw the Sharp, Focused Area on Top ---
    // This reveals the original image within the defined focus circle.
    ctx.save(); // Save current state (which includes the blurred image with highlights)
    ctx.beginPath();
    ctx.arc(focusX, focusY, actualFocusRadius, 0, Math.PI * 2); 
    ctx.clip(); // Set the circular clipping path
    // Draw the original, sharp image. It will only be visible within the clip path.
    ctx.drawImage(originalImg, 0, 0, w, h); 
    ctx.restore(); // Remove clipping path and restore previous canvas state

    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 Bokeh Filter Application allows users to enhance their images by applying a bokeh effect, which creates a visually appealing blur around a focused area. Users can adjust parameters such as blur strength, focus area position, focus radius, and highlight characteristics, including shape and size. This tool is useful for photographers and graphic designers looking to emphasize subjects in their images, create artistic effects, or enhance the aesthetic quality of photos for social media, presentations, or print. By isolating and highlighting specific parts of an image while softening the background, it adds depth and dimension to visual compositions.

Leave a Reply

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