Please bookmark this page to avoid losing your image tool!

Image Superhero Movie Poster Template

(Free & Supports Bulk Upload)

Drag & drop your images here or

The result will appear here...
You can edit the below JavaScript code to customize the image tool.
async function processImage(
    originalImg,
    titleText = "SUPERHERO RISING",
    taglineText = "THEIR TIME IS NOW",
    bottomText = "EXPERIENCE IT IN CINEMAS",
    titleFont = "Anton", 
    bodyFont = "Arial", 
    titleColor = "#FFD700", // Gold
    titleOutlineColor = "#000000",
    taglineColor = "#FFFFFF",
    bottomTextColor = "#E0E0E0", // Light gray
    bgColorTop = "#0A102A", // Dark Navy Blue-ish Blackstone
    bgColorBottom = "#000000", // Black
    imageGlowAmount = 15, 
    imageGlowColor = "#FFFFFF4D" // Semi-transparent white (30% opacity, e.g. #RRGGBBAA)
) {

    const FONT_URLS = {
        "Anton": "https://fonts.gstatic.com/s/anton/v25/1Ptgg87LROyAm0K08iAcA.woff2",
        "Bebas Neue": "https://fonts.gstatic.com/s/bebasneue/v9/JTUSjIg69CK48gW7PXoo9Wlhyw.woff2",
    };

    async function _loadFont(fontFamily, fontUrl) {
        if (!fontFamily || !fontUrl) return;
        
        if (document.fonts && typeof document.fonts.check === 'function' && document.fonts.check(`12px "${fontFamily}"`)) {
            // console.log(`Font "${fontFamily}" already available.`);
            return;
        }
        
        if (typeof FontFace === 'function' && document.fonts && typeof document.fonts.add === 'function') {
            try {
                const font = new FontFace(fontFamily, `url(${fontUrl}) format('woff2')`, { display: 'swap' });
                await font.load();
                document.fonts.add(font);
                // console.log(`FontFace: Font "${fontFamily}" loaded from ${fontUrl}`);
            } catch (e) {
                console.error(`FontFace: Failed to load font "${fontFamily}" from ${fontUrl}:`, e);
                // Font will fallback to system default in canvas drawing if this fails
            }
        } else {
            // Fallback for very old browsers or environments where FontFace API might be disabled/problematic.
            // console.warn(`FontFace API or document.fonts.add not fully supported. Attempting CSS @font-face for ${fontFamily}.`);
            const styleId = `font-loader-style-${fontFamily.replace(/\s+/g, '-')}`;
            if (!document.getElementById(styleId)) {
                const style = document.createElement('style');
                style.id = styleId;
                style.textContent = `
                    @font-face {
                        font-family: '${fontFamily}';
                        src: url('${fontUrl}') format('woff2');
                        font-display: swap; /* Crucial for behavior */
                    }
                `;
                document.head.appendChild(style);
                 // For this fallback, we can't reliably wait, so we proceed.
                 // font-display: swap will help browser to render with fallback then switch.
            }
        }
    }

    // --- Canvas Setup ---
    const CANVAS_WIDTH = 600;
    const CANVAS_HEIGHT = 900;

    const canvas = document.createElement('canvas');
    canvas.width = CANVAS_WIDTH;
    canvas.height = CANVAS_HEIGHT;
    const ctx = canvas.getContext('2d');

    // --- Font Loading ---
    if (titleFont && FONT_URLS[titleFont]) {
        await _loadFont(titleFont, FONT_URLS[titleFont]);
    }
    // Assuming bodyFont (e.g., Arial) is a system font and doesn't need explicit loading.
    // If bodyFont could also be a web font from CDN, similar loading logic would be needed here too.
    // e.g. if (bodyFont && FONT_URLS[bodyFont]) { await _loadFont(bodyFont, FONT_URLS[bodyFont]); }


    // --- Draw Background ---
    const bgGradient = ctx.createLinearGradient(0, 0, 0, canvas.height);
    bgGradient.addColorStop(0, bgColorTop);
    bgGradient.addColorStop(1, bgColorBottom);
    ctx.fillStyle = bgGradient;
    ctx.fillRect(0, 0, canvas.width, canvas.height);

    // --- Layout Constants & Calculations ---
    const titleBaseY = canvas.height * 0.20; // Y position for the middle of the title
    const titleFontSize = Math.floor(canvas.height * 0.10);

    const bottomTextBaseY = canvas.height * 0.95; // Y position for the bottom of the bottom text
    
    // Approximate image vertical positioning based on title and bottom text
    // Make space for title: title's top would be roughly titleBaseY - titleFontSize / 2. Bottom: titleBaseY + titleFontSize / 2.
    const imgMarginFromTitle = canvas.height * 0.03;
    const imgAreaTop = titleBaseY + (titleFontSize / 2) + imgMarginFromTitle;
    
    // Make space for tagline and bottom text
    // Tagline rough height + margin, bottom text rough height + margin
    const estimatedSpaceForLowerTexts = canvas.height * 0.18; 
    const imgAreaBottom = bottomTextBaseY - estimatedSpaceForLowerTexts;

    const imgPaddingHorizontal = canvas.width * 0.08;
    const imgAvailableWidth = canvas.width - 2 * imgPaddingHorizontal;
    const imgAvailableHeight = imgAreaBottom - imgAreaTop;

    let imgDisplayWidth = 0;
    let imgDisplayHeight = 0;
    let imgDrawX = 0;
    let imgDrawY = imgAreaTop; // Default starting Y for image

    if (originalImg && originalImg.width > 0 && originalImg.height > 0 && imgAvailableWidth > 0 && imgAvailableHeight > 0) {
        const aspect = originalImg.width / originalImg.height;
        
        if ((imgAvailableWidth / aspect) <= imgAvailableHeight) {
            // Width constrained: fit to available width
            imgDisplayWidth = imgAvailableWidth;
            imgDisplayHeight = imgDisplayWidth / aspect;
        } else {
            // Height constrained: fit to available height
            imgDisplayHeight = imgAvailableHeight;
            imgDisplayWidth = imgDisplayHeight * aspect;
        }

        imgDrawX = (canvas.width - imgDisplayWidth) / 2;
        // Center the image vertically in its allocated space
        imgDrawY = imgAreaTop + (imgAvailableHeight - imgDisplayHeight) / 2; 
    
        ctx.save();
        if (imageGlowAmount > 0 && imageGlowColor && imageGlowColor !== 'none') {
            try { // Validate color to prevent errors if malformed
                ctx.shadowColor = imageGlowColor; 
                ctx.shadowBlur = imageGlowAmount;
            } catch (e) {
                console.warn("Invalid imageGlowColor:", imageGlowColor);
                // Proceed without shadow if color is invalid
            }
        }
        ctx.drawImage(originalImg, imgDrawX, imgDrawY, imgDisplayWidth, imgDisplayHeight);
        ctx.restore(); // Clear shadow effects
    } else {
        // If no image or invalid image, use a placeholder Y for tagline calculation later
        imgDrawY = canvas.height * 0.4; // Mid-point fallback if image isn't drawn
        imgDisplayHeight = canvas.height * 0.3; // Placeholder height
    }


    // --- Draw Title ---
    ctx.font = `${titleFontSize}px "${titleFont}", Impact, "Franklin Gothic Medium", "Arial Narrow", Arial, sans-serif`;
    ctx.textAlign = 'center';
    ctx.textBaseline = 'middle'; 

    const maxTitleWidth = canvas.width * 0.90; // Max width before text scaling occurs

    if (titleOutlineColor && titleOutlineColor !== 'none' && titleOutlineColor.trim() !== "") {
        ctx.strokeStyle = titleOutlineColor;
        ctx.lineWidth = Math.max(1, titleFontSize / 18); 
        ctx.strokeText(titleText.toUpperCase(), canvas.width / 2, titleBaseY, maxTitleWidth);
    }
    ctx.fillStyle = titleColor;
    ctx.fillText(titleText.toUpperCase(), canvas.width / 2, titleBaseY, maxTitleWidth);


    // --- Draw Tagline ---
    const taglineFontSize = Math.floor(canvas.height * 0.032);
    ctx.font = `bold ${taglineFontSize}px "${bodyFont}", "Helvetica Neue", Helvetica, Arial, sans-serif`;
    ctx.fillStyle = taglineColor;
    ctx.textBaseline = 'top';
    
    // Position tagline below the image (or its placeholder area if no image)
    const taglineY = (imgDrawY + imgDisplayHeight) + canvas.height * 0.04; 
    const maxTaglineWidth = canvas.width * 0.80;
    ctx.fillText(taglineText.toUpperCase(), canvas.width / 2, taglineY, maxTaglineWidth);


    // --- Draw Bottom Text (e.g., Release Info) ---
    const bottomTextFontSize = Math.floor(canvas.height * 0.025);
    ctx.font = `${bottomTextFontSize}px "${bodyFont}", "Helvetica Neue", Helvetica, Arial, sans-serif`;
    ctx.fillStyle = bottomTextColor;
    ctx.textBaseline = 'bottom'; 
    const maxBottomTextWidth = canvas.width * 0.9;
    ctx.fillText(bottomText.toUpperCase(), canvas.width / 2, bottomTextBaseY, maxBottomTextWidth);

    return canvas;
}

Free Image Tool Creator

Can't find the image tool you're looking for?
Create one based on your own needs now!

Description

The Image Superhero Movie Poster Template tool allows users to create visually appealing and customized superhero movie posters. Users can upload an image and automatically generate a poster featuring a title, tagline, and bottom text, all styled with various font choices and colors. Ideal for filmmakers, fans, or anyone looking to promote a superhero-themed event, the tool provides an easy way to craft professional-looking posters that can be shared online or printed for promotional use.

Leave a Reply

Your email address will not be published. Required fields are marked *