You can edit the below JavaScript code to customize the image tool.
Apply Changes
async function processImage(originalImg, lastName = "SMITH", firstName = "JOHN", dob = "01 JAN 1990", issueDate = "01.01.2020", expiryDate = "01.01.2030", licenceNumber = "SMITH0123456AB9CD", address = "123 ANY STREET\nANYTOWN\nAN1 2AB", country = "GB") {
// 1. DYNAMICALLY LOAD FONTS
// Using Google Fonts for a distinct, official look.
const oswaldFont = new FontFace('Oswald', 'url(https://fonts.gstatic.com/s/oswald/v49/TK3_WkUHHAIjg75cFRf3bXL8LICs1_FvgUtiYCrY-A.woff2)');
const dancingScriptFont = new FontFace('Dancing Script', 'url(https://fonts.gstatic.com/s/dancingscript/v24/If2RXTr6YS-zF4S-kcSWSVi_szLviuEViw.woff2)');
try {
await Promise.all([oswaldFont.load(), dancingScriptFont.load()]);
document.fonts.add(oswaldFont);
document.fonts.add(dancingScriptFont);
} catch (e) {
console.error("Font loading failed:", e);
// Fallback to system fonts if Google Fonts fail to load
// The rest of the function will still run, but with basic fonts.
}
// 2. CANVAS SETUP
const canvas = document.createElement('canvas');
const W = 856; // Standard credit card width in pixels (approx 300 DPI)
const H = 540; // Standard credit card height
canvas.width = W;
canvas.height = H;
const ctx = canvas.getContext('2d');
// 3. DRAW BACKGROUND & WATERMARKS
// A subtle gradient background
const bgGradient = ctx.createLinearGradient(0, 0, W, H);
bgGradient.addColorStop(0, '#eaf2f8');
bgGradient.addColorStop(1, '#d2dae2');
ctx.fillStyle = bgGradient;
ctx.fillRect(0, 0, W, H);
// Faint "DVLA" watermark pattern
ctx.save();
ctx.font = 'bold 100px "Oswald"';
ctx.fillStyle = 'rgba(0, 80, 160, 0.04)';
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
ctx.translate(W / 2, H / 2);
ctx.rotate(-Math.PI / 6);
for (let y = -H; y < H; y += 120) {
for (let x = -W; x < W; x += 250) {
ctx.fillText('DVLA', x, y);
}
}
ctx.restore();
// Semi-transparent "ghost" image of the holder
ctx.save();
ctx.globalAlpha = 0.1;
ctx.drawImage(originalImg, 480, 150, 300, 375);
ctx.restore();
// 4. DRAW HEADER ELEMENTS
// "UK" emblem
const drawUKCircle = (x, y, radius) => {
ctx.save();
ctx.fillStyle = '#012169'; // Royal Blue
ctx.beginPath();
ctx.arc(x, y, radius, 0, Math.PI * 2);
ctx.fill();
ctx.fillStyle = 'white';
ctx.font = `bold ${radius * 1.1}px "Oswald"`;
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
ctx.fillText("UK", x, y + 2);
ctx.restore();
};
drawUKCircle(65, 55, 35);
// Title text
ctx.fillStyle = '#012169';
ctx.font = 'bold 36px "Oswald"';
ctx.textAlign = 'left';
ctx.textBaseline = 'top';
ctx.fillText('DRIVING LICENCE', 260, 20);
ctx.font = '22px "Oswald"';
ctx.fillText('UNITED KINGDOM', 260, 65);
// 5. DRAW MAIN CONTENT
// Holder's Photo
ctx.drawImage(originalImg, 40, 120, 180, 230);
ctx.strokeStyle = '#D40000';
ctx.lineWidth = 2;
ctx.strokeRect(40, 120, 180, 230);
// Reusable function to draw labeled data fields
const drawField_ = (num, label, value, x, y, options = {}) => {
ctx.textAlign = 'left';
ctx.textBaseline = 'top';
ctx.fillStyle = '#555';
ctx.font = '14px "Oswald"';
ctx.fillText(`${num} ${label}`, x, y);
ctx.fillStyle = options.color || '#000';
ctx.font = options.font || 'bold 18px "Oswald"';
ctx.fillText(String(value).toUpperCase(), x, y + 16);
};
const dataX = 260;
const dataY = 120;
const fieldGapY = 55;
// Fields 1, 2, 3
drawField_('1.', 'SURNAME', lastName, dataX, dataY);
drawField_('2.', 'FIRST NAME(S)', firstName, dataX, dataY + fieldGapY);
drawField_('3.', 'DATE OF BIRTH / PLACE', `${dob} / ${country}`, dataX, dataY + fieldGapY * 2);
// Field 4 (Dates & Authority)
const dateY = dataY + fieldGapY * 3;
drawField_('4a.', 'DATE OF ISSUE', issueDate, dataX, dateY);
drawField_('4b.', 'DATE OF EXPIRY', expiryDate, dataX + 220, dateY);
drawField_('4c.', 'ISSUING AUTHORITY', 'DVLA', dataX + 440, dateY);
// Field 5 (Licence Number) is prominent
const lNumFormatted = licenceNumber.replace(/(.{5})(.{6})/, '$1 $2 ');
drawField_('5.', 'LICENCE NUMBER', lNumFormatted, dataX, dateY + fieldGapY, {
font: 'bold 24px "Oswald"'
});
// Field 9 (Categories placeholder)
drawField_('9.', 'CATEGORIES', 'AM, A, B1, B, f, k, p, q', dataX, dateY + fieldGapY * 2);
// Signature over the photo
ctx.save();
ctx.globalAlpha = 0.9;
ctx.fillStyle = '#0a2469'; // Blue ink
ctx.font = '35px "Dancing Script"';
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
ctx.fillText(`${firstName} ${lastName}`, 130, 318);
ctx.restore();
// Field 8 (Address) at the bottom
drawField_('8.', 'ADDRESS', '', 40, 420);
const addressLines = address.split('\n');
let addrY = 438;
ctx.fillStyle = '#000';
ctx.font = '16px "Oswald"';
for (const line of addressLines) {
if (line.trim()) {
ctx.fillText(line.trim().toUpperCase(), 40, addrY);
addrY += 20;
}
}
return canvas;
}
Apply Changes