You can edit the below JavaScript code to customize the image tool.
Apply Changes
function processImage(
originalImg,
state = "CALIFORNIA",
name = "Doe, John",
dob = "01/01/1990",
address = "123 Main St\nAnytown, CA 12345",
dlNumber = "A1234567",
expDate = "01/01/2030",
sex = "M",
height = "5'-10\"",
eyes = "BRN"
) {
const canvas = document.createElement('canvas');
const width = 800;
const height_sz = 500;
canvas.width = width;
canvas.height = height_sz;
const ctx = canvas.getContext('2d');
// Make canvas background transparent initially
ctx.clearRect(0, 0, width, height_sz);
// Apply rounded corners clip
ctx.beginPath();
if (ctx.roundRect) {
ctx.roundRect(0, 0, width, height_sz, 20);
} else {
// Fallback for older browsers
ctx.rect(0, 0, width, height_sz);
}
ctx.clip();
// 1. Draw Background (subtle gradient)
const bgGradient = ctx.createLinearGradient(0, 0, 0, height_sz);
bgGradient.addColorStop(0, '#f8fafc'); // White/light slate
bgGradient.addColorStop(1, '#e2e8f0'); // Slightly darker slate
ctx.fillStyle = bgGradient;
ctx.fillRect(0, 0, width, height_sz);
// 2. Draw Decorative Security Pattern (waves)
ctx.strokeStyle = '#cbd5e1';
ctx.lineWidth = 1;
for (let i = -2; i < 20; i++) {
ctx.beginPath();
ctx.moveTo(0, i * 30);
ctx.bezierCurveTo(width / 3, i * 30 + 60, 2 * width / 3, i * 30 - 60, width, i * 30);
ctx.stroke();
}
// 3. Draw Header Bands
// Gold tiny strip
ctx.fillStyle = '#fbbf24';
ctx.fillRect(0, 15, width, 10);
// Main Blue Header
const headerGradient = ctx.createLinearGradient(0, 0, width, 0);
headerGradient.addColorStop(0, '#0284c7');
headerGradient.addColorStop(1, '#38bdf8');
ctx.fillStyle = headerGradient;
ctx.fillRect(0, 25, width, 70);
// 4. Draw Header Text (State)
ctx.fillStyle = '#ffffff';
ctx.font = 'bold 44px Arial, Helvetica, sans-serif';
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
ctx.fillText(state.toUpperCase(), width / 2, 60);
// 5. Draw Document Title
ctx.fillStyle = '#1e293b';
ctx.font = 'bold 22px Arial, Helvetica, sans-serif';
ctx.textAlign = 'center';
ctx.textBaseline = 'alphabetic';
ctx.fillText("DRIVER LICENSE", width / 2, 125);
// 6. Calculate Photo Crop to keep uniform aspect ratio
const photoWidth = 200;
const photoHeight = 260;
const photoX = 40;
const photoY = 150;
const imgAspect = originalImg.width / originalImg.height;
const targetAspect = photoWidth / photoHeight;
let sWidth = originalImg.width;
let sHeight = originalImg.height;
let sx = 0, sy = 0;
if (imgAspect > targetAspect) {
sWidth = originalImg.height * targetAspect;
sx = (originalImg.width - sWidth) / 2;
} else {
sHeight = originalImg.width / targetAspect;
sy = (originalImg.height - sHeight) / 2;
}
// 7. Draw Mock State Seal
const sealX = width - 120;
const sealY = 220;
ctx.save();
ctx.beginPath();
ctx.arc(sealX, sealY, 60, 0, Math.PI * 2);
ctx.lineWidth = 3;
ctx.strokeStyle = 'rgba(251, 191, 36, 0.8)';
ctx.stroke();
ctx.beginPath();
ctx.setLineDash([6, 6]);
ctx.arc(sealX, sealY, 52, 0, Math.PI * 2);
ctx.stroke();
ctx.fillStyle = 'rgba(251, 191, 36, 0.2)';
ctx.fill();
ctx.fillStyle = 'rgba(251, 191, 36, 0.9)';
ctx.font = 'bold 12px Arial';
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
ctx.fillText('STATE SEAL', sealX, sealY);
ctx.restore();
// 8. Draw Ghost Image (bottom right overlay)
ctx.save();
ctx.globalAlpha = 0.15;
ctx.drawImage(originalImg, sx, sy, sWidth, sHeight, width - 180, height_sz - 210, 140, 182);
ctx.restore();
// 9. Draw Main Portrait Photo with Border
ctx.drawImage(originalImg, sx, sy, sWidth, sHeight, photoX, photoY, photoWidth, photoHeight);
ctx.lineWidth = 3;
ctx.strokeStyle = '#1e293b';
ctx.strokeRect(photoX, photoY, photoWidth, photoHeight);
// Helper function for Data Fields
const drawField = (label, value, x, y, valFont = 'bold 20px Arial, Helvetica, sans-serif') => {
ctx.fillStyle = '#dc2626'; // Red for labels
ctx.font = 'bold 12px Arial, Helvetica, sans-serif';
ctx.textAlign = 'left';
ctx.fillText(label, x, y);
ctx.fillStyle = '#0f172a'; // Dark blue/slate for values
ctx.font = valFont;
ctx.fillText(value, x, y + 22);
};
// 10. Draw Data Fields
const startX = 270;
const startY = 165;
drawField('DL NO', dlNumber, startX, startY);
drawField('EXP', expDate, startX + 220, startY);
// Split Name
let lastName = name;
let firstName = '';
if (name.includes(',')) {
const parts = name.split(',');
lastName = parts[0].trim();
firstName = parts[1].trim();
} else {
const parts = name.split(' ');
lastName = parts.pop();
firstName = parts.join(' ');
}
drawField('LN', lastName.toUpperCase(), startX, startY + 55);
drawField('FN', firstName.toUpperCase(), startX, startY + 110);
drawField('DOB', dob, startX, startY + 175);
drawField('SEX', sex, startX + 150, startY + 175);
drawField('HGT', height, startX + 220, startY + 175);
drawField('EYES', eyes, startX + 310, startY + 175);
// Address
ctx.fillStyle = '#dc2626';
ctx.font = 'bold 12px Arial, Helvetica, sans-serif';
ctx.fillText('ADDRESS', startX, startY + 240);
ctx.fillStyle = '#0f172a';
ctx.font = 'bold 18px Arial, Helvetica, sans-serif';
const addressLines = address.split('\n');
for (let i = 0; i < addressLines.length; i++) {
ctx.fillText(addressLines[i].trim(), startX, startY + 262 + (24 * i));
}
// 11. Custom Signature generated from First & Last Name
ctx.fillStyle = '#0f172a';
ctx.font = 'italic 34px "Brush Script MT", "Snell Roundhand", cursive';
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
ctx.fillText((firstName + ' ' + lastName), photoX + (photoWidth / 2), photoY + photoHeight + 35);
// 12. Add a stylized bottom boundary frame to signify an official ID card
ctx.strokeStyle = '#94a3b8';
ctx.lineWidth = 1;
ctx.strokeRect(1, 1, width - 2, height_sz - 2);
return canvas;
}
Apply Changes