Please bookmark this page to avoid losing your image tool!

Image FBI Most Wanted Poster Creator

(Free & Supports Bulk Upload)

Drag & drop your images here or

The result will appear here...
You can edit the below JavaScript code to customize the image tool.
async function processImage(
    originalImg,
    name = "UNSUB",
    aliases = "NONE KNOWN",
    description = "Sex: Unknown\nRace: Unknown\nAge: Approx. 30-40 years\nHeight: Approx. 5'10\" - 6'2\"\nWeight: Approx. 170-190 lbs\nHair: Unknown\nEyes: Unknown\nScars/Marks: May have distinguishing features not visible in photo.",
    crime = "MULTIPLE FELONIES INCLUDING BUT NOT LIMITED TO:\nBANK ROBBERY, ARMED ASSAULT, INTERSTATE FLIGHT TO AVOID PROSECUTION",
    rewardText = "REWARD OF UP TO $1,000,000\nFOR INFORMATION LEADING DIRECTLY TO THE ARREST OF THIS INDIVIDUAL",
    cautionText = "CONSIDERED ARMED AND EXTREMELY DANGEROUS\nDO NOT ATTEMPT TO APPREHEND THIS INDIVIDUAL YOURSELF"
) {
    const canvas = document.createElement('canvas');
    const ctx = canvas.getContext('2d');

    const canvasWidth = 800;
    const canvasHeight = 1100;
    canvas.width = canvasWidth;
    canvas.height = canvasHeight;

    ctx.textBaseline = 'top'; // Easier Y coordinate management

    // Background
    ctx.fillStyle = '#FDF5E6'; // Old Lace / very light beige, common for aged paper
    ctx.fillRect(0, 0, canvasWidth, canvasHeight);

    // Border
    ctx.strokeStyle = '#000000';
    ctx.lineWidth = 5; // Outer thick border
    ctx.strokeRect(10, 10, canvasWidth - 20, canvasHeight - 20);
    ctx.lineWidth = 2; // Inner thin border
    ctx.strokeRect(20, 20, canvasWidth - 40, canvasHeight - 40);

    let currentY = 25; // Start currentY from top margin (inside borders)
    const margin = 40; // Margin for content from the inner border edge
    const contentWidth = canvasWidth - 2 * margin;

    // 1. "WANTED" Header
    let textBlockY = currentY + 35; // Add some top padding for the first element
    ctx.font = 'bold 120px Impact, Haettenschweiler, "Arial Narrow Bold", sans-serif';
    ctx.fillStyle = '#A52A2A'; // Brownish Red (less bright than Firebrick)
    ctx.textAlign = 'center';
    ctx.fillText("WANTED", canvasWidth / 2, textBlockY);
    currentY = textBlockY + 120; // Height of "WANTED" text (approx font size)

    // 2. "BY THE..." Sub-Header
    textBlockY = currentY + 10; // Spacing from "WANTED"
    ctx.font = 'bold 22px "Times New Roman", Times, serif';
    ctx.fillStyle = '#000000'; // Black
    ctx.fillText("BY THE FEDERAL BUREAU OF INVESTIGATION", canvasWidth / 2, textBlockY);
    currentY = textBlockY + 22 + 15; // Height of sub-header + spacing after it

    // 3. Image Area
    const imgMaxHeight = 300; // Max height for the suspect's image
    const imgMaxWidth = contentWidth * 0.7; // Max width for the image, allowing some side margin
    let imgHeight = originalImg.height;
    let imgWidth = originalImg.width;
    const aspectRatio = imgWidth / imgHeight;

    // Scale image to fit constraints
    if (imgHeight > imgMaxHeight) {
        imgHeight = imgMaxHeight;
        imgWidth = imgHeight * aspectRatio;
    }
    if (imgWidth > imgMaxWidth) {
        imgWidth = imgMaxWidth;
        imgHeight = imgWidth / aspectRatio;
    }

    const imgX = (canvasWidth - imgWidth) / 2; // Center the image
    const imgY = currentY + 5; // Small space above image
    
    ctx.fillStyle = '#FFFFFF'; // White "matting" behind photo
    ctx.fillRect(imgX - 7, imgY - 7, imgWidth + 14, imgHeight + 14);
    ctx.strokeStyle = '#000000';
    ctx.lineWidth = 2; // Border for the photo
    ctx.strokeRect(imgX - 5, imgY - 5, imgWidth + 10, imgHeight + 10); 
    ctx.drawImage(originalImg, imgX, imgY, imgWidth, imgHeight);
    currentY = imgY + imgHeight + 10 + 15; // Y below image border + spacing

    // Text Fields Section Helper Function
    const labelFontSize = 18;
    const valueFontSize = 16;
    const fieldLineSpacing = valueFontSize * 1.3; // Line height for multi-line values
    const labelFont = '"Arial Black", Gadget, sans-serif';
    const valueFont = '"Courier New", Courier, monospace'; // "Typewriter" style for values
    const valueIndent = margin + 170; // X position where value text starts (after label)
    const maxValueWidth = contentWidth - (valueIndent - margin); // Max width for value text

    function drawLabelAndValue(label, valueString, startDrawY) {
        let currentLineY = startDrawY;
        ctx.textAlign = 'left';
        ctx.font = `bold ${labelFontSize}px ${labelFont}`;
        ctx.fillStyle = '#000000';
        ctx.fillText(label.toUpperCase() + ":", margin, currentLineY);

        ctx.font = `normal ${valueFontSize}px ${valueFont}`;
        const valueLines = valueString.split('\n'); // Handle explicit newlines in value
        
        for (let i = 0; i < valueLines.length; i++) {
            const line = valueLines[i];
            const words = line.split(' '); // For word wrapping
            let textLine = '';
            for (let n = 0; n < words.length; n++) {
                const testLine = textLine + words[n] + ' ';
                if (ctx.measureText(testLine).width > maxValueWidth && textLine !== '') {
                    ctx.fillText(textLine.trim(), valueIndent, currentLineY);
                    textLine = words[n] + ' ';
                    currentLineY += fieldLineSpacing;
                } else {
                    textLine = testLine;
                }
            }
            ctx.fillText(textLine.trim(), valueIndent, currentLineY);
            if (i < valueLines.length - 1) { // If more pre-split lines follow
                 currentLineY += fieldLineSpacing;
            }
        }
        const labelBottom = startDrawY + labelFontSize;
        const valueBottom = currentLineY + valueFontSize; // Bottom of last line of value text
        return Math.max(labelBottom, valueBottom) + fieldLineSpacing * 0.7; // Y for next field, with spacing
    }
    
    currentY += 10; // Space before first field
    currentY = drawLabelAndValue("NAME", name, currentY);
    currentY = drawLabelAndValue("ALIASES", aliases, currentY);
    
    // Description field (special handling for full width value)
    ctx.textAlign = 'left';
    ctx.font = `bold ${labelFontSize}px ${labelFont}`;
    ctx.fillStyle = '#000000';
    ctx.fillText("DESCRIPTION:", margin, currentY);
    currentY += labelFontSize + 8; // Move Y below "DESCRIPTION:" label text + small gap

    ctx.font = `normal ${valueFontSize}px ${valueFont}`;
    const descriptionLines = description.split('\n');
    let descInnerY = currentY;
    for (let i = 0; i < descriptionLines.length; i++) {
        const line = descriptionLines[i];
        const words = line.split(' ');
        let textLine = '';
        for (let n = 0; n < words.length; n++) {
            const testLine = textLine + words[n] + ' ';
            // For description, value text uses full contentWidth
            if (ctx.measureText(testLine).width > contentWidth && textLine !== '') { 
                ctx.fillText(textLine.trim(), margin, descInnerY);
                textLine = words[n] + ' ';
                descInnerY += fieldLineSpacing;
            } else {
                textLine = testLine;
            }
        }
        ctx.fillText(textLine.trim(), margin, descInnerY);
        if (i < descriptionLines.length - 1) {
             descInnerY += fieldLineSpacing;
        }
    }
    currentY = descInnerY + valueFontSize + fieldLineSpacing * 0.7; // Y for next element

    currentY = drawLabelAndValue("CRIME", crime, currentY);

    // Helper for centered, multi-line (from \n) text blocks (e.g. Reward, Caution)
    function drawCenteredTextBlock(text, startBlockY, fontStyle, fontSize, fontFamily, color, lineHeightFactor = 1.2) {
        ctx.font = `${fontStyle} ${fontSize}px ${fontFamily}`;
        ctx.fillStyle = color;
        ctx.textAlign = 'center';
        const lines = text.toUpperCase().split('\n');
        let lineDrawY = startBlockY;
        for(const line of lines) {
            ctx.fillText(line.trim(), canvasWidth / 2, lineDrawY);
            lineDrawY += fontSize * lineHeightFactor;
        }
        return lineDrawY - (fontSize * (lineHeightFactor - 1)); // Return Y at conceptual bottom of last text line
    }

    currentY += 20; // Extra space before reward
    currentY = drawCenteredTextBlock(rewardText, currentY, 'bold', 26, '"Times New Roman", Times, serif', '#A52A2A', 1.2);
    
    currentY += 20; // Extra space
    currentY = drawCenteredTextBlock(cautionText, currentY, 'bold', 20, 'Arial, sans-serif', '#000000', 1.2);

    // Footer Text
    const footerFontSize = 11; // Slightly smaller for dense footer
    const footerFontFamily = '"Verdana", Geneva, sans-serif';
    const footerTopMargin = 30; 
    const footerLineHeight = footerFontSize * 1.25;
    
    const footerTextContent = "IF YOU HAVE ANY INFORMATION CONCERNING THIS PERSON, PLEASE CONTACT YOUR LOCAL FBI OFFICE OR THE NEAREST U.S. EMBASSY OR CONSULATE. YOU CAN ALSO SUBMIT A TIP ONLINE AT TIPS.FBI.GOV.";
    const footerWords = footerTextContent.split(' ');
    const tempFooterLines = [];
    const originalCtxFontForMeasure = ctx.font; 
    ctx.font = `bold ${footerFontSize}px ${footerFontFamily}`; // Use footer font for measuring
    let currentLineForFooter = "";
    for (const word of footerWords) {
        const testLine = currentLineForFooter + word + " ";
        if (ctx.measureText(testLine).width > contentWidth * 0.95 && currentLineForFooter !== "") {
            tempFooterLines.push(currentLineForFooter.trim());
            currentLineForFooter = word + " ";
        } else {
            currentLineForFooter = testLine;
        }
    }
    tempFooterLines.push(currentLineForFooter.trim());
    ctx.font = originalCtxFontForMeasure; 

    let footerStartY = canvasHeight - 20 - (tempFooterLines.length * footerLineHeight) - (footerLineHeight * 0.5); // Position from inner border-bottom
    
    // Ensure footer doesn't overlap content above it if content is very long
    if (footerStartY < currentY + footerTopMargin) { 
        footerStartY = currentY + footerTopMargin; 
    }
    
    currentY = drawCenteredTextBlock(tempFooterLines.join('\n'), footerStartY, 'bold', footerFontSize, footerFontFamily, '#000000', 1.25);

    // FBI Seal (simplified placeholder)
    const sealSize = 45;
    const sealMarginFromLeft = margin; 
    const sealBottomRefY = canvasHeight - 20 - 10; // Above inner border bottom + some padding
    const sealTopY = sealBottomRefY - sealSize;

    // Check if there's a clear spot for the seal (e.g., not overlapping image, not too close to footer start)
    const spaceBelowImage = imgY + imgHeight + 20;
    const spaceAboveFooter = footerStartY - sealSize - 15; // Ensure seal ends 15px above footer start
    
    if (sealTopY > spaceBelowImage && sealTopY < spaceAboveFooter) { 
        ctx.beginPath();
        const sealCenterX = sealMarginFromLeft + sealSize / 2;
        const sealCenterY = sealTopY + sealSize / 2;
        ctx.arc(sealCenterX, sealCenterY, sealSize / 2, 0, 2 * Math.PI);
        ctx.fillStyle = '#002868'; // FBI Blue
        ctx.fill();
        
        // Text inside seal
        ctx.font = 'bold 11px Arial';
        ctx.fillStyle = '#FFFFFF'; // White text
        ctx.textAlign = 'center';
        // Adjust Y for two lines of text, considering textBaseline='top'
        const textLineHeightSeal = 11;
        ctx.fillText("FBI", sealCenterX, sealCenterY - textLineHeightSeal * 0.8); 
        ctx.fillText("SEAL", sealCenterX, sealCenterY + textLineHeightSeal * 0.3);
    }
    
    return canvas;
}

Free Image Tool Creator

Can't find the image tool you're looking for?
Create one based on your own needs now!

Description

The Image FBI Most Wanted Poster Creator allows users to create custom wanted posters by inputting an image along with details such as the suspect’s name, aliases, physical description, crime details, and reward information. This tool can be useful for law enforcement agencies, crime awareness campaigns, or any scenario where information about a wanted individual needs to be visually presented in an informative format. Users can customize key aspects of the poster, including design and text content, and then generate a high-quality image suitable for distribution or sharing.

Leave a Reply

Your email address will not be published. Required fields are marked *