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