You can edit the below JavaScript code to customize the image tool.
Apply Changes
/**
* Applies a Vaporwave/Synthwave filter with artifacts and CRT/VHS effects to an image.
*
* @param {HTMLImageElement} originalImg The original image element to process.
* @param {number} glitchIntensity Intensity of the horizontal glitch effect. Range: 0 to 100. Default: 10.
* @param {number} scanlineOpacity Opacity of the CRT-style scanlines. Range: 0 to 1. Default: 0.2.
* @param {number} chromaticAberration Pixel offset for the RGB channel split effect. Range: 0 to 50. Default: 5.
* @param {number} noiseAmount Amount of random noise to add. Range: 0 to 100. Default: 20.
* @param {string} tintColor The color for the overall vaporwave tint. Should be a CSS color string. Default: '#ff00ff'.
* @param {number} tintOpacity The opacity of the tint layer. Range: 0 to 1. Default: 0.3.
* @returns {HTMLCanvasElement} A new canvas element with the filtered image.
*/
function processImage(originalImg, glitchIntensity = 10, scanlineOpacity = 0.2, chromaticAberration = 5, noiseAmount = 20, tintColor = '#ff00ff', tintOpacity = 0.3) {
// 1. Setup Canvas
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d', {
willReadFrequently: true
});
const w = originalImg.naturalWidth;
const h = originalImg.naturalHeight;
canvas.width = w;
canvas.height = h;
// 2. Initial Image Filtering (Synthwave Look)
// Apply saturation, contrast, and brightness to get the base style
ctx.filter = 'saturate(1.7) contrast(1.3) brightness(1.1)';
ctx.drawImage(originalImg, 0, 0, w, h);
ctx.filter = 'none';
// 3. Chromatic Aberration
if (chromaticAberration > 0) {
const imageData = ctx.getImageData(0, 0, w, h);
const data = imageData.data;
// Create separate data arrays for each color channel
const rData = new Uint8ClampedArray(data.length);
const gData = new Uint8ClampedArray(data.length);
const bData = new Uint8ClampedArray(data.length);
for (let i = 0; i < data.length; i += 4) {
// Red channel data
rData[i] = data[i];
rData[i + 3] = data[i + 3];
// Green channel data
gData[i + 1] = data[i + 1];
gData[i + 3] = data[i + 3];
// Blue channel data
bData[i + 2] = data[i + 2];
bData[i + 3] = data[i + 3];
}
// Clear the canvas and prepare for recompositing
ctx.clearRect(0, 0, w, h);
ctx.globalCompositeOperation = 'lighter';
// Use a single temporary canvas to draw each channel
const tempCanvas = document.createElement('canvas');
tempCanvas.width = w;
tempCanvas.height = h;
const tempCtx = tempCanvas.getContext('2d');
// Draw red channel with horizontal offset
tempCtx.putImageData(new ImageData(rData, w, h), 0, 0);
ctx.drawImage(tempCanvas, -chromaticAberration, 0);
// Draw green channel (no offset)
tempCtx.putImageData(new ImageData(gData, w, h), 0, 0);
ctx.drawImage(tempCanvas, 0, 0);
// Draw blue channel with horizontal offset
tempCtx.putImageData(new ImageData(bData, w, h), 0, 0);
ctx.drawImage(tempCanvas, chromaticAberration, 0);
// Reset composite operation
ctx.globalCompositeOperation = 'source-over';
}
// 4. Vaporwave Tint Overlay
if (tintOpacity > 0 && tintColor) {
ctx.globalCompositeOperation = 'soft-light';
ctx.fillStyle = tintColor;
ctx.globalAlpha = tintOpacity;
ctx.fillRect(0, 0, w, h);
ctx.globalCompositeOperation = 'source-over';
ctx.globalAlpha = 1.0;
}
// 5. Glitch/Artifact Effect
if (glitchIntensity > 0) {
const passes = Math.round(glitchIntensity / 8);
for (let i = 0; i < passes; i++) {
const startY = Math.random() * h;
const sliceHeight = Math.max(1, Math.random() * (h / 15));
const offset = (Math.random() - 0.5) * (w * 0.15);
if (startY + sliceHeight > h) continue;
const sliceData = ctx.getImageData(0, startY, w, sliceHeight);
ctx.putImageData(sliceData, offset, startY);
}
}
// 6. VHS/CRT Scanlines
if (scanlineOpacity > 0) {
ctx.fillStyle = `rgba(0, 0, 0, ${scanlineOpacity})`;
for (let i = 0; i < h; i += 4) {
ctx.fillRect(0, i, w, 2);
}
}
// 7. Analog Noise
if (noiseAmount > 0) {
const imageData = ctx.getImageData(0, 0, w, h);
const data = imageData.data;
const amount = Math.abs(noiseAmount);
for (let i = 0; i < data.length; i += 4) {
// Don't add noise to fully transparent pixels
if (data[i + 3] === 0) continue;
const random = (Math.random() - 0.5) * amount;
const r = data[i] + random;
const g = data[i + 1] + random;
const b = data[i + 2] + random;
data[i] = Math.max(0, Math.min(255, r));
data[i + 1] = Math.max(0, Math.min(255, g));
data[i + 2] = Math.max(0, Math.min(255, b));
}
ctx.putImageData(imageData, 0, 0);
}
return canvas;
}
Apply Changes