You can edit the below JavaScript code to customize the image tool.
Apply Changes
/**
* Creates a "Radio Sound Visualizer" effect on an image, simulating an old CRT screen
* with static, scanlines, glitches, and an optional oscilloscope waveform.
*
* @param {Image} originalImg The original javascript Image object.
* @param {number} [noiseAmount=0.2] The amount of noise/static to apply (0 to 1). Higher is more noise.
* @param {number} [scanlineHeight=1] The height of each scanline in pixels.
* @param {number} [scanlineGap=1] The gap between each scanline in pixels.
* @param {number} [scanlineOpacity=0.1] The opacity of the scanlines (0 to 1).
* @param {number} [glitchIntensity=0.1] The frequency and magnitude of the horizontal glitch effect (0 to 1).
* @param {number} [enableGrayscale=1] Whether to convert the image to grayscale (1 for true, 0 for false).
* @param {number} [showWaveform=1] Whether to draw an oscilloscope waveform overlay (1 for true, 0 for false).
* @param {string} [waveformColor='rgba(50, 255, 50, 0.6)'] The color of the waveform.
* @param {number} [waveformAmplitude=30] The vertical amplitude of the waveform in pixels.
* @returns {HTMLCanvasElement} A canvas element with the visualizer effect applied.
*/
function processImage(
originalImg,
noiseAmount = 0.2,
scanlineHeight = 1,
scanlineGap = 1,
scanlineOpacity = 0.1,
glitchIntensity = 0.1,
enableGrayscale = 1,
showWaveform = 1,
waveformColor = 'rgba(50, 255, 50, 0.6)',
waveformAmplitude = 30
) {
// 1. Setup Canvas
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
const {
naturalWidth: width,
naturalHeight: height
} = originalImg;
canvas.width = width;
canvas.height = height;
// 2. Draw base image with grayscale if enabled
if (enableGrayscale === 1) {
ctx.filter = 'grayscale(100%)';
}
ctx.drawImage(originalImg, 0, 0, width, height);
ctx.filter = 'none';
// 3. Apply Glitch Effect (if enabled)
// This effect works by creating a copy of the image and then redrawing it
// onto the main canvas in horizontal slices, some of which are randomly shifted.
if (glitchIntensity > 0) {
const tempCanvas = document.createElement('canvas');
tempCanvas.width = width;
tempCanvas.height = height;
const tempCtx = tempCanvas.getContext('2d');
tempCtx.drawImage(canvas, 0, 0); // Copy current image to temp canvas
ctx.clearRect(0, 0, width, height); // Clear main canvas
// Reconstruct image from random slices of the temp canvas
for (let y = 0; y < height;) {
const sliceHeight = Math.floor(Math.random() * (height * 0.05)) + 1;
const horizontalShift = Math.random() < glitchIntensity ?
(Math.random() - 0.5) * (width * glitchIntensity * 0.5) :
0;
// Prevent drawing beyond canvas bounds
const effectiveSliceHeight = Math.min(sliceHeight, height - y);
ctx.drawImage(tempCanvas,
0, y, width, effectiveSliceHeight, // Source rect
horizontalShift, y, width, effectiveSliceHeight // Destination rect
);
y += effectiveSliceHeight;
}
}
// 4. Draw Waveform (if enabled)
// This overlays a glowing, oscilloscope-style wave.
if (showWaveform === 1 && waveformAmplitude > 0) {
ctx.save();
ctx.beginPath();
ctx.strokeStyle = waveformColor;
ctx.lineWidth = Math.max(1, Math.round(width / 500));
ctx.shadowColor = waveformColor;
ctx.shadowBlur = 10;
const centerY = height / 2;
// Use a combination of sine waves for a more organic look
const randomPhase1 = Math.random() * 2 * Math.PI;
const randomFreq1 = (Math.random() * 5 + 2) / width;
const randomPhase2 = Math.random() * 2 * Math.PI;
const randomFreq2 = (Math.random() * 10 + 5) / width;
ctx.moveTo(0, centerY);
for (let x = 0; x < width; x++) {
const wave1 = Math.sin(x * randomFreq1 + randomPhase1);
const wave2 = Math.sin(x * randomFreq2 + randomPhase2);
const noise = (Math.random() - 0.5) * 0.2;
const displacement = (wave1 * 0.6 + wave2 * 0.3 + noise) * waveformAmplitude;
ctx.lineTo(x, centerY + displacement);
}
ctx.stroke();
ctx.restore();
}
// 5. Add Noise (if enabled)
// This applies a random brightness adjustment to pixels to simulate static.
if (noiseAmount > 0) {
const imageData = ctx.getImageData(0, 0, width, height);
const data = imageData.data;
for (let i = 0; i < data.length; i += 4) {
if (Math.random() < noiseAmount) {
const noise = (Math.random() - 0.5) * 128;
data[i] = Math.max(0, Math.min(255, data[i] + noise));
data[i+1] = Math.max(0, Math.min(255, data[i+1] + noise));
data[i+2] = Math.max(0, Math.min(255, data[i+2] + noise));
}
}
ctx.putImageData(imageData, 0, 0);
}
// 6. Add Scanlines (if enabled)
// This overlays dark horizontal lines to mimic a CRT screen.
if (scanlineHeight > 0) {
ctx.save();
ctx.fillStyle = `rgba(0, 0, 0, ${scanlineOpacity})`;
const totalLineHeight = scanlineHeight + scanlineGap;
if (totalLineHeight > 0) {
for (let y = 0; y < height; y += totalLineHeight) {
ctx.fillRect(0, y, width, scanlineHeight);
}
}
ctx.restore();
}
// 7. Return final canvas
return canvas;
}
Apply Changes