Please bookmark this page to avoid losing your image tool!

Image Soap Bubble Bokeh Effect Generator

(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, 
    threshold = 210, 
    minRadius = 8, 
    maxRadius = 30, 
    density = 0.02, 
    color = "rgba(255, 255, 240, 0.75)", 
    thicknessFactor = 0.1
) {
    const canvas = document.createElement('canvas');
    const ctx = canvas.getContext('2d');

    // Ensure originalImg is loaded, otherwise dimensions might be 0
    // This basic check helps, but robust loading should be handled by caller
    if (!originalImg.complete || originalImg.naturalWidth === 0) {
        // Wait for image to load if not already loaded.
        // This is a simple promise wrapper for onload.
        await new Promise((resolve, reject) => {
            originalImg.onload = () => resolve();
            originalImg.onerror = () => {
                console.error("Image failed to load for processing.");
                // Draw a small placeholder or throw error if image fails
                canvas.width = 100;
                canvas.height = 30;
                ctx.fillStyle = "red";
                ctx.fillRect(0, 0, 100, 30);
                ctx.fillStyle = "white";
                ctx.fillText("Error loading image", 5, 20);
                reject(new Error("Image load error"));
            };
            // If src is set and it's not loaded yet, onload will trigger.
            // If src is not set, or image is broken, onerror might trigger.
        });
        if (!originalImg.complete || originalImg.naturalWidth === 0 && canvas.width === 100) { // check if error canvas was set
             return canvas; // return error canvas
        }
    }

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

    canvas.width = imgWidth;
    canvas.height = imgHeight;

    // Parameter sanitization and type conversion
    const paramThreshold = Math.max(0, Math.min(255, Number(threshold)));
    const paramMinRadius = Math.max(1, Number(minRadius));
    // Ensure maxRadius is not less than minRadius
    const paramMaxRadius = Math.max(paramMinRadius, Number(maxRadius)); 
    const paramDensity = Math.max(0, Math.min(1, Number(density)));
    // Ensure color is a string; it should be a valid CSS color.
    const paramColor = String(color); 
    const paramThicknessFactor = Math.max(0.01, Math.min(0.5, Number(thicknessFactor)));

    // 1. Draw the original image onto the output canvas
    ctx.drawImage(originalImg, 0, 0, imgWidth, imgHeight);

    // 2. Prepare for highlight detection using a temporary canvas for getImageData
    const tempCanvas = document.createElement('canvas');
    tempCanvas.width = imgWidth;
    tempCanvas.height = imgHeight;
    // Use { willReadFrequently: true } for potential performance optimization if supported by the browser
    const tempCtx = tempCanvas.getContext('2d', { willReadFrequently: true }); 
    tempCtx.drawImage(originalImg, 0, 0, imgWidth, imgHeight);
    
    let imageData;
    try {
        imageData = tempCtx.getImageData(0, 0, imgWidth, imgHeight);
    } catch (e) {
        console.error("Failed to get image data, possibly due to cross-origin restrictions:", e);
        // Return the canvas with only the original image drawn if pixel processing is not possible
        // This could happen if the image is from a different domain without CORS headers.
        return canvas; 
    }
    const data = imageData.data;

    // 3. Detect highlights and draw soap bubble bokeh circles
    // Adjust scanStep based on minRadius to balance performance and detail.
    // A smaller scanStep means more points are checked, potentially leading to more bubbles.
    const scanStep = Math.max(1, Math.floor(paramMinRadius / 3) + 1); 

    for (let y = 0; y < imgHeight; y += scanStep) {
        for (let x = 0; x < imgWidth; x += scanStep) {
            // Calculate index for the pixel data array (R,G,B,A components)
            const i = (y * imgWidth + x) * 4; 
            const r_val = data[i];
            const g_val = data[i + 1];
            const b_val = data[i + 2];
            // const alpha_val = data[i + 3]; // Alpha of original pixel, not used here

            // Calculate luminosity (perceived brightness)
            // Standard formula for converting RGB to Luminance (Y_linear = 0.2126R + 0.7152G + 0.0722B)
            // Or common one (Y_ITU-R_BT.601 = 0.299R + 0.587G + 0.114B)
            const luminosity = 0.299 * r_val + 0.587 * g_val + 0.114 * b_val;

            // If luminosity is above threshold and random chance passes (based on density)
            if (luminosity > paramThreshold && Math.random() < paramDensity) {
                // Determine bubble properties
                let bubbleRadius = paramMinRadius;
                // If min and max radius are different, pick a random radius in between
                if (paramMaxRadius > paramMinRadius) { 
                     bubbleRadius = paramMinRadius + Math.random() * (paramMaxRadius - paramMinRadius);
                }
                
                // Add some jitter (random offset) to the bubble's position
                // This makes the bubble placement look more natural than a strict grid
                const jitterX = (Math.random() - 0.5) * scanStep * 0.8; 
                const jitterY = (Math.random() - 0.5) * scanStep * 0.8;
                const bubbleX = x + jitterX;
                const bubbleY = y + jitterY;

                // Calculate line width for the bubble ring based on its radius
                const lineWidth = Math.max(1, bubbleRadius * paramThicknessFactor);

                // Draw the bubble ring on the main canvas
                ctx.beginPath();
                ctx.arc(bubbleX, bubbleY, bubbleRadius, 0, 2 * Math.PI, false); // Full circle
                
                ctx.strokeStyle = paramColor; 
                ctx.lineWidth = lineWidth;
                
                ctx.stroke();
            }
        }
    }

    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 Soap Bubble Bokeh Effect Generator allows users to add a visually appealing soap bubble bokeh effect to their images. This tool enhances photos by detecting highlights and overlaying circular bokeh bubbles with customizable properties such as size, density, and color. It is ideal for creative projects, photography enhancements, social media posts, or any occasion where an artistic touch is desired to beautify images.

Leave a Reply

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

Other Image Tools:

Image Center Graduated ND Filter Effect Tool

Image Breakthrough Photography X4 ND Filter Effect

Photo Filter Effect Creator for Yashica T4 Point-and-Shoot

Image AGFA APX 25 Film Filter Effect Tool

Image Singh-Ray Gold-N-Blue Polarizer Effect Tool

Image Black and White Blue Filter Effect Tool

Image Pinhole Solargraphy Effect Creator

Image Kodak Vision3 500T Motion Picture Film Effect Simulator

Image Soft Focus Filter Effect for Nikon Nikkor

Image Bergger Pancro 400 Film Filter Effect Tool

Image Agfa Optima Filter Effect Application

Image Technicolor 3-Strip Process Filter Effect

Image Cyanotype Process Filter Effect

Image Black and White with Orange #21 Filter Effect Tool

Image Bleach Bypass Effect Filter

Image IMAX Camera Filter Effect Tool

Image Super 8 Film Filter Effect Tool

Image Anamorphic Lens Flare Filter Effect Tool

Image Prism Photography Filter Effect Tool

Image Freelensing Effect Creator

Image Tiffen Glimmerglass Filter Effect Tool

Image Mamiya RZ67 Medium Format Filter Effect Tool

Image Wet Plate Collodion Filter Effect Tool

Image Ilford Pan F Plus 50 Filter Effect Tool

Image X-ray Photography Filter Effect Tool

Image Radial Graduated Filter Effect Tool

Image Lee 80A Cooling Filter Effect Application

Image Autochrome Lumière Filter Effect Tool

Photo Infrared 720nm Filter Effect Tool

Image 10-Stop ND Filter Effect Tool

Photo Full Spectrum Filter Effect Tool

Image Motion Blur Filter Effect Tool

Image Panavision Film Look Filter Effect Tool

Image Rolleiflex TLR Camera Filter Effect Tool

Image Lee 85B Warming Filter Effect Application

Image Tiffen Black Pro-Mist Filter Effect Tool

See All →