Please bookmark this page to avoid losing your image tool!

Image Binocular View 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, lensSizeRatio = 0.45, lensSeparationFactor = 0.7, blurAmount = 2) {
    const canvas = document.createElement('canvas');
    const ctx = canvas.getContext('2d');

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

    if (imgWidth === 0 || imgHeight === 0) {
        // Cannot process a 0-dimension image
        canvas.width = 1; // Avoid 0-size canvas for safety
        canvas.height = 1;
        // Optionally draw a black pixel or leave it transparent
        // console.warn("Image has zero dimensions. Returning a 1x1 canvas.");
        return canvas;
    }

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

    // Clamp parameters to sensible ranges to prevent visual errors or calculation issues
    const clampedLensSizeRatio = Math.max(0.01, Math.min(lensSizeRatio, 0.5)); // Radius 1% to 50% of image height
    const clampedLensSeparationFactor = Math.max(0, Math.min(lensSeparationFactor, 2.0)); // 0 (concentric) to 2.0 (lenses separated by their diameter)
    const clampedBlurAmount = Math.max(0, blurAmount);

    // 1. Calculate lens parameters
    // Ideal radius based on image height and user's preference (lensSizeRatio)
    const R_from_height_constraint = imgHeight * clampedLensSizeRatio;
    
    // Radius constraint based on image width and lens separation, to ensure lenses fit horizontally.
    // The total horizontal span of the two lenses is approximately:
    // (canvasCenterX + xOffset + R) - (canvasCenterX - xOffset - R) = 2 * xOffset + 2 * R
    // Where xOffset = R * clampedLensSeparationFactor.
    // So, span = 2 * R * clampedLensSeparationFactor + 2 * R = 2 * R * (clampedLensSeparationFactor + 1).
    // This span must be <= imgWidth.
    // So, R <= imgWidth / (2 * (clampedLensSeparationFactor + 1)).
    // Add a small epsilon (1e-6) to denominator in case (clampedLensSeparationFactor + 1) is extremely small,
    // though clamping already prevents it from being <= 1.
    const R_from_width_constraint = (imgWidth / 2) / (clampedLensSeparationFactor + 1 + 1e-6); 

    // Final radius is the minimum of the two constraints
    const R = Math.min(R_from_height_constraint, R_from_width_constraint);

    // If calculated Radius is too small (e.g., due to extreme aspect ratio and parameters),
    // it might be better to draw the original image or a fallback.
    if (R < 1) { // Less than 1 pixel radius is not meaningful for a circle.
        // console.warn("Calculated lens radius is too small. Drawing original image.");
        ctx.drawImage(originalImg, 0, 0, imgWidth, imgHeight);
        return canvas;
    }

    const centerY = imgHeight / 2;
    const canvasCenterX = imgWidth / 2;
    
    // Horizontal offset of each lens's center from the canvas's horizontal center
    const xOffset = R * clampedLensSeparationFactor; 
    const cx1 = canvasCenterX - xOffset; // Center X of the left lens
    const cx2 = canvasCenterX + xOffset; // Center X of the right lens

    // 2. Create a mask canvas for the binocular shape
    // This mask will be black where the view is obscured, and transparent for the lenses.
    const maskCanvas = document.createElement('canvas');
    maskCanvas.width = imgWidth;
    maskCanvas.height = imgHeight;
    // Context 'willReadFrequently' is an optimization hint for performance if available/applicable.
    const maskCtx = maskCanvas.getContext('2d', { willReadFrequently: true }); 

    // Fill the entire mask canvas with solid black
    maskCtx.fillStyle = 'black';
    maskCtx.fillRect(0, 0, imgWidth, imgHeight);

    // "Punch out" two transparent circular areas from the black mask for the lenses
    maskCtx.globalCompositeOperation = 'destination-out'; 
    // The fillStyle for destination-out doesn't matter for color, only for alpha (must be opaque to erase)
    maskCtx.fillStyle = 'white'; 
    
    maskCtx.beginPath();
    maskCtx.arc(cx1, centerY, R, 0, 2 * Math.PI);
    maskCtx.fill();

    maskCtx.beginPath(); // Start a new path for the second circle
    maskCtx.arc(cx2, centerY, R, 0, 2 * Math.PI);
    maskCtx.fill();
    
    // Reset globalCompositeOperation to default
    maskCtx.globalCompositeOperation = 'source-over'; 

    // 3. Draw the original image onto the main destination canvas
    ctx.drawImage(originalImg, 0, 0, imgWidth, imgHeight);

    // 4. Apply blur to the mask if blurAmount > 0, then draw the mask over the image
    // The blur is applied to the edges of the black mask.
    if (clampedBlurAmount > 0 && typeof ctx.filter !== 'undefined') {
        ctx.filter = `blur(${clampedBlurAmount}px)`;
        ctx.drawImage(maskCanvas, 0, 0);
        ctx.filter = 'none'; // Reset filter for any subsequent drawing on this context (good practice)
    } else {
        // If no blur is requested, or the filter API is not supported by the browser, draw the sharp mask directly
        ctx.drawImage(maskCanvas, 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 Binocular View Filter Effect Tool allows users to apply a binocular lens effect to their images. This tool can create a visually appealing filter by simulating two separate circular lenses on an image, adjusted by customizable parameters such as lens size, separation, and blur amount. Use cases include enhancing photographs for artistic presentations, creating unique visual effects for social media, or incorporating creative elements into digital art projects. This tool is particularly useful for anyone looking to add an interesting focal point or a playful twist to their images.

Leave a Reply

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