You can edit the below JavaScript code to customize the image tool.
Apply Changes
function processImage(
originalImg,
idNumber = "WDL123456789",
lastName = "DOE",
firstName = "JANE SMITH",
dob = "01/01/1990",
expDate = "01/01/2028",
issueDate = "01/01/2023",
addressLine1 = "123 CHERRY BLOSSOM LN",
addressLine2 = "OLYMPIA, WA 98501",
sex = "F",
height = "5-06",
weight = "130",
eyes = "BRN",
hair = "BLK",
donor = "Y"
) {
// Standard ID Card Dimensions ~CR80, upscaled for clarity
const width = 950;
const height_px = 600;
const canvas = document.createElement("canvas");
canvas.width = width;
canvas.height = height_px;
const ctx = canvas.getContext("2d");
// 1. Background Gradient (Pastel Peach to Mint Green to Light Blue)
const bgGrad = ctx.createLinearGradient(0, 0, width, height_px);
bgGrad.addColorStop(0, "#fee9db");
bgGrad.addColorStop(0.5, "#d7ebdd");
bgGrad.addColorStop(1, "#dde5ed");
ctx.fillStyle = bgGrad;
ctx.fillRect(0, 0, width, height_px);
// 2. Security "Guilloche" Waves Pattern
ctx.lineWidth = 0.5;
for (let i = -50; i < height_px + 50; i += 18) {
ctx.beginPath();
ctx.moveTo(0, i);
ctx.bezierCurveTo(300, i - 25, 600, i + 25, width, i);
ctx.strokeStyle = (i % 36 === 0) ? "rgba(162, 22, 80, 0.06)" : "rgba(10, 58, 112, 0.06)";
ctx.stroke();
}
// 3. Header Mountain Silhouette Background
ctx.fillStyle = "rgba(10, 58, 112, 0.08)";
ctx.beginPath();
ctx.moveTo(0, 160);
ctx.lineTo(80, 130);
ctx.lineTo(180, 150);
ctx.lineTo(350, 90);
ctx.lineTo(500, 130);
ctx.lineTo(680, 80);
ctx.lineTo(820, 110);
ctx.lineTo(950, 60);
ctx.lineTo(950, 0);
ctx.lineTo(0, 0);
ctx.closePath();
ctx.fill();
// 4. Large Yellow "WA" Background Watermark
ctx.font = "bold 320px Arial";
ctx.fillStyle = "rgba(255, 215, 0, 0.15)";
ctx.textAlign = "center";
ctx.fillText("WA", width / 2 + 100, 450);
ctx.textAlign = "left";
// 5. Header Texts
// "WASHINGTON"
ctx.font = "bold 58px 'Times New Roman', Times, serif";
ctx.fillStyle = "#051f4e";
ctx.fillText("WASHINGTON", 320, 75);
// "USA"
ctx.font = "bold 26px Arial, sans-serif";
ctx.fillStyle = "#051f4e";
ctx.fillText("USA", 240, 70);
// "FEDERAL LIMITS APPLY"
ctx.font = "bold 14px Arial, sans-serif";
ctx.fillStyle = "#000";
ctx.fillText("FEDERAL LIMITS APPLY", 750, 40);
// "IDENTIFICATION CARD" Banner
ctx.fillStyle = "#A21650"; // Dark Pink commonly used for WA ID (contrasted to Green/Blue for DL)
ctx.fillRect(320, 85, 450, 36);
ctx.font = "bold 22px Arial, sans-serif";
ctx.fillStyle = "#FFF";
ctx.fillText("IDENTIFICATION CARD", 420, 111);
// Helper to draw rounded rectangles
function drawRoundRect(x, y, w, h, r) {
ctx.beginPath();
ctx.moveTo(x + r, y);
ctx.lineTo(x + w - r, y);
ctx.quadraticCurveTo(x + w, y, x + w, y + r);
ctx.lineTo(x + w, y + h - r);
ctx.quadraticCurveTo(x + w, y + h, x + w - r, y + h);
ctx.lineTo(x + r, y + h);
ctx.quadraticCurveTo(x, y + h, x, y + h - r);
ctx.lineTo(x, y + r);
ctx.quadraticCurveTo(x, y, x + r, y);
ctx.closePath();
}
// 6. Photo Calculations (Maintain Aspect Ratio 3:4)
const pW = 260;
const pH = 346;
const pX = 40;
const pY = 140;
let imgW = originalImg.width;
let imgH = originalImg.height;
let targetRatio = pW / pH;
let imgRatio = imgW / imgH;
let sx, sy, sw, sh;
if (imgRatio > targetRatio) {
sh = imgH;
sw = imgH * targetRatio;
sx = (imgW - sw) / 2;
sy = 0;
} else {
sw = imgW;
sh = imgW / targetRatio;
sx = 0;
sy = (imgH - sh) / 2;
}
// 7. Draw Main Photo
ctx.save();
drawRoundRect(pX, pY, pW, pH, 12);
ctx.clip();
ctx.drawImage(originalImg, sx, sy, sw, sh, pX, pY, pW, pH);
ctx.restore();
ctx.strokeStyle = "rgba(0,0,0,0.2)";
ctx.lineWidth = 1;
ctx.stroke(); // Draw border for the clipped photo
// 8. Draw Ghost Photo (Faded, bottom right)
ctx.save();
ctx.globalAlpha = 0.35;
drawRoundRect(740, 340, 160, 213, 8);
ctx.clip();
ctx.drawImage(originalImg, sx, sy, sw, sh, 740, 340, 160, 213);
ctx.restore();
// 9. Info Fields Setup
const startX = 330;
const labelColor = "#A21650"; // WA field labels matching ID pink/red tone
const valColorText = "#000";
const valColorRed = "#d41c1c";
let currY = 175;
// Helper to draw Label + Text
function drawLabelAndVal(label, val, x, y, valFont, valColor, spacing = 0) {
ctx.font = "bold 13px Arial, sans-serif";
ctx.fillStyle = labelColor;
ctx.fillText(label, x, y);
ctx.font = valFont;
ctx.fillStyle = valColor;
// Calculate dynamic spacing if not provided
if (spacing === 0) {
spacing = ctx.measureText(label).width + 8;
}
ctx.fillText(val, x + spacing, y + (valFont.includes("32px") ? 2 : 1));
}
// ID Number (4d)
ctx.font = "bold 14px Arial, sans-serif";
ctx.fillStyle = labelColor;
ctx.fillText("4d", startX, currY);
ctx.font = "bold 34px Arial, sans-serif";
ctx.fillStyle = "#051f4e"; // Dark blue for ID number
ctx.fillText(idNumber, startX + 30, currY + 2);
// DOB & EXP Row
currY += 45;
drawLabelAndVal("3 DOB", dob, startX, currY, "bold 22px Arial", valColorRed, 50);
drawLabelAndVal("4b EXP", expDate, startX + 220, currY, "bold 22px Arial", valColorRed, 60);
// Name Fields
currY += 45;
drawLabelAndVal("1", lastName, startX, currY, "bold 22px Arial", valColorText, 25);
currY += 32;
drawLabelAndVal("2", firstName, startX, currY, "bold 22px Arial", valColorText, 25);
// Address
currY += 45;
ctx.font = "bold 13px Arial"; ctx.fillStyle = labelColor; ctx.fillText("8", startX, currY);
ctx.font = "bold 18px Arial"; ctx.fillStyle = valColorText;
ctx.fillText(addressLine1, startX + 25, currY);
ctx.fillText(addressLine2, startX + 25, currY + 24);
// Physical Attributes Row
currY += 75;
const physLabels = ["15 SEX", "16 HGT", "17 WGT", "18 EYES", "HAIR"];
const physVals = [sex, height, weight, eyes, hair];
const physX = [startX, startX + 85, startX + 175, startX + 265, startX + 355];
for (let i = 0; i < 5; i++) {
ctx.font = "bold 13px Arial";
ctx.fillStyle = labelColor;
ctx.fillText(physLabels[i], physX[i], currY);
ctx.font = "bold 19px Arial";
ctx.fillStyle = valColorText;
ctx.fillText(physVals[i], physX[i], currY + 26);
}
// Issue Date
currY += 70;
drawLabelAndVal("4a ISS", issueDate, startX, currY, "bold 18px Arial", valColorText, 55);
// 10. Donor Status
if (donor.toUpperCase() === "Y" || donor.toUpperCase() === "YES" || donor.toUpperCase() === "TRUE") {
ctx.fillStyle = "#D32F2F";
ctx.font = "40px Arial, sans-serif";
ctx.fillText("♥", 820, 200);
ctx.fillStyle = "#000";
ctx.font = "bold 12px Arial, sans-serif";
ctx.fillText("DONOR", 813, 222);
}
// 11. Fake Barcode & Document Discriminator
ctx.font = "24px monospace";
ctx.fillStyle = "#333";
ctx.fillText("|| ||| | || | ||| ||", 740, 570);
ctx.font = "12px Arial";
ctx.fillStyle = "#555";
ctx.fillText("DD 109283746591029", 740, 585);
// Bottom Left Text
ctx.font = "bold 10px Arial";
ctx.fillStyle = labelColor;
ctx.fillText("WASHINGTON STATE IDENTIFICATION CARD", 30, 585);
// 12. Signature (Overlapping bottom of the photo)
ctx.font = "italic 44px 'Brush Script MT', 'Cedarville Cursive', 'Bradley Hand', 'Lucida Handwriting', cursive";
ctx.fillStyle = "#111"; // Almost black, simulating pen
let sigText = firstName + " " + lastName;
// Capitalize first letters only for cursive aesthetics
sigText = sigText.toLowerCase().replace(/\b\w/g, c => c.toUpperCase());
ctx.save();
ctx.shadowColor = "rgba(255,255,255,0.7)";
ctx.shadowBlur = 4;
// Rotate counter-clockwise slightly for natural flair
ctx.translate(65, 520);
ctx.rotate(-0.06);
ctx.fillText(sigText, 0, 0);
ctx.restore();
return canvas;
}
Apply Changes