You can edit the below JavaScript code to customize the image tool.
Apply Changes
/**
* Creates a custom Oklahoma Driver's License image.
* IMPORTANT: This tool is for novelty and entertainment purposes only.
* Creating and using fake identification is illegal and can have severe consequences.
* This function does not create a real or passable ID.
*/
async function processImage(
originalImg,
licenseNumber = '999000111',
issueDate = '08-14-2023',
expirationDate = '08-14-2027',
dateOfBirth = '08-14-1990',
lastName = 'DOE',
firstName = 'JANE',
middleName = 'A',
address = '123 ANYWHERE ST',
city = 'OKLAHOMA CITY',
state = 'OK',
zipCode = '73102',
sex = 'F',
height = '5\'-06"',
weight = '140 LBS',
eyes = 'BRO'
) {
/**
* Dynamically loads a Google Font by creating a <link> element.
* This ensures the font is available for use on the canvas.
* @param {string} fontName - The name of the font to load from Google Fonts.
*/
const loadGoogleFont = async (fontName, fontStyle = '') => {
const fontId = `google-font-${fontName.replace(/\s/g, '-')}`;
if (document.getElementById(fontId)) {
await document.fonts.load(`${fontStyle} 12px "${fontName.split(':')[0]}"`);
return; // Already added
}
const link = document.createElement('link');
link.id = fontId;
link.rel = 'stylesheet';
link.href = `https://fonts.googleapis.com/css2?family=${fontName.replace(/\s/g, '+')}&display=swap`;
document.head.appendChild(link);
// Wait for the font to be loaded and ready for use.
await document.fonts.load(`${fontStyle} 12px "${fontName.split(':')[0]}"`);
};
// Load necessary fonts from Google Fonts
await loadGoogleFont('Roboto+Condensed:wght@400;700', 'normal');
await loadGoogleFont('Roboto+Condensed:wght@400;700', 'bold');
await loadGoogleFont('Dancing+Script', 'normal');
await loadGoogleFont('Libre+Barcode+39+Text', 'normal');
// Canvas setup based on CR80 ID card dimensions (scaled up for resolution)
const W = 1011;
const H = 638;
const canvas = document.createElement('canvas');
canvas.width = W;
canvas.height = H;
const ctx = canvas.getContext('2d');
ctx.imageSmoothingEnabled = true;
// --- Draw Background ---
const gradient = ctx.createLinearGradient(0, 0, W, H);
gradient.addColorStop(0, '#d1e9f1');
gradient.addColorStop(0.5, '#e0f2f1');
gradient.addColorStop(1, '#e3f2e4');
ctx.fillStyle = gradient;
ctx.fillRect(0, 0, W, H);
// --- Draw Header ---
// Simple state seal representation
ctx.fillStyle = '#6e9bc7';
ctx.beginPath();
ctx.arc(80, 80, 45, 0, Math.PI * 2);
ctx.fill();
ctx.fillStyle = 'white';
ctx.font = 'bold 50px "Roboto Condensed"';
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
ctx.fillText('OK', 80, 80);
// Reset canvas text alignment for subsequent drawing
ctx.textAlign = 'left';
ctx.textBaseline = 'alphabetic';
// Header Text
ctx.fillStyle = '#1e3a8a'; // Dark Blue
ctx.font = 'bold 70px "Roboto Condensed"';
ctx.fillText('OKLAHOMA', 150, 90);
ctx.fillStyle = '#4b5563'; // Gray
ctx.font = '40px "Roboto Condensed"';
ctx.fillText('DRIVER LICENSE', 155, 135);
// --- Draw Photos ---
// Main Photo
const photoX = 40;
const photoY = 180;
const photoW = 300;
const photoH = 375;
ctx.drawImage(originalImg, photoX, photoY, photoW, photoH);
ctx.strokeStyle = '#374151';
ctx.lineWidth = 2;
ctx.strokeRect(photoX, photoY, photoW, photoH);
// Ghost Photo (semi-transparent overlay)
ctx.globalAlpha = 0.15;
ctx.drawImage(originalImg, 400, 250, 400, 500);
ctx.globalAlpha = 1.0;
// --- Draw Data Fields ---
const dataStartX = 380;
const labelColor = '#d9534f';
const dataColor = '#1f2937';
const labelFont = '20px "Roboto Condensed"';
const dataFont = 'bold 24px "Roboto Condensed"';
const drawField = (label, value, x, y) => {
ctx.font = labelFont;
ctx.fillStyle = labelColor;
ctx.fillText(label, x, y);
ctx.font = dataFont;
ctx.fillStyle = dataColor;
ctx.fillText(value.toUpperCase(), x + 5, y + 25);
};
// DL Number (larger and more prominent)
ctx.font = labelFont;
ctx.fillStyle = labelColor;
ctx.fillText('DLN', dataStartX, 175);
ctx.font = 'bold 36px "Roboto Condensed"';
ctx.fillStyle = labelColor;
ctx.fillText(licenseNumber, dataStartX + 45, 178);
let currentY = 220;
const lineSpacing = 65;
// Name Fields
drawField('LN', lastName, dataStartX, currentY);
drawField('FN', `${firstName} ${middleName}`, dataStartX + 250, currentY);
currentY += lineSpacing;
// Address Fields
drawField('ADDRESS', address, dataStartX, currentY);
currentY += lineSpacing;
drawField('', `${city}, ${state} ${zipCode}`, dataStartX, currentY);
currentY += lineSpacing;
// Date Fields
drawField('DOB', dateOfBirth, dataStartX, currentY);
drawField('ISS', issueDate, dataStartX + 250, currentY);
drawField('EXP', expirationDate, dataStartX + 500, currentY);
currentY += lineSpacing;
// Physical Attributes
drawField('SEX', sex, dataStartX, currentY);
drawField('HGT', height, dataStartX + 120, currentY);
drawField('WGT', weight, dataStartX + 270, currentY);
drawField('EYES', eyes, dataStartX + 420, currentY);
// --- Draw Signature ---
const sigX = 40;
const sigY = 590;
ctx.strokeStyle = '#1f2937';
ctx.lineWidth = 1;
ctx.beginPath();
ctx.moveTo(sigX, sigY);
ctx.lineTo(sigX + 300, sigY);
ctx.stroke();
ctx.fillStyle = '#0a2140';
ctx.font = '35px "Dancing Script"';
ctx.fillText(`${firstName} ${lastName}`, sigX + 20, sigY - 10);
// --- Draw Footer Barcode ---
ctx.font = '40px "Libre Barcode 39 Text"';
ctx.fillStyle = '#000';
ctx.textAlign = 'center';
ctx.fillText(`*${licenseNumber}${lastName}*`, W/2, H - 25);
return canvas;
}
Apply Changes