Please bookmark this page to avoid losing your image tool!

Image Software Finder

(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.
/**
 * Tries to find the name of the software used to create or edit an image by parsing its EXIF metadata.
 * This function works best with original JPEG files that have been loaded via a FileReader into a
 * data URI, as browsers often strip metadata from images for privacy and security reasons.
 *
 * @param {Image} originalImg The javascript Image object to be processed.
 * The image's `src` attribute is expected to be a `data:image/jpeg;base64,...` URI.
 * @returns {HTMLElement} A div element containing the result of the analysis.
 */
function processImage(originalImg) {
    const container = document.createElement('div');
    container.style.fontFamily = 'Arial, sans-serif';
    container.style.padding = '20px';
    container.style.maxWidth = '600px';
    container.style.margin = '20px auto';
    container.style.border = '1px solid #e0e0e0';
    container.style.borderRadius = '8px';
    container.style.boxShadow = '0 4px 8px rgba(0,0,0,0.1)';
    container.style.textAlign = 'center';
    container.style.backgroundColor = '#ffffff';

    const header = document.createElement('h2');
    header.textContent = 'Image Software Finder';
    header.style.color = '#333';
    header.style.marginBottom = '20px';
    container.appendChild(header);
    
    const resultBox = document.createElement('div');
    resultBox.style.padding = '15px';
    resultBox.style.borderRadius = '5px';
    resultBox.style.backgroundColor = '#f9f9f9';
    resultBox.style.border = '1px solid #eee';
    resultBox.style.minHeight = '120px';
    resultBox.style.display = 'flex';
    resultBox.style.flexDirection = 'column';
    resultBox.style.justifyContent = 'center';
    resultBox.style.alignItems = 'center';
    
    container.appendChild(resultBox);

    /**
     * Parses the EXIF data from a base64-encoded JPEG image source to find the software tag.
     * @param {string} imgSrc The `src` attribute of an Image object.
     * @returns {{found: boolean, software?: string, reason?: string}} Result object.
     */
    const findSoftwareInExif = (imgSrc) => {
        try {
            if (!imgSrc.startsWith('data:image/jpeg;base64,') && !imgSrc.startsWith('data:image/jpg;base64,')) {
                return { found: false, reason: 'Image is not a direct-loaded JPEG file. Metadata might be inaccessible.' };
            }

            const base64Data = imgSrc.split(',')[1];
            const binaryStr = atob(base64Data);
            const len = binaryStr.length;
            const bytes = new Uint8Array(len);
            for (let i = 0; i < len; i++) {
                bytes[i] = binaryStr.charCodeAt(i);
            }

            const view = new DataView(bytes.buffer);

            // Check for JPEG Start Of Image marker
            if (view.getUint16(0) !== 0xFFD8) {
                return { found: false, reason: 'Not a valid JPEG file structure.' };
            }
            
            let offset = 2;
            let exifOffset = -1;

            // Scan for the APP1 marker (0xFFE1) which contains EXIF data
            while (offset < view.byteLength - 2) {
                const marker = view.getUint16(offset);
                if (marker === 0xFFE1) {
                    // Check for "Exif\0\0" identifier
                    if (view.getUint32(offset + 4) === 0x45786966 && view.getUint16(offset + 8) === 0x0000) {
                        exifOffset = offset + 10; // Start of TIFF header
                        break;
                    }
                }
                const segmentLength = view.getUint16(offset + 2);
                if (segmentLength <= 2) break; // Avoid infinite loop on corrupt data
                offset += 2 + segmentLength;
            }
            
            if (exifOffset === -1) {
                return { found: false, reason: 'No EXIF data block found in the image.' };
            }
            
            // --- TIFF Header Parsing ---
            const tiffHeaderOffset = exifOffset;
            let littleEndian;
            const byteOrder = view.getUint16(tiffHeaderOffset);
            if (byteOrder === 0x4949) littleEndian = true; // "II" for Intel (little-endian)
            else if (byteOrder === 0x4D4D) littleEndian = false; // "MM" for Motorola (big-endian)
            else return { found: false, reason: 'Invalid EXIF data: incorrect byte order.' };

            if (view.getUint16(tiffHeaderOffset + 2, littleEndian) !== 0x002A) {
                return { found: false, reason: 'Invalid EXIF data: missing TIFF identifier.' };
            }

            let ifdOffset = view.getUint32(tiffHeaderOffset + 4, littleEndian);

            const readString = (stringOffset, length) => {
                let str = '';
                // -1 to exclude the null terminator character
                for (let i = 0; i < length - 1; i++) {
                    str += String.fromCharCode(view.getUint8(stringOffset + i));
                }
                return str;
            };

            // --- Image File Directory (IFD) Parsing ---
            while (ifdOffset !== 0) {
                if (tiffHeaderOffset + ifdOffset >= view.byteLength) break; // Boundary check

                const currentIfdOffset = tiffHeaderOffset + ifdOffset;
                const numEntries = view.getUint16(currentIfdOffset, littleEndian);
                const ifdEntryOffset = currentIfdOffset + 2;

                for (let i = 0; i < numEntries; i++) {
                    const entryOffset = ifdEntryOffset + i * 12;
                    if (entryOffset + 12 > view.byteLength) break; // Boundary check

                    const tag = view.getUint16(entryOffset, littleEndian);
                    
                    if (tag === 0x0131) { // Software Tag ID
                        const type = view.getUint16(entryOffset + 2, littleEndian);
                        if (type !== 2) continue; // Type 2 is ASCII String

                        const count = view.getUint32(entryOffset + 4, littleEndian);
                        let valueOrOffset = view.getUint32(entryOffset + 8, littleEndian);
                        
                        let stringOffset;
                        // If the string is longer than 4 bytes, the value is an offset
                        if (count > 4) {
                            stringOffset = tiffHeaderOffset + valueOrOffset;
                        } else {
                            stringOffset = entryOffset + 8;
                        }

                        if (stringOffset + count > view.byteLength) continue; // Boundary check

                        const softwareName = readString(stringOffset, count);
                        return { found: true, software: softwareName.trim() };
                    }
                }
                
                const nextIfdOffsetLocation = ifdEntryOffset + numEntries * 12;
                if(nextIfdOffsetLocation + 4 > view.byteLength) break; // Boundary check
                ifdOffset = view.getUint32(nextIfdOffsetLocation, littleEndian);
            }

            return { found: false, reason: 'Software tag not found in EXIF data.' };
        } catch (error) {
            console.error("Error parsing EXIF data:", error);
            return { found: false, reason: 'An error occurred while processing the image file.' };
        }
    };

    const result = findSoftwareInExif(originalImg.src);

    if (result.found) {
        resultBox.innerHTML = `
            <p style="margin: 0; font-weight: bold; color: #28a745;">Software Found in Metadata:</p>
            <p style="margin: 10px 0 0; font-size: 1.2em; color: #333; font-family: 'Courier New', monospace; background-color: #e9f5ec; padding: 10px; border-radius: 4px; word-break: break-all;">${result.software}</p>
        `;
    } else {
        resultBox.style.backgroundColor = '#fff3cd';
        resultBox.style.borderColor = '#ffeeba';
        resultBox.innerHTML = `
            <p style="margin: 0; font-weight: bold; color: #856404;">Could not determine software.</p>
            <p style="margin: 5px 0 15px; font-size: 0.9em; color: #555;">Reason: ${result.reason}</p>
            <p style="font-size: 0.85em; color: #666; text-align: left; line-height: 1.4; border-top: 1px solid #ddd; padding-top: 10px;">
                <strong>How this works:</strong> This tool reads technical information (EXIF metadata) embedded in JPEG files. This data is often stripped by websites and apps. For best results, use an original JPEG file directly from a device or photo editor.
            </p>
        `;
    }

    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 Software Finder is a tool designed to identify the software used to create or edit an image by analyzing its EXIF metadata. This is particularly useful for photographers, graphic designers, and anyone interested in understanding the origins or editing history of a JPEG image. By uploading a JPEG file with intact metadata, users can easily discover which software application was used, aiding in tasks such as verifying image authenticity or simply satisfying curiosity about the tools employed in image editing.

Leave a Reply

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