Please bookmark this page to avoid losing your image tool!

Paranormal Investigation Image File 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,
    caseId = "CASE-001X",
    location = "CLASSIFIED",
    customTimestamp = "", // If empty, uses current time. Provide string like "2023-10-27 14:35:00"
    effectLevel = 3,      // 0-10 (0: no noise, 10: max noise)
    monochrome = 1,       // 1 for grayscale, 0 for color
    scanLines = 1,        // 1 to add scan lines, 0 for no scan lines
    headerText = "PARANORMAL EVIDENCE",
    footerText = "FILE: RESTRICTED",
    fontFamily = "Share Tech Mono", // "Share Tech Mono" (loads from Google Fonts), "monospace", "Courier New", etc.
    infoTextColor = "#33FF33",       // Light green for info text (timestamp, case ID, location)
    headerFooterBgColor = "#111111", // Dark gray/black for header and footer backgrounds
    headerTextColor = "#FF0000",     // Red for header text
    footerTextColor = "#FF0000"      // Red for footer banner text
) {

    async function _ensureFontLoaded(fontFamilyName, cssUrl) {
        const fontId = `font-link-${fontFamilyName.replace(/\s+/g, '-')}`;
        
        // Check if font is already usable
        if (document.fonts.check(`12px "${fontFamilyName}"`)) {
             return true;
        }

        // If link tag for CSS is not present, add it
        if (!document.getElementById(fontId)) {
            const link = document.createElement('link');
            link.id = fontId;
            link.href = cssUrl;
            link.rel = 'stylesheet';
            
            const p = new Promise((resolve, reject) => {
                link.onload = () => resolve(true); // CSS loaded
                link.onerror = () => reject(new Error(`Failed to load CSS: ${cssUrl}`));
            });
            document.head.appendChild(link);
            try {
                await p; // Wait for CSS to download
            } catch(err) {
                 console.warn(err.message);
                 return false; // CSS failed to load
            }
        }
        
        // CSS is linked (or was already present), now wait for the specific font to be usable
        try {
            await document.fonts.load(`12px "${fontFamilyName}"`);
            return document.fonts.check(`12px "${fontFamilyName}"`); // Final check
        } catch (e) {
            console.warn(`Failed to load font "${fontFamilyName}" after linking CSS. It might be loading or fallback will be used.`, e);
            return false; // Font failed to load or make itself available via API in time
        }
    }

    let effectiveFontFamily = fontFamily;
    if (fontFamily.toLowerCase() === "share tech mono") {
        const fontLoaded = await _ensureFontLoaded("Share Tech Mono", "https://fonts.googleapis.com/css2?family=Share+Tech+Mono&display=swap");
        if (!fontLoaded) {
            effectiveFontFamily = "monospace"; // Fallback if "Share Tech Mono" fails
            console.warn("Fell back to monospace font.");
        } else {
            effectiveFontFamily = "Share Tech Mono"; // Use the canonical name
        }
    }


    // 1. Create fxCanvas for image effects
    const fxCanvas = document.createElement('canvas');
    fxCanvas.width = originalImg.width;
    fxCanvas.height = originalImg.height;
    const fxCtx = fxCanvas.getContext('2d');

    // Draw original image
    fxCtx.drawImage(originalImg, 0, 0, originalImg.width, originalImg.height);

    // Apply effects
    if (monochrome === 1 || effectLevel > 0) {
        const imageData = fxCtx.getImageData(0, 0, fxCanvas.width, fxCanvas.height);
        const data = imageData.data;
        const noiseStrength = effectLevel * 5; // Max noise +-50 per channel for level 10

        for (let i = 0; i < data.length; i += 4) {
            // Grayscale
            if (monochrome === 1) {
                const avg = (data[i] + data[i + 1] + data[i + 2]) / 3;
                data[i] = avg;     // Red
                data[i + 1] = avg; // Green
                data[i + 2] = avg; // Blue
            }

            // Noise
            if (effectLevel > 0) {
                const noise = (Math.random() - 0.5) * 2 * noiseStrength;
                data[i] = Math.max(0, Math.min(255, data[i] + noise));
                data[i + 1] = Math.max(0, Math.min(255, data[i + 1] + noise));
                data[i + 2] = Math.max(0, Math.min(255, data[i + 2] + noise));
            }
        }
        fxCtx.putImageData(imageData, 0, 0);
    }

    // Scan lines
    if (scanLines === 1) {
        fxCtx.fillStyle = "rgba(0, 0, 0, 0.15)";
        for (let y = 0; y < fxCanvas.height; y += 3) { // 1px line every 3px
            fxCtx.fillRect(0, y, fxCanvas.width, 1);
        }
    }

    // 2. Create outputCanvas for final composition
    const headerHeight = 40;
    const footerHeight = 80; // Allows for 3 lines of info + footer banner
    
    const outputCanvas = document.createElement('canvas');
    outputCanvas.width = originalImg.width;
    outputCanvas.height = headerHeight + originalImg.height + footerHeight;
    const outputCtx = outputCanvas.getContext('2d');

    // Fill entire canvas (useful if image is transparent or smaller areas for some reason)
    outputCtx.fillStyle = headerFooterBgColor; // Default background for whole thing
    outputCtx.fillRect(0, 0, outputCanvas.width, outputCanvas.height);


    // Draw Header
    outputCtx.fillStyle = headerFooterBgColor;
    outputCtx.fillRect(0, 0, outputCanvas.width, headerHeight);
    
    const headerFontSize = Math.max(10, Math.min(headerHeight * 0.5, outputCanvas.width / (headerText.length * 0.60 + 2))); // Dynamic font size
    outputCtx.font = `bold ${headerFontSize}px ${effectiveFontFamily}`;
    outputCtx.fillStyle = headerTextColor;
    outputCtx.textAlign = "center";
    outputCtx.textBaseline = "middle";
    outputCtx.fillText(headerText, outputCanvas.width / 2, headerHeight / 2);

    // Draw processed image
    outputCtx.drawImage(fxCanvas, 0, headerHeight);

    // Draw Footer
    const footerYStart = headerHeight + originalImg.height;
    outputCtx.fillStyle = headerFooterBgColor;
    outputCtx.fillRect(0, footerYStart, outputCanvas.width, footerHeight);

    // Info text (timestamp, case ID, location)
    const infoFontSize = Math.max(8, Math.min(14, outputCanvas.width / 30)); // Small dynamic font size for info
    const infoLineHeight = infoFontSize * 1.3;
    const infoPaddingTop = footerHeight * 0.15;
    let currentTextY = footerYStart + infoPaddingTop;
    
    outputCtx.font = `${infoFontSize}px ${effectiveFontFamily}`;
    outputCtx.fillStyle = infoTextColor;
    outputCtx.textAlign = "left";
    outputCtx.textBaseline = "top";

    let timestampStr = customTimestamp;
    if (!customTimestamp) {
        const now = new Date();
        timestampStr = `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, '0')}-${String(now.getDate()).padStart(2, '0')} ${String(now.getHours()).padStart(2, '0')}:${String(now.getMinutes()).padStart(2, '0')}:${String(now.getSeconds()).padStart(2, '0')}`;
    }
    
    outputCtx.fillText(`TIME: ${timestampStr}`, 10, currentTextY);
    currentTextY += infoLineHeight;
    outputCtx.fillText(`CASE: ${caseId}`, 10, currentTextY);
    currentTextY += infoLineHeight;
    outputCtx.fillText(`LOC: ${location}`, 10, currentTextY);

    // Footer banner text
    const footerBannerFontSize = Math.max(10, Math.min(footerHeight * 0.25, outputCanvas.width / (footerText.length * 0.60 + 2))); // Dynamic font size
    outputCtx.font = `bold ${footerBannerFontSize}px ${effectiveFontFamily}`;
    outputCtx.fillStyle = footerTextColor;
    outputCtx.textAlign = "center";
    outputCtx.textBaseline = "bottom";
    outputCtx.fillText(footerText, outputCanvas.width / 2, outputCanvas.height - (footerHeight * 0.1));
    
    return outputCanvas;
}

Free Image Tool Creator

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

Description

The Paranormal Investigation Image File Creator is a specialized tool designed to transform images into stylized representations ideal for paranormal investigations. Users can enhance their images by applying effects such as monochrome filtering, noise, and scan lines, giving them an eerie quality. The tool also allows users to add custom headers and footers containing relevant investigation information, including case IDs, timestamps, and locations. With options for dynamic font styles and colors, this tool is particularly useful for ghost hunters, investigators, and enthusiasts looking to present their findings in a professional, thematic manner.

Leave a Reply

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