You can edit the below JavaScript code to customize the image tool.
Apply Changes
async function processImage(originalImg, lastName = "DOE", firstName = "JOHN", dob = "01/01/1990", idNumber = "I1234567", expDate = "01/01/2030", address1 = "123 MAIN ST", address2 = "SACRAMENTO, CA 95814", sex = "M", hair = "BRN", eyes = "BRO", height = "5'-10\"", weight = "180 lb") {
// 1. Load Custom Fonts
const style = document.createElement('style');
style.innerHTML = `@import url('https://fonts.googleapis.com/css2?family=Great+Vibes&family=Roboto:wght@400;700&display=swap');`;
document.head.appendChild(style);
try {
await document.fonts.load('400 60px "Great Vibes"');
await document.fonts.load('700 20px "Roboto"');
await document.fonts.load('400 20px "Roboto"');
} catch (e) {
console.warn("Fonts may not have loaded completely.", e);
}
// 2. Setup Canvas
const canvas = document.createElement('canvas');
const w = 800;
const h = 508; // Typical credit card aspect ratio ~ 1.585
canvas.width = w;
canvas.height = h;
const ctx = canvas.getContext('2d');
// 3. Rounded Boundaries Clip
const radius = 25;
ctx.beginPath();
ctx.moveTo(radius, 0);
ctx.lineTo(w - radius, 0);
ctx.quadraticCurveTo(w, 0, w, radius);
ctx.lineTo(w, h - radius);
ctx.quadraticCurveTo(w, h, w - radius, h);
ctx.lineTo(radius, h);
ctx.quadraticCurveTo(0, h, 0, h - radius);
ctx.lineTo(0, radius);
ctx.quadraticCurveTo(0, 0, radius, 0);
ctx.clip();
// 4. Draw Background Linear Gradient
const gradient = ctx.createLinearGradient(0, 0, w, h);
gradient.addColorStop(0, '#c7dced'); // Light blue
gradient.addColorStop(0.5, '#f5f0db'); // Pale gold/beige
gradient.addColorStop(1, '#e3c5d6'); // Light pinkish
ctx.fillStyle = gradient;
ctx.fillRect(0, 0, w, h);
// 5. Draw Security Lines (Guilloche Pattern)
ctx.lineWidth = 1;
for (let wave = 1; wave < 35; wave++) {
ctx.beginPath();
for (let x = 0; x <= w; x += 5) {
let y = h / 2 + Math.sin(x * 0.015 + wave * 0.4) * 90 + (wave * 18 - 320);
if (x === 0) ctx.moveTo(x, y);
else ctx.lineTo(x, y);
}
ctx.strokeStyle = (wave % 2 === 0) ? 'rgba(255, 255, 255, 0.4)' : 'rgba(120, 180, 240, 0.2)';
ctx.stroke();
}
// 6. Draw California Map Watermark
ctx.save();
ctx.translate(330, 90);
ctx.scale(1.8, 1.8);
ctx.fillStyle = 'rgba(230, 210, 130, 0.45)';
ctx.beginPath();
ctx.moveTo(35, 0);
ctx.lineTo(70, 35);
ctx.lineTo(135, 120);
ctx.lineTo(165, 200);
ctx.lineTo(125, 225);
ctx.lineTo(95, 205);
ctx.lineTo(55, 150);
ctx.lineTo(40, 90);
ctx.lineTo(5, 50);
ctx.closePath();
ctx.fill();
ctx.restore();
// 7. Draw Header Elements
ctx.textAlign = 'center';
ctx.fillStyle = '#1b4e82';
ctx.font = 'normal 60px "Great Vibes", cursive';
ctx.fillText('California', w / 2, 75);
ctx.font = 'bold 15px "Roboto", Arial';
ctx.textAlign = 'left';
ctx.fillText('USA', 30, 45);
ctx.textAlign = 'center';
ctx.font = 'bold 18px "Roboto", Arial';
ctx.fillText('IDENTIFICATION CARD', w / 2, 115);
// Draw REAL ID Gold Star
ctx.save();
ctx.translate(730, 50);
ctx.fillStyle = '#D4AF37'; // Gold
ctx.beginPath();
for (let i = 0; i < 5; i++) {
ctx.lineTo(Math.cos((18 + i * 72) / 180 * Math.PI) * 22, -Math.sin((18 + i * 72) / 180 * Math.PI) * 22);
ctx.lineTo(Math.cos((54 + i * 72) / 180 * Math.PI) * 10, -Math.sin((54 + i * 72) / 180 * Math.PI) * 10);
}
ctx.closePath();
ctx.fill();
ctx.restore();
// 8. Image Drawing Helper Function
function drawImageCover(imgData, boxX, boxY, boxW, boxH, alpha = 1.0) {
ctx.save();
ctx.globalAlpha = alpha;
// White border
ctx.fillStyle = '#ffffff';
ctx.fillRect(boxX - 3, boxY - 3, boxW + 6, boxH + 6);
ctx.strokeStyle = '#cccccc';
ctx.lineWidth = 1;
ctx.strokeRect(boxX - 3, boxY - 3, boxW + 6, boxH + 6);
ctx.beginPath();
ctx.rect(boxX, boxY, boxW, boxH);
ctx.clip();
let imgAspect = imgData.width / imgData.height;
let boxAspect = boxW / boxH;
let drawW, drawH, drawX, drawY;
if (imgAspect > boxAspect) {
drawH = boxH;
drawW = imgData.width * (boxH / imgData.height);
drawX = boxX + (boxW - drawW) / 2;
drawY = boxY;
} else {
drawW = boxW;
drawH = imgData.height * (boxW / imgData.width);
drawX = boxX;
drawY = boxY + (boxH - drawH) / 6;
}
ctx.drawImage(imgData, drawX, drawY, drawW, drawH);
ctx.restore();
}
// Draw Main Photo
drawImageCover(originalImg, 30, 135, 200, 260);
// Draw Ghost Photo
drawImageCover(originalImg, 640, 315, 110, 143, 0.35);
// 9. Draw Text Fields
ctx.textAlign = 'left';
function drawLineData(label, val, x, y, isRed = false, overrideLabelFont, overrideValFont) {
ctx.fillStyle = '#0a3663';
ctx.font = overrideLabelFont || 'bold 12px "Roboto", Arial, sans-serif';
ctx.fillText(label, x, y);
let lblWidth = ctx.measureText(label).width;
ctx.fillStyle = isRed ? '#cc1f1f' : '#000000';
ctx.font = overrideValFont || 'bold 16px "Roboto", Arial, sans-serif';
ctx.fillText(val, x + lblWidth + 10, y);
}
// Row 1
drawLineData('ID', idNumber, 260, 160, false, null, 'bold 20px "Roboto", Arial');
drawLineData('DOB', dob, 480, 160, true);
// Row 2
drawLineData('EXP', expDate, 260, 200, true);
// Row 3
drawLineData('LN', lastName, 260, 240);
// Row 4
drawLineData('FN', firstName, 260, 280);
// Address
ctx.fillStyle = '#000000';
ctx.font = '16px "Roboto", Arial, sans-serif';
ctx.fillText(address1, 310, 315);
ctx.fillText(address2, 310, 340);
// Traits Table
ctx.strokeStyle = '#0a3663';
ctx.lineWidth = 1.5;
ctx.beginPath();
ctx.moveTo(260, 375);
ctx.lineTo(610, 375);
ctx.stroke();
const cols = [
{ label: 'SEX', val: sex, x: 260 },
{ label: 'HAIR', val: hair, x: 330 },
{ label: 'EYES', val: eyes, x: 400 },
{ label: 'HGT', val: height, x: 470 },
{ label: 'WGT', val: weight, x: 540 }
];
cols.forEach(col => {
ctx.fillStyle = '#0a3663';
ctx.font = 'bold 11px "Roboto", Arial';
ctx.fillText(col.label, col.x, 395);
ctx.fillStyle = '#000000';
ctx.font = 'bold 15px "Roboto", Arial';
ctx.fillText(col.val, col.x, 415);
});
// Issuance Date
ctx.fillStyle = '#0a3663';
ctx.font = 'bold 12px "Roboto", Arial';
const currentDate = new Date();
const issDate = ('0' + (currentDate.getMonth() + 1)).slice(-2) + '/' + ('0' + currentDate.getDate()).slice(-2) + '/' + currentDate.getFullYear();
ctx.fillText('ISS ' + issDate, 30, 425);
// Photo overlay DOB watermark
ctx.save();
ctx.fillStyle = 'rgba(255, 255, 255, 0.9)';
ctx.shadowColor = 'black';
ctx.shadowBlur = 3;
ctx.font = 'bold 18px "Roboto", Arial';
ctx.fillText('DOB ' + dob, 35, 385);
ctx.restore();
// 10. Drawer Signature
ctx.textAlign = 'center';
ctx.fillStyle = '#03172e';
ctx.font = 'normal 42px "Great Vibes", cursive';
ctx.fillText(`${firstName} ${lastName}`, 420, 475);
// Return the generated ID canvas
return canvas;
}
Apply Changes