You can edit the below JavaScript code to customize the image tool.
Apply Changes
function processImage(originalImg, glitchLevel = "15", noiseLevel = "25", showTextOverlay = "1") {
const canvas = document.createElement('canvas');
const width = originalImg.width;
const height = originalImg.height;
// Set canvas dimensions to match the original image
canvas.width = width;
canvas.height = height;
const ctx = canvas.getContext('2d');
// Draw the original image onto the canvas
ctx.drawImage(originalImg, 0, 0);
let imageData;
try {
imageData = ctx.getImageData(0, 0, width, height);
} catch (e) {
console.error("Failed to read image data. This may be due to cross-origin restrictions:", e);
return canvas;
}
const data = imageData.data;
// Create a copy of the original pixels to read unmodified data during shifting
const tempData = new Uint8ClampedArray(data);
// Parse parameters
const glitch = Number(glitchLevel);
const noiseAmt = Number(noiseLevel);
// Calculate the pixel shift for the chromatic aberration effect
const shiftOffset = Math.floor(width * (glitch / 1000));
// Contrast settings
const contrast = 1.15; // 15% increase in contrast
const intercept = 128 * (1 - contrast);
// Pixel manipulation loop
for (let y = 0; y < height; y++) {
for (let x = 0; x < width; x++) {
const i = (y * width + x) * 4;
// Chromatic Aberration: Shift Red right, Blue left
const rX = Math.min(width - 1, Math.max(0, x + shiftOffset));
const bX = Math.min(width - 1, Math.max(0, x - shiftOffset));
const rI = (y * width + rX) * 4;
const bI = (y * width + bX) * 4;
let r = tempData[rI]; // Red comes from shifted pixel
let g = tempData[i + 1]; // Green stays in place
let b = tempData[bI + 2]; // Blue comes from opposite shifted pixel
// Apply Contrast
r = r * contrast + intercept;
g = g * contrast + intercept;
b = b * contrast + intercept;
// Apply Noise
if (noiseAmt > 0) {
const noise = (Math.random() - 0.5) * noiseAmt;
r += noise;
g += noise;
b += noise;
}
// Apply slight green/vintage tint
g += 10;
// Clamp and assign back to the image data array
data[i] = r;
data[i + 1] = g;
data[i + 2] = b;
// Alpha (data[i + 3]) remains untouched
}
}
// Put modified pixels back to the canvas
ctx.putImageData(imageData, 0, 0);
// Apply retro horizontal scanlines
ctx.fillStyle = 'rgba(0, 0, 0, 0.15)';
for (let y = 0; y < height; y += 4) {
ctx.fillRect(0, y, width, 2);
}
// Apply vignette effect
const gradient = ctx.createRadialGradient(width / 2, height / 2, height / 3, width / 2, height / 2, Math.max(width, height) / 1.2);
gradient.addColorStop(0, 'rgba(0, 0, 0, 0)');
gradient.addColorStop(1, 'rgba(0, 0, 0, 0.7)');
ctx.fillStyle = gradient;
ctx.fillRect(0, 0, width, height);
// Draw the "Eric_" VHS-style OSD (On-Screen Display) text overlay
if (String(showTextOverlay) === "1") {
ctx.shadowColor = "black";
ctx.shadowBlur = 4;
ctx.shadowOffsetX = 2;
ctx.shadowOffsetY = 2;
// Responsive font size
const fontSize = Math.max(16, Math.floor(height * 0.06));
ctx.font = `bold ${fontSize}px "Courier New", Courier, monospace`;
// Top Left: PLAY / ERIC_
ctx.fillStyle = "white";
ctx.fillText("PLAY", width * 0.05, height * 0.05 + fontSize);
ctx.fillText("ERIC_", width * 0.05, height * 0.05 + fontSize * 2.2);
// Top Right: REC and blinking dot mimic
ctx.fillStyle = "#ff3333";
const recText = "REC •";
const recWidth = ctx.measureText(recText).width;
ctx.fillText(recText, width * 0.95 - recWidth, height * 0.05 + fontSize);
// Bottom Left: Fake timestamp
ctx.fillStyle = "white";
const d = new Date();
const hrs = d.getHours().toString().padStart(2, '0');
const mins = d.getMinutes().toString().padStart(2, '0');
const timeStr = `SP ${hrs}:${mins}`;
ctx.fillText(timeStr, width * 0.05, height * 0.95);
}
return canvas;
}
Apply Changes