Please bookmark this page to avoid losing your image tool!

Image Carnival Fair Poster 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,
    titleText = "CARNIVAL FUN!",
    detailsText = "GAMES - RIDES - FOOD - PRIZES",
    taglineText = "COME ONE, COME ALL!",
    bannerText = "GRAND EVENT!",
    primaryBgColor = "#D90429", // Strong Red
    secondaryBgColor = "#FFFFFF", // White for stripes
    accentColor = "#FFD700", // Gold/Yellow
    textColor = "#FFFFFF", // White for main title/tagline
    bannerTextColor = "#000000", // Black for text on banner
    fontFamily = "Bangers" // Default font to load dynamically
) {
    const canvas = document.createElement('canvas');
    const ctx = canvas.getContext('2d');

    const posterWidth = 600;
    const posterHeight = 800;
    canvas.width = posterWidth;
    canvas.height = posterHeight;

    // 1. Font handling
    let currentFont = fontFamily; // This might change to a fallback font
    const dynamicFonts = {
        "Bangers": "https://fonts.gstatic.com/s/bangers/v24/FeVQS0BTqb0h60ACL5k.woff2",
        "Lobster": "https://fonts.gstatic.com/s/lobster/v30/neILzCirqoswsqX9zoKmMw.woff2",
        "Luckiest Guy": "https://fonts.gstatic.com/s/luckiestguy/v18/_gP_1RrxsjcxVyin9l9n_j2hTd52.woff2",
        "Limelight": "https://fonts.gstatic.com/s/limelight/v21/XLYkIZL7aopIFB2 திருச்சிUr-v9-.woff2" // Note: Truncated font name for Limelight due to non-ASCII
    };
    // Correcting font name for Limelight or similar
    if (fontFamily === "Limelight") dynamicFonts["Limelight"] = "https://fonts.gstatic.com/s/limelight/v21/XLYkIZL7aopIFB2_oGg.woff2";


    if (dynamicFonts[fontFamily]) {
        if (document.fonts) {
            try {
                if (!document.fonts.check(`1em "${fontFamily}"`)) {
                    const fontFace = new FontFace(fontFamily, `url(${dynamicFonts[fontFamily]}) format('woff2')`);
                    await fontFace.load();
                    document.fonts.add(fontFace);
                    await document.fonts.ready; 
                    if (!document.fonts.check(`1em "${fontFamily}"`)) {
                         console.warn(`Font "${fontFamily}" loaded but check() returns false. Attempting to use.`);
                    }
                    console.log(`Font "${fontFamily}" loaded dynamically.`);
                } else {
                    console.log(`Font "${fontFamily}" is already available.`);
                }
                currentFont = fontFamily;
            } catch (e) {
                console.error(`Failed to load font "${fontFamily}":`, e);
                currentFont = "Arial, sans-serif";
            }
        } else {
            console.warn("document.fonts API not supported. Using fallback font for dynamic request.");
            currentFont = "Arial, sans-serif";
        }
    } else {
        console.log(`Using provided font "${fontFamily}" assuming it's available or loaded externally.`);
        currentFont = fontFamily; // Assume it's a system font or loaded elsewhere
    }

    // 2. Background (Stripes)
    ctx.save();
    const stripeWidth = 50;
    for (let i = 0; i * stripeWidth < posterWidth; i++) {
        ctx.fillStyle = (i % 2 === 0) ? primaryBgColor : secondaryBgColor;
        ctx.fillRect(i * stripeWidth, 0, stripeWidth, posterHeight);
    }
    ctx.restore();

    // 3. Decorative Border
    ctx.save();
    const outerBorderWidth = 20;
    ctx.strokeStyle = accentColor;
    ctx.lineWidth = outerBorderWidth;
    ctx.strokeRect(
        outerBorderWidth / 2,
        outerBorderWidth / 2,
        posterWidth - outerBorderWidth,
        posterHeight - outerBorderWidth
    );

    const innerBorderVisualGap = 5; 
    const innerBorderLineWidth = 5;
    const innerBorderRectX = outerBorderWidth + innerBorderVisualGap;
    const innerBorderRectY = outerBorderWidth + innerBorderVisualGap;
    const innerBorderRectW = posterWidth - 2 * (outerBorderWidth + innerBorderVisualGap);
    const innerBorderRectH = posterHeight - 2 * (outerBorderWidth + innerBorderVisualGap);

    ctx.strokeStyle = primaryBgColor;
    ctx.lineWidth = innerBorderLineWidth;
    ctx.strokeRect(innerBorderRectX, innerBorderRectY, innerBorderRectW, innerBorderRectH);
    ctx.restore();

    // Helper for drawing text
    function drawStyledText(text, x, y, fontSize, font, fillStyle, shadowSettings, strokeSettings) {
        ctx.save();
        ctx.font = `bold ${fontSize}px "${font}"`;
        ctx.fillStyle = fillStyle;
        ctx.textAlign = 'center';
        ctx.textBaseline = 'middle';

        if (shadowSettings && shadowSettings.color && shadowSettings.color !== 'transparent') {
            ctx.shadowColor = shadowSettings.color;
            ctx.shadowOffsetX = shadowSettings.offsetX || 0;
            ctx.shadowOffsetY = shadowSettings.offsetY || 0;
            ctx.shadowBlur = shadowSettings.blur || 0;
        }

        if (strokeSettings && strokeSettings.color && strokeSettings.color !== 'transparent' && strokeSettings.width > 0) {
            ctx.strokeStyle = strokeSettings.color;
            ctx.lineWidth = strokeSettings.width;
            ctx.strokeText(text, x, y);
        }
        
        ctx.fillText(text, x, y);
        ctx.restore();
    }

    // 4. Title Text
    const titleY = 90; // Adjusted Y for better spacing
    drawStyledText(titleText, posterWidth / 2, titleY, 70, currentFont, textColor,
        { color: 'rgba(0,0,0,0.7)', offsetX: 4, offsetY: 4, blur: 6 },
        { color: 'black', width: 4 }
    );

    // 5. Image Placement
    const imgFramePadding = 10;
    // Available space for image container (frame + image) considering main borders
    const mainBorderTotalWidth = outerBorderWidth + innerBorderVisualGap + innerBorderLineWidth;
    const imgAreaMargin = mainBorderTotalWidth + 10; // 10px margin from inner border
    
    const imgContainerX = imgAreaMargin;
    const imgContainerY = titleY + 70; // Space below title
    const imgContainerWidth = posterWidth - 2 * imgAreaMargin;
    const imgContainerHeight = 300; 

    let dWidth, dHeight, dx, dy;
    const imgAspectRatio = originalImg.width / originalImg.height;
    const availableImgContentWidth = imgContainerWidth - 2 * imgFramePadding;
    const availableImgContentHeight = imgContainerHeight - 2 * imgFramePadding;
    const contentAspectRatio = availableImgContentWidth / availableImgContentHeight;

    if (imgAspectRatio > contentAspectRatio) {
        dWidth = availableImgContentWidth;
        dHeight = dWidth / imgAspectRatio;
    } else {
        dHeight = availableImgContentHeight;
        dWidth = dHeight * imgAspectRatio;
    }

    dx = imgContainerX + imgFramePadding + (availableImgContentWidth - dWidth) / 2;
    dy = imgContainerY + imgFramePadding + (availableImgContentHeight - dHeight) / 2;
    
    ctx.save();
    ctx.fillStyle = secondaryBgColor; 
    ctx.fillRect(imgContainerX, imgContainerY, imgContainerWidth, imgContainerHeight); 
    ctx.strokeStyle = accentColor;
    ctx.lineWidth = 5; 
    ctx.strokeRect(imgContainerX, imgContainerY, imgContainerWidth, imgContainerHeight); 

    ctx.drawImage(originalImg, dx, dy, dWidth, dHeight);
    ctx.restore();

    // 6. Details Text
    const detailsY = imgContainerY + imgContainerHeight + 45; // Adjusted Y
    drawStyledText(detailsText, posterWidth / 2, detailsY, 30, currentFont, accentColor,
        { color: 'rgba(0,0,0,0.5)', offsetX: 2, offsetY: 2, blur: 3 },
        { color: primaryBgColor, width: 2 }
    );

    // 7. Banner with text
    const bannerY = detailsY + 60;
    const bannerHeight = 60;
    const bannerWidth = posterWidth * 0.85;
    const bannerRectX = (posterWidth - bannerWidth) / 2;

    ctx.save();
    ctx.fillStyle = accentColor;
    ctx.fillRect(bannerRectX, bannerY - bannerHeight / 2, bannerWidth, bannerHeight);

    ctx.font = `bold 35px "${currentFont}"`;
    ctx.fillStyle = bannerTextColor;
    ctx.textAlign = 'center';
    ctx.textBaseline = 'middle';
    ctx.shadowColor = 'rgba(255,255,255,0.4)'; 
    ctx.shadowOffsetX = 1;
    ctx.shadowOffsetY = 1;
    ctx.shadowBlur = 1;
    if (bannerTextColor !== primaryBgColor && bannerTextColor !== 'transparent') {
        ctx.strokeStyle = 'rgba(0,0,0,0.15)';
        ctx.lineWidth = 1;
        if (ctx.lineWidth > 0) ctx.strokeText(bannerText, posterWidth / 2, bannerY);
    }
    ctx.fillText(bannerText, posterWidth / 2, bannerY);
    ctx.restore();

    // 8. Tagline Text
    const taglineY = bannerY + bannerHeight / 2 + 50; // Adjusted Y
    drawStyledText(taglineText, posterWidth / 2, taglineY, 40, currentFont, textColor,
        { color: 'rgba(0,0,0,0.7)', offsetX: 3, offsetY: 3, blur: 5 },
        { color: 'black', width: 3 }
    );

    // 9. Decorative stars
    function drawStar(cx, cy, spikes, outerRadius, innerRadius, starFillColor) {
        ctx.save();
        let rot = Math.PI / 2 * 3;
        let x = cx;
        let y = cy;
        const step = Math.PI / spikes;

        ctx.beginPath();
        ctx.moveTo(cx, cy - outerRadius);
        for (let i = 0; i < spikes; i++) {
            x = cx + Math.cos(rot) * outerRadius;
            y = cy + Math.sin(rot) * outerRadius;
            ctx.lineTo(x, y);
            rot += step;

            x = cx + Math.cos(rot) * innerRadius;
            y = cy + Math.sin(rot) * innerRadius;
            ctx.lineTo(x, y);
            rot += step;
        }
        ctx.lineTo(cx, cy - outerRadius);
        ctx.closePath();
        ctx.fillStyle = starFillColor;
        ctx.fill();
        ctx.restore();
    }
    
    const starPositions = [
        { x: 60, y: posterHeight - 60, outerR: 20, innerR: 10 },
        { x: posterWidth - 60, y: posterHeight - 60, outerR: 20, innerR: 10 },
        { x: posterWidth / 2, y: posterHeight - 45, outerR: 25, innerR: 12 },
        { x: 70, y: titleY + 170, outerR: 15, innerR: 7 }, 
        { x: posterWidth - 70, y: titleY + 170, outerR: 15, innerR: 7 },
        { x: 45, y: 45, outerR: 12, innerR: 5}, 
        { x: posterWidth - 45, y: 45, outerR: 12, innerR: 5}
    ];
    starPositions.forEach(s => drawStar(s.x, s.y, 5, s.outerR, s.innerR, accentColor));

    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 Carnival Fair Poster Creator allows users to design vibrant and engaging carnival-themed posters. This online tool provides customizable options for title text, details, tagline, and banner, along with the ability to include images and apply distinct background colors and styles. Users can utilize it to create promotional posters for events such as fairs, carnivals, festivals, or any gatherings requiring eye-catching visuals. The tool’s user-friendly interface enables quick adjustments to design elements, making it ideal for event planners, marketers, and anyone looking to create festive promotional materials.

Leave a Reply

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