You can edit the below JavaScript code to customize the image tool.
Apply Changes
function processImage(
originalImg,
p_fullName = "JOHN A. DOE",
p_address = "123 MAIN ST, ANYTOWN, ST 12345",
p_dateOfBirth = "01/01/1980",
p_licenseNumber = "A12345678",
p_issueDate = "01/01/2020",
p_expiryDate = "01/01/2028",
p_stateName = "STATE OF EXAMPLE",
p_licenseClass = "C",
p_sex = "M",
p_height = "5'-10\"",
p_eyeColor = "BLU",
p_signatureText = "John A. Doe", // If empty, just a line will be drawn
p_realIdStar = "YES", // "YES" or "NO"
p_organDonor = "YES" // "YES" or "NO"
) {
const W = 600;
const H = 380;
const canvas = document.createElement('canvas');
canvas.width = W;
canvas.height = H;
const ctx = canvas.getContext('2d');
// Helper function to draw a star (for Real ID)
function _drawStarFS(context, cx, cy, spikes, outerRadius, innerRadius) {
let rot = Math.PI / 2 * 3;
let x = cx;
let y = cy;
let step = Math.PI / spikes;
context.beginPath();
context.moveTo(cx, cy - outerRadius);
for (let i = 0; i < spikes; i++) {
x = cx + Math.cos(rot) * outerRadius;
y = cy + Math.sin(rot) * outerRadius;
context.lineTo(x, y);
rot += step;
x = cx + Math.cos(rot) * innerRadius;
y = cy + Math.sin(rot) * innerRadius;
context.lineTo(x, y);
rot += step;
}
context.lineTo(cx, cy - outerRadius);
context.closePath();
}
// 1. Background
ctx.fillStyle = '#E8F0F8'; // A light, slightly blueish background
ctx.fillRect(0, 0, W, H);
// Subtle background grid (placeholder for security patterns)
ctx.strokeStyle = '#D0D8E0';
ctx.lineWidth = 0.5;
for (let i = 0; i < W; i += 10) {
ctx.beginPath(); ctx.moveTo(i, 0); ctx.lineTo(i, H); ctx.stroke();
}
for (let i = 0; i < H; i += 10) {
ctx.beginPath(); ctx.moveTo(0, i); ctx.lineTo(W, i); ctx.stroke();
}
ctx.lineWidth = 1; // Reset line width
// 2. Header
ctx.textAlign = 'center';
ctx.fillStyle = '#003366'; // Dark blue for header
ctx.font = 'bold 26px Arial';
ctx.fillText(p_stateName.toUpperCase(), W / 2, 45);
ctx.font = 'bold 18px Arial';
ctx.fillText("DRIVER LICENSE", W / 2, 70);
// 3. Photo
const photoX = 30;
const photoY = 90;
const photoWidth = 100;
const photoHeight = 125;
if (originalImg && originalImg.complete && originalImg.naturalWidth !== 0) {
try {
ctx.drawImage(originalImg, photoX, photoY, photoWidth, photoHeight);
} catch (e) {
console.error("Error drawing image:", e);
// Draw a placeholder if image drawing fails
ctx.fillStyle = '#CCCCCC';
ctx.fillRect(photoX, photoY, photoWidth, photoHeight);
ctx.fillStyle = '#888888';
ctx.font = '12px Arial';
ctx.textAlign = 'center';
ctx.fillText("Photo Error", photoX + photoWidth/2, photoY + photoHeight/2);
}
} else {
ctx.fillStyle = '#CCCCCC';
ctx.fillRect(photoX, photoY, photoWidth, photoHeight);
ctx.fillStyle = '#888888';
ctx.font = '12px Arial';
ctx.textAlign = 'center';
ctx.fillText("No Photo", photoX + photoWidth/2, photoY + photoHeight/2);
}
ctx.strokeStyle = '#333';
ctx.strokeRect(photoX, photoY, photoWidth, photoHeight);
ctx.textAlign = 'left'; // Reset textAlign
// 4. Main Information Block (Right of Photo)
ctx.fillStyle = 'black';
const infoX = photoX + photoWidth + 20;
let currentY = photoY + 5;
const N_lh = 18;
const B_lh = 22;
const labelWidth = 70;
const valueX = infoX + labelWidth;
// License Number
ctx.font = '10px Arial';
ctx.fillText("NUMBER", infoX, currentY);
ctx.font = 'bold 14px "Courier New", monospace';
ctx.fillText(String(p_licenseNumber).toUpperCase(), valueX, currentY);
currentY += B_lh;
// Full Name
ctx.font = '10px Arial';
ctx.fillText("NAME", infoX, currentY);
ctx.font = 'bold 12px Arial';
ctx.fillText(String(p_fullName).toUpperCase(), valueX, currentY);
currentY += B_lh;
// Address
ctx.font = '10px Arial';
ctx.fillText("ADDRESS", infoX, currentY);
ctx.font = '10px Arial';
const addressLines = String(p_address).toUpperCase().split(',');
let addrLineY = currentY;
if (addressLines.length > 0 && addressLines[0].trim() !== "") {
ctx.fillText(addressLines[0].trim(), valueX, addrLineY);
if (addressLines.length > 1 && addressLines.slice(1).join(',').trim() !== "") {
addrLineY += N_lh - 4;
ctx.fillText(addressLines.slice(1).join(',').trim(), valueX, addrLineY);
}
}
currentY = addrLineY + N_lh;
// Date of Birth
ctx.font = '10px Arial';
ctx.fillText("DOB", infoX, currentY);
ctx.font = '12px Arial';
ctx.fillText(String(p_dateOfBirth), valueX, currentY);
currentY += N_lh;
// Issue Date
ctx.font = '10px Arial';
ctx.fillText("ISS", infoX, currentY);
ctx.font = '12px Arial';
ctx.fillText(String(p_issueDate), valueX, currentY);
currentY += N_lh;
// Expiry Date
ctx.font = '10px Arial';
ctx.fillText("EXP", infoX, currentY);
ctx.font = '12px Arial';
ctx.fillText(String(p_expiryDate), valueX, currentY);
// 5. Physical Descriptors and Class (Below Photo)
let physDescY = photoY + photoHeight + 18;
const physDescX = photoX;
const physColWidth = 75;
const physValOffset = 30;
ctx.font = '10px Arial';
ctx.fillText("SEX", physDescX, physDescY);
ctx.font = '12px Arial';
ctx.fillText(String(p_sex).toUpperCase(), physDescX + physValOffset, physDescY);
ctx.font = '10px Arial';
ctx.fillText("HGT", physDescX + physColWidth, physDescY);
ctx.font = '12px Arial';
ctx.fillText(String(p_height).toUpperCase(), physDescX + physColWidth + physValOffset, physDescY);
ctx.font = '10px Arial';
ctx.fillText("EYES", physDescX + physColWidth*2, physDescY);
ctx.font = '12px Arial';
ctx.fillText(String(p_eyeColor).toUpperCase(), physDescX + physColWidth*2 + physValOffset, physDescY);
physDescY += N_lh;
ctx.font = '10px Arial';
ctx.fillText("CLASS", physDescX, physDescY);
ctx.font = '12px Arial';
ctx.fillText(String(p_licenseClass).toUpperCase(), physDescX + physValOffset, physDescY);
if (String(p_organDonor).toUpperCase() === "YES") {
ctx.fillStyle = 'red';
ctx.font = 'bold 11px Arial';
ctx.fillText("❤ ORGAN DONOR", physDescX + physColWidth -5 , physDescY);
ctx.fillStyle = 'black';
}
// 6. Signature Area
const sigLineY = H - 50;
const sigXstart = photoX;
const sigXend = infoX + 180;
const sigTextY = sigLineY - 7;
ctx.beginPath();
ctx.moveTo(sigXstart, sigLineY);
ctx.lineTo(sigXend, sigLineY);
ctx.strokeStyle = 'black';
ctx.lineWidth = 1;
ctx.stroke();
if (p_signatureText && String(p_signatureText).trim() !== "") {
ctx.font = "italic 18px 'Segoe Script', cursive";
ctx.fillStyle = '#102040';
ctx.textAlign = 'left';
ctx.fillText(String(p_signatureText), sigXstart + 5, sigTextY);
}
ctx.font = '8px Arial';
ctx.fillStyle = 'black';
ctx.textAlign = 'center';
ctx.fillText("SIGNATURE", (sigXstart + sigXend) / 2, sigLineY + 10);
ctx.textAlign = 'left';
// 7. Ghost Photo
const ghWidth = 45;
const ghHeight = 55;
const ghX = W - ghWidth - 30;
const ghY = H - ghHeight - 60;
if (originalImg && originalImg.complete && originalImg.naturalWidth !== 0) {
try {
ctx.globalAlpha = 0.35;
ctx.drawImage(originalImg, ghX, ghY, ghWidth, ghHeight);
ctx.globalAlpha = 1.0;
} catch (e) {
ctx.globalAlpha = 1.0; // Reset alpha if error
// placeholder for ghost photo error
}
}
ctx.strokeStyle = '#B0B0B0';
ctx.lineWidth = 0.5;
ctx.strokeRect(ghX, ghY, ghWidth, ghHeight);
ctx.lineWidth = 1;
// 8. Real ID Star
if (String(p_realIdStar).toUpperCase() === "YES") {
const starCenterX = W - 40;
const starCenterY = 40;
const starOuterRadius = 13;
const starInnerRadius = 5;
ctx.beginPath();
ctx.arc(starCenterX, starCenterY, starOuterRadius, 0, 2 * Math.PI, false);
ctx.fillStyle = '#FFD700';
ctx.fill();
ctx.fillStyle = 'white';
_drawStarFS(ctx, starCenterX, starCenterY, 5, starOuterRadius * 0.85, starInnerRadius * 0.8);
ctx.fill();
}
// Footer text
ctx.font = 'bold 8px Arial';
ctx.fillStyle = '#555555';
ctx.textAlign = 'right';
const footerText = String(p_stateName).split(" ").map(s => s[0]).join("") + "-ID";
ctx.fillText(footerText.toUpperCase(), W - 15, H - 15);
ctx.textAlign = 'left';
return canvas;
}
Apply Changes