Please bookmark this page to avoid losing your image tool!

Minnesota Driver’s License Image Generator

(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,
    lastName = "PUBLIC",
    firstName = "JOHN",
    address1 = "123 MAIN ST",
    address2 = "MINNEAPOLIS, MN 55401",
    dob = "01/01/1990",
    dlNumber = "A123-456-789-123",
    exp = "01/01/2028",
    sex = "M",
    height = "5'-10\"",
    eyes = "BLU",
    weight = "180",
    cardClass = "D"
) {
    // Normalize string inputs to uppercase as typical for IDs
    lastName = lastName.toUpperCase();
    firstName = firstName.toUpperCase();
    address1 = address1.toUpperCase();
    address2 = address2.toUpperCase();
    dlNumber = dlNumber.toUpperCase();
    dob = dob.toUpperCase();
    exp = exp.toUpperCase();
    sex = sex.toUpperCase();
    height = height.toUpperCase();
    eyes = eyes.toUpperCase();
    weight = weight.toUpperCase();
    cardClass = cardClass.toUpperCase();

    // Dynamically load Dancing Script font for the signature
    const fontId = 'google-font-dancing-script';
    if (!document.getElementById(fontId)) {
        const link = document.createElement('link');
        link.id = fontId;
        link.rel = 'stylesheet';
        link.href = 'https://fonts.googleapis.com/css2?family=Dancing+Script:wght@700&display=swap';
        document.head.appendChild(link);
        await new Promise(resolve => {
            link.onload = resolve;
            setTimeout(resolve, 1500); // 1.5s fallback to ensure execution continues
        });
    }
    // Attempt to strictly wait for font readiness
    try {
        await document.fonts.load('28px "Dancing Script"');
    } catch (e) {
        console.warn("Font loading gracefully failed.", e);
    }

    // Initialize Canvas (Standard ID Card Aspect Ratio, high-res)
    const cw = 800;
    const ch = 500;
    const canvas = document.createElement("canvas");
    canvas.width = cw;
    canvas.height = ch;
    const ctx = canvas.getContext("2d");

    // Helper: Rounded Rectangle Path Builder
    function buildRoundRectPath(x, y, w, h, r) {
        ctx.beginPath();
        ctx.moveTo(x + r, y);
        ctx.lineTo(x + w - r, y);
        ctx.arcTo(x + w, y, x + w, y + r, r);
        ctx.lineTo(x + w, y + h - r);
        ctx.arcTo(x + w, y + h, x + w - r, y + h, r);
        ctx.lineTo(x + r, y + h);
        ctx.arcTo(x, y + h, x, y + h - r, r);
        ctx.lineTo(x, y + r);
        ctx.arcTo(x, y, x + r, y, r);
        ctx.closePath();
    }

    // Step 1: Base Card Clip (Round the external borders)
    buildRoundRectPath(0, 0, cw, ch, 15);
    ctx.clip();

    // Step 2: Base Background Gradient
    let cardGrd = ctx.createLinearGradient(0, 100, 0, 500);
    cardGrd.addColorStop(0, "#ffffff");
    cardGrd.addColorStop(0.5, "#eef6fa"); // subtle blueish tint
    cardGrd.addColorStop(1, "#f4eee0"); // subtle yellowish tint
    ctx.fillStyle = cardGrd;
    ctx.fillRect(0, 0, cw, ch);

    // Step 3: Draw Wavy Header Motif (like MN Real ID)
    ctx.beginPath();
    ctx.moveTo(0, 0);
    ctx.lineTo(cw, 0);
    ctx.lineTo(cw, 140);
    ctx.bezierCurveTo(600, 100, 300, 160, 0, 110);
    ctx.closePath();
    let headGrd = ctx.createLinearGradient(0, 0, cw, 0);
    headGrd.addColorStop(0, "#8cd731"); // nature green
    headGrd.addColorStop(0.5, "#3d97e2"); // lake blue
    headGrd.addColorStop(1, "#f7df2b"); // sun yellow
    ctx.fillStyle = headGrd;
    ctx.fill();

    // Step 4: Watermark & Guilloche Pattern (MN shape with repeated text overlaying)
    ctx.save();
    ctx.translate(450, 280);
    const scale = 320;
    const mnPoints = [
        [-0.15, -0.45], [0.0, -0.45], [0.0, -0.3], [0.35, -0.15], [0.15, 0.0],
        [0.1, 0.15], [0.3, 0.3], [0.3, 0.45], [-0.3, 0.45],
        [-0.3, 0.05], [-0.4, -0.15], [-0.4, -0.35], [-0.15, -0.35]
    ];
    ctx.beginPath();
    ctx.moveTo(mnPoints[0][0] * scale, mnPoints[0][1] * scale);
    for (let i = 1; i < mnPoints.length; i++) {
        ctx.lineTo(mnPoints[i][0] * scale, mnPoints[i][1] * scale);
    }
    ctx.closePath();
    
    // Fill slightly and clip for inner micro-text watermark
    ctx.fillStyle = "rgba(100, 150, 200, 0.08)";
    ctx.fill();
    ctx.lineWidth = 3;
    ctx.strokeStyle = "rgba(100, 150, 200, 0.15)";
    ctx.stroke();
    
    ctx.clip(); // Limit text to map boundaries
    ctx.fillStyle = "rgba(100, 150, 200, 0.15)";
    ctx.font = "bold 12px Arial";
    for(let y = -250; y < 250; y += 20) {
        for(let x = -250; x < 250; x += 100) {
            ctx.fillText("MINNESOTA", x + ((y / 20) % 2) * 40, y);
        }
    }
    ctx.restore();

    // Step 5: Draw Top Header Text
    ctx.font = "bold 56px Helvetica, Arial";
    ctx.fillStyle = "#ffffff";
    ctx.textAlign = "center";
    ctx.shadowColor = "rgba(0,0,0,0.5)";
    ctx.shadowBlur = 4;
    ctx.shadowOffsetX = 1;
    ctx.shadowOffsetY = 1;
    ctx.fillText("MINNESOTA", cw / 2, 65);

    ctx.shadowBlur = 0;
    ctx.shadowOffsetX = 0;
    ctx.shadowOffsetY = 0;

    // Sub-header Text
    ctx.font = "bold 17px Arial";
    ctx.fillStyle = "#0c2858";
    ctx.fillText("DRIVER'S LICENSE", cw / 2, 95);

    // USA Circular Stamp
    ctx.beginPath();
    ctx.arc(50, 50, 22, 0, Math.PI * 2);
    ctx.fillStyle = "rgba(255, 255, 255, 0.85)";
    ctx.fill();
    ctx.fillStyle = "#0c2858";
    ctx.font = "bold 15px Arial";
    ctx.fillText("USA", 50, 55);

    // Real ID Star Stamp
    ctx.save();
    ctx.translate(740, 60);
    ctx.beginPath();
    ctx.arc(0, 0, 24, 0, Math.PI * 2);
    ctx.fillStyle = "#d3a625"; // metallic gold
    ctx.fill();
    ctx.lineWidth = 1.5;
    ctx.strokeStyle = "#a37c15";
    ctx.stroke();

    ctx.beginPath();
    let spikes = 5, outerRadius = 14, innerRadius = 5.5;
    let rot = Math.PI / 2 * 3, step = Math.PI / spikes;
    ctx.moveTo(0, -outerRadius);
    for (let i = 0; i < spikes; i++) {
        ctx.lineTo(Math.cos(rot) * outerRadius, Math.sin(rot) * outerRadius);
        rot += step;
        ctx.lineTo(Math.cos(rot) * innerRadius, Math.sin(rot) * innerRadius);
        rot += step;
    }
    ctx.closePath();
    ctx.fillStyle = "#ffffff";
    ctx.fill();
    ctx.restore();

    // Step 6: Text Field Details Helpers
    function drawField(labelNo, labelText, value, x, y, isRed = false, customFont = "bold 19px Arial") {
        ctx.textAlign = "left";
        
        // Red numbering color for field prefixes in MN style
        ctx.font = "bold 10px Arial";
        ctx.fillStyle = "#d32f2f";
        ctx.fillText(labelNo, x, y - 20);
        let noWidth = ctx.measureText(labelNo).width + 3;
        
        // Blue descriptive text
        ctx.fillStyle = "#0c2858";
        ctx.font = "10px Arial";
        ctx.fillText(labelText, x + noWidth, y - 20);
        
        // Final Value mapping
        ctx.font = customFont;
        ctx.fillStyle = isRed ? "#d32f2f" : "#000000";
        ctx.fillText(value, x, y);
    }

    // Map out the fields
    drawField("4d", "DL NO.", dlNumber, 245, 155, false, "bold 26px Arial");
    drawField("3", "DOB", dob, 245, 205, true);
    drawField("4b", "EXP", exp, 395, 205, true);
    drawField("4a", "ISS", "08/15/2023", 535, 205); // Simulated issuance date
    drawField("1", "NAME", lastName, 245, 260);
    drawField("", "", firstName, 245, 283);
    
    drawField("8", "ADDRESS", address1, 245, 335);
    drawField("", "", address2, 245, 358);

    drawField("15", "SEX", sex, 245, 410);
    drawField("16", "HGT", height, 315, 410);
    drawField("17", "WGT", weight, 395, 410);
    drawField("18", "EYES", eyes, 475, 410);

    drawField("9", "CLASS", cardClass, 245, 465);
    drawField("9a", "END", "NONE", 325, 465);
    drawField("12", "REST", "NONE", 415, 465);

    // Document Discriminator Vertical Text
    ctx.save();
    ctx.translate(225, 420);
    ctx.rotate(-Math.PI / 2);
    ctx.font = "10px Arial";
    ctx.fillStyle = "#666666";
    ctx.fillText("DD: 494532882190A", 0, 0);
    ctx.restore();

    // Step 7: Draw Image Profiles (Main and Ghost)
    function drawImgWithinRect(img, x, y, w, h, isGhost = false) {
        ctx.save();
        if (isGhost) ctx.globalAlpha = 0.35;
        
        buildRoundRectPath(x, y, w, h, 8);
        ctx.clip();
        
        const imgAspect = img.width / img.height;
        const rectAspect = w / h;
        let sx, sy, sw, sh;
        
        if (imgAspect > rectAspect) {
            sh = img.height;
            sw = img.height * rectAspect;
            sx = (img.width - sw) / 2;
            sy = 0;
        } else {
            sw = img.width;
            sh = img.width / rectAspect;
            sx = 0;
            sy = (img.height - sh) / 2;
        }
        
        ctx.drawImage(img, sx, sy, sw, sh, x, y, w, h);
        ctx.restore();

        // Draw thin boundary line for the portrait box
        ctx.lineWidth = 1;
        ctx.strokeStyle = isGhost ? "rgba(100,100,100,0.2)" : "#aaaaaa";
        buildRoundRectPath(x, y, w, h, 8);
        ctx.stroke();
    }

    if (originalImg && originalImg.width && originalImg.height) {
        // Main Photo
        drawImgWithinRect(originalImg, 35, 130, 180, 240, false);
        // Ghost Photo
        drawImgWithinRect(originalImg, 630, 290, 135, 180, true);
    }

    // Step 8: Client Signature
    ctx.textAlign = "center";
    ctx.font = '28px "Dancing Script", cursive';
    ctx.fillStyle = "#000000";
    ctx.fillText(`${firstName} ${lastName}`, 125, 420);
    
    // Thin line under signature
    ctx.beginPath();
    ctx.moveTo(40, 425);
    ctx.lineTo(210, 425);
    ctx.lineWidth = 1;
    ctx.strokeStyle = "#999999";
    ctx.stroke();
    
    // Tiny signature label text
    ctx.font = "8px Arial";
    ctx.fillStyle = "#0c2858";
    ctx.fillText("SIGNATURE", 125, 435);

    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

This tool allows users to generate a simulated Minnesota-style driver’s license image by inputting personal details and an uploaded photo. Users can customize various identification fields such as name, address, date of birth, driver’s license number, expiration date, and physical attributes like height, weight, and eye color. The generator processes these inputs to create a high-resolution digital layout featuring a stylized background, watermark effects, and both a primary and a ghost portrait. This tool can be used for creative projects, UI/UX design prototyping, or as a placeholder in software development testing.

Leave a Reply

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