You can edit the below JavaScript code to customize the image tool.
Apply Changes
function processImage(
originalImg,
aestheticType = "VHS",
subtitleText = "I have translated the original audio.\\n Enjoy!",
watermarkText = "DVDRip.HIFI.x264",
intensity = 5
) {
// Create a canvas to work on
const canvas = document.createElement('canvas');
const w = originalImg.width;
const h = originalImg.height;
canvas.width = w;
canvas.height = h;
const ctx = canvas.getContext('2d');
// Draw the initial image
ctx.drawImage(originalImg, 0, 0, w, h);
// Define bounds for effect intensity
const effLevel = Math.max(1, Math.min(20, intensity));
let imgData = ctx.getImageData(0, 0, w, h);
const data = imgData.data;
// Apply visual degradations based on aesthetic type
if (aestheticType.toUpperCase() === "VHS") {
const shiftX = Math.floor((w * (effLevel * 0.05)) / 100) || 2;
for (let y = 0; y < h; y++) {
// Wave distortion
const waveX = Math.sin(y * 0.05) * (effLevel * 0.5);
for (let x = 0; x < w; x++) {
const i = (y * w + x) * 4;
// Chromatic Aberration (RGB split)
const srcXIdR = Math.max(0, Math.min(w - 1, x + shiftX + Math.floor(waveX)));
const rI = (y * w + srcXIdR) * 4;
const srcXIdB = Math.max(0, Math.min(w - 1, x - shiftX + Math.floor(waveX / 2)));
const bI = (y * w + srcXIdB) * 4;
// Replace Red and Blue channels for tracking mismatch
data[i] = data[rI]; // Red
data[i+1] = data[i+1]; // Green (stays the same)
data[i+2] = data[bI+2]; // Blue
// Adding grain/noise
if (Math.random() < (0.01 * effLevel)) {
const noise = (Math.random() - 0.5) * 80;
data[i] += noise;
data[i+1] += noise;
data[i+2] += noise;
}
// Scanlines (Darken every alternating block of pixels)
if (y % 6 < 3) {
data[i] *= 0.85;
data[i+1] *= 0.85;
data[i+2] *= 0.85;
}
// Color grading: slight green hue for VHS
data[i] *= 0.95;
data[i+1] *= 1.05;
data[i+2] *= 0.95;
}
}
ctx.putImageData(imgData, 0, 0);
} else {
// DVD Rip blocky compression artifact effect
const scaleFactor = 1 / (effLevel * 0.5);
const cw = Math.max(1, Math.floor(w * scaleFactor));
const ch = Math.max(1, Math.floor(h * scaleFactor));
// Pixelate by down-scaling and up-scaling with out smoothing
const tempCanvas = document.createElement('canvas');
tempCanvas.width = cw;
tempCanvas.height = ch;
const tempCtx = tempCanvas.getContext('2d');
tempCtx.drawImage(canvas, 0, 0, cw, ch);
ctx.imageSmoothingEnabled = false;
ctx.drawImage(tempCanvas, 0, 0, cw, ch, 0, 0, w, h);
// Additional color crushing (macroblocks simulation)
imgData = ctx.getImageData(0, 0, w, h);
const crushedData = imgData.data;
for (let i = 0; i < crushedData.length; i += 4) {
crushedData[i] = Math.round(crushedData[i] / 16) * 16;
crushedData[i+1] = Math.round(crushedData[i+1] / 16) * 16;
crushedData[i+2] = Math.round(crushedData[i+2] / 16) * 16;
}
ctx.putImageData(imgData, 0, 0);
}
// Add User Interface Text, Metadata, and Subtitles
// OSD Top Indicators (Audio Track Info)
if (aestheticType.toUpperCase() === "VHS") {
const topOsdSize = Math.max(16, h * 0.05);
ctx.font = `bold ${topOsdSize}px "Courier New", Courier, monospace`;
ctx.textBaseline = 'top';
// Play text
ctx.fillStyle = '#0f0'; // Neon Green VHS text
ctx.textAlign = 'left';
ctx.fillText('PLAY ►', w * 0.05, h * 0.08);
// HIFI Audio text
ctx.fillStyle = '#fff';
ctx.textAlign = 'right';
ctx.fillText('SP HIFI AUDIO', w * 0.95, h * 0.08);
} else {
const topOsdSize = Math.max(14, h * 0.035);
ctx.font = `${topOsdSize}px Arial, sans-serif`;
ctx.textBaseline = 'top';
ctx.fillStyle = 'rgba(255, 255, 255, 0.7)';
ctx.textAlign = 'left';
ctx.fillText('TITLE 1 CHAPTER 4', w * 0.05, h * 0.05);
ctx.textAlign = 'right';
ctx.fillText('AUDIO 1/1 AC3', w * 0.95, h * 0.05);
}
// Subtitles (Language Dub Translator overlay)
const subSize = Math.max(20, h * 0.06);
ctx.font = `bold ${subSize}px "Arial", sans-serif`;
ctx.textAlign = 'center';
ctx.textBaseline = 'bottom';
ctx.lineWidth = Math.max(3, subSize * 0.15);
ctx.strokeStyle = '#000000';
ctx.fillStyle = '#f0db0f'; // Subtitle Yellow
// Parse "\n" to actual new lines
const lines = subtitleText.replace(/\\n/g, '\n').split('\n');
const startY = h * 0.9 - ((lines.length - 1) * (subSize * 1.3));
lines.forEach((line, index) => {
const yPos = startY + (index * subSize * 1.3);
ctx.strokeText(line, w / 2, yPos);
ctx.fillText(line, w / 2, yPos);
});
// Download Text By (Bottom Corner Watermark)
const wmSize = Math.max(12, h * 0.025);
ctx.font = `${wmSize}px "Arial", sans-serif`;
ctx.textAlign = 'right';
ctx.textBaseline = 'bottom';
ctx.fillStyle = 'rgba(255, 255, 255, 0.5)';
ctx.fillText(`Downloaded By: ${watermarkText}`, w - (w * 0.02), h - (h * 0.02));
return canvas;
}
Apply Changes