Please bookmark this page to avoid losing your image tool!

Image Travel Postcard Frame Designer

(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.
function processImage(originalImg,
    locationText = "DESTINATION",
    greetingText = "Greetings from",
    topText = "SOUVENIR",
    fontFamily = "cursive",
    textColor = "#333333",
    cardBackgroundColor = "#FFF8DC", // Cornsilk
    imageMarginPx = 15, // Border around the image
    imageMarginColor = "white",
    outerPaddingPx = 25, // Padding for the whole card content
    displayStamp = 1, // 0 for no, 1 for yes
    stampDetailsColor = "#5A5A5A",
    cardEdgeWidthPx = 2,
    cardEdgeColor = "#D3D3D3" // LightGray
) {
    const imgW = originalImg.width;
    const imgH = originalImg.height;

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

    // 1. Calculate dimensions
    const spacing = outerPaddingPx * 0.5; // Spacing between elements

    // Determine base height for text sections, ensuring it's not too small
    const baseHeightUnitForText = Math.max(20, outerPaddingPx * 0.8); 
    
    const topTextSectionHeight = topText ? Math.max(30, baseHeightUnitForText * 1.2) : 0;
    const bottomTextSectionHeight = (greetingText || locationText) ? Math.max(40, baseHeightUnitForText * 1.8) : 0;

    canvas.width = imgW + (2 * imageMarginPx) + (2 * outerPaddingPx);
    canvas.height = (2 * outerPaddingPx) +
                    topTextSectionHeight + (topTextSectionHeight > 0 ? spacing : 0) +
                    (imgH + 2 * imageMarginPx) +
                    ((greetingText || locationText) ? spacing : 0) + bottomTextSectionHeight;

    // 2. Draw card background
    ctx.fillStyle = cardBackgroundColor;
    ctx.fillRect(0, 0, canvas.width, canvas.height);

    // 3. Draw card edge/border
    if (cardEdgeWidthPx > 0) {
        ctx.strokeStyle = cardEdgeColor;
        ctx.lineWidth = cardEdgeWidthPx;
        // Draw a rect slightly inset if border is thick, to ensure it's fully visible
        const inset = cardEdgeWidthPx / 2;
        ctx.strokeRect(
            inset,
            inset,
            canvas.width - cardEdgeWidthPx,
            canvas.height - cardEdgeWidthPx
        );
    }

    let currentY = outerPaddingPx;
    ctx.textAlign = "center";
    ctx.textBaseline = "middle"; // Consistent baseline for easier vertical centering

    // 4. Draw Top Text
    if (topText) {
        const fontSize = topTextSectionHeight * 0.6; // Font size is 60% of its allocated section height
        ctx.font = `bold ${fontSize}px ${fontFamily}`;
        ctx.fillStyle = textColor;
        ctx.fillText(topText.toUpperCase(), canvas.width / 2, currentY + topTextSectionHeight / 2);
        currentY += topTextSectionHeight + spacing;
    }

    // 5. Draw Image Area (image margin/border + image itself)
    const imageAreaX = outerPaddingPx;
    const imageAreaY = currentY;
    const imageAreaWidth = imgW + 2 * imageMarginPx;
    const imageAreaHeight = imgH + 2 * imageMarginPx;

    // Draw image margin (which acts as a border around the image)
    if (imageMarginPx > 0) {
        ctx.fillStyle = imageMarginColor;
        ctx.fillRect(imageAreaX, imageAreaY, imageAreaWidth, imageAreaHeight);
    }

    // Draw the actual image
    ctx.drawImage(originalImg, imageAreaX + imageMarginPx, imageAreaY + imageMarginPx, imgW, imgH);
    currentY += imageAreaHeight + spacing;

    // 6. Draw Bottom Text (Greeting & Location)
    if (greetingText || locationText) {
        ctx.fillStyle = textColor;

        if (greetingText && locationText) {
            // Roughly allocate 45% height for greeting, 55% for location text
            const greetingPartHeight = bottomTextSectionHeight * 0.45;
            const locationPartHeight = bottomTextSectionHeight * 0.55;

            const greetingFontSize = Math.max(10, greetingPartHeight * 0.7); // Use 70% of its part, min 10px
            const locationFontSize = Math.max(12, locationPartHeight * 0.6); // Use 60% of its part, min 12px

            const greetingY = currentY + greetingPartHeight / 2;
            const locationY = currentY + greetingPartHeight + locationPartHeight / 2;

            ctx.font = `italic ${greetingFontSize}px ${fontFamily}`;
            ctx.fillText(greetingText, canvas.width / 2, greetingY);

            ctx.font = `bold ${locationFontSize}px ${fontFamily}`;
            ctx.fillText(locationText.toUpperCase(), canvas.width / 2, locationY);

        } else if (locationText) { // Only location text
            const locationFontSize = Math.max(12, bottomTextSectionHeight * 0.5); // Use 50% of total height, min 12px
            ctx.font = `bold ${locationFontSize}px ${fontFamily}`;
            ctx.fillText(locationText.toUpperCase(), canvas.width / 2, currentY + bottomTextSectionHeight / 2);
        } else if (greetingText) { // Only greeting text
            const greetingFontSize = Math.max(10, bottomTextSectionHeight * 0.5); // Use 50% of total height, min 10px
            ctx.font = `italic ${greetingFontSize}px ${fontFamily}`;
            ctx.fillText(greetingText, canvas.width / 2, currentY + bottomTextSectionHeight / 2);
        }
        // currentY += bottomTextSectionHeight; // Not strictly needed as stamp is positioned independently
    }

    // 7. Draw Stamp Graphic (Optional)
    if (displayStamp === 1) {
        const stampSizeRatio = 0.10; // Stamp size relative to shorter_canvas_dimension
        const stampSize = Math.max(30, Math.min(canvas.width, canvas.height) * stampSizeRatio); // Min size 30px
        const stampMarginFromEdge = outerPaddingPx * 0.6; // How far from top-right edges
        
        const stampX = canvas.width - stampSize - stampMarginFromEdge;
        const stampY = stampMarginFromEdge;

        ctx.strokeStyle = stampDetailsColor;
        const stampBorderWidth = Math.max(1, stampSize * 0.05); // Border width relative to stamp size
        ctx.lineWidth = stampBorderWidth;
        ctx.strokeRect(stampX, stampY, stampSize, stampSize);

        // Simple decorative "X" lines inside stamp (like a cancellation mark)
        const innerLineMargin = stampSize * 0.2; // Margin for inner lines
        ctx.beginPath();
        ctx.moveTo(stampX + innerLineMargin, stampY + innerLineMargin);
        ctx.lineTo(stampX + stampSize - innerLineMargin, stampY + stampSize - innerLineMargin);
        ctx.moveTo(stampX + stampSize - innerLineMargin, stampY + innerLineMargin);
        ctx.lineTo(stampX + innerLineMargin, stampY + stampSize - innerLineMargin);
        ctx.lineWidth = Math.max(1, stampBorderWidth * 0.7); // Slightly thinner lines inside
        ctx.stroke();
    }

    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 Travel Postcard Frame Designer is a versatile online tool that allows users to create personalized postcard-style images. You can customize your postcards by adding a beautiful frame around your images, with options to include custom text for greetings, locations, and decorative stamps. This tool is perfect for travel enthusiasts looking to present their travel memories creatively, make unique postcards for friends and family, or add a personal touch to social media posts. Its user-friendly interface enables easy adjustments to text, colors, and layouts, providing a fun way to enhance your travel photography.

Leave a Reply

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