Please bookmark this page to avoid losing your image tool!

Image Magazine Cover Template Creator

(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,
    // --- Canvas Settings ---
    canvasWidth = 600,
    canvasAspectRatio = "3:4", // Format "width:height", e.g., "3:4" for portrait

    // --- Magazine Title ---
    magazineTitle = "YOUR MAGAZINE",
    magazineTitleFont = "Bebas Neue",
    magazineTitleFontUrl = "https://fonts.gstatic.com/s/bebasneue/v9/JTUSjIg69CK48gW7PXoo9Wlhyw.woff2",
    magazineTitleFallbackFont = "Impact, sans-serif",
    magazineTitleSizeRatio = 0.15, // Relative to canvas width
    magazineTitleColor = "white",
    magazineTitleStrokeColor = "rgba(0,0,0,0.6)",
    magazineTitleStrokeWidth = 3, // Pixels
    magazineTitleYRatio = 0.12, // Y position of text vertical center, from top (ratio of canvas height)
    magazineTitleAlign = "center", // 'left', 'center', 'right'
    magazineTitleXMarginRatio = 0.05, // Margin from L/R edge if align is left/right (ratio of canvas width)

    // --- Main Headline ---
    headline = "AMAZING CONTENT INSIDE!",
    headlineFont = "Anton",
    headlineFontUrl = "https://fonts.gstatic.com/s/anton/v23/1Ptgg87LROyWN4o4CmSKZmNB.woff2",
    headlineFallbackFont = "'Arial Black', Gadget, sans-serif",
    headlineSizeRatio = 0.07, // Relative to canvas width
    headlineColor = "yellow",
    headlineBgColor = "rgba(200, 0, 0, 0.75)", // Example: Red banner background
    headlineYRatio = 0.45, // Y position of the headline's vertical center (ratio of canvas height)
    headlineAlign = "center", // 'left', 'center', 'right'
    headlineXMarginRatio = 0.05, // Margin for L/R alignment
    headlineBgFullWidth = true, // If true, BG spans canvas width. If false and centered, fits text.
    headlineBgPaddingRatio = 0.25, // Padding for BG around text, relative to font size

    // --- Sub-Headlines / Teasers ---
    subHeadlines = "• Exclusive: The Full Story!\n• Top 10 New Discoveries\n• Stunning Photography Section", // Separate lines with \n
    subFont = "Arial, sans-serif",
    subFontUrl = "", // Arial is web-safe, no URL needed
    subFallbackFont = "sans-serif",
    subSizeRatio = 0.03, // Relative to canvas width
    subColor = "white",
    subBgColor = "rgba(0,0,0,0.4)", // Optional subtle background for each line; empty string for no background
    subAlign = "left", // 'left', 'center', 'right'
    subXRatio = 0.05, // If left: margin from left. If right: margin from right. If center: X position (0.5 for true center)
    subStartYRatio = 0.25, // Y position of the top of the first sub-headline
    subLineHeightRatio = 1.4, // Line height relative to sub-headline font size
    subBgPaddingRatio = 0.2, // Padding for sub-headline BG

    // --- Footer ---
    footerTextLeft = "MARCH 2024 | VOL. 1, ISSUE 3",
    footerTextRight = "$5.99 USD",
    footerFont = "Arial, sans-serif",
    footerFontUrl = "",
    footerFallbackFont = "sans-serif",
    footerSizeRatio = 0.025, // Relative to canvas width
    footerColor = "white",
    footerMarginRatio = 0.03, // Margin from L/R edges and bottom

    // --- Barcode ---
    barcodeText = "9771234567003",
    barcodeBgColor = "white",
    barcodeColor = "black",
    barcodeHeightRatio = 0.07, // Relative to canvas height
    barcodeWidthRatio = 0.12, // Relative to canvas width
    barcodeXAlign = "left", // 'left' or 'right', relative to footerMarginRatio
    barcodeBottomAlignYRatio = 0.08 // Distance from canvas bottom to barcode bottom edge
) {

    const loadFont = async (fontName, fontUrl, fallbackFont) => {
        if (!fontName || fontName.toLowerCase() === 'inherit' || fontName.toLowerCase() === 'sans-serif' || fontName.toLowerCase() === 'serif' || fontName.toLowerCase() === 'monospace') { // common generic fallbacks
             return fallbackFont; // Use fallback directly if fontName is generic
        }
        if (!fontUrl) return `"${fontName}", ${fallbackFont}`;
        try {
            const font = new FontFace(fontName, `url(${fontUrl})`);
            await font.load();
            document.fonts.add(font);
            return `"${fontName}", ${fallbackFont}`;
        } catch (e) {
            console.warn(`Failed to load font ${fontName} from ${fontUrl}. Using fallback. Error:`, e);
            return fallbackFont;
        }
    };

    const [
        loadedMagazineTitleFontFamily,
        loadedHeadlineFontFamily,
        loadedSubFontFamily,
        loadedFooterFontFamily
    ] = await Promise.all([
        loadFont(magazineTitleFont, magazineTitleFontUrl, magazineTitleFallbackFont),
        loadFont(headlineFont, headlineFontUrl, headlineFallbackFont),
        loadFont(subFont, subFontUrl, subFallbackFont),
        loadFont(footerFont, footerFontUrl, footerFallbackFont)
    ]);

    const canvas = document.createElement('canvas');
    const ctx = canvas.getContext('2d');

    const ratioParts = canvasAspectRatio.split(':').map(Number);
    if (ratioParts.length !== 2 || isNaN(ratioParts[0]) || isNaN(ratioParts[1]) || ratioParts[0] <= 0 || ratioParts[1] <= 0) {
        console.warn("Invalid canvasAspectRatio format. Using 3:4 default.");
        canvas.height = canvasWidth * (4 / 3);
    } else {
        canvas.height = canvasWidth * (ratioParts[1] / ratioParts[0]);
    }
    canvas.width = canvasWidth;

    // Draw background image (cover and center)
    const imgAspectRatio = originalImg.width / originalImg.height;
    const canvasAspect = canvas.width / canvas.height;
    let drawWidth, drawHeight, offsetX, offsetY;

    if (imgAspectRatio > canvasAspect) {
        drawHeight = canvas.height;
        drawWidth = drawHeight * imgAspectRatio;
        offsetX = (canvas.width - drawWidth) / 2;
        offsetY = 0;
    } else {
        drawWidth = canvas.width;
        drawHeight = drawWidth / imgAspectRatio;
        offsetX = 0;
        offsetY = (canvas.height - drawHeight) / 2;
    }
    ctx.drawImage(originalImg, offsetX, offsetY, drawWidth, drawHeight);

    // Helper for X position based on alignment
    const getTextX = (align, totalWidth, marginRatio) => {
        const margin = totalWidth * marginRatio;
        if (align === 'left') return margin;
        if (align === 'center') return totalWidth / 2;
        if (align === 'right') return totalWidth - margin;
        return totalWidth / 2;
    };
    
    // --- Magazine Title ---
    if (magazineTitle) {
        const fontSize = canvas.width * magazineTitleSizeRatio;
        ctx.font = `bold ${fontSize}px ${loadedMagazineTitleFontFamily}`;
        ctx.fillStyle = magazineTitleColor;
        ctx.textAlign = magazineTitleAlign;
        ctx.textBaseline = 'middle';
        
        const titleX = getTextX(magazineTitleAlign, canvas.width, magazineTitleXMarginRatio);
        const titleY = canvas.height * magazineTitleYRatio;

        if (magazineTitleStrokeWidth > 0 && magazineTitleStrokeColor) {
            ctx.strokeStyle = magazineTitleStrokeColor;
            ctx.lineWidth = magazineTitleStrokeWidth;
            ctx.strokeText(magazineTitle.toUpperCase(), titleX, titleY);
        }
        ctx.fillText(magazineTitle.toUpperCase(), titleX, titleY);
    }

    // --- Main Headline ---
    if (headline) {
        const fontSize = canvas.width * headlineSizeRatio;
        ctx.font = `bold ${fontSize}px ${loadedHeadlineFontFamily}`;
        ctx.textAlign = headlineAlign;
        ctx.textBaseline = 'middle';
        
        const headlineTextX = getTextX(headlineAlign, canvas.width, headlineXMarginRatio);
        const headlineTextY = canvas.height * headlineYRatio;

        if (headlineBgColor) {
            const textMetrics = ctx.measureText(headline.toUpperCase());
            const textHeightEst = fontSize; 
            const padding = fontSize * headlineBgPaddingRatio;
            const bgHeight = textHeightEst + padding * 2;
            let bgWidth = canvas.width;
            let bgX = 0;

            if (!headlineBgFullWidth && headlineAlign === 'center') {
                bgWidth = textMetrics.width + padding * 2;
                bgX = headlineTextX - bgWidth / 2;
            } else if (!headlineBgFullWidth && headlineAlign === 'left') {
                bgWidth = textMetrics.width + padding * 2;
                bgX = headlineTextX - padding; // headlineTextX is already margin
            } else if (!headlineBgFullWidth && headlineAlign === 'right') {
                 bgWidth = textMetrics.width + padding * 2;
                 bgX = headlineTextX + padding - bgWidth; // headlineTextX is (canvas.width - margin)
            }
            // else, full width banner (bgX=0, bgWidth=canvas.width)
            
            const bgY = headlineTextY - bgHeight / 2;
            ctx.fillStyle = headlineBgColor;
            ctx.fillRect(bgX, bgY, bgWidth, bgHeight);
        }
        
        ctx.fillStyle = headlineColor;
        ctx.fillText(headline.toUpperCase(), headlineTextX, headlineTextY);
    }

    // --- Sub-Headlines ---
    if (subHeadlines) {
        const lines = subHeadlines.split('\n').filter(line => line.trim() !== '');
        if (lines.length > 0) {
            const fontSize = canvas.width * subSizeRatio;
            ctx.font = `${fontSize}px ${loadedSubFontFamily}`;
            ctx.textAlign = subAlign;
            ctx.textBaseline = 'top';

            let currentY = canvas.height * subStartYRatio;
            const lineHeight = fontSize * subLineHeightRatio;
            const padding = fontSize * subBgPaddingRatio;
            
            let actualSubX;
            if (subAlign === 'left') {
                actualSubX = canvas.width * subXRatio;
            } else if (subAlign === 'right') {
                actualSubX = canvas.width * (1 - subXRatio); // subXRatio is margin from right
            } else { // center
                actualSubX = canvas.width * subXRatio; // subXRatio should be 0.5 for true center
            }

            for (const line of lines) {
                if (subBgColor) {
                    const textMetrics = ctx.measureText(line);
                    const textWidth = textMetrics.width;
                    const bgH = fontSize + padding * 2;
                    const bgY = currentY - padding;
                    let bgX, bgW = textWidth + padding * 2;

                    if (subAlign === 'left') {
                        bgX = actualSubX - padding;
                    } else if (subAlign === 'right') {
                        bgX = actualSubX - textWidth - padding;
                    } else { // center
                        bgX = actualSubX - textWidth/2 - padding;
                    }
                    ctx.fillStyle = subBgColor;
                    ctx.fillRect(bgX, bgY, bgW, bgH);
                }
                ctx.fillStyle = subColor;
                ctx.fillText(line, actualSubX, currentY);
                currentY += lineHeight;
            }
        }
    }
    
    // --- Footer Text ---
    const footerSideMarginPx = canvas.width * footerMarginRatio;
    const footerBottomMarginPx = canvas.height * footerMarginRatio;

    if (footerTextLeft || footerTextRight) {
        const fontSize = canvas.width * footerSizeRatio;
        ctx.font = `${fontSize}px ${loadedFooterFontFamily}`;
        ctx.fillStyle = footerColor;
        ctx.textBaseline = 'bottom';
        const footerY = canvas.height - footerBottomMarginPx;

        if (footerTextLeft) {
            ctx.textAlign = 'left';
            ctx.fillText(footerTextLeft, footerSideMarginPx, footerY);
        }
        if (footerTextRight) {
            ctx.textAlign = 'right';
            ctx.fillText(footerTextRight, canvas.width - footerSideMarginPx, footerY);
        }
    }

    // --- Barcode ---
    if (barcodeText) {
        const bcHeight = canvas.height * barcodeHeightRatio;
        const bcWidth = canvas.width * barcodeWidthRatio;
        
        const bcBottomYPos = canvas.height - (canvas.height * barcodeBottomAlignYRatio);
        const bcY = bcBottomYPos - bcHeight;
        
        let bcX;
        if (barcodeXAlign === 'left') {
            bcX = footerSideMarginPx; // Align with footer text margin
        } else { // 'right'
            bcX = canvas.width - footerSideMarginPx - bcWidth;
        }

        ctx.fillStyle = barcodeBgColor;
        ctx.fillRect(bcX, bcY, bcWidth, bcHeight);

        ctx.fillStyle = barcodeColor;
        const barPadding = bcWidth * 0.05;
        let currentX = bcX + barPadding;
        while(currentX < bcX + bcWidth - barPadding) {
            const barWidthValue = Math.max(1, Math.random() * 2.5 + 1); // Random width 1-3.5px
            if (currentX + barWidthValue <= bcX + bcWidth - barPadding) {
                 if (Math.random() > 0.15) { // 85% chance to draw bar
                    const barHeightFactor = Math.random() * 0.2 + 0.75; // Varying height (75-95%)
                    ctx.fillRect(currentX, bcY + bcHeight * 0.08, barWidthValue, bcHeight * 0.7 * barHeightFactor);
                 }
            }
            currentX += barWidthValue + Math.max(1, Math.random() * 1.5); // Random spacing 1-2.5px
        }
        
        const textFontSize = Math.max(6, Math.min(bcHeight * 0.18, (bcWidth * 0.9) / (barcodeText.length * 0.6)));
        ctx.font = `bold ${textFontSize}px ${loadedFooterFontFamily}`;
        ctx.textAlign = 'center';
        ctx.textBaseline = 'bottom'; 
        ctx.fillText(barcodeText, bcX + bcWidth / 2, bcY + bcHeight - (bcHeight * 0.05));
    }

    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 Magazine Cover Template Creator is an online tool designed to help users create custom magazine covers by combining images and text elements. Users can upload their own images and utilize templates to add a magazine title, headlines, sub-headlines, footer information, and a barcode. This tool is ideal for graphic designers, marketing professionals, or anyone looking to produce visually appealing magazine cover designs for print or digital publications. With adjustable parameters such as font styles, colors, and layout settings, users can personalize their covers to align with their brand or creative vision.

Leave a Reply

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