You can edit the below JavaScript code to customize the image tool.
Apply Changes
function processImage(originalImg, glowColorStr = "100,100,255", glowStrength = 0.8, blurAmount = 10, edgeThreshold = 30) {
// 1. Parse glowColorStr and set up glow color components
let r_glow = 100, g_glow = 100, b_glow = 255; // Default glow color (light bluish-purple)
// Validate and parse glowColorStr
if (typeof glowColorStr === 'string') {
const colorParts = glowColorStr.split(',');
if (colorParts.length === 3) {
const parsedR = parseInt(colorParts[0].trim(), 10);
const parsedG = parseInt(colorParts[1].trim(), 10);
const parsedB = parseInt(colorParts[2].trim(), 10);
if (!isNaN(parsedR) && !isNaN(parsedG) && !isNaN(parsedB)) {
r_glow = Math.max(0, Math.min(255, parsedR));
g_glow = Math.max(0, Math.min(255, parsedG));
b_glow = Math.max(0, Math.min(255, parsedB));
} else {
console.warn(`Invalid numbers in glowColorStr: "${glowColorStr}". Using default color [${r_glow},${g_glow},${b_glow}].`);
}
} else {
console.warn(`Invalid format for glowColorStr: "${glowColorStr}". Expected "R,G,B" string. Using default color [${r_glow},${g_glow},${b_glow}].`);
}
} else {
console.warn(`glowColorStr is not a string: "${glowColorStr}". Using default color [${r_glow},${g_glow},${b_glow}].`);
}
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
const width = originalImg.naturalWidth || originalImg.width;
const height = originalImg.naturalHeight || originalImg.height;
if (width === 0 || height === 0) {
// Handle invalid image dimensions by returning a minimal canvas
console.warn("Image has zero width or height.");
canvas.width = 1;
canvas.height = 1;
return canvas;
}
canvas.width = width;
canvas.height = height;
// Create a temporary canvas for edge detection processing
const tempCanvas = document.createElement('canvas');
tempCanvas.width = width;
tempCanvas.height = height;
// Add { willReadFrequently: true } if frequent getImageData/putImageData operations are expected
const tempCtx = tempCanvas.getContext('2d', { willReadFrequently: true });
// Draw original image on temp canvas
tempCtx.drawImage(originalImg, 0, 0, width, height);
// Get image data for edge detection
let imageData;
try {
imageData = tempCtx.getImageData(0, 0, width, height);
} catch (e) {
console.error("Could not get image data, possibly due to CORS or other security restrictions.", e);
// Fallback: return a canvas with the original image drawn, without the effect
ctx.drawImage(originalImg, 0, 0, width, height);
return canvas;
}
const data = imageData.data;
// Prepare pixel data for the edge mask. Initialized to transparent black (all zeros).
const edgePixelData = new Uint8ClampedArray(width * height * 4);
// Edge Detection (Simplified gradient magnitude)
// Skip 1-pixel border to avoid boundary checks for neighbors; these pixels will remain transparent in edgePixelData.
for (let y = 1; y < height - 1; y++) {
for (let x = 1; x < width - 1; x++) {
const i = (y * width + x) * 4; // Current pixel index in the data array
// Helper to get grayscale intensity (average of R,G,B) for a pixel at a given offset
const getGrayscale = (pixelStartIndex) =>
(data[pixelStartIndex] + data[pixelStartIndex + 1] + data[pixelStartIndex + 2]) / 3;
// Calculate offsets for neighboring pixels
const W_offset = (y * width + (x - 1)) * 4;
const E_offset = (y * width + (x + 1)) * 4;
const N_offset = ((y - 1) * width + x) * 4;
const S_offset = ((y + 1) * width + x) * 4;
const valW = getGrayscale(W_offset);
const valE = getGrayscale(E_offset);
const valN = getGrayscale(N_offset);
const valS = getGrayscale(S_offset);
// Sobel-like gradient calculation (simplified)
const gradX = valE - valW;
const gradY = valS - valN; // In image coordinates, Y typically increases downwards
const magnitude = Math.sqrt(gradX * gradX + gradY * gradY);
if (magnitude > edgeThreshold) {
edgePixelData[i] = r_glow; // Red component of glow color
edgePixelData[i + 1] = g_glow; // Green component of glow color
edgePixelData[i + 2] = b_glow; // Blue component of glow color
edgePixelData[i + 3] = 255; // Alpha (fully opaque)
}
// Pixels not meeting threshold remain transparent black due to Uint8ClampedArray initialization
}
}
// Create an ImageData object from our manually constructed edge pixel data
const edgeImageData = new ImageData(edgePixelData, width, height);
// Canvas for the colored edges (pre-blur)
const edgeColorCanvas = document.createElement('canvas');
edgeColorCanvas.width = width;
edgeColorCanvas.height = height;
const edgeColorCtx = edgeColorCanvas.getContext('2d');
edgeColorCtx.putImageData(edgeImageData, 0, 0);
// Canvas for the blurred glow
const glowCanvas = document.createElement('canvas');
glowCanvas.width = width;
glowCanvas.height = height;
const glowCtx = glowCanvas.getContext('2d');
// Apply blur to the colored edges to create the glow effect
const sanitizedBlurAmount = Math.max(0, blurAmount); // Ensure blur is not negative
if (sanitizedBlurAmount > 0) {
glowCtx.filter = `blur(${sanitizedBlurAmount}px)`;
}
glowCtx.drawImage(edgeColorCanvas, 0, 0, width, height);
if (sanitizedBlurAmount > 0) { // Reset filter only if it was applied
glowCtx.filter = 'none';
}
// Composite onto the main output canvas
// 1. Draw the original image
ctx.drawImage(originalImg, 0, 0, width, height);
// 2. Draw the glow layer on top using 'lighter' for an additive effect
ctx.globalCompositeOperation = 'lighter';
ctx.globalAlpha = Math.max(0, Math.min(1, glowStrength)); // Clamp strength to [0,1]
ctx.drawImage(glowCanvas, 0, 0, width, height);
// Reset global alpha and composite operation to defaults for subsequent drawing operations if any
ctx.globalAlpha = 1.0;
ctx.globalCompositeOperation = 'source-over';
return canvas;
}
Apply Changes