You can edit the below JavaScript code to customize the image tool.
Apply Changes
/**
* Creates a canvas element representing a novelty California-style ID card.
* This is intended for creative and novelty purposes only. Do not use for any fraudulent or illegal activity.
* The design is a simplified artistic representation and not an exact replica of any official document.
*
* @param {Image} originalImg The user's portrait image.
* @param {string} lastName The last name to display on the ID.
* @param {string} firstName The first name to display on the ID.
* @param {string} address The address line.
* @param {string} dob The date of birth (e.g., "01-01-1990").
* @param {string} issueDate The issue date (e.g., "01-01-2024").
* @param {string} expDate The expiration date (e.g., "01-01-2029").
* @param {string} idNumber The ID number.
* @param {string} sex The sex (e.g., "F" or "M").
* @param {string} hair The hair color abbreviation (e.g., "BRN").
* @param {string} eyes The eye color abbreviation (e.g., "BRN").
* @param {string} height The height (e.g., "5-05").
* @param {string} weight The weight (e.g., "120").
* @returns {Promise<HTMLCanvasElement>} A promise that resolves with the canvas element containing the generated ID card.
*/
async function processImage(
originalImg,
lastName = "DOE",
firstName = "JANE",
address = "123 MAIN ST ANYTOWN, CA 91234",
dob = "01-01-1990",
issueDate = "01-01-2024",
expDate = "01-01-2029",
idNumber = "D12345678",
sex = "F",
hair = "BRN",
eyes = "BRN",
height = "5-05",
weight = "120"
) {
// Helper function to dynamically load a font if it's not already available.
const loadFont = async (fontName, fontUrl) => {
if ([...document.fonts].some(f => f.family === fontName)) {
return; // Font already loaded
}
const fontFace = new FontFace(fontName, `url(${fontUrl})`);
try {
await fontFace.load();
document.fonts.add(fontFace);
} catch (e) {
console.error(`Font ${fontName} could not be loaded from ${fontUrl}:`, e);
}
};
// Load fonts needed for the ID card design
await Promise.all([
loadFont('Roboto Condensed', 'https://fonts.gstatic.com/s/robotocondensed/v27/ieVl2ZhZI2eCN5jzbjEETS9weq8-19-7DRs5.woff2'),
loadFont('Satisfy', 'https://fonts.gstatic.com/s/satisfy/v15/rP2Hp2yn6lkG5EJnan1Baw.woff2')
]);
// Canvas setup - standard ID card aspect ratio (CR80: 85.6mm x 53.98mm ≈ 1.586)
const W = 856;
const H = 540;
const canvas = document.createElement('canvas');
canvas.width = W;
canvas.height = H;
const ctx = canvas.getContext('2d');
// --- Draw Background ---
const bgGradient = ctx.createLinearGradient(0, 0, W, H);
bgGradient.addColorStop(0, '#f0f8ff'); // AliceBlue
bgGradient.addColorStop(0.5, '#fff0f5'); // LavenderBlush
bgGradient.addColorStop(1, '#f5deb3'); // Wheat
ctx.fillStyle = bgGradient;
ctx.fillRect(0, 0, W, H);
// Draw subtle watermark (simplified poppy flower)
ctx.save();
ctx.globalAlpha = 0.08;
ctx.font = '300px "Arial"';
ctx.fillStyle = '#ffb6c1'; // LightPink
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
ctx.fillText('🏵️', W * 0.65, H * 0.55);
ctx.restore();
// --- Draw Header ---
ctx.fillStyle = '#e6f0ff';
ctx.fillRect(0, 0, W, 80);
ctx.fillStyle = '#b3d1ff';
ctx.fillRect(0, 80, W, 2);
// Header Text
ctx.font = 'bold 36px "Roboto Condensed", sans-serif';
ctx.fillStyle = '#003366';
ctx.fillText("CALIFORNIA", 250, 55);
// Header simplified Bear - a simple path
ctx.fillStyle = '#003366';
ctx.beginPath();
ctx.moveTo(210, 60); ctx.lineTo(210, 50); ctx.lineTo(190, 40);
ctx.bezierCurveTo(180, 20, 150, 20, 140, 35);
ctx.lineTo(135, 30); ctx.lineTo(130, 35); ctx.lineTo(140, 45);
ctx.lineTo(150, 55); ctx.lineTo(165, 55); ctx.lineTo(165, 60);
ctx.lineTo(170, 60); ctx.lineTo(180, 55); ctx.lineTo(195, 55);
ctx.lineTo(200, 60);
ctx.closePath();
ctx.fill();
// ID Type
ctx.font = '22px "Roboto Condensed", sans-serif';
ctx.fillStyle = 'black';
ctx.textAlign = 'right';
ctx.fillText("IDENTIFICATION CARD", W - 30, 55);
// Main Photo
const photoX = 30, photoY = 100, photoW = 200, photoH = 250;
ctx.drawImage(originalImg, photoX, photoY, photoW, photoH);
ctx.strokeStyle = '#ccc';
ctx.strokeRect(photoX, photoY, photoW, photoH);
// Ghost Photo (semi-transparent)
ctx.globalAlpha = 0.2;
ctx.drawImage(originalImg, W - 350, 180, 300, 375);
ctx.globalAlpha = 1.0;
// --- Draw Information Fields ---
ctx.textAlign = 'left';
const startX = 260, startY = 110, lineHeight = 35;
const labelColor = '#666', valueColor = '#000';
const drawField = (label, value, x, y, options = {}) => {
const { labelSize = 16, valueSize = 20 } = options;
ctx.font = `${labelSize}px "Roboto Condensed", sans-serif`;
ctx.fillStyle = labelColor;
ctx.fillText(label, x, y);
ctx.font = `bold ${valueSize}px "Roboto Condensed", sans-serif`;
ctx.fillStyle = valueColor;
ctx.fillText(value.toUpperCase(), x, y + 20);
};
// ID Number (in red)
ctx.font = `bold 24px "Roboto Condensed", sans-serif`;
ctx.fillStyle = 'red';
ctx.fillText(`ID ${idNumber}`, startX, startY + 20);
// Names
drawField("LN", lastName, startX, startY + lineHeight * 1.5);
drawField("FN", firstName, startX + 250, startY + lineHeight * 1.5);
// Address
drawField("ADD", address, startX, startY + lineHeight * 3, { valueSize: 18 });
// Details Grid
const detailY1 = startY + lineHeight * 5;
const detailY2 = detailY1 + 60;
const detailY3 = detailY2 + 60;
const detailX1 = startX, detailX2 = startX + 150, detailX3 = startX + 300;
drawField("DOB", dob, detailX1, detailY1);
drawField("ISS", issueDate, detailX2, detailY1);
drawField("EXP", expDate, detailX3, detailY1);
drawField("SEX", sex, detailX1, detailY2);
drawField("HGT", height, detailX2, detailY2);
drawField("WGT", weight, detailX3, detailY2);
drawField("HAIR", hair, detailX1, detailY3);
drawField("EYES", eyes, detailX2, detailY3);
// Signature
ctx.fillStyle = labelColor;
ctx.font = `16px "Roboto Condensed", sans-serif`;
ctx.fillText("SIGNATURE", photoX, photoY + photoH + 25);
ctx.font = `30px "Satisfy", cursive`;
ctx.fillStyle = '#00008b'; // DarkBlue
ctx.fillText(`${firstName} ${lastName}`, photoX + 5, photoY + photoH + 65);
// REAL ID indicator (gold star)
ctx.save();
ctx.fillStyle = '#DAA520'; // Goldenrod
ctx.beginPath();
ctx.translate(W - 70, 110);
const starRadius = 25;
for (let i = 0; i < 5; i++) {
const angle = i * 4 * Math.PI / 5;
ctx.lineTo(Math.cos(angle) * starRadius, Math.sin(angle) * starRadius);
}
ctx.closePath();
ctx.fill();
ctx.restore();
// Bottom Bar (simulating barcode data)
ctx.fillStyle = '#f0f0f0';
ctx.fillRect(0, H - 40, W, 40);
ctx.font = '20px "Courier New", monospace';
ctx.fillStyle = '#000';
const barcodeText = `IDCA${idNumber.replace(/\D/g, "")}<<${lastName.slice(0,5)}<${firstName.slice(0,3)}`;
ctx.fillText(barcodeText, 20, H-15);
return canvas;
}
Apply Changes