You can edit the below JavaScript code to customize the image tool.
Apply Changes
function processImage(
originalImg,
surname = "SMITH",
givenNames = "JOHN ARTHUR",
dob = "01-01-1990",
placeOfBirth = "LONDON",
issueDate = "15-05-2022",
expiryDate = "14-05-2032",
licenseNumber = "SMITH901010A99X",
address = "10 DOWNING STREET, WESTMINSTER, LONDON, SW1A 2AA"
) {
// Create the container UI
const container = document.createElement("div");
container.style.display = "flex";
container.style.flexDirection = "column";
container.style.alignItems = "center";
container.style.gap = "20px";
container.style.fontFamily = "sans-serif";
container.style.width = "100%";
container.style.padding = "20px";
container.style.boxSizing = "border-box";
// Create the canvas for the realistic driving licence (Standard ID 856x539 px)
const canvas = document.createElement("canvas");
canvas.width = 856;
canvas.height = 539;
canvas.style.maxWidth = "100%";
canvas.style.boxShadow = "0 8px 24px rgba(0,0,0,0.15)";
canvas.style.borderRadius = "12px";
const ctx = canvas.getContext("2d");
// 1. Draw the gradient background (Realistic pink/purple/blue tones)
const bgGradient = ctx.createLinearGradient(0, 0, 856, 539);
bgGradient.addColorStop(0, "#f4dce9"); // Pinkish
bgGradient.addColorStop(0.4, "#e0dcf4"); // Purplish
bgGradient.addColorStop(1, "#cce8ea"); // Light Cyan
ctx.fillStyle = bgGradient;
ctx.fillRect(0, 0, 856, 539);
// 2. Draw standard guilloche/security patterns (Sine waves)
ctx.lineWidth = 0.5;
for (let j = 0; j < 3; j++) {
for (let i = 0; i < 40; i++) {
ctx.beginPath();
const yOffset = i * 15;
ctx.moveTo(0, yOffset);
for (let x = 0; x < 856; x += 5) {
const y = yOffset + Math.sin(x / (20 + j * 10) + i) * (10 + j * 5);
ctx.lineTo(x, y);
}
if (j === 0) ctx.strokeStyle = "rgba(180, 200, 230, 0.4)";
if (j === 1) ctx.strokeStyle = "rgba(220, 180, 200, 0.3)";
if (j === 2) ctx.strokeStyle = "rgba(230, 220, 180, 0.2)";
ctx.stroke();
}
}
// Central circular watermark (Steering wheel/crest illusion)
ctx.globalAlpha = 0.08;
ctx.beginPath();
ctx.arc(520, 270, 120, 0, Math.PI * 2);
ctx.lineWidth = 15;
ctx.strokeStyle = "#333";
ctx.stroke();
ctx.moveTo(520, 150); ctx.lineTo(520, 390);
ctx.moveTo(400, 270); ctx.lineTo(640, 270);
ctx.stroke();
ctx.globalAlpha = 1.0;
// 3. Draw Flag Area (Generic UK flag representation)
ctx.fillStyle = "#012169";
ctx.fillRect(30, 30, 80, 56);
ctx.strokeStyle = "#fff"; ctx.lineWidth = 6;
ctx.beginPath(); ctx.moveTo(30, 30); ctx.lineTo(110, 86); ctx.stroke();
ctx.beginPath(); ctx.moveTo(110, 30); ctx.lineTo(30, 86); ctx.stroke();
ctx.strokeStyle = "#C8102E"; ctx.lineWidth = 2;
ctx.beginPath(); ctx.moveTo(30, 30); ctx.lineTo(110, 86); ctx.stroke();
ctx.beginPath(); ctx.moveTo(110, 30); ctx.lineTo(30, 86); ctx.stroke();
ctx.strokeStyle = "#fff"; ctx.lineWidth = 12;
ctx.beginPath(); ctx.moveTo(70, 30); ctx.lineTo(70, 86); ctx.stroke();
ctx.beginPath(); ctx.moveTo(30, 58); ctx.lineTo(110, 58); ctx.stroke();
ctx.strokeStyle = "#C8102E"; ctx.lineWidth = 7;
ctx.beginPath(); ctx.moveTo(70, 30); ctx.lineTo(70, 86); ctx.stroke();
ctx.beginPath(); ctx.moveTo(30, 58); ctx.lineTo(110, 58); ctx.stroke();
ctx.strokeStyle = "rgba(0,0,0,0.1)"; ctx.lineWidth = 1;
ctx.strokeRect(30, 30, 80, 56);
// 4. Header Text
ctx.fillStyle = "#8a5c73"; // Deep pinkish burgundy
ctx.font = "bold 26px Arial, sans-serif";
ctx.fillText("DRIVING LICENCE", 130, 50);
ctx.fillStyle = "#333";
ctx.font = "italic 16px Arial, sans-serif";
ctx.fillText("UNITED KINGDOM", 130, 72);
// 5. Draw the Main Portrait Photo (Original Image)
const imgRatio = originalImg.width / originalImg.height;
const targetRatio = 180 / 230;
let sW = originalImg.width, sH = originalImg.height, sX = 0, sY = 0;
if (imgRatio > targetRatio) {
sW = originalImg.height * targetRatio;
sX = (originalImg.width - sW) / 2;
} else {
sH = originalImg.width / targetRatio;
sY = (originalImg.height - sH) / 2;
}
// Image Background + Render
ctx.fillStyle = "#ffffff";
ctx.fillRect(30, 115, 180, 230);
ctx.drawImage(originalImg, sX, sY, sW, sH, 30, 115, 180, 230);
ctx.strokeStyle = "rgba(0,0,0,0.4)";
ctx.lineWidth = 1;
ctx.strokeRect(30, 115, 180, 230);
// Security Overlap Fade at bottom of image
const imgGrad = ctx.createLinearGradient(0, 300, 0, 345);
imgGrad.addColorStop(0, "rgba(255,255,255,0)");
imgGrad.addColorStop(1, "rgba(240,245,250,0.6)");
ctx.fillStyle = imgGrad;
ctx.fillRect(30, 300, 180, 45);
// 6. Draw the Ghost Portrait (Security Measure)
ctx.globalAlpha = 0.25;
ctx.drawImage(originalImg, sX, sY, sW, sH, 700, 360, 120, 153);
ctx.globalAlpha = 1.0;
// 7. Write the Fields
function drawLabel(text, x, y) {
ctx.fillStyle = "#996677";
ctx.font = "italic 11px Arial, sans-serif";
ctx.fillText(text, x, y);
}
function drawValue(text, x, y, size = 16) {
ctx.fillStyle = "#111";
ctx.font = `bold ${size}px Arial, sans-serif`;
ctx.fillText(text, x, y);
}
// Line 1: Surname
drawLabel("1. Surname", 230, 120);
drawValue(surname.toUpperCase(), 245, 138);
// Line 2: First names
drawLabel("2. First names", 230, 170);
drawValue(givenNames.toUpperCase(), 245, 188);
// Line 3: DOB and Place
drawLabel("3. Date and place of birth", 230, 220);
drawValue(`${dob} ${placeOfBirth.toUpperCase()}`, 245, 238);
// Line 4a, 4b, 4c: Issue, Expiry, Authority
drawLabel("4a. Date of issue", 230, 270);
drawLabel("4b. Date of expiry", 400, 270);
drawLabel("4c. Issuing authority", 570, 270);
drawValue(issueDate, 245, 288);
drawValue(expiryDate, 415, 288);
drawValue("DVLA", 585, 288);
// Line 5: Licence Number
drawLabel("5. Licence number", 230, 320);
drawValue(licenseNumber.toUpperCase(), 245, 342, 22); // Slightly larger font
// Line 7: Signature
drawLabel("7. Signature", 230, 390);
ctx.fillStyle = "#000044"; // Dark blue ink look
ctx.font = "32px 'Brush Script MT', 'Caveat', 'Segoe Script', cursive";
const sigText = `${givenNames.split(" ")[0].charAt(0)}. ${surname}`;
ctx.fillText(sigText, 250, 420);
// Line 8: Address
drawLabel("8. Address", 440, 390);
const addrLines = address.split(',');
for (let i = 0; i < addrLines.length && i < 4; i++) {
drawValue(addrLines[i].trim().toUpperCase(), 455, 408 + (i * 18), 14);
}
// Line 9: Categories
drawLabel("9. Categories", 230, 470);
drawValue("AM / A / B1 / B", 245, 488);
// Append Canvas to Container
container.appendChild(canvas);
// 8. Add the "Download/Print as PDF" button
const btn = document.createElement("button");
btn.textContent = "Download / Print as PDF";
btn.style.padding = "12px 24px";
btn.style.fontSize = "16px";
btn.style.fontWeight = "bold";
btn.style.cursor = "pointer";
btn.style.border = "none";
btn.style.borderRadius = "8px";
btn.style.background = "#0056b3";
btn.style.color = "#fff";
btn.style.boxShadow = "0 4px 6px rgba(0,0,0,0.1)";
btn.style.transition = "background 0.2s";
btn.onmouseover = () => btn.style.background = "#004494";
btn.onmouseout = () => btn.style.background = "#0056b3";
// Handle PDF saving through Native Printing Dialogue
btn.onclick = () => {
try {
const dataUrl = canvas.toDataURL("image/jpeg", 1.0);
const iframe = document.createElement("iframe");
iframe.style.display = "none";
document.body.appendChild(iframe);
iframe.contentDocument.write(`
<html>
<head>
<title>Driving Licence</title>
<style>
@page { size: landscape; margin: 0; }
body { margin: 0; display: flex; justify-content: center; align-items: center; height: 100vh; background: #fff; }
img { max-width: 100%; max-height: 100%; object-fit: contain; }
</style>
</head>
<body>
<img src="${dataUrl}" />
</body>
</html>
`);
iframe.contentDocument.close();
iframe.onload = () => {
iframe.contentWindow.focus();
iframe.contentWindow.print();
setTimeout(() => document.body.removeChild(iframe), 2000); // Cleanup
};
} catch (e) {
alert("Could not generate PDF. The original image must be securely hosted (CORS) to allow exporting.");
}
};
container.appendChild(btn);
return container;
}
Apply Changes