You can edit the below JavaScript code to customize the image tool.
function processImage(originalImg, burnLevel = 0.4, strength = 0.8, roughness = 0.5, burntColorHex = "#4A2A19") {
// Helper function to parse hex color string to an RGB object {r, g, b}
function hexToRgb(hex) {
hex = hex.startsWith('#') ? hex.slice(1) : hex;
let r = 0, g = 0, b = 0;
if (hex.length === 3) { // Short hex format #RGB
r = parseInt(hex[0] + hex[0], 16);
g = parseInt(hex[1] + hex[1], 16);
b = parseInt(hex[2] + hex[2], 16);
} else if (hex.length === 6) { // Full hex format #RRGGBB
r = parseInt(hex.substring(0, 2), 16);
g = parseInt(hex.substring(2, 4), 16);
b = parseInt(hex.substring(4, 6), 16);
} else {
// Fallback for invalid hex format (e.g. wrong length)
console.warn("Invalid burntColorHex format (length). Using default dark brown (#4A2A19). Input was: " + burntColorHex);
return { r: 74, g: 42, b: 25 }; // Default dark brown
}
// Check if parsing resulted in NaN (e.g. invalid characters in hex string)
if (isNaN(r) || isNaN(g) || isNaN(b)) {
console.warn("Failed to parse burntColorHex (invalid characters). Using default dark brown (#4A2A19). Input was: " + burntColorHex);
return { r: 74, g: 42, b: 25 }; // Default dark brown
}
return { r, g, b };
}
const canvas = document.createElement('canvas');
// Add { willReadFrequently: true } for potential performance optimization hint
const ctx = canvas.getContext('2d', { willReadFrequently: true });
const width = originalImg.naturalWidth || originalImg.width;
const height = originalImg.naturalHeight || originalImg.height;
// Handle cases where the image might not have valid dimensions
if (width === 0 || height === 0) {
canvas.width = 1; // Set to smallest possible valid canvas
canvas.height = 1;
console.warn("Original image has zero width or height.")
return canvas; // Return an empty (1x1) canvas
}
canvas.width = width;
canvas.height = height;
// Draw the original image onto the canvas
ctx.drawImage(originalImg, 0, 0, width, height);
const imageData = ctx.getImageData(0, 0, width, height);
const data = imageData.data;
const centerX = width / 2;
const centerY = height / 2;
// Calculate the maximum distance from the center to a corner (for normalization)
const maxDistFromCenter = Math.sqrt(centerX * centerX + centerY * centerY);
const burntRGB = hexToRgb(burntColorHex);
// Clamp parameters to ensure they are within their valid [0, 1] range
burnLevel = Math.max(0, Math.min(1, burnLevel));
strength = Math.max(0, Math.min(1, strength));
roughness = Math.max(0, Math.min(1, roughness));
for (let y = 0; y < height; y++) {
for (let x = 0; x < width; x++) {
const idx = (y * width + x) * 4;
const originalR = data[idx];
const originalG = data[idx+1];
const originalB = data[idx+2];
// const originalA = data[idx+3]; // Alpha is preserved in this effect
const dx = x - centerX;
const dy = y - centerY;
const distFromCenter = Math.sqrt(dx * dx + dy * dy);
// Normalized distance: 0 at center, 1 at corners. Handle 1x1 image case (maxDistFromCenter can be 0).
let normDist = (maxDistFromCenter === 0) ? 0 : distFromCenter / maxDistFromCenter;
// Introduce irregularity to the burn edge based on roughness
// This perturbs the normalized distance, making the burn boundary uneven.
// Max perturbation: roughness * 0.1 * normDist (scales with distance to make center less noisy)
// Or a simpler, fixed max perturbation:
const roughnessMagnitude = roughness * 0.1; // Max +/-10% of radius for roughness=1
const roughnessEffect = (Math.random() - 0.5) * 2.0 * roughnessMagnitude;
normDist = Math.max(0, Math.min(1, normDist + roughnessEffect));
let pixelBurnFactor = 0; // How much this pixel is affected (0 to 1)
if (burnLevel > 1e-6) { // Check if burnLevel is effectively greater than 0
// The burn effect starts at a radius determined by burnLevel
// burnLevel = 0 means no area is burnt.
// burnLevel = 1 means burn can extend to the center.
const burnStartRadius = 1.0 - burnLevel;
if (normDist >= burnStartRadius) {
// Calculate intensity: 0 at burnStartRadius, 1 at image edge (normDist=1)
pixelBurnFactor = (normDist - burnStartRadius) / burnLevel;
pixelBurnFactor = Math.max(0, Math.min(1, pixelBurnFactor)); // Clamp to [0,1]
// Apply a power curve to make the burn effect more concentrated towards the edge
pixelBurnFactor = Math.pow(pixelBurnFactor, 2.0);
}
}
// If burnLevel is 0, pixelBurnFactor remains 0, so no effect applied.
if (pixelBurnFactor > 0) {
// The overall strength of the effect on this specific pixel
const effectStrengthOnPixel = pixelBurnFactor * strength;
// Blend original color with the burntRGB color
let r = originalR * (1 - effectStrengthOnPixel) + burntRGB.r * effectStrengthOnPixel;
let g = originalG * (1 - effectStrengthOnPixel) + burntRGB.g * effectStrengthOnPixel;
let b = originalB * (1 - effectStrengthOnPixel) + burntRGB.b * effectStrengthOnPixel;
// Update pixel data, ensuring values are clamped to [0, 255]
data[idx] = Math.max(0, Math.min(255, r));
data[idx+1] = Math.max(0, Math.min(255, g));
data[idx+2] = Math.max(0, Math.min(255, b));
// data[idx+3] = originalA; // Alpha channel remains unchanged
}
}
}
// Write the modified pixel data back to the canvas
ctx.putImageData(imageData, 0, 0);
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 Burnt Edges Filter Effect Tool allows users to apply a burnt edges effect to their images. This tool provides customizable options for the level of burn, the strength of the effect, roughness of the burn edges, and the color of the burnt effect. It can be used for artistic photo editing, enhancing the visual appeal of images for creative projects, or creating dramatic or vintage-inspired effects on photos. Whether for personal use or professional graphic design, this tool helps to transform standard images into unique visual pieces.
Trying this effect