Please bookmark this page to avoid losing your image tool!

Image Newspaper Front Page 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,
    newspaperName = "The Daily Chronicle",
    headline = "MAJOR EVENT SHAKES THE CITY",
    subHeadline = "An in-depth look at the recent occurrences and their profound impact on the community.",
    articleText = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.",
    imageCaption = "Photo: A key moment captured during the unfolding events.",
    dateInfo = "", // Default to empty, will be populated by new Date() if empty
    editionInfo = "Vol. LXVII, No. 105",
    priceInfo = "$1.50",
    fontFamily = "Times New Roman, serif",
    backgroundColor = "#f4f1e8", // Off-white, slightly yellowish paper color
    textColor = "#1a1a1a" // Very dark grey, not pure black for text
) {
    const canvas = document.createElement('canvas');
    const ctx = canvas.getContext('2d');

    canvas.width = 800;
    canvas.height = 1200; // Fixed height, content might be clipped if too long

    // --- Helper function for text wrapping ---
    // yBaseline: the y-coordinate for the baseline of the first line of text.
    // Returns the y-coordinate for the baseline of the line *after* the last line of text drawn.
    function wrapText(context, text, x, yBaseline, maxWidth, lineHeight, textAlign = 'left', font = null, color = null) {
        if (font) context.font = font;
        if (color) context.fillStyle = color;
        context.textAlign = textAlign;

        const words = String(text).split(' ');
        let lineContent = '';
        let currentLineBaseline = yBaseline;
        const canvasBottomEdge = context.canvas.height - 10; // 10px buffer from absolute bottom

        // Check if the very first line would already be too low
        if (currentLineBaseline > canvasBottomEdge) {
            return currentLineBaseline; // Don't draw anything if starting point is already off-canvas
        }

        for (let n = 0; n < words.length; n++) {
            const testLine = lineContent + words[n] + ' ';
            const metrics = context.measureText(testLine); // Uses current font
            const testWidth = metrics.width;

            if (testWidth > maxWidth && lineContent.length > 0) { // If line is too long AND it's not the first word on this new line
                context.fillText(lineContent.trim(), x, currentLineBaseline);
                lineContent = words[n] + ' '; // Start new line with current word
                currentLineBaseline += lineHeight;
                if (currentLineBaseline > canvasBottomEdge) { // Check if new line baseline is too low
                    return currentLineBaseline; // Stop, as next line would be (partially) off
                }
            } else {
                lineContent = testLine;
            }
        }
        
        // Draw the last or only line, if it's within bounds
        if (lineContent.trim().length > 0 && currentLineBaseline <= canvasBottomEdge + lineHeight/2) { // Allow if baseline is slightly over if text still fits
             context.fillText(lineContent.trim(), x, currentLineBaseline);
        }
        return currentLineBaseline + lineHeight; 
    }

    // Default dateInfo if not provided or empty
    if (!dateInfo || dateInfo.trim() === "") {
        try {
            dateInfo = new Date().toLocaleDateString(undefined, { weekday: 'long', year: 'numeric', month: 'long', day: 'numeric' });
        } catch (e) { // Fallback for environments where toLocaleDateString with options might fail (e.g. older Node)
            dateInfo = new Date().toDateString();
        }
    }

    // Helper to determine baseline for the first line of a text block
    // blockTopY is the desired top visual edge of the text block.
    // fontSize is used to estimate where the baseline of the first line should be.
    const getFirstLineBaseline = (blockTopY, fontSize) => blockTopY + fontSize; 

    // --- Start Drawing ---
    ctx.fillStyle = backgroundColor;
    ctx.fillRect(0, 0, canvas.width, canvas.height);

    let currentElementTopY = 20; // Tracks the Y where the top of the next element/block should start

    // 1. Newspaper Name (Masthead)
    const mastheadFontSize = 70;
    const mastheadFont = `bold ${mastheadFontSize}px "${fontFamily}"`; // Quote font family for names with spaces
    const mastheadLineHeight = mastheadFontSize * 1.0; 
    let textBlockEndY = wrapText(ctx, newspaperName, canvas.width / 2, getFirstLineBaseline(currentElementTopY, mastheadFontSize), canvas.width - 60, mastheadLineHeight, 'center', mastheadFont, textColor);
    currentElementTopY = textBlockEndY - mastheadLineHeight + 5; // Update Y to estimated bottom of this text block + spacing

    // 2. Top Rule
    ctx.fillStyle = textColor; 
    ctx.fillRect(40, currentElementTopY, canvas.width - 80, 2);
    currentElementTopY += 2 + 5; 

    // 3. Date/Edition/Price Line
    const fullDateLineText = `${dateInfo}  •  ${editionInfo}  •  ${priceInfo}`;
    const dateLineFontSize = 14;
    const dateLineFont = `${dateLineFontSize}px "${fontFamily}"`;
    const dateLineLineHeight = dateLineFontSize * 1.2;
    textBlockEndY = wrapText(ctx, fullDateLineText, canvas.width / 2, getFirstLineBaseline(currentElementTopY, dateLineFontSize), canvas.width - 80, dateLineLineHeight, 'center', dateLineFont, textColor);
    currentElementTopY = textBlockEndY - dateLineLineHeight + 5;

    // 4. Main Rule (thicker)
    ctx.fillRect(20, currentElementTopY, canvas.width - 40, 3);
    currentElementTopY += 3 + 15;

    // 5. Headline
    const headlineFontSize = 56;
    const headlineFont = `bold ${headlineFontSize}px "${fontFamily}"`;
    const headlineLineHeight = headlineFontSize * 1.1;
    textBlockEndY = wrapText(ctx, headline, canvas.width / 2, getFirstLineBaseline(currentElementTopY, headlineFontSize), canvas.width - 50, headlineLineHeight, 'center', headlineFont, textColor);
    currentElementTopY = textBlockEndY - headlineLineHeight + 10;

    // 6. Sub-Headline
    if (subHeadline && subHeadline.trim() !== "") {
        const subHeadlineFontSize = 22;
        const subHeadlineFont = `italic ${subHeadlineFontSize}px "${fontFamily}"`;
        const subHeadlineLineHeight = subHeadlineFontSize * 1.2;
        textBlockEndY = wrapText(ctx, subHeadline, canvas.width / 2, getFirstLineBaseline(currentElementTopY, subHeadlineFontSize), canvas.width - 100, subHeadlineLineHeight, 'center', subHeadlineFont, textColor);
        currentElementTopY = textBlockEndY - subHeadlineLineHeight + 25;
    } else {
        currentElementTopY += 10; // Add some space if no subheadline
    }

    // 7. Main Image
    const imgRenderY = currentElementTopY; 
    const imgMarginH = 50;
    const imgContainerWidth = canvas.width - 2 * imgMarginH;
    const imgMaxHeight = 320;

    let imgDrawWidth = originalImg.width;
    let imgDrawHeight = originalImg.height;
    const aspectRatio = originalImg.width / originalImg.height;

    if (imgDrawWidth > imgContainerWidth) {
        imgDrawWidth = imgContainerWidth;
        imgDrawHeight = imgDrawWidth / aspectRatio;
    }
    if (imgDrawHeight > imgMaxHeight) {
        imgDrawHeight = imgMaxHeight;
        imgDrawWidth = imgDrawHeight * aspectRatio;
    }
    
    if (imgRenderY + imgDrawHeight < canvas.height - 10) { // Check if image fits
        const imgX = (canvas.width - imgDrawWidth) / 2;
        ctx.drawImage(originalImg, imgX, imgRenderY, imgDrawWidth, imgDrawHeight);
        ctx.strokeStyle = textColor;
        ctx.lineWidth = 1;
        ctx.strokeRect(imgX - 1, imgRenderY - 1, imgDrawWidth + 2, imgDrawHeight + 2);
        currentElementTopY = imgRenderY + imgDrawHeight + 5;
    } else { // Image doesn't fit, skip drawing it and its caption
        currentElementTopY = imgRenderY; // Keep currentY, don't add image height
        imageCaption = ""; // Clear caption as image is not shown
    }
    

    // 8. Image Caption
    if (imageCaption && imageCaption.trim() !== "") {
        const captionFontSize = 12;
        const captionFont = `italic ${captionFontSize}px "${fontFamily}"`;
        const captionLineHeight = captionFontSize * 1.2;
        textBlockEndY = wrapText(ctx, imageCaption, canvas.width / 2, getFirstLineBaseline(currentElementTopY, captionFontSize), canvas.width - 100, captionLineHeight, 'center', captionFont, textColor);
        currentElementTopY = textBlockEndY - captionLineHeight + 15;
    } else {
        currentElementTopY += 5; // Minimal space if no caption / image was skipped
    }

    // 9. Article Text (Multi-column)
    const articleTextStartY = currentElementTopY; 
    const articleFontSize = 13;
    const articleFont = `${articleFontSize}px "${fontFamily}"`;
    const articleLineHeight = articleFontSize * 1.35;
    const numColumns = 3;
    const columnGutter = 18;
    const pageMargins = 40;
    const articleBlockWidth = canvas.width - 2 * pageMargins;
    const columnWidth = (articleBlockWidth - (numColumns - 1) * columnGutter) / numColumns;

    const wordsInArticle = String(articleText).split(' ').filter(w => w.length > 0); // Filter out empty strings from multiple spaces
    let wordIdx = 0;
    
    for (let i = 0; i < numColumns; i++) {
        if (wordIdx >= wordsInArticle.length) break; // All words used

        const columnX = pageMargins + i * (columnWidth + columnGutter);
        
        // Distribute remaining words among remaining columns for this segment.
        // This is a simplified distribution; actual visual result depends on text content.
        const remainingWords = wordsInArticle.length - wordIdx;
        const remainingColumns = numColumns - i;
        const wordsForThisColumnApprox = Math.ceil(remainingWords / remainingColumns);
        
        let textForThisColumn;
        if (i < numColumns - 1) {
            textForThisColumn = wordsInArticle.slice(wordIdx, wordIdx + wordsForThisColumnApprox).join(' ');
        } else {
            textForThisColumn = wordsInArticle.slice(wordIdx).join(' '); // Last column takes all remaining
        }
        wordIdx += wordsForThisColumnApprox; 
        
        if (textForThisColumn.trim()) {
            // All columns start drawing their text from the same `articleTextStartY`.
            // wrapText will handle clipping at the bottom of the canvas.
            wrapText(ctx, textForThisColumn, columnX, getFirstLineBaseline(articleTextStartY, articleFontSize), columnWidth, articleLineHeight, 'left', articleFont, textColor);
        }
    }

    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 Newspaper Front Page Template Creator is a tool that allows users to create a personalized newspaper-style front page using their own images and text. Users can input details such as the newspaper’s name, main headline, sub-headline, date, edition information, and article text. The tool formats this information in a visually appealing layout reminiscent of traditional newspaper designs, complete with customizable fonts and colors. This tool can be ideal for creating mock-up newspapers for special events, personal projects, or educational purposes, enabling users to showcase important news stories or announcements in a classic format.

Leave a Reply

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