You can edit the below JavaScript code to customize the image tool.
Apply Changes
function processImage(originalImg, neonColor = "#00FFFF", glowIntensity = 15, edgeThreshold = 30, backgroundColor = "#000000") {
// Determine dimensions seamlessly for Image, Canvas, or Video objects
const width = originalImg.naturalWidth || originalImg.videoWidth || originalImg.width;
const height = originalImg.naturalHeight || originalImg.videoHeight || originalImg.height;
// 1. Create a canvas to extract pixel data
const canvas = document.createElement('canvas');
canvas.width = width;
canvas.height = height;
const ctx = canvas.getContext('2d');
// Draw the original image to process
ctx.drawImage(originalImg, 0, 0, width, height);
const imgData = ctx.getImageData(0, 0, width, height);
const data = imgData.data;
// 2. Convert to grayscale for edge detection
const gray = new Float32Array(width * height);
for (let i = 0; i < data.length; i += 4) {
// Simple luminance calculation
gray[i >> 2] = data[i] * 0.299 + data[i + 1] * 0.587 + data[i + 2] * 0.114;
}
// 3. Apply Sobel operator to find edges
const edgeData = new Uint8ClampedArray(width * height * 4);
const threshold = Number(edgeThreshold);
for (let y = 1; y < height - 1; y++) {
for (let x = 1; x < width - 1; x++) {
const idx1 = y * width + x;
const idx0 = idx1 - width; // (y - 1) * width + x
const idx2 = idx1 + width; // (y + 1) * width + x
const p00 = gray[idx0 - 1], p01 = gray[idx0], p02 = gray[idx0 + 1];
const p10 = gray[idx1 - 1], p12 = gray[idx1 + 1];
const p20 = gray[idx2 - 1], p21 = gray[idx2], p22 = gray[idx2 + 1];
// Sobel kernels
const gx = -p00 + p02 - 2 * p10 + 2 * p12 - p20 + p22;
const gy = -p00 - 2 * p01 - p02 + p20 + 2 * p21 + p22;
const mag = Math.sqrt(gx * gx + gy * gy);
let alpha = mag - threshold;
if (alpha > 0) {
alpha = alpha > 255 ? 255 : alpha;
const outIdx = idx1 << 2;
edgeData[outIdx] = 255; // R
edgeData[outIdx + 1] = 255; // G
edgeData[outIdx + 2] = 255; // B
edgeData[outIdx + 3] = alpha; // Alpha
}
}
}
// 4. Create an isolated canvas for the white edges
const edgeCanvas = document.createElement('canvas');
edgeCanvas.width = width;
edgeCanvas.height = height;
const edgeCtx = edgeCanvas.getContext('2d');
edgeCtx.putImageData(new ImageData(edgeData, width, height), 0, 0);
// 5. Create a tinted variations for the luminous color glow
const tintCanvas = document.createElement('canvas');
tintCanvas.width = width;
tintCanvas.height = height;
const tintCtx = tintCanvas.getContext('2d');
// Draw the grayscale edges, then source-in to colorize them
tintCtx.drawImage(edgeCanvas, 0, 0);
tintCtx.globalCompositeOperation = 'source-in';
tintCtx.fillStyle = neonColor;
tintCtx.fillRect(0, 0, width, height);
// 6. Build the final composition
const finalCanvas = document.createElement('canvas');
finalCanvas.width = width;
finalCanvas.height = height;
const finalCtx = finalCanvas.getContext('2d');
// Solid Background
finalCtx.fillStyle = backgroundColor;
finalCtx.fillRect(0, 0, width, height);
// Use lighter/additive blending to accumulate glow realistically
finalCtx.globalCompositeOperation = 'lighter';
// Blur passes to create the neon aura (spread outwards)
const intensity = Number(glowIntensity);
const blurPasses = [
intensity * 0.25, // intense core blur
intensity * 0.75, // middle glow
intensity * 1.5, // outer fade
intensity * 3.0 // ambient atmospheric scatter
];
for (let blur of blurPasses) {
if (blur > 0) {
finalCtx.filter = `blur(${blur}px)`;
finalCtx.drawImage(tintCanvas, 0, 0);
}
}
// Remove blur for drawing the clean neon tube outlines
finalCtx.filter = 'none';
finalCtx.drawImage(tintCanvas, 0, 0);
// Add a slightly translucent pure white core to simulate the hottest part of the neon gas
finalCtx.globalCompositeOperation = 'source-over';
finalCtx.globalAlpha = 0.65;
finalCtx.drawImage(edgeCanvas, 0, 0);
return finalCanvas;
}
Apply Changes