You can edit the below JavaScript code to customize the image tool.
Apply Changes
async function processImage(originalImg, title = "SKY SCREAM", theme = "LIGHTS OUT", tagline = "PREPARE FOR THE RIDE OF YOUR LIFE", year = "2019") {
// 1. Dynamically load Google Fonts for the movie poster aesthetic
await new Promise((resolve) => {
const link = document.createElement('link');
link.href = 'https://fonts.googleapis.com/css2?family=Anton&family=Creepster&family=Oswald:wght@400;700&display=swap';
link.rel = 'stylesheet';
link.onload = async () => {
try {
// Ensure fonts are parsed and ready before drawing
await document.fonts.load('50px Creepster');
await document.fonts.load('100px Anton');
await document.fonts.load('24px Oswald');
resolve();
} catch (err) {
resolve(); // Proceed with system fallback fonts if it fails
}
};
link.onerror = () => resolve(); // Proceed if network blocks it
document.head.appendChild(link);
});
// 2. Setup Canvas strictly to Movie Poster Ratio (2:3)
const width = 800;
const height = 1200;
const canvas = document.createElement('canvas');
canvas.width = width;
canvas.height = height;
const ctx = canvas.getContext('2d');
// 3. Draw Background Image (Scale to Cover)
const scale = Math.max(width / originalImg.width, height / originalImg.height);
const imgW = originalImg.width * scale;
const imgH = originalImg.height * scale;
const imgX = (width - imgW) / 2;
const imgY = (height - imgH) / 2;
ctx.drawImage(originalImg, imgX, imgY, imgW, imgH);
// 4. Apply "Lights Out" Horror/Night Theme Overlay
ctx.globalCompositeOperation = 'multiply';
ctx.fillStyle = '#05101c'; // Deep dark night blue
ctx.fillRect(0, 0, width, height);
ctx.globalCompositeOperation = 'screen';
const moonGrad = ctx.createRadialGradient(width/2, 350, 20, width/2, 350, 600);
moonGrad.addColorStop(0, 'rgba(40, 80, 110, 0.45)');
moonGrad.addColorStop(1, 'rgba(0, 0, 0, 0)');
ctx.fillStyle = moonGrad;
ctx.fillRect(0, 0, width, height);
ctx.globalCompositeOperation = 'source-over';
// Vignette
const vigGrad = ctx.createRadialGradient(width/2, height/2, 200, width/2, height/2, 900);
vigGrad.addColorStop(0, 'rgba(0,0,0,0)');
vigGrad.addColorStop(1, 'rgba(0,0,0,0.98)');
ctx.fillStyle = vigGrad;
ctx.fillRect(0, 0, width, height);
// 5. Draw Distant Bats silhouettes
ctx.fillStyle = 'rgba(0,0,0,0.8)';
for(let i=0; i<25; i++) {
const bx = 100 + Math.random() * 600;
const by = 100 + Math.random() * 450;
const s = 1 + Math.random() * 1.5;
ctx.beginPath();
ctx.moveTo(bx, by);
ctx.quadraticCurveTo(bx + 10*s, by - 10*s, bx + 20*s, by - 2*s);
ctx.quadraticCurveTo(bx + 10*s, by - 5*s, bx, by + 3*s);
ctx.quadraticCurveTo(bx - 10*s, by - 5*s, bx - 20*s, by - 2*s);
ctx.quadraticCurveTo(bx - 10*s, by - 10*s, bx, by);
ctx.fill();
}
// 6. Draw Background Coaster Loop Silhouette
ctx.save();
const bgPath = new Path2D();
bgPath.moveTo(50, 1200);
bgPath.bezierCurveTo(300, 1000, 750, 850, 750, 500);
bgPath.bezierCurveTo(750, 150, 250, 150, 250, 500);
bgPath.bezierCurveTo(250, 850, 450, 1000, 900, 1200);
ctx.shadowBlur = 10;
ctx.shadowColor = 'rgba(0,0,0,0.8)';
ctx.lineCap = 'round';
// Track Spine
ctx.lineWidth = 8;
ctx.strokeStyle = '#020202';
ctx.stroke(bgPath);
// Track Cross-Ties (Ladder effect)
ctx.lineWidth = 26;
ctx.setLineDash([4, 18]);
ctx.strokeStyle = '#050505';
ctx.stroke(bgPath);
ctx.restore();
// 7. Render Movie Poster Typography
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
// Theme Subtitle (LIGHTS OUT)
ctx.font = '65px Creepster, Impact, cursive';
ctx.fillStyle = '#cc0000'; // Blood red
ctx.shadowColor = '#000000';
ctx.shadowBlur = 15;
ctx.shadowOffsetX = 3;
ctx.shadowOffsetY = 3;
ctx.fillText(theme.toUpperCase(), width/2, 220);
// Main Title Main (SKY SCREAM)
// Create cinematic metallic gradient
const textGrad = ctx.createLinearGradient(0, 260, 0, 400);
textGrad.addColorStop(0, '#ffffff');
textGrad.addColorStop(0.5, '#c0c0c0');
textGrad.addColorStop(1, '#666666');
ctx.font = '125px Anton, Impact, sans-serif';
ctx.fillStyle = textGrad;
ctx.shadowBlur = 25;
ctx.shadowOffsetX = 5;
ctx.shadowOffsetY = 5;
ctx.lineWidth = 4;
ctx.strokeStyle = '#000000';
ctx.strokeText(title.toUpperCase(), width/2, 340);
ctx.fillText(title.toUpperCase(), width/2, 340);
// Tagline
ctx.shadowBlur = 10;
ctx.font = '26px Oswald, Helvetica, sans-serif';
ctx.fillStyle = '#dddddd';
if ('letterSpacing' in ctx) ctx.letterSpacing = '10px';
ctx.fillText(tagline.toUpperCase(), width/2, 450);
if ('letterSpacing' in ctx) ctx.letterSpacing = '0px';
// Bottom Poster Credits & Year
ctx.font = 'bold 45px Anton, Impact, sans-serif';
ctx.fillStyle = '#cc0000';
ctx.fillText(`— ${year} —`, width/2, 1040);
ctx.font = '16px "Oswald", "Arial Narrow", sans-serif';
ctx.fillStyle = '#888888';
if ('letterSpacing' in ctx) ctx.letterSpacing = '2px';
const credits1 = "STARRING THE ULTIMATE THRILL SEEKERS DIRECTED BY ADRENALINE PRODUCED BY HOLIDAY PARK";
ctx.fillText(credits1, width/2, 1120);
const credits2 = "A LIGHTS OUT PRODUCTION SOUNDTRACK BY GRAVITY RATED R FOR EXTREME TERROR";
ctx.fillText(credits2, width/2, 1150);
if ('letterSpacing' in ctx) ctx.letterSpacing = '0px';
// 8. Draw Foreground Coaster Swoop
ctx.save();
const fgPath = new Path2D();
fgPath.moveTo(-50, 950);
fgPath.bezierCurveTo(200, 800, 600, 1100, 1000, 900);
ctx.shadowBlur = 25;
ctx.shadowColor = '#000000';
// FG Track Spine
ctx.lineWidth = 18;
ctx.strokeStyle = '#020202';
ctx.stroke(fgPath);
// FG Track Cross-Ties
ctx.lineWidth = 55;
ctx.setLineDash([8, 30]);
ctx.strokeStyle = '#010101';
ctx.stroke(fgPath);
ctx.restore();
// 9. Apply Cinematic Film Grain / Noise Overlay
const noiseCanvas = document.createElement('canvas');
noiseCanvas.width = width;
noiseCanvas.height = height;
const nCtx = noiseCanvas.getContext('2d');
const nData = nCtx.createImageData(width, height);
const dataRef = nData.data;
for (let i = 0; i < dataRef.length; i += 4) {
const val = Math.random() * 255;
dataRef[i] = val;
dataRef[i+1] = val;
dataRef[i+2] = val;
dataRef[i+3] = 18; // Very transparent noise
}
nCtx.putImageData(nData, 0, 0);
ctx.globalCompositeOperation = 'overlay';
ctx.drawImage(noiseCanvas, 0, 0);
ctx.globalCompositeOperation = 'source-over';
return canvas;
}
Apply Changes