Please bookmark this page to avoid losing your image tool!

Image Halo 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.
async function processImage(originalImg, haloColorStr = "255,255,255", haloBlurRadiusParam = "10", haloIntensityParam = "0.5") {
    // Validate that originalImg is an HTMLImageElement
    if (!(originalImg instanceof HTMLImageElement)) {
        console.error("Image Halo Filter: originalImg parameter must be an HTMLImageElement.");
        // Return a minimal canvas or throw an error, depending on desired strictness
        const errCanvas = document.createElement('canvas');
        errCanvas.width = 1;
        errCanvas.height = 1;
        return errCanvas;
    }

    // Coerce and validate numeric parameters
    const haloBlurRadius = Math.max(0, Number(haloBlurRadiusParam));
    const haloIntensity = Math.max(0, Math.min(1, Number(haloIntensityParam)));

    // Parse haloColorStr (expected format: "R,G,B", e.g., "255,0,0" for red)
    const colorParts = String(haloColorStr).split(',').map(s => parseInt(s.trim(), 10));
    let r = 255, g = 255, b = 255; // Default to white if parsing fails

    if (colorParts.length === 3 && colorParts.every(num => !isNaN(num) && num >= 0 && num <= 255)) {
        [r, g, b] = colorParts;
    } else {
        console.warn(`Image Halo Filter: Invalid haloColorStr ('${haloColorStr}'). Expected format 'R,G,B' (e.g., '255,255,0'). Defaulting to white.`);
    }
    const shadowRgbaColor = `rgba(${r},${g},${b},${haloIntensity})`;

    // Handle image loading: Ensure the image is fully loaded to get its dimensions.
    // If originalImg.complete is false, it means the image is still loading or hasn't started.
    if (!originalImg.complete) {
        try {
            await new Promise((resolve, reject) => {
                // Define event handlers
                const loadHandler = () => {
                    cleanup();
                    resolve();
                };
                const errorHandler = () => {
                    cleanup();
                    reject(new Error("Image failed to load."));
                };
                // Define a cleanup function to remove listeners
                const cleanup = () => {
                    originalImg.removeEventListener('load', loadHandler);
                    originalImg.removeEventListener('error', errorHandler);
                };

                // Attach event listeners
                originalImg.addEventListener('load', loadHandler);
                originalImg.addEventListener('error', errorHandler);

                // Edge case: If the image becomes complete right after the initial check
                // but before listeners are attached, this promise might never resolve.
                // However, standard behavior is that 'load' will still fire if src is set and loading.
                // If src is not set, it won't load. If already errored, 'error' handler should catch it if called again (or rely on .complete).
            });
        } catch (error) {
            console.error(`Image Halo Filter: ${error.message}`);
            const errorCanvas = document.createElement('canvas');
            errorCanvas.width = 1; errorCanvas.height = 1;
            return errorCanvas;
        }
    }
    
    // At this point, originalImg should be 'complete'. Now check its dimensions.
    const imgWidth = originalImg.naturalWidth;
    const imgHeight = originalImg.naturalHeight;

    if (imgWidth === 0 || imgHeight === 0) {
        console.warn("Image Halo Filter: Image has zero dimensions (it might be an invalid, empty, or errored image). Returning an empty canvas.");
        const emptyCanvas = document.createElement('canvas');
        emptyCanvas.width = 1; emptyCanvas.height = 1;
        return emptyCanvas;
    }

    // --- Main image processing starts here ---

    // 1. Create an offscreen canvas to draw the original image.
    // This is a robust way to ensure shadow effects apply correctly based on the image's alpha,
    // as drawing a canvas onto another canvas reliably supports shadow effects.
    const offscreenCanvas = document.createElement('canvas');
    const offscreenCtx = offscreenCanvas.getContext('2d');
    offscreenCanvas.width = imgWidth;
    offscreenCanvas.height = imgHeight;
    offscreenCtx.drawImage(originalImg, 0, 0, imgWidth, imgHeight);

    // 2. Determine padding for the output canvas to accommodate the halo blur.
    // Using Math.ceil to ensure integer dimensions for the canvas if blurRadius is fractional.
    const padding = haloBlurRadius > 0 ? Math.ceil(haloBlurRadius) : 0; 
    
    // 3. Create the output canvas.
    const outputCanvas = document.createElement('canvas');
    const outputCtx = outputCanvas.getContext('2d');
    outputCanvas.width = imgWidth + padding * 2;
    outputCanvas.height = imgHeight + padding * 2;

    // 4. Configure shadow properties on the output canvas context.
    outputCtx.shadowColor = shadowRgbaColor;
    outputCtx.shadowBlur = haloBlurRadius; // shadowBlur can be a float
    outputCtx.shadowOffsetX = 0; // Center the shadow horizontally
    outputCtx.shadowOffsetY = 0; // Center the shadow vertically

    // 5. Draw the offscreen canvas (containing the original image) onto the output canvas.
    // This operation draws the image and its shadow (the halo).
    // The image is drawn offset by 'padding' to provide space for the halo.
    outputCtx.drawImage(offscreenCanvas, padding, padding, imgWidth, imgHeight);

    // 6. Optional but recommended: Redraw the image on top without shadow effects.
    // This ensures the image itself remains crisp and is not subtly blended with its own shadow color.
    // This step is only meaningful if a halo was actually applied.
    if (haloIntensity > 0 && haloBlurRadius > 0) {
        outputCtx.shadowColor = 'transparent'; // Effectively disable shadow
        outputCtx.shadowBlur = 0;
        // By default, globalCompositeOperation is 'source-over', which is what we want here.
        outputCtx.drawImage(offscreenCanvas, padding, padding, imgWidth, imgHeight);
    }
    
    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 Halo Filter Application allows users to enhance their images by adding a customizable halo effect. This tool can apply a colored halo around an image, adjustable for color, blur radius, and intensity. Ideal for artists, designers, and social media users, this filter can create visually appealing effects for images in projects like graphic design, photography editing, or even personal social media posts, making images stand out with a unique glow.

Leave a Reply

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