Please bookmark this page to avoid losing your image tool!

Halloween Death Certificate Template

(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,
    deceasedName = "Unknown Soul",
    causeOfDeath = "Terminal Spookiness",
    dateOfDeath = `October 31, ${new Date().getFullYear()}`,
    placeOfDeath = "The Haunted Manor",
    issuingAuthority = "Ministry of Midnight Frights",
    signatureName = "Grim R. Eaper, Chief Mortician"
) {

    const certificateWidth = 800;
    const certificateHeight = 600;

    // --- Font Loading ---
    const titleFontFamily = 'Metal Mania';
    const decorativeFontFamily = 'Cinzel'; // For labels and important text
    const bodyFontFamily = 'Times New Roman'; // Fallback and body text

    async function loadGoogleFont(fontFamily, weight = '400') {
        if (typeof document === 'undefined' || !document.fonts) {
            // console.warn("document.fonts API not available. Skipping custom font loading.");
            return false; // Environment without document or document.fonts (e.g., Node.js test)
        }
        const fontCssFamily = fontFamily.replace(/\s+/g, '+');
        const fontCheckString = `12px "${fontFamily}"`; // Generic string to check if font is loaded

        try {
            if (document.fonts.check(fontCheckString)) {
                // Font is already known to the FontFaceSet. Attempt to ensure it's loaded.
                await document.fonts.load(fontCheckString);
                return true;
            }
        } catch (e) {
            // console.warn(`Error checking font ${fontFamily}: ${e.message}`);
            // Proceed to attempt loading via link if check fails or not supported
        }

        const linkId = `google-font-${fontCssFamily}-${weight}`;
        if (document.getElementById(linkId)) {
            // Stylesheet already added, try to load font
            try {
                await document.fonts.load(fontCheckString);
                return true;
            } catch (e) {
                // console.warn(`Error loading already-linked font ${fontFamily}: ${e.message}`);
                return false;
            }
        }

        return new Promise((resolve) => {
            const link = document.createElement('link');
            link.id = linkId;
            link.rel = 'stylesheet';
            link.href = `https://fonts.googleapis.com/css2?family=${fontCssFamily}:wght@${weight}&display=swap`;

            link.onload = async () => {
                try {
                    await document.fonts.load(fontCheckString);
                    resolve(true);
                } catch (e) {
                    console.warn(`Failed to load font "${fontFamily}" (weight ${weight}) using document.fonts.load. Error: ${e.message}`);
                    resolve(false);
                }
            };
            link.onerror = () => {
                console.warn(`Failed to load stylesheet for font: ${fontFamily} from ${link.href}`);
                resolve(false);
            };
            document.head.appendChild(link);
        });
    }

    // Load necessary fonts
    await Promise.all([
        loadGoogleFont(titleFontFamily, '400'),
        loadGoogleFont(decorativeFontFamily, '400'), // Cinzel has various weights, 400 is common
    ]);

    // --- Canvas Setup ---
    const canvas = document.createElement('canvas');
    canvas.width = certificateWidth;
    canvas.height = certificateHeight;
    const ctx = canvas.getContext('2d');

    // --- Helper: wrapText ---
    function wrapText(context, text, x, y, maxWidth, lineHeight) {
        const words = text.split(' ');
        let line = '';
        let currentTextY = y;
        const originalTextAlign = context.textAlign; // Preserve original alignment
        context.textAlign = 'left'; // wrapText assumes left alignment for positioning

        for (let n = 0; n < words.length; n++) {
            const testLine = line + words[n] + ' ';
            const metrics = context.measureText(testLine);
            const testWidth = metrics.width;
            if (testWidth > maxWidth && n > 0) {
                context.fillText(line.trim(), x, currentTextY);
                line = words[n] + ' ';
                currentTextY += lineHeight;
            } else {
                line = testLine;
            }
        }
        context.fillText(line.trim(), x, currentTextY);
        context.textAlign = originalTextAlign; // Restore original alignment
        return currentTextY + lineHeight; // Return Y for the baseline of the next potential line
    }

    // --- Helper: drawLabelAndValue ---
    function drawLabelAndValue(currentCtx, label, value, x, y, labelFont, valueFont, lHeight, valIndent, valMaxWidth) {
        currentCtx.textAlign = 'left';
        currentCtx.font = labelFont;
        currentCtx.fillStyle = 'black';
        currentCtx.fillText(label, x, y);

        currentCtx.font = valueFont;
        const valueX = x + valIndent;
        // Ensure valMaxWidth is positive
        const effectiveValMaxWidth = Math.max(10, valMaxWidth - (valIndent > 0 ? 0 : Math.abs(valIndent)));

        // Use wrapText for the value part. Pass fillStyle as it might change.
        const originalFillStyle = currentCtx.fillStyle;
        currentCtx.fillStyle = 'black'; // Ensure value is black
        const nextY = wrapText(currentCtx, value, valueX, y, effectiveValMaxWidth, lHeight);
        currentCtx.fillStyle = originalFillStyle;
        return nextY; // Y position for the next element, includes last line height
    }


    // --- Background and Border ---
    ctx.fillStyle = '#FAF0E6'; // Linen / Parchment
    ctx.fillRect(0, 0, certificateWidth, certificateHeight);

    ctx.strokeStyle = '#5C4033'; // Dark Brown
    ctx.lineWidth = 10;
    ctx.strokeRect(10, 10, certificateWidth - 20, certificateHeight - 20);

    ctx.strokeStyle = '#000000'; // Black
    ctx.lineWidth = 2;
    ctx.strokeRect(20, 20, certificateWidth - 40, certificateHeight - 40);

    // --- Title ---
    ctx.fillStyle = '#800000'; // Dark Red
    ctx.font = `60px "${titleFontFamily}", "Times New Roman", serif`;
    ctx.textAlign = 'center';
    ctx.fillText("CERTIFICATE OF DEATH", certificateWidth / 2, 80);

    // Decorative line under title
    ctx.beginPath();
    ctx.moveTo(50, 100);
    ctx.lineTo(certificateWidth - 50, 100);
    ctx.strokeStyle = 'black';
    ctx.lineWidth = 1;
    ctx.stroke();

    let currentY = 130; // Starting Y for content below title

    // --- Photo Area ---
    const photoBoxWidth = 140;
    const photoBoxHeight = 170;
    const photoMargin = 40;
    const photoX = certificateWidth - photoBoxWidth - photoMargin;
    const photoY = currentY;

    ctx.strokeStyle = 'black';
    ctx.lineWidth = 1;
    ctx.strokeRect(photoX -1, photoY -1, photoBoxWidth + 2, photoBoxHeight + 2); // Border for photo
    ctx.fillStyle = '#E0E0E0'; // Light gray background for photo box
    ctx.fillRect(photoX, photoY, photoBoxWidth, photoBoxHeight);


    if (originalImg && originalImg.complete && originalImg.naturalWidth > 0) {
        const imgAspect = originalImg.naturalWidth / originalImg.naturalHeight;
        const boxAspect = photoBoxWidth / photoBoxHeight;
        let dw, dh, dxDraw, dyDraw;

        if (imgAspect > boxAspect) { // Image wider than box aspect ratio
            dw = photoBoxWidth;
            dh = dw / imgAspect;
            dxDraw = photoX;
            dyDraw = photoY + (photoBoxHeight - dh) / 2;
        } else { // Image taller or same aspect ratio
            dh = photoBoxHeight;
            dw = dh * imgAspect;
            dxDraw = photoX + (photoBoxWidth - dw) / 2;
            dyDraw = photoY;
        }
        ctx.drawImage(originalImg, dxDraw, dyDraw, dw, dh);
    } else {
        ctx.font = `italic 14px "${bodyFontFamily}", serif`;
        ctx.fillStyle = '#555555';
        ctx.textAlign = 'center';
        wrapText(ctx, "Photo of Deceased Not Available", photoX + photoBoxWidth / 2, photoY + photoBoxHeight / 2 - 14, photoBoxWidth - 10, 16);
    }


    // --- Text Fields Area ---
    const textStartX = 40;
    // Max width for text fields block (left of photo)
    const textBlockMaxWidth = photoX - textStartX - 20; // 20 for margin between text and photo

    const fieldLabelFont = `bold 17px "${decorativeFontFamily}", "${bodyFontFamily}", serif`;
    const fieldValueFont = `16px "${bodyFontFamily}", serif`;
    const fieldLineHeight = 20;
    const valueIndentFromLabelStart = 190; // Fixed indent for value from textStartX
    const valueMaxWidth = textBlockMaxWidth - valueIndentFromLabelStart;
    const fieldVerticalSpacing = 8; // Extra space after each field is drawn

    currentY = drawLabelAndValue(ctx, "Full Name of Deceased:", deceasedName, textStartX, currentY, fieldLabelFont, fieldValueFont, fieldLineHeight, valueIndentFromLabelStart, valueMaxWidth) + fieldVerticalSpacing;
    currentY = drawLabelAndValue(ctx, "Date of Demise:", dateOfDeath, textStartX, currentY, fieldLabelFont, fieldValueFont, fieldLineHeight, valueIndentFromLabelStart, valueMaxWidth) + fieldVerticalSpacing;
    currentY = drawLabelAndValue(ctx, "Cause of Demise:", causeOfDeath, textStartX, currentY, fieldLabelFont, fieldValueFont, fieldLineHeight, valueIndentFromLabelStart, valueMaxWidth) + fieldVerticalSpacing;
    currentY = drawLabelAndValue(ctx, "Place of Demise:", placeOfDeath, textStartX, currentY, fieldLabelFont, fieldValueFont, fieldLineHeight, valueIndentFromLabelStart, valueMaxWidth) + fieldVerticalSpacing;


    // --- Attestation Text ---
    // Ensure currentY is below both the text fields and the photo
    currentY = Math.max(currentY, photoY + photoBoxHeight + 20); 
    currentY += 10; // Margin before attestation paragraph

    ctx.font = `italic 15px "${bodyFontFamily}", serif`;
    ctx.fillStyle = 'black';
    ctx.textAlign = 'left';
    const attestationText = `This document solemnly certifies that the aforementioned individual, ${deceasedName}, has officially ceased all vital signs and has departed from the mortal coil. This certificate is issued under the high authority of ${issuingAuthority} and serves as an official record of their transition to the great unknown. Witnessed and recorded on this fateful day.`;
    // The attestation spans the full width below the fields/photo.
    currentY = wrapText(ctx, attestationText, textStartX, currentY, certificateWidth - (2 * textStartX), 18);


    // --- Signature Area ---
    const signatureAreaY = certificateHeight - 100;
    // If content is too long, it might overlap. For this template, we assume it fits.
    // It's better to make sure signatureAreaY is below currentY if currentY grew too much
    // currentY = Math.max(currentY + 20, signatureAreaY); // Position signature area dynamically (can push canvas longer) or cap content
    currentY = signatureAreaY; // For fixed size canvas, use fixed position

    ctx.font = `16px "${bodyFontFamily}", serif`;
    ctx.fillStyle = 'black';
    ctx.textAlign = 'left';

    const signedByText = "Signed and Certified By:";
    ctx.fillText(signedByText, textStartX, currentY);

    const signatureLineY = currentY + 30;
    ctx.beginPath();
    ctx.moveTo(textStartX, signatureLineY);
    ctx.lineTo(textStartX + 280, signatureLineY);
    ctx.lineWidth = 1;
    ctx.strokeStyle = 'black';
    ctx.stroke();

    ctx.font = `italic 16px "${decorativeFontFamily}", "${bodyFontFamily}", serif`;
    ctx.fillText(signatureName, textStartX, signatureLineY - 5); // Signature name above the line
    ctx.font = `14px "${bodyFontFamily}", serif`;
    ctx.fillText(`(${issuingAuthority})`, textStartX, signatureLineY + 20);


    // --- Official Seal ---
    const sealRadius = 35;
    const sealX = certificateWidth - textStartX - sealRadius - 10; // Right align seal
    const sealY = signatureLineY - sealRadius / 2;

    ctx.beginPath();
    ctx.arc(sealX, sealY, sealRadius, 0, Math.PI * 2);
    ctx.fillStyle = '#8B0000'; // Dark red for seal
    ctx.fill();

    ctx.strokeStyle = '#DAA520'; // Gold border for seal
    ctx.lineWidth = 2;
    ctx.stroke();
    // Additional decorative circles for seal
    ctx.beginPath();
    ctx.arc(sealX, sealY, sealRadius - 5, 0, Math.PI * 2);
    ctx.stroke();


    ctx.fillStyle = '#DAA520'; // Gold text on seal
    ctx.font = `bold 10px "${titleFontFamily}", "Arial", sans-serif`;
    ctx.textAlign = 'center';
    ctx.fillText("OFFICIAL", sealX, sealY - 5);
    ctx.fillText("SEAL OF", sealX, sealY + 5);
    ctx.fillText("FRIGHTS", sealX, sealY + 15);

    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 Halloween Death Certificate Template tool allows users to create a whimsical, themed certificate of death for Halloween celebrations or events. This tool enables customization of the certificate by specifying the name of the deceased, cause of death, date and place of death, as well as the issuing authority and signatory name. It is designed for fun purposes, suitable for parties, ghost tours, or as a humorous addition to Halloween decorations. Users can upload an image to be included in the certificate and obtain a uniquely styled document that blends festive spirit with morbid humor.

Leave a Reply

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

Other Image Tools:

Image Anatomical Illustration Frame Creator

Image Romance Novel Cover Template Creator

Image Tabloid Headline Template

Image Space Mission Patch Template Creator

Image Cassette Tape Cover Template Creator

Image Passport Page Template Generator

Image Old Map Frame With Compass Rose Decorator

Image Diploma and Degree Certificate Framer

Image Soviet Propaganda Poster Style Generator

Image Yu-Gi-Oh Card Template Creator

Image Ancient Roman Greek Tablet Frame Creator

Image Marriage Certificate Template Creator

Image Video Game Achievement Frame Creator

Image Newspaper Front Page Template Creator

Image Botanical Illustration Frame Creator

Image Vinyl Record Sleeve Template Creator

Vintage Photo Booth Strip Template Generator

Image Cyberpunk Interface Frame Designer

Image Detective Novel Cover Template

Image Achievement Certificate Framer

Image Illuminated Manuscript Frame Generator

Image Art Deco Poster Frame Creator

Image Egyptian Papyrus Scroll Frame Designer

Image Vintage Postage Stamp Frame Creator

Image Magic: The Gathering Card Frame Generator

Image Birth Certificate Template Generator

Image Driver’s License Template Creator

Image Scout Explorer Badge Template Creator

Image Steampunk Document Frame Creator

Image Vintage Scientific Illustration Frame Creator

Image Magazine Cover Template Creator

Image Album Cover Template Creator

Image Medieval Bestiary Page Template

Image Polaroid Instant Photo Frame

Image Pulp Fiction Book Cover Template

Image Medieval Manuscript Frame Creator

See All →