You can edit the below JavaScript code to customize the image tool.
Apply Changes
async function processImage(originalImg, stateName = 'TEXAS', plateNumber = 'auto', expDate = 'auto', vin = '1A2B3C4D5E6F7G8H9', year = 0, make = 'GENERIC', model = 'VEHICLE') {
// --- 1. Handle Dynamic Default Parameters ---
if (plateNumber === 'auto') {
const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
const nums = '0123456789';
let p = '';
for (let i = 0; i < 3; i++) p += chars.charAt(Math.floor(Math.random() * chars.length));
p += ' ';
for (let i = 0; i < 4; i++) p += nums.charAt(Math.floor(Math.random() * nums.length));
plateNumber = p;
}
if (expDate === 'auto') {
const d = new Date();
d.setDate(d.getDate() + 45); // Set expiration 45 days from now
expDate = `${(d.getMonth() + 1).toString().padStart(2,'0')}-${d.getDate().toString().padStart(2,'0')}-${d.getFullYear()}`;
}
if (year === 0) {
year = new Date().getFullYear();
}
// --- 2. Dynamically Load Required Google Font ---
const fontName = 'Oswald';
const fontWeight = '700';
const fontUrl = `https://fonts.googleapis.com/css2?family=${fontName.replace(' ', '+')}:wght@${fontWeight}&display=swap`;
// Check if the font's <link> tag already exists to avoid duplicates
if (!document.querySelector(`link[href="${fontUrl}"]`)) {
const link = document.createElement('link');
link.rel = 'stylesheet';
link.href = fontUrl;
// Create a promise to wait for the stylesheet to load
const fontLoadPromise = new Promise((resolve, reject) => {
link.onload = resolve;
link.onerror = reject;
});
document.head.appendChild(link);
await fontLoadPromise;
}
// Ensure the font is ready for use in the canvas
await document.fonts.load(`${fontWeight} 10px '${fontName}'`);
// --- 3. Canvas Setup ---
const canvas = document.createElement('canvas');
const width = 800;
const height = 400;
const scale = 2; // Render at 2x resolution for better quality
canvas.width = width * scale;
canvas.height = height * scale;
canvas.style.width = `${width}px`;
canvas.style.height = `${height}px`;
const ctx = canvas.getContext('2d');
ctx.scale(scale, scale);
// Define colors
const bgColor = '#FFFFFF';
const textColor = '#000000';
const expColor = '#D32F2F'; // Red for expiration date
// --- 4. Drawing the Plate ---
// Background
ctx.fillStyle = bgColor;
ctx.fillRect(0, 0, width, height);
// Optional Watermark using the input image
if (originalImg && originalImg.width > 0 && originalImg.height > 0) {
ctx.save();
ctx.globalAlpha = 0.08;
const imgAspectRatio = originalImg.width / originalImg.height;
let drawWidth = width * 0.5;
let drawHeight = drawWidth / imgAspectRatio;
if (drawHeight > height * 0.5) {
drawHeight = height * 0.5;
drawWidth = drawHeight * imgAspectRatio;
}
const x = (width - drawWidth) / 2;
const y = (height - drawHeight) / 2;
ctx.drawImage(originalImg, x, y, drawWidth, drawHeight);
ctx.restore();
}
// Border
ctx.strokeStyle = textColor;
ctx.lineWidth = 10;
ctx.strokeRect(ctx.lineWidth / 2, ctx.lineWidth / 2, width - ctx.lineWidth, height - ctx.lineWidth);
// State Name
ctx.fillStyle = textColor;
ctx.textAlign = 'center';
ctx.font = `bold 40px ${fontName}, sans-serif`;
ctx.textBaseline = 'top';
ctx.fillText(stateName.toUpperCase(), width / 2, 20);
// Expiration Date
ctx.fillStyle = expColor;
ctx.textAlign = 'right';
ctx.font = 'bold 24px Arial, sans-serif';
ctx.fillText('VALID THRU', width - 20, 25);
ctx.font = 'bold 36px Arial, sans-serif';
ctx.fillText(expDate, width - 20, 50);
// Main Plate Number
ctx.fillStyle = textColor;
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
const plateText = plateNumber.toUpperCase();
let plateFontSize = 150;
ctx.font = `${fontWeight} ${plateFontSize}px '${fontName}', sans-serif`;
// Auto-adjust font size to fit the plate width
while (ctx.measureText(plateText).width > width - 80) {
plateFontSize -= 5;
ctx.font = `${fontWeight} ${plateFontSize}px '${fontName}', sans-serif`;
}
ctx.fillText(plateText, width / 2, height / 2 + 15);
// "TEMPORARY" text below plate number
ctx.font = 'bold 30px Arial, sans-serif';
ctx.letterSpacing = '5px';
ctx.fillText('TEMPORARY', width / 2, height / 2 + 15 + (plateFontSize / 2) + 20);
ctx.letterSpacing = '0px';
// Vehicle Info at the bottom
ctx.fillStyle = textColor;
ctx.textBaseline = 'alphabetic';
ctx.textAlign = 'left';
ctx.font = '20px "Courier New", monospace';
const vehicleInfo1 = `YR: ${year} MK: ${make.toUpperCase()} MDL: ${model.toUpperCase()}`;
const vehicleInfo2 = `VIN: ${vin.toUpperCase()}`;
ctx.fillText(vehicleInfo1, 25, height - 50);
ctx.fillText(vehicleInfo2, 25, height - 25);
// --- 5. Return Canvas ---
return canvas;
}
Apply Changes