Please bookmark this page to avoid losing your image tool!

Editable Realistic State Driver License Photo Template 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.
function processImage(originalImg, state = 'CA') {
    // Determine canvas dimensions (CR80 standard ratio equivalent roughly)
    const canvas = document.createElement('canvas');
    const w = 1000;
    const h = 630;
    canvas.width = w;
    canvas.height = h;
    const ctx = canvas.getContext('2d');

    // Make sure we have a valid image before starting specific draws
    if (!originalImg || !originalImg.width || !originalImg.height) {
        console.error("Invalid or un-loaded image passed.");
        return canvas;
    }

    // Process State ID
    let requestedState = (state || 'CA').trim().toUpperCase();
    let stateAbbr = requestedState.substring(0, 2);

    // Round corner clipping for realistic physical card
    ctx.beginPath();
    const radius = 25;
    ctx.moveTo(radius, 0);
    ctx.arcTo(w, 0, w, h, radius);
    ctx.arcTo(w, h, 0, h, radius);
    ctx.arcTo(0, h, 0, 0, radius);
    ctx.arcTo(0, 0, w, 0, radius);
    ctx.closePath();
    ctx.clip();

    // 1. Draw Background & Security Patterns
    // Base solid fill
    ctx.fillStyle = '#ffffff';
    ctx.fillRect(0, 0, w, h);

    // Shared generic wavy security pattern base (Guilloche-style look)
    ctx.save();
    ctx.lineWidth = 1.5;
    for (let i = -h; i < h * 2; i += 18) {
        ctx.beginPath();
        ctx.moveTo(0, i);
        ctx.bezierCurveTo(w / 3, i + 180, w * 2 / 3, i - 180, w, i);
        ctx.strokeStyle = 'rgba(150, 160, 200, 0.08)';
        ctx.stroke();
    }
    ctx.restore();

    // 2. Draw State-Specific Header/Background details
    if (requestedState === 'CA' || requestedState === 'CALIFORNIA') {
        stateAbbr = 'CA';
        // Linear gradient background
        const grad = ctx.createLinearGradient(0, 0, w, h);
        grad.addColorStop(0, '#f2f7fb');
        grad.addColorStop(0.5, '#fffdef');
        grad.addColorStop(1, '#e3f1fb');
        ctx.fillStyle = grad;
        ctx.fillRect(0, 0, w, h);

        // Header Text
        ctx.font = 'bold 46px Georgia, serif';
        ctx.fillStyle = '#C90000'; // CA Red
        ctx.textAlign = 'center';
        ctx.textBaseline = 'top';
        ctx.fillText("CALIFORNIA", w / 2, 35);

        ctx.font = 'bold 18px Arial';
        ctx.fillStyle = '#003399';
        ctx.textAlign = 'right';
        ctx.fillText("DRIVER LICENSE", w - 40, 45);

    } else if (requestedState === 'NY' || requestedState === 'NEW YORK') {
        stateAbbr = 'NY';
        // Faint map/lines grid pattern
        ctx.beginPath();
        for (let i = 120; i < h; i += 25) {
            ctx.moveTo(0, i);
            ctx.lineTo(w, i);
        }
        ctx.strokeStyle = '#e0ecf8';
        ctx.lineWidth = 2;
        ctx.stroke();

        // Top Banner
        ctx.fillStyle = '#002D72';
        ctx.fillRect(0, 0, w, 90);
        ctx.fillStyle = '#ffce00';
        ctx.fillRect(0, 90, w, 6);

        // Header Text
        ctx.font = 'bold 42px Arial';
        ctx.fillStyle = '#ffce00';
        ctx.textAlign = 'left';
        ctx.textBaseline = 'top';
        ctx.fillText("NEW YORK STATE", 40, 25);

    } else if (requestedState === 'TX' || requestedState === 'TEXAS') {
        stateAbbr = 'TX';
        ctx.fillStyle = '#f6f9ff';
        ctx.fillRect(0, 0, w, h);

        // TX Top Split Banner
        ctx.fillStyle = '#bf0a30'; // Red
        ctx.fillRect(0, 0, w / 3, 90);
        ctx.fillStyle = '#002868'; // Blue
        ctx.fillRect(w / 3, 0, w * 2 / 3, 90);

        // Draw basic white star
        ctx.fillStyle = '#ffffff';
        ctx.beginPath();
        const cx = w / 6, cy = 45, outerR = 25, innerR = 10;
        let rot = Math.PI / 2 * 3;
        ctx.moveTo(cx, cy - outerR);
        for (let i = 0; i < 5; i++) {
            ctx.lineTo(cx + Math.cos(rot) * outerR, cy + Math.sin(rot) * outerR);
            rot += Math.PI / 5;
            ctx.lineTo(cx + Math.cos(rot) * innerR, cy + Math.sin(rot) * innerR);
            rot += Math.PI / 5;
        }
        ctx.closePath();
        ctx.fill();

        // Header Text
        ctx.font = 'bold 50px Arial';
        ctx.fillStyle = '#ffffff';
        ctx.textAlign = 'center';
        ctx.textBaseline = 'top';
        ctx.fillText("TEXAS", w / 2 + w / 6, 25);

    } else {
        // Generic Template for any other state
        // Procedurally generate unique theme color from string hash
        let hash = 0;
        for (let i = 0; i < requestedState.length; i++) hash = requestedState.charCodeAt(i) + ((hash << 5) - hash);
        const hue = Math.abs(hash % 360);

        ctx.fillStyle = '#f8f8f8';
        ctx.fillRect(0, 0, w, h);

        // Mesh background
        ctx.lineWidth = 1;
        ctx.strokeStyle = `hsla(${hue}, 40%, 70%, 0.2)`;
        for (let x = 0; x < w; x += 30) { ctx.beginPath(); ctx.moveTo(x, 0); ctx.lineTo(x + 150, h); ctx.stroke(); }
        for (let y = 0; y < h; y += 30) { ctx.beginPath(); ctx.moveTo(0, y); ctx.lineTo(w, y + 150); ctx.stroke(); }

        // Top Banner
        ctx.fillStyle = `hsl(${hue}, 70%, 25%)`;
        ctx.fillRect(0, 0, w, 90);
        ctx.fillStyle = `hsl(${(hue + 45) % 360}, 80%, 55%)`; // Accent line
        ctx.fillRect(0, 90, w, 8);

        // Header Text
        ctx.font = 'bold 45px Arial';
        ctx.fillStyle = '#ffffff';
        ctx.textAlign = 'center';
        ctx.textBaseline = 'top';
        ctx.fillText(requestedState, w / 2, 25);
    }

    // Reset common font and text properties
    ctx.textAlign = 'left';
    ctx.textBaseline = 'top';

    // 3. Central Portrait and Photo Drawing
    const pX = 40, pY = 130, pW = 250, pH = 330;
    
    // Scale and crop the original image to strictly fit the ID portrait box aspect ratio
    const aspect = originalImg.width / originalImg.height;
    const targetAspect = pW / pH;
    let sx = 0, sy = 0, sw = originalImg.width, sh = originalImg.height;
    
    if (aspect > targetAspect) {
        // Image is wider than needed
        sw = originalImg.height * targetAspect;
        sx = (originalImg.width - sw) / 2;
    } else {
        // Image is taller than needed
        sh = originalImg.width / targetAspect;
        sy = (originalImg.height - sh) / 2;
    }

    // Draw main portrait
    ctx.drawImage(originalImg, sx, sy, sw, sh, pX, pY, pW, pH);

    // Portrait border
    ctx.strokeStyle = '#555';
    ctx.lineWidth = 2;
    ctx.strokeRect(pX, pY, pW, pH);

    // Draw bottom-right ghost (faint duplicate image) for security look
    ctx.globalAlpha = 0.2;
    ctx.drawImage(originalImg, sx, sy, sw, sh, w - 210, h - 260, 160, 211);
    ctx.globalAlpha = 1.0;

    // 4. Fill ID Data Attributes
    const rightColX = 720;
    // Driver License Number Box
    ctx.fillStyle = '#000';
    ctx.font = 'bold 12px Arial';
    ctx.fillText("4d DL No", rightColX, 130);
    ctx.font = 'bold 28px Arial';
    ctx.fillStyle = '#b00';
    ctx.fillText("D12345678", rightColX + 60, 126);

    // Dates block
    ctx.font = 'bold 12px Arial'; ctx.fillStyle = '#000'; ctx.fillText("4b EXP", rightColX, 180);
    ctx.font = 'bold 22px Arial'; ctx.fillStyle = '#b00'; ctx.fillText("01/01/2030", rightColX + 60, 175);
    
    ctx.font = 'bold 12px Arial'; ctx.fillStyle = '#000'; ctx.fillText("3 DOB", rightColX, 220);
    ctx.font = 'bold 22px Arial'; ctx.fillStyle = '#b00'; ctx.fillText("01/01/1990", rightColX + 60, 215);
    
    ctx.font = 'bold 12px Arial'; ctx.fillStyle = '#000'; ctx.fillText("4a ISS", rightColX, 260);
    ctx.font = 'bold 18px Arial'; ctx.fillStyle = '#000'; ctx.fillText("01/01/2020", rightColX + 60, 257);

    // Person Data
    const textX = 330;
    let nY = 140;

    ctx.font = '12px Arial'; ctx.fillStyle = '#777'; ctx.fillText("1", textX, nY);
    ctx.font = 'bold 24px Arial'; ctx.fillStyle = '#000'; ctx.fillText("SAMPLE", textX + 20, nY - 3);

    ctx.font = '12px Arial'; ctx.fillStyle = '#777'; ctx.fillText("2", textX, nY + 40);
    ctx.font = 'bold 24px Arial'; ctx.fillStyle = '#000'; ctx.fillText("JANE A", textX + 20, nY + 37);

    ctx.font = '12px Arial'; ctx.fillStyle = '#777'; ctx.fillText("8", textX, nY + 95);
    ctx.font = 'bold 18px Arial'; ctx.fillStyle = '#000';
    ctx.fillText("1234 ANYWHERE ST", textX + 20, nY + 93);
    ctx.fillText(`CITY, ${stateAbbr} 12345-6789`, textX + 20, nY + 115);

    // Physical details row
    let attrY = nY + 175;
    const physicalAttrs = [
        { l: "SEX", v: "F" },
        { l: "HAIR", v: "BRN" },
        { l: "EYES", v: "BRN" },
        { l: "HGT", v: "5'-06\"" },
        { l: "WGT", v: "140 lb" },
        { l: "CLASS", v: "C" }
    ];

    let currX = textX;
    physicalAttrs.forEach(attr => {
        ctx.font = '12px Arial'; ctx.fillStyle = '#777'; ctx.fillText(attr.l, currX, attrY);
        ctx.font = 'bold 18px Arial'; ctx.fillStyle = '#000'; ctx.fillText(attr.v, currX, attrY + 18);
        currX += 75;
    });

    // Endorsements
    ctx.font = '14px Arial'; ctx.fillStyle = '#777';
    ctx.fillText("9 END   NONE", textX, attrY + 60);
    ctx.fillText("12 REST NONE", textX + 160, attrY + 60);

    // 5. Holograms / Overlays for ultra realism
    ctx.save();
    // Repeating faint text globally
    ctx.globalAlpha = 0.04;
    ctx.font = 'bold 40px Arial';
    ctx.fillStyle = '#000';
    ctx.translate(w / 2, h / 2);
    ctx.rotate(-Math.PI / 8);
    for (let i = -700; i < 700; i += 220) {
        for (let j = -600; j < 600; j += 100) {
            ctx.fillText("AUTHENTIC", i, j);
        }
    }
    ctx.restore();

    // Circular Hologram overlaying the bottom right corner of portrait
    ctx.save();
    ctx.globalCompositeOperation = "color-dodge";
    const hX = pX + pW, hY = pY + pH;
    const gradSeal = ctx.createRadialGradient(hX, hY, 10, hX, hY, 140);
    gradSeal.addColorStop(0, "rgba(255, 0, 0, 0.4)");
    gradSeal.addColorStop(0.33, "rgba(0, 255, 0, 0.3)");
    gradSeal.addColorStop(0.66, "rgba(0, 0, 255, 0.4)");
    gradSeal.addColorStop(1, "rgba(255, 255, 255, 0)");
    ctx.fillStyle = gradSeal;
    ctx.beginPath();
    ctx.arc(hX, hY, 140, 0, Math.PI * 2);
    ctx.fill();
    
    // Holographic text ring element
    ctx.globalAlpha = 0.4;
    ctx.font = "bold 20px Arial";
    ctx.fillStyle = "rgba(255,255,255,0.7)";
    ctx.translate(hX - 30, hY - 30);
    ctx.rotate(-Math.PI / 4);
    ctx.fillText("SECURE · ISSUANCE", -80, 0);
    ctx.restore();

    // 6. Draw Signature
    ctx.save();
    ctx.globalAlpha = 0.85;
    ctx.font = 'normal 46px "Brush Script MT", "Cedarville Cursive", cursive';
    ctx.fillStyle = '#000044'; // Signature ink color
    ctx.translate(textX + 50, attrY + 120);
    ctx.rotate(-0.06); // Slight signature slant
    ctx.fillText("Jane A Sample", 0, 0);
    ctx.restore();

    // 7. Dummy Barcode / Front MRZ
    let bcX = 40;
    let bcY = 560;
    ctx.fillStyle = 'rgba(0, 0, 0, 0.85)';
    // A classic random 1D barcode looking block at the bottom
    Math.seedrandom = 12345; // Just use math.random but deterministic style length
    for (let i = 0; i < 90; i++) {
        let barW = (Math.random() > 0.5) ? 2 : 5;
        let gap = (Math.random() > 0.5) ? 2 : 4;
        ctx.fillRect(bcX, bcY, barW, 35);
        bcX += barW + gap;
    }

    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 realistic driver’s license photo templates by applying a portrait image to a customized ID card layout. The generator supports various state-specific themes (such as California, New York, and Texas) or produces a generic template with unique color schemes. It automatically applies advanced visual elements including security patterns, guilloché-style backgrounds, holographic overlays, ghosted portrait duplicates, and simulated barcodes. This tool can be used for creative projects, graphic design mockups, or as a template for educational presentations and theatrical props.

Leave a Reply

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