Please bookmark this page to avoid losing your image tool!

Image About Information Viewer

(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, theme = "light") {
    // Basic image checks
    const w = originalImg.naturalWidth;
    const h = originalImg.naturalHeight;

    const isDark = theme.toLowerCase() === "dark";
    const bgColor = isDark ? "#121212" : "#ffffff";
    const panelBg = isDark ? "#1e1e1e" : "#f1f5f9";
    const textColor = isDark ? "#e2e8f0" : "#1e293b";
    const labelColor = isDark ? "#94a3b8" : "#64748b";
    const borderColor = isDark ? "#334155" : "#e2e8f0";

    const container = document.createElement("div");
    container.style.fontFamily = "-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif";
    container.style.backgroundColor = bgColor;
    container.style.color = textColor;
    container.style.padding = "24px";
    container.style.borderRadius = "12px";
    container.style.maxWidth = "600px";
    container.style.boxShadow = isDark ? "0 4px 6px -1px rgba(0, 0, 0, 0.5)" : "0 4px 6px -1px rgba(0, 0, 0, 0.1)";
    container.style.boxSizing = "border-box";
    container.style.margin = "0 auto";

    if (!w || !h) {
        container.innerText = "Error: Image failed to load or has invalid dimensions.";
        container.style.color = "#ef4444";
        return container;
    }

    // Header setup
    const header = document.createElement("div");
    header.style.display = "flex";
    header.style.alignItems = "center";
    header.style.justifyContent = "space-between";
    header.style.marginBottom = "20px";
    header.style.borderBottom = `1px solid ${borderColor}`;
    header.style.paddingBottom = "16px";

    const title = document.createElement("h2");
    title.innerText = "À propos Information";
    title.style.margin = "0";
    title.style.fontSize = "20px";
    title.style.fontWeight = "600";
    header.appendChild(title);

    const thumb = document.createElement("img");
    thumb.src = originalImg.src;
    thumb.style.width = "48px";
    thumb.style.height = "48px";
    thumb.style.objectFit = "cover";
    thumb.style.borderRadius = "8px";
    thumb.style.border = `1px solid ${borderColor}`;
    header.appendChild(thumb);
    container.appendChild(header);

    // Helpers
    function getAspectRatioStr(width, height) {
        const gcd = (a, b) => (b === 0 ? a : gcd(b, a % b));
        const divisor = gcd(width, height);
        const num = width / divisor;
        const den = height / divisor;
        const ratio = width / height;

        const commonRatios = [
            { num: 16, den: 9 }, { num: 4, den: 3 }, { num: 1, den: 1 },
            { num: 3, den: 2 }, { num: 21, den: 9 }, { num: 9, den: 16 },
            { num: 3, den: 4 }, { num: 2, den: 3 }
        ];

        for (let cr of commonRatios) {
            if (Math.abs(ratio - (cr.num / cr.den)) < 0.01) {
                if (num > 100 || den > 100) return `~${cr.num}:${cr.den}`;
                return `${cr.num}:${cr.den}`;
            }
        }
        if (num > 100 || den > 100) return `${(width / height).toFixed(2)}:1`;
        return `${num}:${den}`;
    }

    function formatBytes(bytes) {
        if (!+bytes) return '0 Bytes';
        const k = 1024;
        const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB'];
        const i = Math.floor(Math.log(bytes) / Math.log(k));
        return `${parseFloat((bytes / Math.pow(k, i)).toFixed(2))} ${sizes[i]}`;
    }

    // Calculations
    const mp = ((w * h) / 1000000).toFixed(2);
    let format = "Unknown";
    let srcType = "External / HTML";
    let fileSizeStr = "Not Available";

    if (originalImg.src.startsWith('data:image/')) {
        srcType = "Data URI (Base64)";
        const mimeMatch = originalImg.src.match(/data:image\/([a-zA-Z0-9+-]+);/);
        if (mimeMatch) format = mimeMatch[1].toUpperCase();

        const base64str = originalImg.src.split(",")[1] || "";
        const padding = (base64str.match(/=+$/) || [""])[0].length;
        const bytes = (base64str.length * 3) / 4 - padding;
        fileSizeStr = formatBytes(bytes);
    } else if (originalImg.src.startsWith('blob:')) {
        srcType = "Blob URL";
    } else {
        try {
            const urlObj = new URL(originalImg.src, window.location.href);
            const extMatch = urlObj.pathname.match(/\.([a-zA-Z0-9]+)$/);
            if (extMatch) {
                format = extMatch[1].toUpperCase();
                if (format === 'JPEG') format = 'JPG';
            }
        } catch(e) {}
    }

    // Analyze Canvas Details safely (Checking Transperency & Grayscale)
    let hasTransparency = false;
    let colorSpace = "RGB";
    try {
        const canvas = document.createElement("canvas");
        const tw = Math.min(w, 800); // Scale down large images for performance checks
        const th = Math.min(h, 800);
        canvas.width = tw;
        canvas.height = th;
        const ctx = canvas.getContext("2d");
        ctx.drawImage(originalImg, 0, 0, tw, th);
        const imgData = ctx.getImageData(0, 0, tw, th).data;
        
        let hasAlpha = false;
        for (let i = 3; i < imgData.length; i += 4) {
            if (imgData[i] < 255) {
                hasAlpha = true;
                break;
            }
        }
        
        let isGrayscale = true;
        for (let i = 0; i < imgData.length; i += 44) {
             const r = imgData[i], g = imgData[i+1], b = imgData[i+2];
             if (r !== g || g !== b) {
                 isGrayscale = false;
                 break;
             }
        }

        hasTransparency = hasAlpha;
        colorSpace = isGrayscale ? "Grayscale" : "RGB (True Color)";
    } catch (e) {
        hasTransparency = "Unknown (CORS)";
        colorSpace = "Unknown (CORS)";
    }

    // Rendering Base Details 
    const details = [
        { label: "Dimensions", value: `${w} × ${h} px` },
        { label: "Aspect Ratio", value: getAspectRatioStr(w, h) },
        { label: "Megapixels", value: `${mp} MP` },
        { label: "File Size Estimate", value: fileSizeStr },
        { label: "Detected Format", value: format },
        { label: "Color Profiling", value: colorSpace },
        { label: "Contains Transparency", value: hasTransparency === true ? "Yes" : (hasTransparency === false ? "No" : hasTransparency) },
        { label: "Source Protocol", value: srcType }
    ];

    const content = document.createElement("div");
    content.style.backgroundColor = panelBg;
    content.style.borderRadius = "8px";
    content.style.padding = "16px";
    
    details.forEach((inf, idx) => {
        const row = document.createElement("div");
        row.style.display = "flex";
        row.style.justifyContent = "space-between";
        row.style.padding = "8px 0";
        if (idx !== details.length - 1) {
            row.style.borderBottom = `1px solid ${borderColor}`;
        }

        const lbl = document.createElement("span");
        lbl.innerText = inf.label;
        lbl.style.color = labelColor;
        lbl.style.fontWeight = "500";
        lbl.style.fontSize = "14px";

        const val = document.createElement("span");
        val.innerText = inf.value;
        val.style.fontWeight = "600";
        val.style.fontSize = "14px";
        val.style.textAlign = "right";
        val.style.wordBreak = "break-word";
        val.style.marginLeft = "12px";

        row.appendChild(lbl);
        row.appendChild(val);
        content.appendChild(row);
    });

    container.appendChild(content);

    // Dynamic EXIF extraction logic
    try {
        await new Promise((resolve, reject) => {
            if (window.EXIF) return resolve();
            const script = document.createElement("script");
            script.src = "https://cdn.jsdelivr.net/npm/exif-js";
            script.onload = resolve;
            script.onerror = reject;
            document.head.appendChild(script);
        });

        await new Promise((resolve) => {
            window.EXIF.getData(originalImg, function() {
                const tags = window.EXIF.getAllTags(this);
                if (tags && Object.keys(tags).length > 0) {
                    const exifSection = document.createElement("div");
                    exifSection.style.marginTop = "24px";
                    
                    const exifTitle = document.createElement("h3");
                    exifTitle.innerText = "EXIF Metadata";
                    exifTitle.style.fontSize = "16px";
                    exifTitle.style.margin = "0 0 12px 0";
                    exifTitle.style.fontWeight = "600";
                    exifSection.appendChild(exifTitle);
                    
                    const exifContent = document.createElement("div");
                    exifContent.style.backgroundColor = panelBg;
                    exifContent.style.borderRadius = "8px";
                    exifContent.style.padding = "16px";
                    
                    let empty = true;
                    // Excluded heavily nested/binary tags 
                    const skipTags = ["MakerNote", "thumbnail", "UserComment", "ComponentsConfiguration", "SceneType"];

                    for (const key in tags) {
                        if (skipTags.includes(key)) continue;
                        let val = tags[key];

                        if (Array.isArray(val)) {
                            val = val.map(v => {
                                if (v && v.numerator !== undefined && v.denominator !== undefined) {
                                    return (v.numerator / (v.denominator || 1));
                                }
                                return String(v);
                            }).join(", ");
                        } else if (val && typeof val === "object") {
                            if (val.numerator !== undefined && val.denominator !== undefined) {
                                val = (val.numerator / (val.denominator || 1));
                            } else if (val instanceof String) {
                                val = val.toString();
                            } else {
                                val = JSON.stringify(val);
                            }
                        }
                        
                        if (typeof val === "string" || typeof val === "number") {
                            if (val.toString().trim() === "") continue;
                            const decVal = typeof val === "number" && !Number.isInteger(val) ? val.toFixed(4) : val;

                            empty = false;
                            const row = document.createElement("div");
                            row.style.display = "flex";
                            row.style.justifyContent = "space-between";
                            row.style.padding = "6px 0";
                            row.style.borderBottom = `1px solid ${borderColor}`;
                            row.style.alignItems = "center";
                            
                            const lbl = document.createElement("span");
                            lbl.innerText = key.replace(/([A-Z])/g, ' $1').trim(); // Spread CamelCase
                            lbl.style.color = labelColor;
                            lbl.style.fontSize = "13px";
                            lbl.style.marginRight = "10px";
                            lbl.style.whiteSpace = "nowrap";
                            
                            const v = document.createElement("span");
                            v.innerText = decVal;
                            v.style.fontSize = "13px";
                            v.style.fontWeight = "500";
                            v.style.textAlign = "right";
                            v.style.wordBreak = "break-word";
                            
                            row.appendChild(lbl);
                            row.appendChild(v);
                            exifContent.appendChild(row);
                        }
                    }
                    
                    if (!empty) {
                        if (exifContent.lastChild) exifContent.lastChild.style.borderBottom = "none";
                        exifSection.appendChild(exifContent);
                        container.appendChild(exifSection);
                    }
                }
                resolve();
            });
        });
    } catch (e) {
        // Soft fail EXIF - keep the basic info view robust & clean
        console.warn("EXIF processing skipped or failed.", e);
    }
    
    return container;
}

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 About Information Viewer is a diagnostic tool designed to provide a comprehensive overview of an image’s technical properties. It extracts and displays essential details such as dimensions, aspect ratio, megapixel count, file size, and detected format. Additionally, the tool analyzes color profiling to identify if an image is in RGB or grayscale and checks for the presence of transparency. For images containing embedded metadata, the tool also retrieves and presents EXIF data, offering insights into the technical settings used when the image was captured. This utility is useful for photographers, web developers, and designers who need to verify image specifications, optimize assets for the web, or audit file metadata.

Leave a Reply

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