You can edit the below JavaScript code to customize the image tool.
Apply Changes
function processImage(
originalImg,
caption = "[computer hacking voices]",
tintColor = "#00FF41",
glitchAmount = 6,
scanlineOpacity = 0.3,
showBinary = 1
) {
const canvas = document.createElement("canvas");
const ctx = canvas.getContext("2d");
const width = originalImg.width;
const height = originalImg.height;
canvas.width = width;
canvas.height = height;
// 1. Draw the original image to access its pixel data
ctx.drawImage(originalImg, 0, 0);
// Helper function to parse hex color to RGB
function parseColor(hex) {
hex = hex.replace(/^#/, '');
if (hex.length === 3) {
hex = hex.split('').map(c => c + c).join('');
}
const int = parseInt(hex, 16);
return {
r: (int >> 16) & 255,
g: (int >> 8) & 255,
b: int & 255
};
}
const rgb = parseColor(tintColor);
// 2. Tint and Glitch (Chromatic Aberration) Effect via Pixel Manipulation
const srcImgData = ctx.getImageData(0, 0, width, height);
const srcData = srcImgData.data;
const dstImgData = ctx.createImageData(width, height);
const dstData = dstImgData.data;
const shiftX = Math.floor(Number(glitchAmount));
for (let y = 0; y < height; y++) {
for (let x = 0; x < width; x++) {
let idx = (y * width + x) * 4;
// Calculate indices for glitch offsets (R shifted left, B shifted right)
let xR = Math.max(0, x - shiftX);
let xB = Math.min(width - 1, x + shiftX);
let idxR = (y * width + xR) * 4;
let idxB = (y * width + xB) * 4;
// Calculate luminance for each shifted channel using Rec. 601 coefficients
let lumR = 0.299 * srcData[idxR] + 0.587 * srcData[idxR+1] + 0.114 * srcData[idxR+2];
let lumG = 0.299 * srcData[idx] + 0.587 * srcData[idx+1] + 0.114 * srcData[idx+2];
let lumB = 0.299 * srcData[idxB] + 0.587 * srcData[idxB+1] + 0.114 * srcData[idxB+2];
// Map the luminance values to the chosen Hacker Tint Color
dstData[idx] = (lumR / 255) * rgb.r;
dstData[idx+1] = (lumG / 255) * rgb.g;
dstData[idx+2] = (lumB / 255) * rgb.b;
dstData[idx+3] = srcData[idx+3]; // Keep original alpha
}
}
ctx.putImageData(dstImgData, 0, 0);
// 3. Matrix-Style Binary Character Overlay
if (Number(showBinary) !== 0) {
ctx.font = Math.max(10, Math.floor(width * 0.015)) + 'px monospace';
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
const step = Math.max(15, Math.floor(width * 0.025));
for (let i = step / 2; i < width; i += step) {
for (let j = step / 2; j < height; j += step) {
// Scatter characters randomly across the image
if (Math.random() > 0.65) {
ctx.fillStyle = `rgba(${rgb.r}, ${rgb.g}, ${rgb.b}, ${Math.random() * 0.45})`;
ctx.fillText(Math.random() > 0.5 ? '0' : '1', i, j);
}
}
}
}
// 4. CRT Scanlines Overlay
const opacity = Number(scanlineOpacity);
if (opacity > 0) {
ctx.fillStyle = `rgba(0, 0, 0, ${opacity})`;
for (let y = 0; y < height; y += 3) {
ctx.fillRect(0, y, width, 1.5);
}
}
// 5. Screen Vignette (Edge Darkening)
const gradient = ctx.createRadialGradient(width/2, height/2, width/3, width/2, height/2, width * 0.8);
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);
// 6. The Meme Subtitle Caption Overlay
if (caption && caption.trim() !== "") {
const capStr = caption.trim();
const fontSize = Math.max(16, Math.floor(height * 0.05)); // Scale with image height
ctx.font = `bold ${fontSize}px Arial, sans-serif`;
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
// Measure the caption block to draw the standard black backing
const textMetrics = ctx.measureText(capStr);
const padX = fontSize;
const padY = fontSize / 2;
const boxW = textMetrics.width + padX * 2;
const boxH = fontSize + padY * 2;
const boxX = width / 2 - boxW / 2;
const boxY = height - boxH - Math.max(10, height * 0.05); // 5% spacing from bottom
// Draw subtitle background
ctx.fillStyle = 'rgba(0, 0, 0, 0.85)';
ctx.fillRect(boxX, boxY, boxW, boxH);
// Draw subtitle text
ctx.fillStyle = '#FFFFFF';
ctx.fillText(capStr, width / 2, boxY + boxH / 2 + (fontSize * 0.08)); // Slight optical adjustment
}
return canvas;
}
Apply Changes