You can edit the below JavaScript code to customize the image tool.
Apply Changes
function processImage(originalImg, smokeIntensity = 0.6, smokeColor = "220,220,220", particleCount = 200, particleSizeMax = 150, smokeBlurRadius = 35) {
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
// Use naturalWidth/Height for HTMLImageElement, otherwise fallback to width/height
const width = originalImg.naturalWidth || originalImg.width;
const height = originalImg.naturalHeight || originalImg.height;
canvas.width = width;
canvas.height = height;
// 1. Draw the original image onto the main canvas
ctx.drawImage(originalImg, 0, 0, width, height);
// 2. Create smoke layer on a separate temporary canvas
const smokeCanvas = document.createElement('canvas');
const smokeCtx = smokeCanvas.getContext('2d');
smokeCanvas.width = width;
smokeCanvas.height = height;
// Parse and validate smokeColor parameter (expected format: "R,G,B")
const colorParts = smokeColor.split(',').map(c => parseInt(c.trim(), 10));
let r = colorParts.length > 0 && !isNaN(colorParts[0]) ? colorParts[0] : 220; // Default R
let g = colorParts.length > 1 && !isNaN(colorParts[1]) ? colorParts[1] : 220; // Default G
let b = colorParts.length > 2 && !isNaN(colorParts[2]) ? colorParts[2] : 220; // Default B
// Clamp RGB values to 0-255 range
r = Math.max(0, Math.min(255, r));
g = Math.max(0, Math.min(255, g));
b = Math.max(0, Math.min(255, b));
// Generate smoke particles (semi-transparent circles)
for (let i = 0; i < particleCount; i++) {
const x = Math.random() * width;
const y = Math.random() * height;
const radius = Math.random() * particleSizeMax;
// Individual particle alpha: random, relatively low values work best before blurring
const particleAlpha = Math.random() * 0.2 + 0.05; // e.g., 0.05 to 0.25
smokeCtx.fillStyle = `rgba(${r}, ${g}, ${b}, ${particleAlpha})`;
smokeCtx.beginPath();
smokeCtx.arc(x, y, radius, 0, 2 * Math.PI);
smokeCtx.fill();
}
// Blur the smoke layer to make particles appear like smooth smoke clouds
if (smokeBlurRadius > 0) {
// Ensure settings are appropriate for the blur operation
smokeCtx.globalAlpha = 1.0;
smokeCtx.globalCompositeOperation = 'source-over';
// Apply blur filter by drawing the canvas onto itself.
// The filter affects drawing operations, so this re-draw applies the blur.
smokeCtx.filter = `blur(${smokeBlurRadius}px)`;
smokeCtx.drawImage(smokeCanvas, 0, 0);
// Clear the filter to prevent it from affecting subsequent draws (if any)
smokeCtx.filter = 'none';
}
// 3. Composite the blurred smoke layer onto the main canvas (with original image)
// Clamp smokeIntensity to ensure it's a valid alpha value (0-1)
ctx.globalAlpha = Math.max(0, Math.min(1, smokeIntensity));
// 'overlay' blend mode often works well for smoke, interacting with image brightness.
// 'screen' is another option for lighter smoke.
ctx.globalCompositeOperation = 'overlay';
ctx.drawImage(smokeCanvas, 0, 0, width, height); // Draw the smoke
// Reset globalAlpha and globalCompositeOperation to their default states
ctx.globalAlpha = 1.0;
ctx.globalCompositeOperation = 'source-over';
return canvas;
}
Apply Changes