Please bookmark this page to avoid losing your image tool!

Image Argentine Passport Editor

(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,
    surname = "PÉREZ",
    givenNames = "JUAN CARLOS",
    nationality = "ARGENTINA",
    dateOfBirth = "01 JAN / ENE 1990",
    sex = "M",
    dateOfIssue = "01 JAN / ENE 2023",
    dateOfExpiry = "01 JAN / ENE 2033",
    authority = "RENAPER",
    documentNo = "12.345.678",
    passportNo = "AAA123456",
    signatureText = "Juan Carlos Pérez"
) {
    // 1. Setup Canvas
    const width = 1250;
    const height = 880;
    const canvas = document.createElement('canvas');
    canvas.width = width;
    canvas.height = height;
    const ctx = canvas.getContext('2d');

    // 2. Load Fonts
    try {
        const signatureFont = new FontFace('Great Vibes', 'url(https://fonts.gstatic.com/s/greatvibes/v15/RWmMoKWR9v4ksMvYd2g_05o.woff2)');
        const mrzFont = new FontFace('OCR-A Std', 'url(https://fonts.gstatic.com/s/ocrastd/v18/PlI-FlOai_a20zia1RMC0w.woff2)');
        await Promise.all([signatureFont.load(), mrzFont.load()]);
        document.fonts.add(signatureFont);
        document.fonts.add(mrzFont);
    } catch (e) {
        console.error("Font loading failed, continuing with fallback fonts.", e);
    }

    // 3. Draw Background
    const gradient = ctx.createLinearGradient(0, 0, width, height);
    gradient.addColorStop(0, '#e8f4ff');
    gradient.addColorStop(1, '#d0e8ff');
    ctx.fillStyle = gradient;
    ctx.fillRect(0, 0, width, height);

    // Faint background text "ARG"
    ctx.font = 'bold 250px Arial';
    ctx.fillStyle = 'rgba(0, 90, 158, 0.08)';
    ctx.textAlign = 'center';
    ctx.textBaseline = 'middle';
    ctx.fillText('ARG', width / 2, height / 2 + 50);

    // Simplified Coat of Arms (Sol de Mayo) in the background
    ctx.fillStyle = 'rgba(255, 223, 0, 0.15)';
    ctx.beginPath();
    const sunX = width * 0.65;
    const sunY = height * 0.55;
    const sunRadius = 180;
    ctx.arc(sunX, sunY, sunRadius, 0, Math.PI * 2);
    ctx.fill();
    for (let i = 0; i < 16; i++) {
        ctx.save();
        ctx.translate(sunX, sunY);
        ctx.rotate(i * Math.PI / 8);
        ctx.beginPath();
        ctx.moveTo(0, sunRadius);
        ctx.lineTo(-20, sunRadius + 50);
        ctx.lineTo(20, sunRadius + 50);
        ctx.closePath();
        ctx.fill();
        ctx.restore();
    }
    ctx.textAlign = 'left';
    ctx.textBaseline = 'alphabetic';


    // 4. Draw Header
    ctx.fillStyle = '#005a9e';
    ctx.font = 'bold 30px Arial';
    ctx.fillText('REPÚBLICA ARGENTINA', 400, 60);
    ctx.font = '24px Arial';
    ctx.fillText('MERCOSUR', 400, 95);
    ctx.font = 'bold 42px Arial';
    ctx.fillText('Pasaporte / Passport', 400, 150);


    // 5. Draw Photo and Ghost Image
    ctx.drawImage(originalImg, 50, 180, 300, 400);
    ctx.strokeStyle = '#ccc';
    ctx.strokeRect(50, 180, 300, 400);

    ctx.globalAlpha = 0.2;
    ctx.drawImage(originalImg, 400, 500, 150, 200);
    ctx.globalAlpha = 1.0;


    // 6. Draw Data Fields
    const startX = 400;
    const startY = 200;
    const lineSpacing = 65;
    const colSpacing1 = 280;
    const colSpacing2 = 560;

    const drawField = (label, value, x, y) => {
        ctx.font = '18px Arial';
        ctx.fillStyle = '#666';
        ctx.fillText(label, x, y);
        ctx.font = 'bold 22px "Courier New", monospace';
        ctx.fillStyle = '#000';
        ctx.fillText(value.toUpperCase(), x, y + 25);
    };

    drawField('Tipo / Type', 'P', startX, startY);
    drawField('Código del país / Code', 'ARG', startX + colSpacing1, startY);
    drawField('N° de Pasaporte / Passport No.', passportNo, startX + colSpacing2, startY);
    drawField('Apellidos / Surnames', surname, startX, startY + lineSpacing);
    drawField('Nombres / Given Names', givenNames, startX, startY + lineSpacing * 2);
    drawField('Nacionalidad / Nationality', nationality, startX, startY + lineSpacing * 3);
    drawField('N° de Documento / Document No.', documentNo, startX + colSpacing1, startY + lineSpacing * 3);
    drawField('Fecha de Nacimiento / Date of Birth', dateOfBirth, startX, startY + lineSpacing * 4);
    drawField('Sexo / Sex', sex, startX + colSpacing1, startY + lineSpacing * 4);
    drawField('Fecha de Emisión / Date of Issue', dateOfIssue, startX, startY + lineSpacing * 5);
    drawField('Fecha de Vencimiento / Date of Expiry', dateOfExpiry, startX + colSpacing1, startY + lineSpacing * 5);
    drawField('Autoridad / Authority', authority, startX, startY + lineSpacing * 6);


    // 7. Draw Signature
    const sigX = 850;
    const sigY = 680;
    ctx.font = '18px Arial';
    ctx.fillStyle = '#666';
    ctx.fillText("Firma del titular / Holder's signature", sigX, sigY + 30);
    ctx.beginPath();
    ctx.moveTo(sigX, sigY + 10);
    ctx.lineTo(sigX + 350, sigY + 10);
    ctx.strokeStyle = '#aaa';
    ctx.lineWidth = 1;
    ctx.stroke();

    ctx.fillStyle = '#111';
    ctx.font = `50px "Great Vibes", cursive`;
    ctx.textAlign = 'center';
    ctx.fillText(signatureText, sigX + 175, sigY);
    ctx.textAlign = 'left';


    // 8. Generate and Draw Machine Readable Zone (MRZ)
    const mrzStartY = height - 100;
    ctx.fillStyle = '#fff';
    ctx.fillRect(0, mrzStartY - 10, width, 110);
    ctx.font = '36px "OCR-A Std", "Courier New", monospace';
    ctx.fillStyle = '#000';

    const charValues = {
        '<': 0, '0': 0, '1': 1, '2': 2, '3': 3, '4': 4, '5': 5, '6': 6, '7': 7, '8': 8, '9': 9,
        'A': 10, 'B': 11, 'C': 12, 'D': 13, 'E': 14, 'F': 15, 'G': 16, 'H': 17, 'I': 18, 'J': 19,
        'K': 20, 'L': 21, 'M': 22, 'N': 23, 'O': 24, 'P': 25, 'Q': 26, 'R': 27, 'S': 28, 'T': 29,
        'U': 30, 'V': 31, 'W': 32, 'X': 33, 'Y': 34, 'Z': 35
    };

    const calculateCheckDigit = (data) => {
        const weights = [7, 3, 1];
        let sum = 0;
        for (let i = 0; i < data.length; i++) {
            sum += (charValues[data[i]] || 0) * weights[i % 3];
        }
        return sum % 10;
    };

    const normalize = (str, len) => String(str).toUpperCase().replace(/[^A-Z0-9]/g, '').padEnd(len, '<');
    const normalizeName = (str) => str.toUpperCase().normalize("NFD").replace(/[\u0300-\u036f]/g, "").replace(/[^A-Z]/g, ' ').replace(/\s+/g, '<');

    const monthMap = {JAN: "01", ENE: "01", FEB: "02", MAR: "03", APR: "04", ABR: "04", MAY: "05", JUN: "06", JUL: "07", AUG: "08", AGO: "08", SEP: "09", OCT: "10", NOV: "11", DEC: "12", DIC: "12" };
    const parseDate = (dateStr) => {
        const parts = dateStr.toUpperCase().split(/[\s/]+/);
        const year = parts[parts.length - 1].slice(-2);
        const month = monthMap[parts[1]] || "01";
        const day = parts[0];
        return `${year}${month}${day}`;
    };

    // Line 1
    const mrzName = (normalizeName(surname) + '<<' + normalizeName(givenNames)).padEnd(39, '<');
    const line1 = ('P<ARG' + mrzName).substring(0, 44);

    // Line 2
    const mrzPassportNo = normalize(passportNo, 9);
    const passNoCD = calculateCheckDigit(mrzPassportNo);
    const mrzDob = parseDate(dateOfBirth);
    const dobCD = calculateCheckDigit(mrzDob);
    const mrzGender = sex.toUpperCase() === 'M' ? 'M' : sex.toUpperCase() === 'F' ? 'F' : '<';
    const mrzExpiry = parseDate(dateOfExpiry);
    const expiryCD = calculateCheckDigit(mrzExpiry);
    const mrzPersonalNo = normalize(documentNo.replace(/\./g, ''), 14);
    const personalNoCD = calculateCheckDigit(mrzPersonalNo);
    const composite = `${mrzPassportNo}${passNoCD}${mrzDob}${dobCD}${mrzExpiry}${expiryCD}${mrzPersonalNo.substring(0,14)}${personalNoCD}`;
    const finalCD = calculateCheckDigit(composite);

    let line2 = mrzPassportNo + passNoCD;
    line2 += 'ARG';
    line2 += mrzDob + dobCD;
    line2 += mrzGender;
    line2 += mrzExpiry + expiryCD;
    line2 += mrzPersonalNo + personalNoCD;
    line2 += finalCD;
    line2 = line2.padEnd(44, '<');
    
    ctx.fillText(line1, 30, mrzStartY + 30);
    ctx.fillText(line2.substring(0, 44), 30, mrzStartY + 80);

    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 Argentine Passport Editor is an online tool that allows users to customize and generate a digital representation of an Argentine passport. Users can upload their own images and input personal details such as surname, given names, nationality, date of birth, sex, passport number, and signature. The tool visually composes these elements into a passport layout, complete with a machine-readable zone (MRZ) that conforms to standard passport formats. This utility is useful for creating mock-ups for design purposes, educational demonstrations of document formats, or personal use for identification purposes in a safe and secure manner.

Leave a Reply

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