You can edit the below JavaScript code to customize the image tool.
Apply Changes
async function processImage(originalImg, name = "JOHN DOE", reward = "$1,000,000", crime = "FOR TRAIN ROBBERY", condition = "DEAD OR ALIVE") {
// Sanitize and ensure fallbacks
name = name || "JOHN DOE";
reward = reward || "$1,000,000";
crime = crime || "FOR TRAIN ROBBERY";
condition = condition || "DEAD OR ALIVE";
// 1. Dynamically load standard "Wanted" Western Font (Rye from Google Fonts)
const fontName = 'Rye';
const link = document.createElement('link');
link.rel = 'stylesheet';
link.href = `https://fonts.googleapis.com/css2?family=${fontName}&display=swap`;
document.head.appendChild(link);
// Create a hidden div to force the browser to request and apply the font
const div = document.createElement('div');
div.style.fontFamily = `"${fontName}", serif`;
div.style.position = 'absolute';
div.style.visibility = 'hidden';
div.textContent = 'Font Trigger';
document.body.appendChild(div);
// Wait until the font is loaded or timeout (fallback to web safe serif)
if (document.fonts && document.fonts.ready) {
await document.fonts.ready;
} else {
await new Promise(r => setTimeout(r, 600));
}
div.remove();
// 2. Set up the canvas
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
const width = 600;
const height = 800;
canvas.width = width;
canvas.height = height;
const fontFamily = `"${fontName}", "Times New Roman", Times, serif`;
// 3. Draw Vintage Paper Background
// Base parchment color
ctx.fillStyle = '#dac4a1';
ctx.fillRect(0, 0, width, height);
// Add paper grain / noise
ctx.fillStyle = 'rgba(62, 39, 35, 0.08)';
for (let i = 0; i < 6000; i++) {
const x = Math.random() * width;
const y = Math.random() * height;
const w = 1 + Math.random() * 2;
const h = 1 + Math.random() * 2;
ctx.fillRect(x, y, w, h);
}
// Add burnt / vignetted edges
const grd = ctx.createRadialGradient(width / 2, height / 2, width / 3, width / 2, height / 2, height * 0.7);
grd.addColorStop(0, 'rgba(0,0,0,0)');
grd.addColorStop(1, 'rgba(40, 20, 10, 0.5)');
ctx.fillStyle = grd;
ctx.fillRect(0, 0, width, height);
// 4. Draw Outer Vintage Borders
ctx.strokeStyle = '#3e2723'; // Dark brown
ctx.lineWidth = 10;
ctx.strokeRect(20, 20, width - 40, height - 40);
ctx.lineWidth = 3;
ctx.strokeRect(36, 36, width - 72, height - 72);
// 5. Shared Text Helper
ctx.fillStyle = '#3e2723';
ctx.textAlign = 'center';
ctx.textBaseline = 'top';
// Helper text-fitting function to scale down font if text is too long
function drawFitText(text, y, defaultSize, maxW = 500) {
let size = defaultSize;
ctx.font = `${size}px ${fontFamily}`;
while (ctx.measureText(text).width > maxW && size > 15) {
size--;
ctx.font = `${size}px ${fontFamily}`;
}
ctx.fillText(text, width / 2, y);
}
// 6. Draw "WANTED" Header
ctx.shadowColor = 'rgba(0,0,0,0.3)';
ctx.shadowBlur = 4;
ctx.shadowOffsetX = 2;
ctx.shadowOffsetY = 2;
drawFitText("WANTED", 60, 90);
ctx.shadowColor = 'transparent'; // Reset shadow for remaining text
// 7. Draw Condition (e.g. DEAD OR ALIVE)
drawFitText(`★ ${condition.toUpperCase()} ★`, 165, 25);
// 8. Process and Draw the Image (with vintage photo filter)
const boxW = 380;
const boxH = 320;
const boxX = (width - boxW) / 2;
const boxY = 220;
// Image frame/backdrop
ctx.fillStyle = '#c7a982';
ctx.fillRect(boxX - 8, boxY - 8, boxW + 16, boxH + 16);
ctx.strokeStyle = '#3e2723';
ctx.lineWidth = 6;
ctx.strokeRect(boxX - 8, boxY - 8, boxW + 16, boxH + 16);
ctx.lineWidth = 2;
ctx.strokeRect(boxX - 3, boxY - 3, boxW + 6, boxH + 6);
// Calculate "object-fit: cover" dimensions
let drawW, drawH, drawX, drawY;
const imgRatio = originalImg.width / originalImg.height;
const boxRatio = boxW / boxH;
if (imgRatio > boxRatio) {
// Image is wider than frame -> slice edges
drawH = boxH;
drawW = drawH * imgRatio;
drawX = boxX - (drawW - boxW) / 2;
drawY = boxY;
} else {
// Image is taller than frame -> slice top/bottom
drawW = boxW;
drawH = drawW / imgRatio;
drawX = boxX;
drawY = boxY - (drawH - boxH) / 2;
}
// Clip to inner frame to render cropped image correctly
ctx.save();
ctx.beginPath();
ctx.rect(boxX, boxY, boxW, boxH);
ctx.clip();
// Solid background behind image just in case it has transparency
ctx.fillStyle = '#ebddc8';
ctx.fillRect(boxX, boxY, boxW, boxH);
// Apply filters to make the image look old, sepia, and contrasting
ctx.filter = 'sepia(0.85) contrast(1.3) brightness(0.9) grayscale(0.3)';
ctx.drawImage(originalImg, drawX, drawY, drawW, drawH);
ctx.restore(); // Restore context state to remove clipping out of bounds
// 9. Draw Details Below Image
drawFitText(name.toUpperCase(), 565, 55);
drawFitText(crime.toUpperCase(), 635, 25);
drawFitText("REWARD", 680, 25);
drawFitText(reward.toUpperCase(), 705, 60);
return canvas;
}
Apply Changes