You can edit the below JavaScript code to customize the image tool.
Apply Changes
async function processImage(
originalImg,
title = "THE CONJURING",
subtitle = "LAST RITES",
tagline = "BASED ON THE TRUE CASE FILES OF ED & LORRAINE WARREN",
releaseText = "IN THEATERS 2025",
tintStyle = "cold"
) {
// 1. Create and configure the canvas for a standard movie poster ratio (2:3)
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
canvas.width = 800;
canvas.height = 1200;
// 2. Dynamically load the 'Cinzel' Google Font (perfect for horror/Conjuring style)
const fontUrl = 'https://fonts.googleapis.com/css2?family=Cinzel:wght@400;700&display=swap';
if (!document.querySelector(`link[href="${fontUrl}"]`)) {
const link = document.createElement('link');
link.rel = 'stylesheet';
link.href = fontUrl;
document.head.appendChild(link);
}
// Wait for the font to load to ensure it renders correctly on the canvas
try {
await document.fonts.load('70px "Cinzel"');
} catch (e) {
console.warn('Font loading failed or time out, falling back to serif.', e);
}
// 3. Draw the original image using "object-fit: cover" logic
const scale = Math.max(canvas.width / originalImg.width, canvas.height / originalImg.height);
const w = originalImg.width * scale;
const h = originalImg.height * scale;
const x = (canvas.width - w) / 2;
const y = (canvas.height - h) / 2;
ctx.fillStyle = '#000000';
ctx.fillRect(0, 0, canvas.width, canvas.height);
ctx.drawImage(originalImg, x, y, w, h);
// 4. Apply Horror Cinematic Image Processing (Pixel Manipulation)
const imgData = ctx.getImageData(0, 0, canvas.width, canvas.height);
const data = imgData.data;
for (let i = 0; i < data.length; i += 4) {
let r = data[i];
let g = data[i + 1];
let b = data[i + 2];
// Calculate luma (grayscale conversion)
let luma = 0.2126 * r + 0.7152 * g + 0.0722 * b;
// Increase contrast dramatically for a dark, moody feel
luma = (luma - 128) * 1.5 + 85;
// Apply a color tint based on the chosen style
let tr, tg, tb;
if (tintStyle.toLowerCase() === "blood") {
tr = luma * 1.15; tg = luma * 0.7; tb = luma * 0.7;
} else if (tintStyle.toLowerCase() === "warm") {
tr = luma * 1.05; tg = luma * 0.95; tb = luma * 0.75;
} else {
// "cold" (default Conjuring cinematic look)
tr = luma * 0.75; tg = luma * 0.9; tb = luma * 1.05;
}
// Add cinematic film grain (noise)
let noise = (Math.random() - 0.5) * 45;
data[i] = Math.min(255, Math.max(0, tr + noise));
data[i + 1] = Math.min(255, Math.max(0, tg + noise));
data[i + 2] = Math.min(255, Math.max(0, tb + noise));
}
ctx.putImageData(imgData, 0, 0);
// 5. Add Vignette (Darkening the edges)
const vignetteGrad = ctx.createRadialGradient(
canvas.width / 2, canvas.height / 2, canvas.height * 0.2,
canvas.width / 2, canvas.height / 2, canvas.height * 0.75
);
vignetteGrad.addColorStop(0, 'rgba(0, 0, 0, 0)');
vignetteGrad.addColorStop(0.5, 'rgba(0, 0, 0, 0.4)');
vignetteGrad.addColorStop(1, 'rgba(0, 0, 0, 0.95)');
ctx.fillStyle = vignetteGrad;
ctx.fillRect(0, 0, canvas.width, canvas.height);
// 6. Add Bottom Gradient Fade (To make text readable)
const bottomGrad = ctx.createLinearGradient(0, canvas.height * 0.5, 0, canvas.height);
bottomGrad.addColorStop(0, 'rgba(0,0,0,0)');
bottomGrad.addColorStop(0.6, 'rgba(0,0,0,0.85)');
bottomGrad.addColorStop(1, 'rgba(0,0,0,1)');
ctx.fillStyle = bottomGrad;
ctx.fillRect(0, 0, canvas.width, canvas.height);
// 7. Add Subtle Distressed Border
ctx.strokeStyle = 'rgba(255, 255, 255, 0.08)';
ctx.lineWidth = 2;
ctx.strokeRect(30, 30, canvas.width - 60, canvas.height - 60);
// 8. Draw Typography
ctx.textAlign = 'center';
ctx.shadowColor = 'rgba(0, 0, 0, 0.9)';
ctx.shadowBlur = 15;
ctx.shadowOffsetX = 0;
ctx.shadowOffsetY = 4;
const setLetterSpacing = (spacing) => {
if ('letterSpacing' in ctx) {
ctx.letterSpacing = spacing;
}
};
// Tagline (Warren True Case Files)
ctx.font = '400 16px "Cinzel", serif';
ctx.fillStyle = '#b5b5b5';
setLetterSpacing('5px');
ctx.fillText(tagline.toUpperCase(), canvas.width / 2, 830);
// Main Title
ctx.font = '700 80px "Cinzel", serif';
ctx.fillStyle = '#ffffff';
setLetterSpacing('14px');
ctx.fillText(title.toUpperCase(), canvas.width / 2, 920);
// Subtitle (Last Rites)
ctx.font = '400 45px "Cinzel", serif';
ctx.fillStyle = '#c4b69d'; // Sickly pale yellow/white
setLetterSpacing('22px');
ctx.fillText(subtitle.toUpperCase(), canvas.width / 2, 1000);
// Add a separator line
ctx.shadowBlur = 0;
ctx.fillStyle = 'rgba(255, 255, 255, 0.3)';
ctx.fillRect(canvas.width / 2 - 150, 1060, 300, 1);
// Release Date Text
ctx.shadowBlur = 10;
ctx.font = '700 24px "Cinzel", serif';
ctx.fillStyle = '#9e1b1b'; // Blood red
setLetterSpacing('8px');
ctx.fillText(releaseText.toUpperCase(), canvas.width / 2, 1120);
return canvas;
}
Apply Changes