You can edit the below JavaScript code to customize the image tool.
Apply Changes
async function processImage(originalImg, mainText = "OUIJA", subText = "ORIGIN OF EVIL", noiseAmount = 20) {
// 1. Setup Canvas
const canvas = document.createElement("canvas");
const w = originalImg.width;
const h = originalImg.height;
canvas.width = w;
canvas.height = h;
const ctx = canvas.getContext("2d");
// 2. Load the classic serif "Cinzel" font to match the Ouija poster aesthetic
if (!document.getElementById('cinzel-font-ouija')) {
const link = document.createElement('link');
link.id = 'cinzel-font-ouija';
link.rel = 'stylesheet';
link.href = 'https://fonts.googleapis.com/css2?family=Cinzel:wght@600&display=swap';
document.head.appendChild(link);
}
// Wait for the font API to ensure font is usable in canvas before drawing
if (document.fonts && document.fonts.load) {
try {
await document.fonts.load('600 20px "Cinzel"');
} catch(e) {
console.warn("Font loading error, continuing with fallback:", e);
}
await document.fonts.ready;
} else {
// Fallback delay for older browsers
await new Promise(resolve => setTimeout(resolve, 800));
}
// 3. Draw base image with eerie glowing bloom effect
ctx.drawImage(originalImg, 0, 0, w, h);
// Only apply blur screen if filter is supported
if (typeof ctx.filter !== "undefined") {
ctx.globalCompositeOperation = "screen";
ctx.filter = `blur(${Math.max(2, w * 0.008)}px)`;
ctx.globalAlpha = 0.5;
ctx.drawImage(originalImg, 0, 0, w, h);
// Reset context
ctx.globalCompositeOperation = "source-over";
ctx.filter = "none";
ctx.globalAlpha = 1.0;
}
// 4. Vintage Horror Sepia / Golden Gradient Map & Noise integration
const imgData = ctx.getImageData(0, 0, w, h);
const data = imgData.data;
// Linear interpolation helper
const lerp = (start, end, t) => start + (end - start) * t;
const noiseLvl = Number(noiseAmount) || 0;
for (let i = 0; i < data.length; i += 4) {
const r = data[i];
const g = data[i+1];
const b = data[i+2];
// Calculate original luminance
let luma = 0.299 * r + 0.587 * g + 0.114 * b;
// High contrast adjustment for drastic, punchy movie poster look
luma = ((luma / 255 - 0.45) * 1.6 + 0.45) * 255;
luma = Math.max(0, Math.min(255, luma));
const t = luma / 255;
// Dark, eerie vintage color mapping
// Shadows: Deep greenish-black
// Midtones: Rich creeping amber/gold
// Highlights: Sickly pale bleached yellow
let nr, ng, nb;
if (t < 0.5) {
const t2 = t * 2;
nr = lerp(4, 165, t2);
ng = lerp(8, 115, t2);
nb = lerp(6, 50, t2);
} else {
const t2 = (t - 0.5) * 2;
nr = lerp(165, 250, t2);
ng = lerp(115, 235, t2);
nb = lerp(50, 205, t2);
}
// Cinematic noise pass
const noise = (Math.random() - 0.5) * noiseLvl;
data[i] = Math.max(0, Math.min(255, nr + noise));
data[i+1] = Math.max(0, Math.min(255, ng + noise));
data[i+2] = Math.max(0, Math.min(255, nb + noise));
}
ctx.putImageData(imgData, 0, 0);
// 5. Heavy Vignette to focus the center intensely
const vignetteOffset = Math.min(w, h);
const gradient = ctx.createRadialGradient(w/2, h/2, vignetteOffset * 0.2, w/2, h/2, vignetteOffset * 0.85);
gradient.addColorStop(0, 'rgba(0,0,0,0)');
gradient.addColorStop(0.5, 'rgba(0,0,0,0.3)');
gradient.addColorStop(1, 'rgba(0,0,0,0.95)');
ctx.fillStyle = gradient;
ctx.fillRect(0, 0, w, h);
// 6. Draw the Logo Style Text
// Custom function to draw text with very wide tracking (letter-spacing)
function drawSpacedText(ctx, text, centerX, y, letterSpacing) {
ctx.textAlign = "left";
let totalWidth = 0;
let widths = [];
for (let i = 0; i < text.length; i++) {
let cw = ctx.measureText(text[i]).width;
widths.push(cw);
totalWidth += cw;
}
totalWidth += letterSpacing * (text.length - 1);
let startX = centerX - totalWidth / 2;
for (let i = 0; i < text.length; i++) {
ctx.fillText(text[i], startX, y);
startX += widths[i] + letterSpacing;
}
return totalWidth;
}
ctx.textBaseline = "middle";
ctx.fillStyle = "#ffffff";
// Glowing text shadows
ctx.shadowColor = "rgba(250, 220, 160, 0.85)";
ctx.shadowBlur = w * 0.015;
// Draw Main Title Text (OUIJA)
const mainFontSize = Math.floor(w * 0.16);
const mainTextY = h * 0.75;
if (mainText) {
ctx.font = `600 ${mainFontSize}px "Cinzel", serif`;
const mainLetterSpacing = w * 0.04;
drawSpacedText(ctx, mainText.toUpperCase(), w/2, mainTextY, mainLetterSpacing);
}
// Draw Sub Title Text (ORIGIN OF EVIL)
if (subText) {
const subFontSize = Math.floor(w * 0.038);
const subTextY = mainTextY + mainFontSize * 0.65;
const subLetterSpacing = w * 0.02;
ctx.font = `600 ${subFontSize}px "Cinzel", serif`;
ctx.shadowBlur = w * 0.008; // subtle shadow for subtext
const subWidth = drawSpacedText(ctx, subText.toUpperCase(), w/2, subTextY, subLetterSpacing);
// Add framing vintage lines around subtext
const lineY = subTextY;
const lineLength = w * 0.12;
const linePadding = w * 0.035;
ctx.beginPath();
// Left flank
ctx.moveTo((w/2) - (subWidth/2) - linePadding - lineLength, lineY);
ctx.lineTo((w/2) - (subWidth/2) - linePadding, lineY);
// Right flank
ctx.moveTo((w/2) + (subWidth/2) + linePadding, lineY);
ctx.lineTo((w/2) + (subWidth/2) + linePadding + lineLength, lineY);
ctx.strokeStyle = "rgba(255, 255, 255, 0.8)";
ctx.lineWidth = Math.max(1.5, w * 0.002);
ctx.shadowBlur = 0; // Disable shadow for clean thin lines
ctx.stroke();
}
return canvas;
}
Apply Changes