Search code examples
phpexif

how to get Description metadata of an image?


I need to get Description metadata of an image

$exif = exif_read_data('img.jpg', 0, true);
foreach ($exif as $key => $section) {
    foreach ($section as $name => $val) {
        echo "$key.$name: $val<br />\n";
    }
}

result:

FILE.FileName: img.jpg<br />
FILE.FileDateTime: 1657032928<br />
FILE.FileSize: 89183<br />
FILE.FileType: 2<br />
FILE.MimeType: image/jpeg<br />
FILE.SectionsFound: ANY_TAG, IFD0, GPS<br />
COMPUTED.html: width="576" height="680"<br />
COMPUTED.Height: 680<br />
COMPUTED.Width: 576<br />
COMPUTED.IsColor: 1<br />
COMPUTED.ByteOrderMotorola: 0<br />
IFD0.Orientation: 1<br />
IFD0.XResolution: 300/1<br />
IFD0.YResolution: 300/1<br />
IFD0.ResolutionUnit: 2<br />
IFD0.Software: GIMP 2.10.32<br />
IFD0.DateTime: 2022:07:05 16:54:23<br />
IFD0.GPS_IFD_Pointer: 148<br />
GPS.GPSAltitude: 0/100<br />

there is no Description metadata (the data is clearly visible inside GIMP, for example)

so how can I get Description metadata of an image ?


Solution

  • Different formats

    (Without any link to the file you tested, I assume that...)

    The reason is that Exif (Exchangeable image file format) is not the only metadata format and that it does not know any item for descriptions. Most likely, because it is primarily inserted by cameras, not programs. There are other metadata formats:

    Files versus metadata

    Which meta formats can be expected in which file formats?

    File formats \ Metadata formats Exif IPTC XMP RIFF QTFF proprietary
    JFIF/JPEG comment
    TIFF, CR2, ORF, DNG, RAW, JPEG-XR, NIFF, MDI many
    PNG, JNG, MNG free text
    GIF comment
    WebP many
    JPEG2000, JPEG-XL, HEIF many
    PSD caption

    Finding description in multiple metadata formats in JFIFile

    PHP can by default parse Exif and IPTC and XML (XMP's format), along with JFIFiles. Combining all this we can find a JFIF's description either in IPTC or XMP metadata, should it be there. Technically descriptions can occur more than once per metadata, and (of course) all of those can differ.

    <?php
        // Don't let the browser interpret this as HTML
        header( 'Content-Type: text/plain; charset=UTF-8' );
    
    
        // Add finding to overall array and take note of metadata format in which it was found
        function found( &$aFound, $sText, $sMeta ) {
            if( !isset( $aFound[$sText] ) ) {  // Text is new?
                $aFound[$sText]= $sMeta; 
            } else {
                $aFound[$sText].= ', '. $sMeta;  // Text is known already, just add metadata format
            }
        }
    
    
        // Store all findings: key=text, value=metadata format(s)
        $aFound= array();
    
        // Parse picture, only JFIF/JPEG picture is supported for metadata
        getimagesize( 'C:/mypic.jpg', $aMeta );
    
        // Any metadata found at all?
        if( is_array( $aMeta ) )
        foreach( $aMeta as $sType=> $sData ) {
            switch( $sType ) {
                case 'APP13':  // IPTC
                    $aIptc= iptcparse( $sData );
                    if( is_array( $aIptc ) ) {  // Might have failed
                        if( isset( $aIptc['2#120'] ) ) {
                            // In theory tags can occur multiple times
                            foreach( $aIptc['2#120'] as $sDesc ) {
                                found( $aFound, $sDesc, 'IPTC' );
                            }
                        }
                    }
                break;
    
                case 'APP1':  // Mostly XMP, but can also be Exif
                    $iStart= strpos( $sData, '<x:xmpmeta' );
                    $iEnd= strpos( $sData, '</x:xmpmeta>', $iStart+ 10 );
                    if( $iStart> 0&& $iEnd> 0 ) {  // Valid XMP
                        $sData= substr( $sData, $iStart, $iEnd- $iStart+ 12 );
    
                        $oDom= new DOMDocument();
                        $oDom-> loadXml( $sData );  // Parse XML data
                        $oXpath= new DOMXpath( $oDom );
                        $oXpath-> registerNamespace( 'rdf', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#' );  // Resource Description Framework
                        $oXpath-> registerNamespace( 'dc', 'http://purl.org/dc/elements/1.1/' );  // Dublin Core
    
                        // First the document/file itself, then in its context the picture related info
                        foreach( $oXpath-> evaluate( '//rdf:Description//dc:description' ) as $oElem ) {
                            if( $oElem-> nodeValue ) found( $aFound, $oElem-> nodeValue, 'XMP' ); else
                            if( $oElem-> textContent ) found( $aFound, $oElem-> textContent, 'XMP' );
                        }
                    }
                break;
            }
        }
    
    
        // Which texts have we found?
        print_r( $aFound );
    

    Related questions/answers