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!
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.