Please bookmark this page to avoid losing your image tool!

Image Jellyfish Glow Filter Effect

(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, blurRadius = 8, saturationBoost = 1.5, brightnessBoost = 1.2, hueStart = 180, hueEnd = 300) {
    // Helper: RGB to HSL
    // r, g, b are 0-255. Output h is 0-360. Output s, l are 0-1.
    function rgbToHsl(r, g, b) {
        r /= 255; g /= 255; b /= 255;
        const max = Math.max(r, g, b), min = Math.min(r, g, b);
        let h, s, l = (max + min) / 2;

        if (max === min) {
            h = s = 0; // achromatic
        } else {
            const d = max - min;
            s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
            switch (max) {
                case r: h = (g - b) / d + (g < b ? 6 : 0); break;
                case g: h = (b - r) / d + 2; break;
                case b: h = (r - g) / d + 4; break;
            }
            h /= 6;
        }
        return [h * 360, s, l];
    }

    // Helper: HSL to RGB
    // Input h is 0-360. Input s, l are 0-1. Output r, g, b are 0-255.
    function hslToRgb(h, s, l) {
        let r, g, b;
        h /= 360; // convert h to 0-1 domain for calculations

        if (s === 0) {
            r = g = b = l; // achromatic
        } else {
            function hue2rgb(p, q, t) {
                if (t < 0) t += 1;
                if (t > 1) t -= 1;
                if (t < 1 / 6) return p + (q - p) * 6 * t;
                if (t < 1 / 2) return q;
                if (t < 2 / 3) return p + (q - p) * (2 / 3 - t) * 6;
                return p;
            }
            const q = l < 0.5 ? l * (1 + s) : l + s - l * s;
            const p = 2 * l - q;
            r = hue2rgb(p, q, h + 1 / 3);
            g = hue2rgb(p, q, h);
            b = hue2rgb(p, q, h - 1 / 3);
        }
        return [Math.round(r * 255), Math.round(g * 255), Math.round(b * 255)];
    }

    // Helper: Check if hue is in range (handles wrap-around for ranges like 330-30)
    function isInHueRange(hue, start, end) {
        // Ensure hue, start, end are within 0-360 for consistent comparison
        // (Though hue from rgbToHsl is already 0-360)
        // For this problem, we assume valid numeric inputs for start/end.
        if (start <= end) { // Normal range, e.g., 60-120 (yellow to green)
            return hue >= start && hue <= end;
        } else { // Wrapped range, e.g., 330-30 (magenta through red to orange)
            return hue >= start || hue <= end;
        }
    }

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

    if (w === 0 || h === 0) {
        // Image not loaded or invalid dimensions
        const emptyCanvas = document.createElement('canvas');
        emptyCanvas.width = Math.max(1, w); // Avoid 0 dimension
        emptyCanvas.height = Math.max(1, h);
        console.warn("Original image has zero dimensions. Returning an empty (or minimal) canvas.");
        return emptyCanvas;
    }

    const outputCanvas = document.createElement('canvas');
    outputCanvas.width = w;
    outputCanvas.height = h;
    const ctx = outputCanvas.getContext('2d');

    // Create a temporary canvas to get original image data.
    // This is robust if originalImg is an HTMLImageElement that might suffer
    // from cross-origin issues if its source is external and CORS isn't set.
    const tempCanvas = document.createElement('canvas');
    tempCanvas.width = w;
    tempCanvas.height = h;
    const tempCtx = tempCanvas.getContext('2d');
    tempCtx.drawImage(originalImg, 0, 0, w, h);
    
    let imageData;
    try {
        imageData = tempCtx.getImageData(0, 0, w, h);
    } catch (e) {
        console.error("Error getting image data (cross-origin issue?): ", e);
        // Fallback: draw the original image on the output canvas and return it
        ctx.drawImage(originalImg, 0, 0, w, h);
        return outputCanvas;
    }
    const data = imageData.data;
    
    // Create glow canvas for the highlight/glow mask
    const glowCanvas = document.createElement('canvas');
    glowCanvas.width = w;
    glowCanvas.height = h;
    // Hinting `willReadFrequently` for `glowCanvas` as it will be drawn later.
    const glowCtx = glowCanvas.getContext('2d', { willReadFrequently: true }); 

    const glowImageData = glowCtx.createImageData(w, h);
    const glowData = glowImageData.data;

    for (let i = 0; i < data.length; i += 4) {
        const r = data[i];
        const g = data[i + 1];
        const b = data[i + 2];
        const a = data[i + 3];

        if (a === 0) { // Skip fully transparent pixels
            glowData[i] = 0; glowData[i+1] = 0; glowData[i+2] = 0; glowData[i+3] = 0;
            continue;
        }

        const [hue, originalS, originalL] = rgbToHsl(r, g, b);

        // Check if pixel is in target hue range and has some minimal saturation/lightness
        // to avoid glowing black/grey/white areas unintentionally unless they have a color tint.
        if (isInHueRange(hue, hueStart, hueEnd) && originalS > 0.05 && originalL > 0.05) {
            const newS = Math.min(1, originalS * saturationBoost);
            const newL = Math.min(1, originalL * brightnessBoost);
            
            const [newR, newG, newB] = hslToRgb(hue, newS, newL);

            glowData[i] = newR;
            glowData[i + 1] = newG;
            glowData[i + 2] = newB;
            glowData[i + 3] = a; // Preserve original alpha for the glow mask points
        } else {
            // Make non-glowing pixels transparent black in the glow layer
            glowData[i] = 0; glowData[i + 1] = 0; glowData[i + 2] = 0; glowData[i + 3] = 0;
        }
    }
    glowCtx.putImageData(glowImageData, 0, 0);

    // --- Composite final image ---
    // 1. Draw original image onto the output canvas
    ctx.drawImage(originalImg, 0, 0, w, h);

    // 2. Composite the blurred glow layer on top
    ctx.save(); // Save current state (like default composite operation and filter)
    
    // Use 'lighter' for an additive blending effect, common for glows.
    // Other options: 'screen' (softer), 'lighten' (max of components).
    ctx.globalCompositeOperation = 'lighter'; 
    
    if (blurRadius > 0) {
        ctx.filter = `blur(${blurRadius}px)`;
    }
    
    // Draw the glowCanvas (which contains the colored highlights).
    // The blur filter applies as this is drawn onto outputCanvas.
    ctx.drawImage(glowCanvas, 0, 0, w, h); 
    
    ctx.restore(); // Restore composite operation and filter to previous state (defaults)
    
    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 Jellyfish Glow Filter Effect tool allows users to apply a colorful glow effect to their images. This effect enhances specific hues within a defined range, increasing saturation and brightness while introducing a soft blur to create a luminous appearance. It is ideal for artists, designers, and social media enthusiasts looking to add a striking and vibrant aesthetic to their photos, making them more visually appealing for presentations, digital artwork, or online sharing.

Leave a Reply

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