You can edit the below JavaScript code to customize the image tool.
Apply Changes
function processImage(originalImg, intensity = 50, phaseOffset = 0, applyScanlines = 1) {
// Parse and normalize parameters
const intIntensity = Math.min(Math.max(Number(intensity) || 50, 0), 200);
const phase = Number(phaseOffset) || Math.random() * 100;
const doScanlines = Number(applyScanlines) !== 0;
// Setup canvas
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
const w = originalImg.width;
const h = originalImg.height;
canvas.width = w;
canvas.height = h;
// Draw original image
ctx.drawImage(originalImg, 0, 0);
// Apply pre-glitch slice shifting
const numSlices = Math.floor(intIntensity / 4);
for (let i = 0; i < numSlices; i++) {
const sliceY = Math.random() * h;
const sliceH = Math.random() * (h / 8) + 1;
const offsetX = (Math.random() - 0.5) * intIntensity * 2;
const offsetY = (Math.random() - 0.5) * (intIntensity / 5);
ctx.drawImage(canvas, 0, sliceY, w, sliceH, offsetX, sliceY + offsetY, w, sliceH);
}
// Get pixel data for fine-grained manipulation
const imgData = ctx.getImageData(0, 0, w, h);
const data = imgData.data;
const outData = new Uint8ClampedArray(data.length);
// Effect modifiers based on intensity
const rOffset = Math.floor(intIntensity / 2);
const bOffset = -Math.floor(intIntensity / 2);
const noiseAmount = intIntensity;
// Sine wave distortion for CRT sync loss
const waveFreq = (Math.random() * 0.05) + 0.01;
const waveAmp = intIntensity / 2;
// Contrast boost factor for the "mania" vibrancy
const contrastFactor = (259 * (intIntensity + 255)) / (255 * (259 - intIntensity));
for (let y = 0; y < h; y++) {
const isScanline = doScanlines && (y % 3 === 0);
// Vertical undulating sync shift
const syncShift = Math.sin(y * waveFreq + phase) * waveAmp;
for (let x = 0; x < w; x++) {
const i = (y * w + x) * 4;
// Base shifted X coordinate
const sx = Math.floor(x + syncShift);
// RGB Channel Split / Chromatic Aberration
const rX = Math.min(Math.max(sx + rOffset, 0), w - 1);
const gX = Math.min(Math.max(sx, 0), w - 1);
const bX = Math.min(Math.max(sx + bOffset, 0), w - 1);
const ri = (y * w + rX) * 4;
const gi = (y * w + gX) * 4;
const bi = (y * w + bX) * 4;
let r = data[ri]; // Red from offset X
let g = data[gi + 1]; // Green from center X
let b = data[bi + 2]; // Blue from offset X
let a = data[gi + 3];
// Mania Contrast/Vibrance Boost
r = contrastFactor * (r - 128) + 128;
g = contrastFactor * (g - 128) + 128;
b = contrastFactor * (b - 128) + 128;
// Add static noise
if (noiseAmount > 0) {
const noise = (Math.random() - 0.5) * noiseAmount;
r += noise;
g += noise;
b += noise;
}
// Apply CRT scanline darkening
if (isScanline) {
r *= 0.5;
g *= 0.5;
b *= 0.5;
}
// Write processed values to output
outData[i] = r;
outData[i + 1] = g;
outData[i + 2] = b;
outData[i + 3] = a;
}
// Randomly invert entire horizontal bands to simulate extreme TV malfunction (tear)
if (Math.random() < (intIntensity / 2500)) {
for (let tx = 0; tx < w; tx++) {
const i = (y * w + tx) * 4;
outData[i] = 255 - outData[i];
outData[i + 1] = 255 - outData[i + 1];
outData[i + 2] = 255 - outData[i + 2];
}
}
}
// Apply back the manipulated pixels
imgData.data.set(outData);
ctx.putImageData(imgData, 0, 0);
// Apply old TV vignette / screen shading effect
const tvGradient = ctx.createRadialGradient(w / 2, h / 2, Math.max(w, h) / 4, w / 2, h / 2, Math.max(w, h) / 1.4);
tvGradient.addColorStop(0, "rgba(0,0,0,0)");
tvGradient.addColorStop(1, "rgba(0,0,0,0.6)");
ctx.fillStyle = tvGradient;
ctx.fillRect(0, 0, w, h);
return canvas;
}
Apply Changes