You can edit the below JavaScript code to customize the image tool.
function processImage(originalImg, particleDensityStr = '0.5', stormStrengthStr = '50', directionAngleStr = '0', spreadFactorStr = '0.3') {
const particleDensity = parseFloat(particleDensityStr);
const stormStrength = parseInt(stormStrengthStr, 10);
const directionAngleDegrees = parseFloat(directionAngleStr);
const spreadFactor = parseFloat(spreadFactorStr);
const imgWidth = originalImg.naturalWidth || originalImg.width;
const imgHeight = originalImg.naturalHeight || originalImg.height;
// Basic validation for numeric parameters
if (isNaN(particleDensity) || particleDensity < 0 || particleDensity > 1 ||
isNaN(stormStrength) || stormStrength < 0 ||
isNaN(directionAngleDegrees) || // Angle can be any valid number
isNaN(spreadFactor) || spreadFactor < 0 || spreadFactor > 1) { // Spread factor is a ratio, typically 0-1
console.error("Invalid parameters for sandstorm effect. Using defaults or returning original. Check ranges (density 0-1, strength >=0, spreadFactor 0-1).");
// Fallback: return a canvas with the original image drawn on it
const fallbackCanvas = document.createElement('canvas');
fallbackCanvas.width = imgWidth || 1; // Use 1x1 if image has no dimensions
fallbackCanvas.height = imgHeight || 1;
if (imgWidth > 0 && imgHeight > 0) { // Only draw if image has valid dimensions
const fbCtx = fallbackCanvas.getContext('2d');
if (fbCtx) {
fbCtx.drawImage(originalImg, 0, 0, imgWidth, imgHeight);
}
}
return fallbackCanvas;
}
if (imgWidth === 0 || imgHeight === 0) {
console.warn("Image has zero width or height. Returning minimal empty canvas.");
const emptyCanvas = document.createElement('canvas');
emptyCanvas.width = 1;
emptyCanvas.height = 1;
return emptyCanvas;
}
const canvas = document.createElement('canvas');
// Using { willReadFrequently: true } is a performance hint for contexts where getImageData is used often.
const ctx = canvas.getContext('2d', { willReadFrequently: true });
canvas.width = imgWidth;
canvas.height = imgHeight;
// Step 1: Draw the original image onto the canvas. This allows us to get its pixel data.
ctx.drawImage(originalImg, 0, 0, imgWidth, imgHeight);
const sourceImageData = ctx.getImageData(0, 0, imgWidth, imgHeight);
const sourceData = sourceImageData.data; // This is a Uint8ClampedArray of [R,G,B,A, R,G,B,A, ...]
// Step 2: Create a new ImageData object for the output. It's initialized to all transparent black pixels.
const destImageData = ctx.createImageData(imgWidth, imgHeight);
const destData = destImageData.data;
const angleRad = directionAngleDegrees * (Math.PI / 180); // Convert direction angle to radians
// Pre-calculate directional vector components for efficiency
const mainDirX = Math.cos(angleRad); // X-component of the main storm direction
const mainDirY = Math.sin(angleRad); // Y-component of the main storm direction
// Perpendicular direction components (for spread). Rotate main direction by 90 degrees.
// cos(angle + PI/2) = -sin(angle) = -mainDirY
// sin(angle + PI/2) = cos(angle) = mainDirX
const perpDirX = -mainDirY;
const perpDirY = mainDirX;
// Step 3: Iterate over each pixel of the source image.
for (let y = 0; y < imgHeight; y++) {
for (let x = 0; x < imgWidth; x++) {
const sourceIndex = (y * imgWidth + x) * 4; // Calculate index in the 1D pixel array
// Extract RGBA components of the source pixel
const r = sourceData[sourceIndex];
const g = sourceData[sourceIndex + 1];
const b = sourceData[sourceIndex + 2];
const a = sourceData[sourceIndex + 3];
// Skip processing for fully transparent pixels in the source image.
if (a === 0) {
continue;
}
// Decide if this pixel should become a "sand particle" based on particleDensity.
if (Math.random() < particleDensity) {
// This pixel becomes a particle.
// Each particle gets its own random fraction of the max stormStrength.
const currentParticleStrength = Math.random() * stormStrength;
// Displacement along the main storm direction.
const mainDisplacement = currentParticleStrength;
// Calculate random perpendicular displacement (spread).
// (Math.random() - 0.5) * 2 gives a range of -1 to 1.
// This value is then scaled by particle strength and the overall spreadFactor.
const perpMagnitude = (Math.random() - 0.5) * 2 * currentParticleStrength * spreadFactor;
// Calculate total displacement vector (dx, dy).
const dx = mainDisplacement * mainDirX + perpMagnitude * perpDirX;
const dy = mainDisplacement * mainDirY + perpMagnitude * perpDirY;
// Calculate the new position (newX, newY) for the particle, rounded to nearest integer.
const newX = Math.round(x + dx);
const newY = Math.round(y + dy);
// If the new position is within the canvas bounds, draw the particle there.
if (newX >= 0 && newX < imgWidth && newY >= 0 && newY < imgHeight) {
const destIndex = (newY * imgWidth + newX) * 4; // Calculate index in destination array
// Place the original pixel color (R,G,B,A) at the new displaced position.
// If multiple particles land on the same (newX, newY), the last one processed overwrites previous ones.
destData[destIndex] = r;
destData[destIndex + 1] = g;
destData[destIndex + 2] = b;
destData[destIndex + 3] = a; // Preserve original alpha of the particle.
}
}
// Pixels that are not chosen to become particles are intentionally not copied to destImageData.
// Since destImageData started transparent, these areas will remain transparent.
// This creates the effect of the image "dissolving" or being carried away by the "storm".
}
}
// Step 4: Clear the canvas. This is necessary because the original image was drawn on it in Step 1.
ctx.clearRect(0, 0, imgWidth, imgHeight);
// Step 5: Put the manipulated pixel data (destImageData) onto the canvas.
ctx.putImageData(destImageData, 0, 0);
// Step 6: Return the canvas element, which now displays the sandstorm effect.
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 Sandstorm Filter Effect Tool allows users to apply a unique sandstorm effect to images, giving them a visually compelling, dynamic appearance. By adjusting parameters such as particle density, storm strength, direction angle, and spread factor, users can create variations of the sandstorm effect tailored to their preferences. This tool can be useful for enhancing artwork, adding dramatic effects to photographs, or creating themed visuals for projects, presentations, or social media content.