Please bookmark this page to avoid losing your image tool!

Image ID 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.
function processImage(
    originalImg,
    fullName = "John Doe",
    idNumber = "ID-12345",
    title = "Employee",
    department = "General Department",
    issueDate = "01/01/2024",
    expiryDate = "01/01/2028",
    companyName = "Secure Identity Corp.",
    signatureText = "", // Default to empty, user can pass fullName or custom.
    cardWidth = 400,
    cardHeight = 240,
    backgroundColor = "#FFFFFF",
    textColor = "#2C3E50",
    accentColor = "#3498DB",
    headerTextColor = "#FFFFFF",
    fontFamily = "Helvetica, Arial, sans-serif",
    signatureFontFamily = "Brush Script MT, cursive, sans-serif",
    cardBorderRadius = 10,
    profilePicSize = 80,
    profilePicStyle = "circle", // "square" or "circle"
    headerFontSize = 20,
    nameFontSize = 18,
    detailFontSize = 15,    // For title
    labelFontSize = 12,     // For ID, Dept, Dates and their labels
    signatureTextSize = 15
) {

    // Helper function to draw rounded rectangles
    function drawRoundedRect(ctx, x, y, width, height, radiusInput) {
        let radius = {tl: 0, tr: 0, br: 0, bl: 0};
        if (typeof radiusInput === 'number') {
            radius = {tl: radiusInput, tr: radiusInput, br: radiusInput, bl: radiusInput};
        } else if (typeof radiusInput === 'object') {
            for (let side in radius) {
                radius[side] = radiusInput[side] || 0;
            }
        }

        ctx.beginPath();
        ctx.moveTo(x + radius.tl, y);
        ctx.lineTo(x + width - radius.tr, y);
        ctx.quadraticCurveTo(x + width, y, x + width, y + radius.tr);
        ctx.lineTo(x + width, y + height - radius.br);
        ctx.quadraticCurveTo(x + width, y + height, x + width - radius.br, y + height);
        ctx.lineTo(x + radius.bl, y + height);
        ctx.quadraticCurveTo(x, y + height, x, y + height - radius.bl);
        ctx.lineTo(x, y + radius.tl);
        ctx.quadraticCurveTo(x, y, x + radius.tl, y);
        ctx.closePath();
    }

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

    // Margins and layout constants
    const padding = Math.min(cardWidth, cardHeight) * 0.045; // General padding
    const headerHeight = headerFontSize + padding * 1.8; // Adjusted for better font fit

    // 1. Card Background
    ctx.fillStyle = backgroundColor;
    if (cardBorderRadius > 0) {
        drawRoundedRect(ctx, 0, 0, cardWidth, cardHeight, cardBorderRadius);
        ctx.fill();
    } else {
        ctx.fillRect(0, 0, cardWidth, cardHeight);
    }
    
    // Clip subsequent drawings to the card's rounded shape
    if (cardBorderRadius > 0) {
        ctx.save(); // Save context state before applying clip
        drawRoundedRect(ctx, 0, 0, cardWidth, cardHeight, cardBorderRadius);
        ctx.clip();
    }

    // 2. Header
    ctx.fillStyle = accentColor;
    ctx.fillRect(0, 0, cardWidth, headerHeight);

    ctx.fillStyle = headerTextColor;
    ctx.font = `bold ${headerFontSize}px ${fontFamily}`;
    ctx.textAlign = 'center';
    ctx.textBaseline = 'middle';
    
    // Basic text fitting for company name in header
    let currentHeaderFontSize = headerFontSize;
    const maxHeaderTextWidth = cardWidth - padding * 4; // More padding for header text
    while(ctx.measureText(companyName).width > maxHeaderTextWidth && currentHeaderFontSize > 8) {
        currentHeaderFontSize--;
        ctx.font = `bold ${currentHeaderFontSize}px ${fontFamily}`;
    }
    ctx.fillText(companyName, cardWidth / 2, headerHeight / 2);

    // 3. Profile Picture
    const profilePicActualSize = profilePicSize;
    const profilePicX = padding * 2;
    const profilePicY = headerHeight + padding;

    // Calculate cropping for the profile picture
    let sx = 0, sy = 0, sWidth = originalImg.width, sHeight = originalImg.height;
    const imgAspectRatio = originalImg.width / originalImg.height;
    const targetAspectRatio = 1; // For square/circle

    if (imgAspectRatio > targetAspectRatio) {
        sWidth = originalImg.height * targetAspectRatio;
        sx = (originalImg.width - sWidth) / 2;
    } else if (imgAspectRatio < targetAspectRatio) {
        sHeight = originalImg.width / targetAspectRatio;
        sy = (originalImg.height - sHeight) / 2;
    }

    ctx.save(); // Save context for potential profile picture clipping
    if (profilePicStyle === 'circle') {
        ctx.beginPath();
        ctx.arc(profilePicX + profilePicActualSize / 2, profilePicY + profilePicActualSize / 2, profilePicActualSize / 2, 0, Math.PI * 2, true);
        ctx.closePath();
        ctx.clip();
    }
    ctx.drawImage(originalImg, sx, sy, sWidth, sHeight, profilePicX, profilePicY, profilePicActualSize, profilePicActualSize);
    ctx.restore(); // Restore context (removes clipping for picture)

    // Border around profile picture
    ctx.strokeStyle = accentColor;
    ctx.lineWidth = 2; // Border thickness
    if (profilePicStyle === 'circle') {
        ctx.beginPath();
        ctx.arc(profilePicX + profilePicActualSize / 2, profilePicY + profilePicActualSize / 2, profilePicActualSize / 2, 0, Math.PI * 2, true);
        ctx.stroke();
    } else { 
        ctx.strokeRect(profilePicX, profilePicY, profilePicActualSize, profilePicActualSize);
    }

    // 4. Text Details
    const textStartX = profilePicX + profilePicActualSize + padding * 1.5;
    let currentY = headerHeight + padding;
    const lineSpacingMultiplier = 1.45; // Increased for better readability
    const textAvailableWidth = cardWidth - textStartX - padding * 2; // Ensure padding on right side

    ctx.fillStyle = textColor;
    ctx.textAlign = 'left';
    ctx.textBaseline = 'top';

    // Full Name
    ctx.font = `bold ${nameFontSize}px ${fontFamily}`;
    ctx.fillText(fullName, textStartX, currentY, textAvailableWidth);
    currentY += nameFontSize * lineSpacingMultiplier;

    // Title
    ctx.font = `${detailFontSize}px ${fontFamily}`;
    ctx.fillText(title, textStartX, currentY, textAvailableWidth);
    currentY += detailFontSize * lineSpacingMultiplier;

    currentY += padding * 0.3; // Smaller space before details block

    // Helper to draw label and value pairs
    function drawLabelValue(label, value, yPos) {
        const labelText = label + " "; // Add space after label
        ctx.font = `bold ${labelFontSize}px ${fontFamily}`;
        ctx.fillText(labelText, textStartX, yPos, textAvailableWidth); 
        
        const labelWidth = ctx.measureText(labelText).width;
        ctx.font = `${labelFontSize}px ${fontFamily}`;
        // Check if value text fits, otherwise it will be drawn outside or compressed by fillText's maxWidth
        const valueMaxWidth = textAvailableWidth - labelWidth - (padding * 0.2);
        ctx.fillText(value, textStartX + labelWidth, yPos, valueMaxWidth > 0 ? valueMaxWidth : 0);
        
        return yPos + labelFontSize * lineSpacingMultiplier;
    }

    currentY = drawLabelValue("ID:", idNumber, currentY);
    currentY = drawLabelValue("Dept:", department, currentY);
    currentY = drawLabelValue("Issued:", issueDate, currentY);
    currentY = drawLabelValue("Expires:", expiryDate, currentY);
    
    // 5. Signature (if signatureText is provided)
    if (signatureText && signatureText.trim() !== "") {
        const signatureLineYOffset = signatureTextSize * 0.8; 
        const signatureAreaMinY = profilePicY + profilePicActualSize + padding; // Below profile picture
        const signatureAreaMaxY = cardHeight - padding - signatureTextSize - signatureLineYOffset; // Above card bottom

        // Position signature: attempt after text details, but ensure it's within bounds
        let signatureTextBaselineY = Math.max(currentY + padding, signatureAreaMinY);
        signatureTextBaselineY = Math.min(signatureTextBaselineY, signatureAreaMaxY);

        ctx.font = `italic ${signatureTextSize}px ${signatureFontFamily}`;
        ctx.fillStyle = textColor;
        ctx.textAlign = 'left';
        ctx.textBaseline = 'alphabetic'; // Better for precise line placement under text
        
        ctx.fillText(signatureText, textStartX, signatureTextBaselineY + signatureTextSize * 0.8, textAvailableWidth);

        ctx.strokeStyle = textColor;
        ctx.lineWidth = 1; 
        ctx.beginPath();
        const signatureDrawLineY = signatureTextBaselineY + signatureTextSize * 0.8 + ctx.lineWidth + 1;
        ctx.moveTo(textStartX, signatureDrawLineY);
        const signatureLineWidth = Math.min(ctx.measureText(signatureText).width * 1.1, textAvailableWidth); 
        ctx.lineTo(textStartX + signatureLineWidth, signatureDrawLineY);
        ctx.stroke();
    }
    
    // Restore context if it was saved for card border clipping
    if (cardBorderRadius > 0) {
        ctx.restore();
    }

    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 ID Card Template Creator is an online tool that allows users to create customized ID cards using their images. Users can input personal details such as name, ID number, title, department, issue and expiry dates, and company name to generate a professional-looking ID card. The tool supports various styles for the profile picture, customizable colors, and text formatting options, making it suitable for businesses, organizations, and events that require identification cards for employees, staff, or participants. Additionally, users can include a signature to enhance the authenticity of the ID card. Overall, this tool simplifies the process of designing and producing ID cards quickly and effectively.

Leave a Reply

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