Please bookmark this page to avoid losing your image tool!

Baseball Card 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,
    playerName = "PLAYER NAME",
    teamName = "TEAM NAME",
    primaryColor = "#D50032", // A common sports red
    secondaryColor = "#002D72", // A common sports blue
    textColor = "#FFFFFF",
    fontFamily = "Anton", // Default to Anton (sporty, will be loaded from CDN if specified)
    playerNumber = "00",
    cardYear = new Date().getFullYear().toString()) {

    let loadedFontFamily = fontFamily;

    // For specific fonts like 'Anton' (our default example), load them.
    // Otherwise, assume the fontFamily string (e.g., 'Arial', 'Impact') is a valid CSS font name.
    if (fontFamily === "Anton") {
        try {
            let fontAvailable = false;
            // Check if the font is already loaded and available in document.fonts
            for (const font of document.fonts) {
                // Check family name and if it's loaded. Note: status might not be 'loaded' immediately.
                if (font.family === "Anton") { // Simplified check relying on FontFaceSet
                   if (font.status === 'loaded') { // explicit check if FontFace object reveals status
                      fontAvailable = true;
                      break;
                   }
                   // For a more robust check, one might rely on document.fonts.check()
                   // but it needs a size too e.g. document.fonts.check("12px Anton")
                }
            }
            // A simpler way is to rely on document.fonts.check specifically for "Anton".
            // If document.fonts.check("1em Anton") is true, it's likely usable.
            // However, let's assume if we add it, it can be re-added without issue or checked against a flag.
            // To prevent multiple load attempts in a session for the same font:
            if (!window._antonFontLoaded) { // Use a global flag or similar mechanism
                 const antonFont = new FontFace('Anton', 'url(https://fonts.gstatic.com/s/anton/v23/1Ptgg87LROyAm3Kz-C8.woff2) format("woff2")');
                 await antonFont.load();
                 document.fonts.add(antonFont);
                 window._antonFontLoaded = true; // Set flag after successful load
                 console.log("Anton font loaded successfully.");
            } else {
                 console.log("Anton font previously loaded or loading initiated.");
            }
        } catch (e) {
            console.error("Failed to load Anton font, falling back to sans-serif:", e);
            loadedFontFamily = "sans-serif"; // Fallback font
        }
    }
    // For other font families, they will be used directly. Browser handles fallback if not found.

    const canvas = document.createElement('canvas');
    const cardWidth = 300;
    const cardHeight = 420;
    canvas.width = cardWidth;
    canvas.height = cardHeight;
    const ctx = canvas.getContext('2d');

    // Card Base
    ctx.fillStyle = "#FFFFFF"; // White card base
    ctx.fillRect(0, 0, cardWidth, cardHeight);

    // Top Angled Banner (Primary Color)
    const topBannerHeight = cardHeight * 0.15;
    ctx.fillStyle = primaryColor;
    ctx.beginPath();
    ctx.moveTo(0, 0);
    ctx.lineTo(cardWidth, 0);
    ctx.lineTo(cardWidth, topBannerHeight * 0.75);
    ctx.lineTo(0, topBannerHeight);
    ctx.closePath();
    ctx.fill();

    // Player Image Area Frame (Secondary Color)
    const imgFrameMargin = cardWidth * 0.05;
    const imgFrameY = topBannerHeight * 0.60;
    const imgFrameWidth = cardWidth - 2 * imgFrameMargin;
    const imgFrameHeight = cardHeight * 0.55;
    ctx.fillStyle = secondaryColor;
    ctx.fillRect(imgFrameMargin, imgFrameY, imgFrameWidth, imgFrameHeight);

    // Player Image
    if (originalImg && originalImg.width > 0 && originalImg.height > 0) {
        const imgPadding = 4;
        const dImgX = imgFrameMargin + imgPadding;
        const dImgY = imgFrameY + imgPadding;
        const dImgWidth = imgFrameWidth - 2 * imgPadding;
        const dImgHeight = imgFrameHeight - 2 * imgPadding;

        const imgAspect = originalImg.width / originalImg.height;
        const destAspect = dImgWidth / dImgHeight;
        let drawWidth, drawHeight, drawX, drawY;

        if (imgAspect > destAspect) { // Image is wider
            drawWidth = dImgWidth;
            drawHeight = dImgWidth / imgAspect;
            drawX = dImgX;
            drawY = dImgY + (dImgHeight - drawHeight) / 2; // Center vertically
        } else { // Image is taller or same aspect
            drawHeight = dImgHeight;
            drawWidth = dImgHeight * imgAspect;
            drawY = dImgY;
            drawX = dImgX + (dImgWidth - drawWidth) / 2; // Center horizontally
        }
        ctx.drawImage(originalImg, drawX, drawY, drawWidth, drawHeight);
    } else {
        // Draw a placeholder if image is invalid
        ctx.fillStyle = "#CCCCCC";
        ctx.fillRect(imgFrameMargin + 4, imgFrameY + 4, imgFrameWidth - 8, imgFrameHeight - 8);
        ctx.fillStyle = "#000000";
        ctx.textAlign = "center";
        ctx.textBaseline = "middle";
        ctx.font = `16px sans-serif`;
        ctx.fillText("No Image", imgFrameMargin + imgFrameWidth/2, imgFrameY + imgFrameHeight/2);
    }


    // Bottom Angled Banner (Primary Color) for Name/Team
    const bottomBannerTopY = imgFrameY + imgFrameHeight - (cardHeight * 0.1);
    const bottomBannerBottomY = cardHeight;
    const bottomBannerAngleOffset = cardHeight * 0.05;

    ctx.fillStyle = primaryColor;
    ctx.beginPath();
    ctx.moveTo(0, bottomBannerTopY + bottomBannerAngleOffset);
    ctx.lineTo(cardWidth, bottomBannerTopY);
    ctx.lineTo(cardWidth, bottomBannerBottomY);
    ctx.lineTo(0, bottomBannerBottomY);
    ctx.closePath();
    ctx.fill();
    
    ctx.lineJoin = 'round'; // For text strokes

    // Common font fallback string to append
    const FONT_FALLBACK = `, "Arial Nova", Arial, sans-serif`;

    // Player Name
    ctx.fillStyle = textColor;
    const playerNameFontSize = cardWidth * 0.095; // Approx 28.5px for 300px width
    ctx.font = `bold ${playerNameFontSize}px "${loadedFontFamily}"${FONT_FALLBACK}`;
    ctx.textAlign = 'center';
    ctx.textBaseline = 'middle';
    
    const nameAreaEffectiveYStart = bottomBannerTopY + (bottomBannerAngleOffset / 2);
    const reservedFooterHeight = cardHeight * 0.08; // For the year/number ribbon
    const nameAreaEffectiveHeight = cardHeight - nameAreaEffectiveYStart - reservedFooterHeight;
    const nameY = nameAreaEffectiveYStart + nameAreaEffectiveHeight * 0.35;

    ctx.strokeStyle = 'rgba(0,0,0,0.6)'; // Text outline color
    ctx.lineWidth = Math.max(1, playerNameFontSize * 0.08); // Relative outline thickness
    ctx.strokeText(playerName.toUpperCase(), cardWidth / 2, nameY);
    ctx.fillText(playerName.toUpperCase(), cardWidth / 2, nameY);

    // Team Name
    const teamNameFontSize = cardWidth * 0.055; // Approx 16.5px
    ctx.font = `bold ${teamNameFontSize}px "${loadedFontFamily}"${FONT_FALLBACK}`; // Team name also bold
    const teamNameY = nameY + playerNameFontSize * 0.55; // Position below player name

    ctx.lineWidth = Math.max(1, teamNameFontSize * 0.08);
    ctx.strokeText(teamName.toUpperCase(), cardWidth / 2, teamNameY);
    ctx.fillText(teamName.toUpperCase(), cardWidth / 2, teamNameY);

    // Footer Ribbon for Year and Number (Secondary Color)
    const footerRibbonHeight = cardHeight * 0.08;
    ctx.fillStyle = secondaryColor;
    ctx.fillRect(0, cardHeight - footerRibbonHeight, cardWidth, footerRibbonHeight);

    const detailFontSize = cardWidth * 0.05; // Approx 15px
    ctx.font = `bold ${detailFontSize}px "${loadedFontFamily}"${FONT_FALLBACK}`;
    ctx.fillStyle = textColor; // Text color for details on the secondaryColor ribbon
    ctx.textBaseline = 'middle';

    // Player Number (no stroke for small text for clarity)
    ctx.textAlign = 'left';
    const numText = playerNumber.startsWith('#') ? playerNumber : `#${playerNumber}`;
    ctx.fillText(numText, cardWidth * 0.05, cardHeight - footerRibbonHeight / 2);

    // Card Year (no stroke)
    ctx.textAlign = 'right';
    ctx.fillText(cardYear, cardWidth * 0.95, cardHeight - footerRibbonHeight / 2);

    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 Baseball Card Template Creator is an online tool that allows users to design custom baseball cards. Users can upload a player image and input various details such as the player’s name, team name, player number, and card year. The tool offers customizable options for colors and fonts, ensuring that each card can be personalized to fit the user’s style. This tool is perfect for creating unique baseball cards for personal use, gifts, team events, or memorabilia. It streamlines the card creation process, making it accessible for sports fans and collectors alike.

Leave a Reply

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