Please bookmark this page to avoid losing your image tool!

Image Solar Flare 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, flareX = 0.5, flareY = 0.5, flareRadius = 50, flareBrightness = 1.2, lensFlareCount = 7, lensFlareOpacity = 0.15) {

    // Parse and validate parameters
    // Convert to string first in case non-string/non-number types are passed, then parse.
    const pFlareX = parseFloat(String(flareX));
    const pFlareY = parseFloat(String(flareY));
    const pFlareRadius = Math.max(0, parseFloat(String(flareRadius))); // Radius cannot be negative
    const pFlareBrightness = Math.max(0, parseFloat(String(flareBrightness))); // Brightness cannot be negative
    const pLensFlareCount = Math.max(0, parseInt(String(lensFlareCount), 10)); // Count cannot be negative
    const pLensFlareOpacity = Math.max(0, Math.min(1, parseFloat(String(lensFlareOpacity)))); // Opacity must be between 0 and 1

    const canvas = document.createElement('canvas');
    const ctx = canvas.getContext('2d');

    // Check if originalImg is valid and has dimensions
    if (!originalImg || typeof originalImg.width === 'undefined' || originalImg.width === 0 || originalImg.height === 0) {
        // If image is not loaded or invalid, return a small empty canvas.
        // This is a safeguard; the problem implies originalImg is a valid, loaded Image object.
        canvas.width = 1; 
        canvas.height = 1;
        // console.warn("processImage: originalImg is invalid or has zero dimensions. Ensure it's loaded before calling.");
        return canvas;
    }

    canvas.width = originalImg.width;
    canvas.height = originalImg.height;

    // Draw the original image onto the canvas
    ctx.drawImage(originalImg, 0, 0, canvas.width, canvas.height);

    // If brightness or radius is effectively zero, no visible flare, so can return early
    if (pFlareBrightness <= 0.001 || pFlareRadius <= 0.01) {
        return canvas;
    }

    // Coordinates for the center of the main flare
    const actualFlareCenterX = canvas.width * pFlareX;
    const actualFlareCenterY = canvas.height * pFlareY;

    // Set blend mode for additive light effects. 'lighter' is equivalent to 'screen' in many contexts but sums color values.
    ctx.globalCompositeOperation = 'lighter';

    // --- Main Flare ---
    // Layer 1: Central white hot spot (small, very bright)
    let gradient = ctx.createRadialGradient(actualFlareCenterX, actualFlareCenterY, 0, actualFlareCenterX, actualFlareCenterY, pFlareRadius * 0.1);
    gradient.addColorStop(0, `rgba(255, 255, 255, ${Math.min(1, 0.95 * pFlareBrightness)})`);
    gradient.addColorStop(1, `rgba(255, 255, 230, ${Math.min(1, 0.8 * pFlareBrightness)})`); // Slightly yellowish white
    ctx.fillStyle = gradient;
    ctx.beginPath();
    ctx.arc(actualFlareCenterX, actualFlareCenterY, pFlareRadius * 0.12, 0, 2 * Math.PI); // Arc slightly larger for good coverage
    ctx.fill();

    // Layer 2: Main colored glow (e.g., yellowish/orange)
    gradient = ctx.createRadialGradient(actualFlareCenterX, actualFlareCenterY, pFlareRadius * 0.05, actualFlareCenterX, actualFlareCenterY, pFlareRadius * 0.5);
    gradient.addColorStop(0, `rgba(255, 220, 180, ${Math.min(1, 0.7 * pFlareBrightness)})`); // Brighter center of glow
    gradient.addColorStop(0.5, `rgba(255, 200, 150, ${Math.min(1, 0.5 * pFlareBrightness)})`);
    gradient.addColorStop(1, `rgba(255, 180, 120, 0)`); // Fades out
    ctx.fillStyle = gradient;
    ctx.beginPath();
    ctx.arc(actualFlareCenterX, actualFlareCenterY, pFlareRadius * 0.5, 0, 2 * Math.PI);
    ctx.fill();

    // Layer 3: Larger, softer halo (can be a warmer color, e.g. orange/reddish)
    gradient = ctx.createRadialGradient(actualFlareCenterX, actualFlareCenterY, pFlareRadius * 0.2, actualFlareCenterX, actualFlareCenterY, pFlareRadius);
    gradient.addColorStop(0, `rgba(255, 180, 100, ${Math.min(1, 0.3 * pFlareBrightness)})`); // Orange tones
    gradient.addColorStop(1, `rgba(255, 150, 50, 0)`); // Fades out
    ctx.fillStyle = gradient;
    ctx.beginPath();
    ctx.arc(actualFlareCenterX, actualFlareCenterY, pFlareRadius, 0, 2 * Math.PI);
    ctx.fill();

    // --- Lens Flare Artifacts (Ghosts) ---
    if (pLensFlareCount > 0 && pLensFlareOpacity > 0) {
        const imgCenterX = canvas.width / 2;
        const imgCenterY = canvas.height / 2;

        // Vector from flare center to image center (artifacts typically appear along this line)
        const vecX = imgCenterX - actualFlareCenterX;
        const vecY = imgCenterY - actualFlareCenterY;

        // Helper function to draw polygons (like hexagons/octagons for some flares)
        // Defined inside processImage to keep it self-contained.
        const _drawPolygon = (polyCtx, x, y, radius, sides, fillStyle, rotation = 0) => {
            if (sides < 3 || radius <= 0) return; // Basic validation
            polyCtx.fillStyle = fillStyle;
            polyCtx.beginPath();
            // Move to the first vertex
            polyCtx.moveTo(
                x + radius * Math.cos(rotation),
                y + radius * Math.sin(rotation)
            );
            // Draw lines to subsequent vertices
            for (let k = 1; k <= sides; k++) {
                polyCtx.lineTo(
                    x + radius * Math.cos(rotation + k * 2 * Math.PI / sides),
                    y + radius * Math.sin(rotation + k * 2 * Math.PI / sides)
                );
            }
            polyCtx.closePath(); // Close path for a filled polygon
            polyCtx.fill();
        };
        
        const colorPresets = [ // For chromatic aberration-like effects in ghosts
            { r: 255, g: 100, b: 100 }, { r: 100, g: 255, b: 100 }, { r: 100, g: 100, b: 255 },
            { r: 255, g: 255, b: 100 }, { r: 100, g: 255, b: 255 }, { r: 255, g: 100, b: 255 }
        ];

        for (let i = 0; i < pLensFlareCount; i++) {
            let t; // Position parameter along the flare-to-center line segment
            if (pLensFlareCount === 1) {
                t = 0.5; // Single artifact: typically placed between flare and image center
            } else {
                // Spread artifacts from slightly 'behind' the flare to past the image center
                const t_start = -0.3; // Relative to flare; negative is further from image center along the line
                const t_end = 1.7;   // Relative to flare; >1 is past image center along the line
                t = t_start + (i / (pLensFlareCount - 1)) * (t_end - t_start);
            }
            
            t += (Math.random() - 0.5) * 0.1; // Add some jitter to position for a more natural look
            const artifactX = actualFlareCenterX + vecX * t;
            const artifactY = actualFlareCenterY + vecY * t;
            
            // Artifacts are generally smaller than the main flare radius. Size can also vary.
            const artifactRadius = (Math.random() * 0.4 + 0.1) * pFlareRadius * 0.5; 
            if (artifactRadius < 1) continue; // Skip if artifact is too small to be visible

            // Calculate opacity for this artifact, scaled by main flare brightness and base artifact opacity
            const baseArtifactAlpha = pLensFlareOpacity * (Math.random() * 0.7 + 0.3); // Vary base opacity per artifact
            const finalArtifactAlpha = Math.min(1, baseArtifactAlpha * pFlareBrightness); 
            
            if (finalArtifactAlpha < 0.01) continue; // Skip if effectively invisible

            // Choose a color for the artifact, can be semi-random or from presets for variety
            const colorPreset = colorPresets[i % colorPresets.length];
            const R = Math.max(0, Math.min(255, colorPreset.r + Math.floor(Math.random() * 60 - 30))); // Add random variation
            const G = Math.max(0, Math.min(255, colorPreset.g + Math.floor(Math.random() * 60 - 30)));
            const B = Math.max(0, Math.min(255, colorPreset.b + Math.floor(Math.random() * 60 - 30)));
            
            // Alternate between polygonal and circular artifacts for visual interest
            if (i % 2 !== 0 && artifactRadius > 5) { // Polygonal artifact
                const sides = (Math.random() < 0.7) ? 6 : 8; // More likely to be a hexagon
                const polyRotation = Math.random() * Math.PI; // Random rotation for the polygon
                
                const polyFillColorStr = `rgba(${R},${G},${B},0.8)`; // Base color for the polygon body
                const polyHaloColorStr = `rgba(${R},${G},${B},0.4)`; // Softer color for the polygon's halo

                ctx.globalAlpha = finalArtifactAlpha; // Set alpha for the main polygon body
                _drawPolygon(ctx, artifactX, artifactY, artifactRadius, sides, polyFillColorStr, polyRotation);

                ctx.globalAlpha = finalArtifactAlpha * 0.5; // Set a reduced alpha for its halo
                _drawPolygon(ctx, artifactX, artifactY, artifactRadius * 1.5, sides, polyHaloColorStr, polyRotation);

            } else { // Circular artifact (glow)
                ctx.globalAlpha = finalArtifactAlpha; // Set alpha for circular glow
                const artifactGradient = ctx.createRadialGradient(artifactX, artifactY, 0, artifactX, artifactY, artifactRadius);
                artifactGradient.addColorStop(0, `rgba(${R},${G},${B},0.7)`); // Center of the glow
                artifactGradient.addColorStop(0.6, `rgba(${R},${G},${B},0.3)`); // Mid-fade state
                artifactGradient.addColorStop(1, `rgba(${R},${G},${B},0)`);   // Edge fades to transparent
                ctx.fillStyle = artifactGradient;
                ctx.beginPath();
                ctx.arc(artifactX, artifactY, artifactRadius, 0, 2 * Math.PI);
                ctx.fill();
            }
        }
        ctx.globalAlpha = 1.0; // Reset global alpha after drawing all artifacts
    }

    // Reset composite operation to default before returning the canvas
    ctx.globalCompositeOperation = 'source-over';

    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 Solar Flare Filter Effect Tool allows users to enhance images by adding a solar flare effect. This tool provides customizable settings to adjust the position, radius, and brightness of the flare, as well as the number and opacity of additional lens flare artifacts. This effect can be used to create visually striking images with dynamic lighting, perfect for enhancing photographs, graphics, or artwork in various digital projects.

Leave a Reply

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