Please bookmark this page to avoid losing your image tool!

Image Yu-Gi-Oh 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,
    cardName = "Card Name",
    cardType = "Effect Monster",
    attribute = "DARK",
    levelRankLinkVal = "7", // For Monsters: Level/Rank. For Link: "L-3". For Spell/Trap: N/A.
    attack = "2500", // For Spell/Trap: N/A.
    defOrLinkMarkers = "2100", // For Monsters: DEF. For Link: "T,B,BL,BR". For Spell/Trap: N/A.
    typeLine = "[Warrior / Effect]", // E.g., "[Dragon/Fusion/Effect]", "[Spell Card]", "[Trap Card / Counter]"
    cardDescription = "Card effect text goes here. It can be quite long and should wrap lines appropriately.",
    serial = "XXXX-EN000",
    pendulumScale = "", // E.g., "4". If non-empty, it's a Pendulum card.
    pendulumEffect = "" // Pendulum effect text, if it's a Pendulum card.
) {
    const canvas = document.createElement('canvas');
    const CARD_WIDTH = 420; // Slightly wider to match proportions better
    const CARD_HEIGHT = 610; // 59mm x 86mm ratio is ~1.457. 420 * 1.457 = ~612
    canvas.width = CARD_WIDTH;
    canvas.height = CARD_HEIGHT;
    const ctx = canvas.getContext('2d');

    // --- Determine if it's a Pendulum card ---
    const isPendulum = pendulumScale !== "" && pendulumScale !== null;

    // --- Define Colors ---
    const COLORS = {
        "Normal Monster": "#FDE68A",
        "Effect Monster": "#FF8B53",
        "Ritual Monster": "#9DB5CC",
        "Fusion Monster": "#A086B7",
        "Synchro Monster": "#CFCFCF",
        "Xyz Monster": "#282828",
        "Link Monster": "#0070DD",
        "Spell Card": "#1D9E74",
        "Trap Card": "#BC5A84",
        "Token": "#DADADA",
        "Skill Card": "#82B9ED",

        // Pendulum monsters use their monster type color for the top half
        "Pendulum Normal Monster": "#FDE68A",
        "Pendulum Effect Monster": "#FF8B53",
        "Pendulum Ritual Monster": "#9DB5CC",
        "Pendulum Fusion Monster": "#A086B7",
        "Pendulum Synchro Monster": "#CFCFCF",
        "Pendulum Xyz Monster": "#282828",

        "NameTextLight": "#FFFFFF",
        "NameTextDark": "#000000",
        "AttributeTextLight": "#000000", // Text on attribute symbol
        "AttributeTextDark": "#FFFFFF",  // For dark attributes

        "AttributeDARK": "#505050", "AttributeLIGHT": "#F0E68C",
        "AttributeEARTH": "#8B4513", "AttributeWATER": "#4682B4",
        "AttributeFIRE": "#FF4500", "AttributeWIND": "#3CB371",
        "AttributeDIVINE": "#FFD700", "AttributeSPELLICON": "#1D9E74", // Using icon background as main color
        "AttributeTRAPICON": "#BC5A84",

        "LevelStar": "#FFD700",
        "RankStar": "#A0A0A0", // Xyz Ranks are often depicted differently or on black stars
        "LinkArrow": "#FF0000",

        "PendulumSpellHalfBG": "#E0F0E0", // Light greenish for the Pendulum spell text area
        "PendulumScaleBox": "#ADD8E6", // Light blue for scale boxes
        "Border": "#1E1E1E",
        "TextBoxInnerBG_Light": "#EFEFEF",
        "TextBoxInnerBG_Dark": "#D0D0D0", // For Xyz mainly
    };

    // --- Layout Constants ---
    const BORDER_WIDTH = 4; // Outer border
    const INNER_PADDING = 18; // Padding from outer border to content area

    const NAME_BAR_X = INNER_PADDING;
    const NAME_BAR_Y = INNER_PADDING;
    const NAME_BAR_HEIGHT = 48;
    const NAME_FONT_SIZE = 28;
    const NAME_X_OFFSET = NAME_BAR_X + 10;
    const NAME_Y_OFFSET = NAME_BAR_Y + NAME_BAR_HEIGHT / 2 + 8;

    const ATTRIBUTE_AREA_X = CARD_WIDTH - INNER_PADDING - 40;
    const ATTRIBUTE_AREA_Y = NAME_BAR_Y + 5;
    const ATTRIBUTE_SIZE = 38;

    let ART_IMAGE_X = INNER_PADDING + (isPendulum ? 0 : 20);
    let ART_IMAGE_Y = NAME_BAR_Y + NAME_BAR_HEIGHT + (isPendulum ? 35 : 10); // Lowered for Pendulum scales
    let ART_IMAGE_WIDTH = CARD_WIDTH - 2 * ART_IMAGE_X;
    let ART_IMAGE_HEIGHT = ART_IMAGE_WIDTH * (isPendulum ? 0.75 : 1); // Pend Art is wider/shorter

    const LEVEL_STAR_SIZE = 18;
    const LEVEL_STAR_GAP = 3;
    const LEVEL_BAR_Y = NAME_BAR_Y + NAME_BAR_HEIGHT - (LEVEL_STAR_SIZE) + 5; // Above artwork, below name for non-Xyz

    const MONSTER_STATS_Y = CARD_HEIGHT - INNER_PADDING - 45;
    const TYPE_LINE_Y = ART_IMAGE_Y + ART_IMAGE_HEIGHT + 25;
    const TYPE_LINE_HEIGHT = 25;
    const TYPE_LINE_FONT_SIZE = 14;

    let DESC_BOX_X = ART_IMAGE_X;
    let DESC_BOX_Y = TYPE_LINE_Y + TYPE_LINE_HEIGHT + 5;
    let DESC_BOX_WIDTH = ART_IMAGE_WIDTH;
    let DESC_BOX_HEIGHT = MONSTER_STATS_Y - DESC_BOX_Y - 10;

    const TEXT_FONT_SIZE = 12.5;
    const TEXT_LINE_HEIGHT = TEXT_FONT_SIZE * 1.2;

    const ATK_DEF_TEXT_Y = CARD_HEIGHT - INNER_PADDING - 18;
    const ATK_TEXT_X = CARD_WIDTH / 2 + 60;
    const DEF_TEXT_X = CARD_WIDTH - INNER_PADDING - 65;
    const SERIAL_TEXT_Y = ATK_DEF_TEXT_Y;
    const SERIAL_TEXT_X = INNER_PADDING + 5;
    const COPYRIGHT_TEXT_Y = CARD_HEIGHT - INNER_PADDING + 8;

    // Pendulum specific adjustments
    const PENDULUM_SCALE_BOX_WIDTH = 50;
    const PENDULUM_SCALE_BOX_HEIGHT = 40;
    const PENDULUM_BLUE_SCALE_X = INNER_PADDING + 5;
    const PENDULUM_RED_SCALE_X = CARD_WIDTH - INNER_PADDING - PENDULUM_SCALE_BOX_WIDTH - 5;
    const PENDULUM_SCALE_Y = NAME_BAR_Y + NAME_BAR_HEIGHT + 5;
    const PENDULUM_TEXT_FONT_SIZE = 11;
    const PENDULUM_EFFECT_BOX_HEIGHT = 80;

    if (isPendulum) {
        ART_IMAGE_Y = PENDULUM_SCALE_Y + PENDULUM_SCALE_BOX_HEIGHT + 5;
        ART_IMAGE_HEIGHT = ART_IMAGE_WIDTH * 0.6; // Adjust art height for pendulum
        
        // Monster effect box is smaller and above pendulum effect box
        const monsterEffectBoxHeight = DESC_BOX_HEIGHT - PENDULUM_EFFECT_BOX_HEIGHT - 15;
        DESC_BOX_HEIGHT = monsterEffectBoxHeight;
    }

    // --- Determine colors based on cardType ---
    let frameColor = COLORS[cardType] || COLORS["Effect Monster"];
    ctx.fillStyle = frameColor;
    ctx.fillRect(0, 0, CARD_WIDTH, CARD_HEIGHT);

    // Outer border
    ctx.strokeStyle = COLORS["Border"];
    ctx.lineWidth = BORDER_WIDTH;
    ctx.strokeRect(BORDER_WIDTH / 2, BORDER_WIDTH / 2, CARD_WIDTH - BORDER_WIDTH, CARD_HEIGHT - BORDER_WIDTH);

    // Inner "content" area background (slightly lighter/different for some card types)
    let contentBgColor = frameColor; // Default to same as frame
    if (cardType === "Xyz Monster") contentBgColor = "#3A3A3A";
    else if (cardType === "Synchro Monster") contentBgColor = "#D8D8D8";
    
    ctx.fillStyle = contentBgColor;
    if (isPendulum) {
        const monsterPartHeight = DESC_BOX_Y + DESC_BOX_HEIGHT + 5;
        ctx.fillRect(INNER_PADDING, INNER_PADDING, CARD_WIDTH - 2 * INNER_PADDING, monsterPartHeight - INNER_PADDING);
        
        // Pendulum lower half (spell-like)
        ctx.fillStyle = COLORS.PendulumSpellHalfBG;
        ctx.fillRect(INNER_PADDING, monsterPartHeight, CARD_WIDTH - 2 * INNER_PADDING, (MONSTER_STATS_Y - 5) - monsterPartHeight);
    } else {
         ctx.fillRect(INNER_PADDING, INNER_PADDING, CARD_WIDTH - 2 * INNER_PADDING, CARD_HEIGHT - 2 * INNER_PADDING);
    }


    // Card Name
    const nameIsLight = cardType === "Xyz Monster" || cardType === "Link Monster" || cardType.startsWith("Pendulum Xyz");
    ctx.fillStyle = nameIsLight ? COLORS.NameTextLight : COLORS.NameTextDark;
    ctx.font = `bold ${NAME_FONT_SIZE}px 'Arial Black', Gadget, sans-serif`;
    ctx.textAlign = "left";
    ctx.fillText(cardName.toUpperCase(), NAME_X_OFFSET, NAME_Y_OFFSET, CARD_WIDTH - INNER_PADDING - NAME_X_OFFSET - ATTRIBUTE_SIZE - 10);

    // Attribute
    // Use uppercase for attribute key, and specific "SPELLICON", "TRAPICON" for spell/trap
    let attributeColorKey = `Attribute${attribute.toUpperCase()}`;
    if (cardType === "Spell Card") attributeColorKey = "AttributeSPELLICON";
    if (cardType === "Trap Card") attributeColorKey = "AttributeTRAPICON";
    
    ctx.fillStyle = COLORS[attributeColorKey] || COLORS.AttributeDARK;
    ctx.beginPath();
    ctx.arc(ATTRIBUTE_AREA_X + ATTRIBUTE_SIZE / 2, ATTRIBUTE_AREA_Y + ATTRIBUTE_SIZE / 2, ATTRIBUTE_SIZE / 2, 0, Math.PI * 2);
    ctx.fill();
    
    ctx.fillStyle = (attribute === "LIGHT" || attribute === "DIVINE") ? COLORS.AttributeTextLight : COLORS.AttributeTextDark;
    if (cardType === "Spell Card" || cardType === "Trap Card") ctx.fillStyle = COLORS.AttributeTextDark;

    ctx.font = `bold ${TEXT_FONT_SIZE * 0.9}px Arial, sans-serif`;
    ctx.textAlign = "center";
    ctx.textBaseline = "middle";
    let attrText = attribute.substring(0,1).toUpperCase();
    if (cardType === "Spell Card") attrText = "魔法"; // Kanji for "Spell"
    if (cardType === "Trap Card") attrText = "罠"; // Kanji for "Trap"
    ctx.fillText(attrText, ATTRIBUTE_AREA_X + ATTRIBUTE_SIZE / 2, ATTRIBUTE_AREA_Y + ATTRIBUTE_SIZE / 2 + 1);
    ctx.textBaseline = "alphabetic"; // Reset

    // Image
    if (originalImg && originalImg.width > 0 && originalImg.height > 0) {
        ctx.fillStyle = "#222"; // Placeholder for artbox background
        ctx.fillRect(ART_IMAGE_X, ART_IMAGE_Y, ART_IMAGE_WIDTH, ART_IMAGE_HEIGHT);

        // Draw image with object-fit: cover behavior
        const artAspect = ART_IMAGE_WIDTH / ART_IMAGE_HEIGHT;
        const imgAspect = originalImg.width / originalImg.height;
        let sx = 0, sy = 0, sWidth = originalImg.width, sHeight = originalImg.height;

        if (imgAspect > artAspect) { // Image wider than art box
            sWidth = originalImg.height * artAspect;
            sx = (originalImg.width - sWidth) / 2;
        } else if (imgAspect < artAspect) { // Image taller than art box
            sHeight = originalImg.width / artAspect;
            sy = (originalImg.height - sHeight) / 2;
        }
        ctx.drawImage(originalImg, sx, sy, sWidth, sHeight, ART_IMAGE_X, ART_IMAGE_Y, ART_IMAGE_WIDTH, ART_IMAGE_HEIGHT);
    }
    // Art Box Border
    ctx.strokeStyle = nameIsLight ? COLORS.NameTextLight : COLORS.NameTextDark; 
    ctx.lineWidth = 1.5;
    ctx.strokeRect(ART_IMAGE_X, ART_IMAGE_Y, ART_IMAGE_WIDTH, ART_IMAGE_HEIGHT);


    // Level/Rank Stars or Link Rating
    const isMonster = !["Spell Card", "Trap Card", "Skill Card"].includes(cardType);
    const isXyz = cardType === "Xyz Monster" || cardType === "Pendulum Xyz Monster";
    const isLink = cardType === "Link Monster";

    if (isMonster && !isLink && levelRankLinkVal && !isNaN(parseInt(levelRankLinkVal))) {
        const numStars = parseInt(levelRankLinkVal);
        ctx.fillStyle = isXyz ? COLORS.RankStar : COLORS.LevelStar;
        const starY = isXyz ? (ART_IMAGE_Y + LEVEL_STAR_SIZE * 1.5) : LEVEL_BAR_Y;
        const startX = isXyz ? (ART_IMAGE_X + LEVEL_STAR_SIZE) 
                             : (CARD_WIDTH - INNER_PADDING - LEVEL_STAR_SIZE - ((numStars -1) * (LEVEL_STAR_SIZE + LEVEL_STAR_GAP)));

        for (let i = 0; i < numStars; i++) {
            const starX = isXyz ? startX + i * (LEVEL_STAR_SIZE + LEVEL_STAR_GAP) 
                                : startX + i * (LEVEL_STAR_SIZE + LEVEL_STAR_GAP);
            ctx.beginPath();
            // Simple circle for stars
            ctx.arc(starX, starY, LEVEL_STAR_SIZE / 2, 0, Math.PI * 2);
            ctx.fill();
            if (isXyz) { // Xyz stars often have inner detail or darker color
                 ctx.strokeStyle = "#000"; ctx.lineWidth=1; ctx.stroke();
            }
        }
    }

    // [Type Line Text] - e.g., [Warrior/Effect]
    ctx.fillStyle = (isXyz || isLink) ? COLORS.NameTextLight : COLORS.NameTextDark;
    ctx.font = `bold ${TYPE_LINE_FONT_SIZE}px 'Stone Serif', 'Times New Roman', serif`;
    ctx.textAlign = "left";
    const typeLineAreaWidth = ART_IMAGE_WIDTH;
    const typeLineBoxX = ART_IMAGE_X;
    if(isPendulum){
        ctx.fillStyle = COLORS.NameTextDark; // Pendulum Type line Text is usually dark
    }
    ctx.fillText(typeLine, typeLineBoxX + 5, TYPE_LINE_Y, typeLineAreaWidth - 10);


    // Description/Effect Text Box
    const textBoxBgColor = (isXyz && !isPendulum) ? COLORS.TextBoxInnerBG_Dark : COLORS.TextBoxInnerBG_Light;
    ctx.fillStyle = textBoxBgColor;
    ctx.fillRect(DESC_BOX_X, DESC_BOX_Y, DESC_BOX_WIDTH, DESC_BOX_HEIGHT);
    ctx.strokeStyle = (isXyz || isLink) ? COLORS.NameTextLight : COLORS.NameTextDark;
    ctx.lineWidth = 0.5;
    ctx.strokeRect(DESC_BOX_X, DESC_BOX_Y, DESC_BOX_WIDTH, DESC_BOX_HEIGHT);
    
    ctx.fillStyle = COLORS.NameTextDark;
    ctx.font = `${TEXT_FONT_SIZE}px 'Stone Serif', 'Times New Roman', serif`;
    ctx.textAlign = "left";
    wrapText(ctx, cardDescription, DESC_BOX_X + 5, DESC_BOX_Y + TEXT_FONT_SIZE + 2, DESC_BOX_WIDTH - 10, TEXT_LINE_HEIGHT);


    // Pendulum Specific Elements
    if (isPendulum) {
        // Scales
        ctx.fillStyle = COLORS.PendulumScaleBox;
        ctx.fillRect(PENDULUM_BLUE_SCALE_X, PENDULUM_SCALE_Y, PENDULUM_SCALE_BOX_WIDTH, PENDULUM_SCALE_BOX_HEIGHT); // Left (Blue)
        ctx.fillRect(PENDULUM_RED_SCALE_X, PENDULUM_SCALE_Y, PENDULUM_SCALE_BOX_WIDTH, PENDULUM_SCALE_BOX_HEIGHT); // Right (Red)
        
        ctx.strokeStyle = COLORS.NameTextDark; ctx.lineWidth = 1;
        ctx.strokeRect(PENDULUM_BLUE_SCALE_X, PENDULUM_SCALE_Y, PENDULUM_SCALE_BOX_WIDTH, PENDULUM_SCALE_BOX_HEIGHT);
        ctx.strokeRect(PENDULUM_RED_SCALE_X, PENDULUM_SCALE_Y, PENDULUM_SCALE_BOX_WIDTH, PENDULUM_SCALE_BOX_HEIGHT);

        ctx.fillStyle = COLORS.NameTextDark;
        ctx.font = `bold ${NAME_FONT_SIZE * 0.8}px Arial, sans-serif`;
        ctx.textAlign = "center";
        ctx.textBaseline = "middle";
        ctx.fillText(pendulumScale, PENDULUM_BLUE_SCALE_X + PENDULUM_SCALE_BOX_WIDTH / 2, PENDULUM_SCALE_Y + PENDULUM_SCALE_BOX_HEIGHT / 2);
        ctx.fillText(pendulumScale, PENDULUM_RED_SCALE_X + PENDULUM_SCALE_BOX_WIDTH / 2, PENDULUM_SCALE_Y + PENDULUM_SCALE_BOX_HEIGHT / 2);
        ctx.textBaseline = "alphabetic"; // Reset

        // Pendulum Effect Box
        const pEffectBoxY = DESC_BOX_Y + DESC_BOX_HEIGHT + 10;
        ctx.fillStyle = COLORS.PendulumSpellHalfBG; // Ensure this part uses the pendulum area background
        ctx.fillRect(DESC_BOX_X, pEffectBoxY, DESC_BOX_WIDTH, PENDULUM_EFFECT_BOX_HEIGHT);
        ctx.strokeStyle = COLORS.NameTextDark; ctx.lineWidth = 0.5;
        ctx.strokeRect(DESC_BOX_X, pEffectBoxY, DESC_BOX_WIDTH, PENDULUM_EFFECT_BOX_HEIGHT);

        ctx.fillStyle = COLORS.NameTextDark;
        ctx.font = `${PENDULUM_TEXT_FONT_SIZE}px 'Stone Serif', 'Times New Roman', serif`;
        ctx.textAlign = "left";
        wrapText(ctx, pendulumEffect, DESC_BOX_X + 5, pEffectBoxY + PENDULUM_TEXT_FONT_SIZE + 2, DESC_BOX_WIDTH - 10, PENDULUM_TEXT_FONT_SIZE * 1.2);
    }

    // ATK/DEF or Link Rating/Arrows
    if (isMonster) {
        ctx.fillStyle = (isXyz || isLink) ? COLORS.NameTextLight : COLORS.NameTextDark;
        ctx.font = `bold ${TYPE_LINE_FONT_SIZE * 1.1}px Arial, sans-serif`;
        ctx.textAlign = "right";

        if (isLink) {
            ctx.fillText(`ATK/${attack}  LINK-${levelRankLinkVal.replace('L-','')}`, CARD_WIDTH - INNER_PADDING - 5, ATK_DEF_TEXT_Y);
            // Draw Link Arrows
            const arrowSize = 10;
            const arrowOffset = 3; // Offset from edge of art box
            const arrows = defOrLinkMarkers.split(',').map(a => a.trim().toUpperCase());

            const positions = {
                T:  { x: ART_IMAGE_X + ART_IMAGE_WIDTH / 2, y: ART_IMAGE_Y - arrowOffset, w: arrowSize, h: arrowSize/2 },
                B:  { x: ART_IMAGE_X + ART_IMAGE_WIDTH / 2, y: ART_IMAGE_Y + ART_IMAGE_HEIGHT + arrowOffset - arrowSize/2, w: arrowSize, h: arrowSize/2 },
                L:  { x: ART_IMAGE_X - arrowOffset, y: ART_IMAGE_Y + ART_IMAGE_HEIGHT / 2, w: arrowSize/2, h: arrowSize },
                R:  { x: ART_IMAGE_X + ART_IMAGE_WIDTH + arrowOffset - arrowSize/2, y: ART_IMAGE_Y + ART_IMAGE_HEIGHT / 2, w: arrowSize/2, h: arrowSize },
                TL: { x: ART_IMAGE_X - arrowOffset, y: ART_IMAGE_Y - arrowOffset, w: arrowSize * 0.7, h: arrowSize * 0.7 },
                TR: { x: ART_IMAGE_X + ART_IMAGE_WIDTH + arrowOffset - arrowSize*0.7, y: ART_IMAGE_Y - arrowOffset, w: arrowSize * 0.7, h: arrowSize * 0.7 },
                BL: { x: ART_IMAGE_X - arrowOffset, y: ART_IMAGE_Y + ART_IMAGE_HEIGHT + arrowOffset - arrowSize*0.7, w: arrowSize * 0.7, h: arrowSize * 0.7 },
                BR: { x: ART_IMAGE_X + ART_IMAGE_WIDTH + arrowOffset - arrowSize*0.7, y: ART_IMAGE_Y + ART_IMAGE_HEIGHT + arrowOffset - arrowSize*0.7, w: arrowSize * 0.7, h: arrowSize * 0.7 },
            };
            ctx.fillStyle = COLORS.LinkArrow;
            arrows.forEach(arrowKey => {
                if (positions[arrowKey]) {
                    const p = positions[arrowKey];
                    // simplified rectangles for arrows
                    if (arrowKey === 'T') ctx.fillRect(p.x - p.w/2, p.y - p.h, p.w, p.h);
                    else if (arrowKey === 'B') ctx.fillRect(p.x - p.w/2, p.y, p.w, p.h);
                    else if (arrowKey === 'L') ctx.fillRect(p.x - p.w, p.y - p.h/2, p.w, p.h);
                    else if (arrowKey === 'R') ctx.fillRect(p.x, p.y - p.h/2, p.w, p.h);
                    else ctx.fillRect(p.x, p.y, p.w, p.h); // Diagonal simplified
                }
            });

        } else { // Normal ATK/DEF
            ctx.fillText(`ATK/${attack}  DEF/${defOrLinkMarkers}`, CARD_WIDTH - INNER_PADDING - 5, ATK_DEF_TEXT_Y);
        }
    }

    // Serial Number
    ctx.fillStyle = (isXyz || isLink) ? COLORS.NameTextLight : COLORS.NameTextDark;
    ctx.font = `${TEXT_FONT_SIZE * 0.8}px Arial, sans-serif`;
    ctx.textAlign = "left";
    ctx.fillText(serial, SERIAL_TEXT_X, SERIAL_TEXT_Y);
    
    // Copyright (very small)
    ctx.textAlign = "right";
    ctx.font = `${TEXT_FONT_SIZE * 0.7}px Arial, sans-serif`;
    ctx.fillText("©STUDIO DICE/SHUEISHA, TV TOKYO, KONAMI", CARD_WIDTH - INNER_PADDING - 5, COPYRIGHT_TEXT_Y);


    // Helper function for text wrapping
    function wrapText(context, text, x, y, maxWidth, lineHeight) {
        const words = text.replace(/\r\n/g, '\n').replace(/\r/g, '\n').split(/ |\n/); // Split by space or newline
        let line = '';
        let currentY = y;
        let firstWordInLine = true;

        for (let n = 0; n < words.length; n++) {
            if (words[n] === '' && text.includes('\n')) { // Check for explicit newline from split
                context.fillText(line, x, currentY);
                line = '';
                currentY += lineHeight;
                firstWordInLine = true;
                continue;
            }
            
            const testWord = words[n] + (firstWordInLine ? "" : " ");
            const testLine = firstWordInLine ? testWord : line + testWord;
            const metrics = context.measureText(testLine);
            const testWidth = metrics.width;

            if (testWidth > maxWidth && !firstWordInLine) {
                context.fillText(line, x, currentY);
                line = words[n] + " ";
                currentY += lineHeight;
                firstWordInLine = false; 
            } else {
                line = firstWordInLine ? testWord : testLine;
                firstWordInLine = false;
            }
        }
        context.fillText(line, x, currentY);
        return currentY + lineHeight;
    }

    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 Yu-Gi-Oh Card Template Creator is a web-based tool that allows users to create custom Yu-Gi-Oh card templates. Users can input various parameters such as card name, type, attributes, attack and defense values, and effects to generate a personalized card image. This tool is useful for Yu-Gi-Oh fans who want to design custom cards for personal use, create fan-made cards for games, or develop unique cards for card tournaments and events. With a user-friendly interface and extensive customization options, this tool helps bring creativity and personalization into the world of Yu-Gi-Oh.

Leave a Reply

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

Other Image Tools:

Image Ancient Roman Greek Tablet Frame Creator

Image Marriage Certificate Template Creator

Image Video Game Achievement Frame Creator

Image Newspaper Front Page Template Creator

Image Botanical Illustration Frame Creator

Image Vinyl Record Sleeve Template Creator

Vintage Photo Booth Strip Template Generator

Image Cyberpunk Interface Frame Designer

Image Detective Novel Cover Template

Image Achievement Certificate Framer

Image Illuminated Manuscript Frame Generator

Image Art Deco Poster Frame Creator

Image Egyptian Papyrus Scroll Frame Designer

Image Vintage Postage Stamp Frame Creator

Image Magic: The Gathering Card Frame Generator

Image Birth Certificate Template Generator

Image Driver’s License Template Creator

Image Scout Explorer Badge Template Creator

Image Steampunk Document Frame Creator

Image Vintage Scientific Illustration Frame Creator

Image Magazine Cover Template Creator

Image Album Cover Template Creator

Image Medieval Bestiary Page Template

Image Polaroid Instant Photo Frame

Image Pulp Fiction Book Cover Template

Image Medieval Manuscript Frame Creator

Image Vintage Advertisement Poster Generator

Victorian Image Calling Card Template

Image Award Certificate Template

Image Military Insignia Patch Template Creator

Image ID Card Template Creator

Image Film Strip Frame Creator

Image Sci-Fi Novel Cover Template

Noir Film Poster Design Template

Image Ancient Scroll Parchment Frame Enhancer

Image Scientific Journal Cover Template Creator

See All →