You can edit the below JavaScript code to customize the image tool.
Apply Changes
function processImage(originalImg, subtitleText = "KURDISH DUB (Shirzad Sendi)", applyVHSEffect = 1, audioUrl = "") {
// Create wrapper container
const container = document.createElement("div");
container.style.position = "relative";
container.style.display = "inline-block";
container.style.maxWidth = "100%";
container.style.fontFamily = "Arial, sans-serif";
container.style.overflow = "hidden";
// Create and setup Canvas
const canvas = document.createElement("canvas");
const ctx = canvas.getContext("2d");
canvas.width = originalImg.width;
canvas.height = originalImg.height;
canvas.style.maxWidth = "100%";
canvas.style.height = "auto";
canvas.style.display = "block";
// Draw the original image onto the canvas
ctx.drawImage(originalImg, 0, 0);
// Apply Retro/Meme VHS Effect if enabled
if (Number(applyVHSEffect) === 1) {
// Red chromatic aberration simulation
ctx.globalAlpha = 0.4;
ctx.fillStyle = "rgba(255, 0, 0, 0.3)";
ctx.fillRect(0, 0, canvas.width, canvas.height);
ctx.translate(4, 0);
ctx.drawImage(originalImg, 0, 0);
ctx.translate(-4, 0);
ctx.globalAlpha = 1.0;
// Scanlines overlay
ctx.fillStyle = "rgba(0,0,0,0.15)";
for (let y = 0; y < canvas.height; y += 4) {
ctx.fillRect(0, y, canvas.width, 2);
}
// VHS Tracking errors (random static horizontal blocks)
for (let i = 0; i < 40; i++) {
ctx.fillStyle = Math.random() > 0.5 ? "rgba(255,255,255,0.25)" : "rgba(0,0,0,0.25)";
ctx.fillRect(
Math.random() * canvas.width,
Math.random() * canvas.height,
Math.random() * (canvas.width * 0.8),
Math.random() * 4 + 1
);
}
// Add standard visual VCR text interfaces
const vhsFontSize = Math.max(20, Math.floor(canvas.height * 0.05));
ctx.font = `${vhsFontSize}px monospace`;
ctx.fillStyle = "white";
ctx.textAlign = "left";
ctx.textBaseline = "top";
ctx.shadowColor = "black";
ctx.shadowBlur = 4;
ctx.fillText("PLAY ►", 30, 30);
const dateStr = "OCT. 24 1993"; // Classic retro meme date
ctx.textAlign = "right";
ctx.fillText(dateStr, canvas.width - 30, canvas.height - vhsFontSize - 30);
// Reset shadow for subsequent drawings
ctx.shadowBlur = 0;
}
// Render the Subtitle Overlay
if (subtitleText.trim() !== "") {
const fontSize = Math.max(30, Math.floor(canvas.height * 0.08));
ctx.font = `bold ${fontSize}px Arial, sans-serif`;
ctx.textAlign = "center";
ctx.textBaseline = "bottom";
const margin = fontSize;
const maxWidth = canvas.width * 0.9;
// Subtitle Edge / Stroke for readability
ctx.strokeStyle = "black";
ctx.lineWidth = Math.max(4, fontSize * 0.15);
ctx.lineJoin = "round";
ctx.strokeText(subtitleText, canvas.width / 2, canvas.height - margin, maxWidth);
// Subtitle Yellow Fill (Classic dubbing style)
ctx.fillStyle = "yellow";
ctx.fillText(subtitleText, canvas.width / 2, canvas.height - margin, maxWidth);
}
container.appendChild(canvas);
// Overlay Play Button
const playBtn = document.createElement('div');
playBtn.innerHTML = '🔊 PLAY DUB';
playBtn.style.position = 'absolute';
playBtn.style.top = '50%';
playBtn.style.left = '50%';
playBtn.style.transform = 'translate(-50%, -50%)';
playBtn.style.fontSize = '24px';
playBtn.style.fontWeight = 'bold';
playBtn.style.color = 'white';
playBtn.style.cursor = 'pointer';
playBtn.style.textShadow = '2px 2px 4px rgba(0,0,0,0.8)';
playBtn.style.background = 'rgba(210, 0, 0, 0.85)';
playBtn.style.padding = '15px 30px';
playBtn.style.borderRadius = '8px';
playBtn.style.border = '2px solid white';
playBtn.style.boxShadow = '0 0 20px rgba(0,0,0,0.6)';
playBtn.style.transition = 'all 0.2s ease-in-out';
playBtn.style.userSelect = 'none';
playBtn.onmouseenter = () => {
playBtn.style.transform = 'translate(-50%, -50%) scale(1.05)';
playBtn.style.background = 'rgba(255, 30, 30, 1)';
};
playBtn.onmouseleave = () => {
playBtn.style.transform = 'translate(-50%, -50%) scale(1)';
playBtn.style.background = 'rgba(210, 0, 0, 0.85)';
};
container.appendChild(playBtn);
// Web Audio Background Setup
let isPlaying = false;
let customAudio = null;
if (audioUrl.trim() !== "") {
customAudio = new Audio(audioUrl);
}
// Simulated deep dramatic intro effect for dubs using Web Audio API
function playDramaticSwoosh() {
try {
const AudioContext = window.AudioContext || window.webkitAudioContext;
if (!AudioContext) return;
const audioCtx = new AudioContext();
const osc = audioCtx.createOscillator();
const gain = audioCtx.createGain();
osc.type = 'square';
osc.frequency.setValueAtTime(150, audioCtx.currentTime);
osc.frequency.exponentialRampToValueAtTime(10, audioCtx.currentTime + 1.0);
gain.gain.setValueAtTime(0.5, audioCtx.currentTime);
gain.gain.exponentialRampToValueAtTime(0.01, audioCtx.currentTime + 1.0);
osc.connect(gain);
gain.connect(audioCtx.destination);
osc.start();
osc.stop(audioCtx.currentTime + 1.0);
} catch (e) {
console.warn("Web Audio API not supported", e);
}
}
// Hook up Play Event
playBtn.addEventListener('click', () => {
if (isPlaying) return;
isPlaying = true;
playBtn.style.opacity = '0.6';
playBtn.innerHTML = '🔊 PLAYING...';
playBtn.style.pointerEvents = 'none';
const resetAudioUI = () => {
isPlaying = false;
playBtn.style.opacity = '1';
playBtn.innerHTML = '🔊 PLAY DUB';
playBtn.style.pointerEvents = 'auto';
};
if (customAudio) {
customAudio.play().catch(err => {
console.error("Audio playback error:", err);
resetAudioUI();
});
customAudio.onended = resetAudioUI;
} else {
// Initiate Web Audio Synth Effect
playDramaticSwoosh();
// Initiate Speech API mimicking the loud dubbed voice meme
if ('speechSynthesis' in window) {
window.speechSynthesis.cancel(); // Clear queued utterances
// Exclude parentheticals text (e.g. "Kurdish Dub (Shirzad Sendi)" -> speaks just "Kurdish Dub")
const textToSpeak = subtitleText.replace(/\([^)]*\)/g, '').trim() || "Kurdish Dub Audio Check";
const msg = new SpeechSynthesisUtterance(textToSpeak);
// Throttle rate & set deep pitch to simulate cinematic dubbing narrator
msg.lang = 'ar-SA'; // Uses Arabic phonetics/voice module default if Kurdish unavailable natively
msg.rate = 0.8;
msg.pitch = 0.3;
msg.volume = 1.0;
let backupTimeout = null;
msg.onend = () => {
clearTimeout(backupTimeout);
resetAudioUI();
};
msg.onerror = () => {
clearTimeout(backupTimeout);
resetAudioUI();
};
// Give synthesizer a 400ms delay allowing the swoosh hit effect to play fully
setTimeout(() => {
window.speechSynthesis.speak(msg);
// Backup timeout to recover button interface if the API hangs
backupTimeout = setTimeout(() => {
window.speechSynthesis.cancel();
resetAudioUI();
}, 10000);
}, 400);
} else {
// Fallback for Unsupported Browsers
setTimeout(resetAudioUI, 1500);
}
}
});
return container;
}
Apply Changes