You can edit the below JavaScript code to customize the image tool.
Apply Changes
function processImage(
originalImg,
sparkCount = 200,
sparkColor = "255,190,0",
sparkSizeMin = 0.5,
sparkSizeMax = 3,
warmthIntensity = 0.3
) {
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
// Ensure the originalImg is loaded, otherwise width/height might be 0
// This function expects a loaded Image object.
canvas.width = originalImg.naturalWidth || originalImg.width;
canvas.height = originalImg.naturalHeight || originalImg.height;
if (canvas.width === 0 || canvas.height === 0) {
console.error("Original image has zero dimensions. Ensure it's loaded.");
// Return an empty canvas or throw an error
return canvas;
}
// 1. Draw the original image
ctx.drawImage(originalImg, 0, 0, canvas.width, canvas.height);
// 2. Apply warmth effect
// Ensure warmthIntensity is clamped between 0 and 1
const clampedWarmth = Math.max(0, Math.min(1, warmthIntensity));
if (clampedWarmth > 0) {
ctx.globalCompositeOperation = 'overlay';
// A reddish-orange color for bonfire warmth. Alpha is controlled by clampedWarmth.
// Color (255, 100, 0) is a deep, slightly fiery orange.
ctx.fillStyle = `rgba(255, 100, 0, ${clampedWarmth})`;
ctx.fillRect(0, 0, canvas.width, canvas.height);
ctx.globalCompositeOperation = 'source-over'; // Reset composite operation
}
// 3. Draw sparks
if (sparkCount > 0) {
// Parse and validate sparkColor
let [r, g, b] = sparkColor.split(',').map(valStr => parseInt(valStr.trim(), 10));
if (isNaN(r) || isNaN(g) || isNaN(b) || sparkColor.split(',').length !== 3) {
console.warn(`Invalid sparkColor format "${sparkColor}". Expected "R,G,B". Defaulting to 255,190,0.`);
[r, g, b] = [255, 190, 0]; // Default orange-yellow
} else {
r = Math.max(0, Math.min(255, r));
g = Math.max(0, Math.min(255, g));
b = Math.max(0, Math.min(255, b));
}
// Validate and prepare spark sizes
let sMin = Math.max(0, sparkSizeMin); // Ensure non-negative
let sMax = Math.max(0, sparkSizeMax); // Ensure non-negative
if (sMin > sMax) { // Ensure min <= max
// Swap if min > max to avoid issues with random range
[sMin, sMax] = [sMax, sMin];
}
// Use 'lighter' composite operation for sparks to make them appear luminous
ctx.globalCompositeOperation = 'lighter';
for (let i = 0; i < sparkCount; i++) {
const x = Math.random() * canvas.width;
const y = Math.random() * canvas.height;
let radius = 0;
if (sMin === sMax) {
radius = sMin;
} else {
radius = sMin + Math.random() * (sMax - sMin);
}
if (radius <= 0) continue; // Skip if radius is zero or negative
const gradient = ctx.createRadialGradient(x, y, 0, x, y, radius);
// Sparks are generally bright and somewhat opaque at their core
const opacity = 0.7 + Math.random() * 0.3; // Opacity range: 0.7 to 1.0
gradient.addColorStop(0, `rgba(${r}, ${g}, ${b}, ${opacity})`); // Bright center
gradient.addColorStop(0.4, `rgba(${r}, ${g}, ${b}, ${opacity * 0.6})`); // Mid glow (softer falloff)
gradient.addColorStop(1, `rgba(${r}, ${g}, ${b}, 0)`); // Transparent edge
ctx.beginPath();
ctx.arc(x, y, radius, 0, Math.PI * 2);
ctx.fillStyle = gradient;
ctx.fill();
}
ctx.globalCompositeOperation = 'source-over'; // Reset composite operation
}
return canvas;
}
Apply Changes