Please bookmark this page to avoid losing your image tool!

Image Diorama Effect 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, focusPosition = 0.5, focusRange = 0.2, blurAmount = 5, saturation = 1.4, contrast = 1.1) {
    // Ensure parameters are numbers
    focusPosition = Number(focusPosition);
    focusRange = Number(focusRange); // Range of the focused area, 0.0 to 1.0 (percentage of image height)
    blurAmount = Number(blurAmount); // Pixel radius for blur
    saturation = Number(saturation); // 1.0 is original, >1 increases saturation
    contrast = Number(contrast);   // 1.0 is original, >1 increases contrast

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

    if (width === 0 || height === 0) {
        console.warn("Image Diorama: Input image has zero width or height. Returning empty canvas.");
        const emptyCanvas = document.createElement('canvas');
        emptyCanvas.width = width;
        emptyCanvas.height = height;
        return emptyCanvas;
    }

    // 1. Create the final canvas to return
    const finalCanvas = document.createElement('canvas');
    finalCanvas.width = width;
    finalCanvas.height = height;
    const finalCtx = finalCanvas.getContext('2d');

    // 2. Prepare the sharp, enhanced layer
    const sharpCanvas = document.createElement('canvas');
    sharpCanvas.width = width;
    sharpCanvas.height = height;
    const sharpCtx = sharpCanvas.getContext('2d');

    let enhancementFilter = '';
    if (saturation !== 1 || contrast !== 1) {
        enhancementFilter = `saturate(${saturation}) contrast(${contrast})`;
    }
    if (enhancementFilter) {
        sharpCtx.filter = enhancementFilter;
    }
    sharpCtx.drawImage(originalImg, 0, 0, width, height);
    sharpCtx.filter = 'none'; // Reset filter

    // 3. Prepare the blurred, enhanced layer
    const blurredCanvas = document.createElement('canvas');
    blurredCanvas.width = width;
    blurredCanvas.height = height;
    const blurredCtx = blurredCanvas.getContext('2d');

    let fullFilterArray = [];
    if (enhancementFilter) {
        fullFilterArray.push(enhancementFilter);
    }
    if (blurAmount > 0) {
        fullFilterArray.push(`blur(${blurAmount}px)`);
    }
    
    if (fullFilterArray.length > 0) {
        blurredCtx.filter = fullFilterArray.join(' ');
    }
    blurredCtx.drawImage(originalImg, 0, 0, width, height);
    blurredCtx.filter = 'none'; // Reset filter

    // 4. Draw the blurred layer as the base on the final canvas
    finalCtx.drawImage(blurredCanvas, 0, 0);

    // 5. Create a masked version of the sharp layer to overlay
    const maskedSharpCanvas = document.createElement('canvas');
    maskedSharpCanvas.width = width;
    maskedSharpCanvas.height = height;
    const maskedSharpCtx = maskedSharpCanvas.getContext('2d');

    // Draw the sharp (but enhanced) image onto this temporary canvas
    maskedSharpCtx.drawImage(sharpCanvas, 0, 0);

    // Helper function to create a robust gradient for the mask
    const createFocusGradient = (ctxForGrad, imgHeight, fPos, fRangeNormalized, bAmt) => {
        const grad = ctxForGrad.createLinearGradient(0, 0, 0, imgHeight);

        const clampedFocusRange = Math.max(0, Math.min(1, fRangeNormalized));

        // Handle full focus: entire image is sharp
        if (clampedFocusRange >= 1.0) {
            grad.addColorStop(0, 'rgba(0,0,0,1)');
            grad.addColorStop(1, 'rgba(0,0,0,1)');
            return grad;
        }
        
        // Handle no focus: entire image uses the blurred version (mask is fully transparent)
        if (clampedFocusRange <= 0 && bAmt > 0) { // Only if blur is active, otherwise no real effect from no focus
            grad.addColorStop(0, 'rgba(0,0,0,0)');
            grad.addColorStop(1, 'rgba(0,0,0,0)');
            return grad;
        }


        const focusCenterPx = imgHeight * fPos;
        const focusRangePxHalf = (imgHeight * clampedFocusRange) / 2;

        const focusBandStartPx = focusCenterPx - focusRangePxHalf;
        const focusBandEndPx = focusCenterPx + focusRangePxHalf;

        // Transition zone width, proportional to blur radius, capped
        let transitionWidthPx = bAmt * 3; // Heuristic: feathering proportional to blur
        transitionWidthPx = Math.min(transitionWidthPx, imgHeight * 0.25); // Cap at 25% of image height
        transitionWidthPx = Math.max(transitionWidthPx, bAmt > 0 ? 1 : 0); // Min 1px transition if blur is active, else 0

        const stops = new Map();

        // Define normalized stop points for the gradient
        const p0_norm = 0; // Top of image
        const p5_norm = 1; // Bottom of image

        // Point where transparency starts before sharp band (top feather starts)
        const p1_norm = Math.max(0, focusBandStartPx - transitionWidthPx) / imgHeight;
        // Point where sharp band begins (top feather ends, full opacity)
        const p2_norm = Math.max(0, focusBandStartPx) / imgHeight;
        // Point where sharp band ends (bottom feather starts, full opacity)
        const p3_norm = Math.min(1, focusBandEndPx / imgHeight);
        // Point where transparency starts after sharp band (bottom feather ends)
        const p4_norm = Math.min(1, focusBandEndPx + transitionWidthPx) / imgHeight;
        
        stops.set(p0_norm, 'rgba(0,0,0,0)'); // Fully transparent at the top edge

        if (p1_norm > p0_norm && p1_norm < p2_norm) {
            stops.set(p1_norm, 'rgba(0,0,0,0)'); // End of top transparent area, start of feather
        }
         // Start of fully opaque (sharp) area
        stops.set(Math.min(p2_norm, p3_norm), 'rgba(0,0,0,1)'); // Use min in case focus range is 0 or negative

        // End of fully opaque (sharp) area
        stops.set(Math.max(p2_norm,p3_norm), 'rgba(0,0,0,1)'); // Max for same reason

        if (p4_norm < p5_norm && p4_norm > p3_norm) {
            stops.set(p4_norm, 'rgba(0,0,0,0)'); // Start of bottom transparent area, end of feather
        }
        
        stops.set(p5_norm, 'rgba(0,0,0,0)'); // Fully transparent at the bottom edge
        
        const sortedStopOffsets = Array.from(stops.keys()).sort((a, b) => a - b);
        for (const offset of sortedStopOffsets) {
            grad.addColorStop(offset, stops.get(offset));
        }
        
        return grad;
    };

    const gradientMask = createFocusGradient(maskedSharpCtx, height, focusPosition, focusRange, blurAmount);
    
    // Apply the gradient as an alpha mask to the sharp layer
    maskedSharpCtx.globalCompositeOperation = 'destination-in';
    maskedSharpCtx.fillStyle = gradientMask;
    maskedSharpCtx.fillRect(0, 0, width, height);
    maskedSharpCtx.globalCompositeOperation = 'source-over'; // Reset composite operation

    // 6. Draw the masked sharp layer onto the final canvas (over the blurred base)
    finalCtx.drawImage(maskedSharpCanvas, 0, 0);

    return finalCanvas;
}

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 Diorama Effect Filter is a powerful tool that enables users to create a diorama-style visual effect on images. By mimicking a shallow depth of field, the tool allows for selective focus, enhancing specific areas of an image while applying a blur effect to the surrounding regions. Users can adjust the focus position, range of focus, blur intensity, saturation, and contrast to achieve their desired artistic results. This tool is particularly useful for photographers, graphic designers, and artists looking to create intriguing images for social media, presentations, or personal projects.

Leave a Reply

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