You can edit the below JavaScript code to customize the image tool.
function processImage(
originalImg,
particleDensity = 20,
particleSize = 8,
sizeVariation = 0.7,
jitterAmount = 5,
minOpacity = 0.1,
maxOpacity = 0.6,
backgroundColor = 'white'
) {
// Sanitize and validate numeric parameters
particleDensity = Number(particleDensity);
if (isNaN(particleDensity) || particleDensity < 0) particleDensity = 20;
particleSize = Number(particleSize);
if (isNaN(particleSize) || particleSize <= 0) particleSize = 8;
sizeVariation = Number(sizeVariation);
if (isNaN(sizeVariation) || sizeVariation < 0 || sizeVariation > 1) sizeVariation = 0.7;
jitterAmount = Number(jitterAmount);
if (isNaN(jitterAmount) || jitterAmount < 0) jitterAmount = 5;
minOpacity = Number(minOpacity);
if (isNaN(minOpacity) || minOpacity < 0 || minOpacity > 1) minOpacity = 0.1;
maxOpacity = Number(maxOpacity);
if (isNaN(maxOpacity) || maxOpacity < 0 || maxOpacity > 1) maxOpacity = 0.6;
if (minOpacity > maxOpacity) {
// Swap if minOpacity is greater than maxOpacity
[minOpacity, maxOpacity] = [maxOpacity, minOpacity];
}
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
// Use naturalWidth/Height for actual image dimensions, fallback to width/height
const imgWidth = originalImg.naturalWidth || originalImg.width;
const imgHeight = originalImg.naturalHeight || originalImg.height;
// Handle cases where the image might not be loaded or has no dimensions
if (imgWidth === 0 || imgHeight === 0) {
console.warn("Original image has zero dimensions. Ensure it's loaded before calling processImage.");
// Create a small placeholder canvas with an error message
canvas.width = 200;
canvas.height = 100;
ctx.fillStyle = '#f0f0f0'; // Light gray background for the error message canvas
ctx.fillRect(0, 0, canvas.width, canvas.height);
ctx.fillStyle = 'red';
ctx.font = '12px Arial';
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
ctx.fillText('Error: Image not loaded or zero dimensions.', canvas.width / 2, canvas.height / 2);
return canvas;
}
canvas.width = imgWidth;
canvas.height = imgHeight;
// Set background color if specified and not transparent
// 'transparent' is a valid CSS color that makes the canvas transparent.
// An empty string or null for backgroundColor will also result in a transparent background.
if (backgroundColor && typeof backgroundColor === 'string' && backgroundColor.trim() !== '') {
ctx.fillStyle = backgroundColor;
ctx.fillRect(0, 0, canvas.width, canvas.height);
}
// Draw the original image onto a temporary canvas to access its pixel data.
// This is a common practice to avoid issues with directly reading from an Image object
// and necessary to handle potential CORS tainting if the image is cross-origin.
const tempCanvas = document.createElement('canvas');
const tempCtx = tempCanvas.getContext('2d');
tempCanvas.width = imgWidth;
tempCanvas.height = imgHeight;
let imageData;
try {
tempCtx.drawImage(originalImg, 0, 0, imgWidth, imgHeight);
imageData = tempCtx.getImageData(0, 0, imgWidth, imgHeight);
} catch (e) {
console.error("Error getting image data:", e);
// Draw an error message on the main canvas if pixel data cannot be accessed
// (e.g., due to CORS restrictions on a tainted canvas)
ctx.fillStyle = 'rgba(230, 230, 230, 0.8)'; // Overwrite with light error background
ctx.fillRect(0, 0, canvas.width, canvas.height);
ctx.fillStyle = 'darkred';
ctx.font = '16px Arial';
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
const errorLines = [`Error: Could not process image data.`];
if (e.name === 'SecurityError') {
errorLines.push(`(This might be a CORS issue if the image is from another domain).`);
}
errorLines.forEach((line, index) => {
ctx.fillText(line, canvas.width / 2, canvas.height / 2 - (10 * (errorLines.length-1)/2) + (index * 20) );
});
return canvas;
}
const data = imageData.data;
// Calculate the total number of particles to draw.
// particleDensity defines how many particles per 1000 pixels of image area.
const numParticles = Math.floor((imgWidth * imgHeight / 1000) * particleDensity);
// Drawing loop for each particle
for (let i = 0; i < numParticles; i++) {
// Pick a random x, y coordinate from the original image to sample its color
const sx = Math.floor(Math.random() * imgWidth);
const sy = Math.floor(Math.random() * imgHeight);
// Calculate the index for the pixel data array
const pixelIndex = (sy * imgWidth + sx) * 4;
const r = data[pixelIndex];
const g = data[pixelIndex + 1];
const b = data[pixelIndex + 2];
// const originalAlpha = data[pixelIndex + 3]; // Original alpha, could be used if needed
// If pixel data components are undefined (should not happen for valid sx, sy), skip this particle
if (typeof r === 'undefined' || typeof g === 'undefined' || typeof b === 'undefined') {
continue;
}
// Calculate properties for the current particle
// particleSize is the average radius
const currentRadius = Math.max(0.5, particleSize * (1 + (Math.random() - 0.5) * 2 * sizeVariation));
const currentOpacity = minOpacity + Math.random() * (maxOpacity - minOpacity);
// Determine the actual drawing position, adding jitter to the sampled position
const drawX = sx + (Math.random() - 0.5) * 2 * jitterAmount;
const drawY = sy + (Math.random() - 0.5) * 2 * jitterAmount;
// Set fill style with sampled color and calculated opacity
ctx.fillStyle = `rgba(${r}, ${g}, ${b}, ${currentOpacity})`;
// Draw the particle (a circle)
ctx.beginPath();
ctx.arc(drawX, drawY, currentRadius, 0, 2 * Math.PI);
ctx.fill();
}
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 Spray Paint Mural Creator tool allows users to transform their images into a unique spray paint mural effect. By adjusting parameters like particle density, size, and opacity, users can create visually striking artistic renditions of their images. This tool is particularly useful for artists and designers looking to add a creative touch to photos, making it suitable for digital art projects, social media posts, decor designs, or any application where an artistic visual interpretation is desired.