function interpretIFD($ifd_data) { // Check that the IFD array is valid if ($ifd_data === false || $ifd_data === null) { // the IFD array is NOT valid - exit return null; } $ifd_interpreted = array(); // Cycle through each tag in the IFD foreach ($ifd_data as $tagid => $exif_tag) { // Ignore the non numeric elements - they aren't tags if (!is_numeric($tagid)) { // Skip Tags Name } else { if ($exif_tag['Decoded'] == true) { // Check if the Tag has been decoded successfully // This tag has been successfully decoded // Check if the tag is a sub-IFD if ($exif_tag['Type'] == "SubIFD") { // This is a sub-IFD tag // Add a sub-heading for the sub-IFD $ifd_interpreted[$exif_tag['Tag Name']] = array(); // Cycle through each sub-IFD in the chain foreach ($exif_tag['Data'] as $subIFD) { // Interpret this sub-IFD and add the html to the secondary output $ifd_interpreted[$exif_tag['Tag Name']][] = zmgJpeg_metadataPlugin::interpretIFD($subIFD, $filename); } } else { if ($exif_tag['Type'] == "Maker Note") { // Check if the tag is a makernote // This is a Makernote Tag // Interpret the Makernote and add the html to the secondary output $ifd_interpreted['Makernote'] = Interpret_Makernote_to_HTML($exif_tag, $filename); } else { if ($exif_tag['Type'] == "IPTC") { // Check if this is a IPTC/NAA Record within the EXIF IFD // This is a IPTC/NAA Record, interpret it $ifd_interpreted['IPTC'] = Interpret_IPTC_to_HTML($exif_tag['Data']); } else { if ($exif_tag['Type'] == "XMP") { // Change: Check for embedded XMP as of version 1.11 // Check if this is a XMP Record within the EXIF IFD // This is a XMP Record, interpret it $ifd_interpreted['XMP'] = Interpret_XMP_to_HTML($exif_tag['Data']); } else { if ($exif_tag['Type'] == "IRB") { // Change: Check for embedded IRB as of version 1.11 // Check if this is a Photoshop IRB Record within the EXIF IFD // This is a Photoshop IRB Record, interpret it and output to the secondary html $ifd_interpreted['IRB'] = Interpret_IRB_to_HTML($exif_tag['Data'], $filename); } else { if ($exif_tag['Type'] == "Numeric") { // Check if the tag is Numeric // Numeric Tag - Output text value as is. $ifd_interpreted[$exif_tag['Tag Name']] = $exif_tag['Text Value']; } else { // Other tag - Output text as preformatted //$ifd_interpreted[$exif_tag['Tag Name']] = trim($exif_tag['Text Value']); } } } } } } } } } return $ifd_interpreted; }
function Interpret_IRB_to_HTML($IRB_array, $filename) { // Create a string to receive the HTML $output_str = ""; // Check if the Photoshop IRB array is valid if ($IRB_array !== FALSE) { // Create another string to receive secondary HTML to be appended at the end $secondary_output_str = ""; // Add the Heading to the HTML $output_str .= "<h2 class=\"Photoshop_Main_Heading\">Contains Photoshop Information Resource Block (IRB)</h2>"; // Add Table to the HTML $output_str .= "<table class=\"Photoshop_Table\" border=1>\n"; // Cycle through each of the Photoshop IRB records, creating HTML for each foreach ($IRB_array as $IRB_Resource) { // Check if the entry is a known Photoshop IRB resource // Get the Name of the Resource if (array_key_exists($IRB_Resource['ResID'], $GLOBALS["Photoshop_ID_Names"])) { $Resource_Name = $GLOBALS['Photoshop_ID_Names'][$IRB_Resource['ResID']]; } else { // Unknown Resource - Make appropriate name $Resource_Name = "Unknown Resource (" . $IRB_Resource['ResID'] . ")"; } // Add HTML for the resource as appropriate switch ($IRB_Resource['ResID']) { case 0x404: // IPTC-NAA IIM Record $secondary_output_str .= Interpret_IPTC_to_HTML(get_IPTC($IRB_Resource['ResData'])); break; case 0x40b: // URL $output_str .= "<tr class=\"Photoshop_Table_Row\"><td class=\"Photoshop_Caption_Cell\">{$Resource_Name}</td><td class=\"Photoshop_Value_Cell\"><a href=\"" . $IRB_Resource['ResData'] . "\">" . htmlentities($IRB_Resource['ResData']) . "</a></td></tr>\n"; break; case 0x40a: // Copyright Marked if (hexdec(bin2hex($IRB_Resource['ResData'])) == 1) { $output_str .= "<tr class=\"Photoshop_Table_Row\"><td class=\"Photoshop_Caption_Cell\">{$Resource_Name}</td><td class=\"Photoshop_Value_Cell\"><pre>Image is Copyrighted Material</pre></td></tr>\n"; } else { $output_str .= "<tr class=\"Photoshop_Table_Row\"><td class=\"Photoshop_Caption_Cell\">{$Resource_Name}</td><td class=\"Photoshop_Value_Cell\"><pre>Image is Not Copyrighted Material</pre></td></tr>\n"; } break; case 0x40d: // Global Lighting Angle $output_str .= "<tr class=\"Photoshop_Table_Row\"><td class=\"Photoshop_Caption_Cell\">{$Resource_Name}</td><td class=\"Photoshop_Value_Cell\"><pre>Global lighting angle for effects layer = " . hexdec(bin2hex($IRB_Resource['ResData'])) . " degrees</pre></td></tr>\n"; break; case 0x419: // Global Altitude $output_str .= "<tr class=\"Photoshop_Table_Row\"><td class=\"Photoshop_Caption_Cell\">{$Resource_Name}</td><td class=\"Photoshop_Value_Cell\"><pre>Global Altitude = " . hexdec(bin2hex($IRB_Resource['ResData'])) . "</pre></td></tr>\n"; break; case 0x421: // Version Info $output_str .= "<tr class=\"Photoshop_Table_Row\"><td class=\"Photoshop_Caption_Cell\">{$Resource_Name}</td><td class=\"Photoshop_Value_Cell\"><pre>\n"; $output_str .= "Version = " . hexdec(bin2hex(substr($IRB_Resource['ResData'], 0, 4))) . "\n"; $output_str .= "Has Real Merged Data = " . ord($IRB_Resource['ResData'][4]) . "\n"; $writer_size = hexdec(bin2hex(substr($IRB_Resource['ResData'], 5, 4))) * 2; $output_str .= "Writer Name = " . HTML_UTF16_Escape(substr($IRB_Resource['ResData'], 9, $writer_size), TRUE) . "\n"; $reader_size = hexdec(bin2hex(substr($IRB_Resource['ResData'], 9 + $writer_size, 4))) * 2; $output_str .= "Reader Name = " . HTML_UTF16_Escape(substr($IRB_Resource['ResData'], 13 + $writer_size, $reader_size), TRUE) . "\n"; $output_str .= "File Version = " . hexdec(bin2hex(substr($IRB_Resource['ResData'], 13 + $writer_size + $reader_size, 4))) . "\n"; $output_str .= "</pre></td></tr>\n"; break; case 0x411: // ICC Untagged if ($IRB_Resource['ResData'] == "") { $output_str .= "<tr class=\"Photoshop_Table_Row\"><td class=\"Photoshop_Caption_Cell\">{$Resource_Name}</td><td class=\"Photoshop_Value_Cell\"><pre>Intentionally untagged - any assumed ICC profile handling disabled</pre></td></tr>\n"; } else { $output_str .= "<tr class=\"Photoshop_Table_Row\"><td class=\"Photoshop_Caption_Cell\">{$Resource_Name}</td><td class=\"Photoshop_Value_Cell\"><pre>Unknown value (0x" . bin2hex($IRB_Resource['ResData']) . ")</pre></td></tr>\n"; } break; case 0x41a: // Slices $output_str .= "<tr class=\"Photoshop_Table_Row\"><td class=\"Photoshop_Caption_Cell\">{$Resource_Name}</td><td class=\"Photoshop_Value_Cell\">"; // Unpack the first 24 bytes $Slices_Info = unpack("NVersion/NBound_top/NBound_left/NBound_bottom/NBound_right/NStringlen", $IRB_Resource['ResData']); $output_str .= "Version = " . $Slices_Info['Version'] . "<br>\n"; $output_str .= "Bounding Rectangle = Top:" . $Slices_Info['Bound_top'] . ", Left:" . $Slices_Info['Bound_left'] . ", Bottom:" . $Slices_Info['Bound_bottom'] . ", Right:" . $Slices_Info['Bound_right'] . " (Pixels)<br>\n"; $Slicepos = 24; // Extract a Unicode String $output_str .= "Text = '" . HTML_UTF16_Escape(substr($IRB_Resource['ResData'], 24, $Slices_Info['Stringlen'] * 2), TRUE) . "'<br>\n"; $Slicepos += $Slices_Info['Stringlen'] * 2; // Unpack the number of Slices $Num_Slices = hexdec(bin2hex(substr($IRB_Resource['ResData'], $Slicepos, 4))); $output_str .= "Number of Slices = " . $Num_Slices . "\n"; $Slicepos += 4; // Cycle through the slices for ($i = 1; $i <= $Num_Slices; $i++) { $output_str .= "<br><br>Slice {$i}:<br>\n"; // Unpack the first 16 bytes of the slice $SliceA = unpack("NID/NGroupID/NOrigin/NStringlen", substr($IRB_Resource['ResData'], $Slicepos)); $Slicepos += 16; $output_str .= "ID = " . $SliceA['ID'] . "<br>\n"; $output_str .= "Group ID = " . $SliceA['GroupID'] . "<br>\n"; $output_str .= "Origin = " . $SliceA['Origin'] . "<br>\n"; // Extract a Unicode String $output_str .= "Text = '" . HTML_UTF16_Escape(substr($IRB_Resource['ResData'], $Slicepos, $SliceA['Stringlen'] * 2), TRUE) . "'<br>\n"; $Slicepos += $SliceA['Stringlen'] * 2; // Unpack the next 24 bytes of the slice $SliceB = unpack("NType/NLeftPos/NTopPos/NRightPos/NBottomPos/NURLlen", substr($IRB_Resource['ResData'], $Slicepos)); $Slicepos += 24; $output_str .= "Type = " . $SliceB['Type'] . "<br>\n"; $output_str .= "Position = Top:" . $SliceB['TopPos'] . ", Left:" . $SliceB['LeftPos'] . ", Bottom:" . $SliceB['BottomPos'] . ", Right:" . $SliceB['RightPos'] . " (Pixels)<br>\n"; // Extract a Unicode String $output_str .= "URL = <a href='" . substr($IRB_Resource['ResData'], $Slicepos, $SliceB['URLlen'] * 2) . "'>" . HTML_UTF16_Escape(substr($IRB_Resource['ResData'], $Slicepos, $SliceB['URLlen'] * 2), TRUE) . "</a><br>\n"; $Slicepos += $SliceB['URLlen'] * 2; // Unpack the length of a Unicode String $Targetlen = hexdec(bin2hex(substr($IRB_Resource['ResData'], $Slicepos, 4))); $Slicepos += 4; // Extract a Unicode String $output_str .= "Target = '" . HTML_UTF16_Escape(substr($IRB_Resource['ResData'], $Slicepos, $Targetlen * 2), TRUE) . "'<br>\n"; $Slicepos += $Targetlen * 2; // Unpack the length of a Unicode String $Messagelen = hexdec(bin2hex(substr($IRB_Resource['ResData'], $Slicepos, 4))); $Slicepos += 4; // Extract a Unicode String $output_str .= "Message = '" . HTML_UTF16_Escape(substr($IRB_Resource['ResData'], $Slicepos, $Messagelen * 2), TRUE) . "'<br>\n"; $Slicepos += $Messagelen * 2; // Unpack the length of a Unicode String $AltTaglen = hexdec(bin2hex(substr($IRB_Resource['ResData'], $Slicepos, 4))); $Slicepos += 4; // Extract a Unicode String $output_str .= "Alt Tag = '" . HTML_UTF16_Escape(substr($IRB_Resource['ResData'], $Slicepos, $AltTaglen * 2), TRUE) . "'<br>\n"; $Slicepos += $AltTaglen * 2; // Unpack the HTML flag if (ord($IRB_Resource['ResData'][$Slicepos]) === 0x1) { $output_str .= "Cell Text is HTML<br>\n"; } else { $output_str .= "Cell Text is NOT HTML<br>\n"; } $Slicepos++; // Unpack the length of a Unicode String $CellTextlen = hexdec(bin2hex(substr($IRB_Resource['ResData'], $Slicepos, 4))); $Slicepos += 4; // Extract a Unicode String $output_str .= "Cell Text = '" . HTML_UTF16_Escape(substr($IRB_Resource['ResData'], $Slicepos, $CellTextlen * 2), TRUE) . "'<br>\n"; $Slicepos += $CellTextlen * 2; // Unpack the last 12 bytes of the slice $SliceC = unpack("NAlignH/NAlignV/CAlpha/CRed/CGreen/CBlue", substr($IRB_Resource['ResData'], $Slicepos)); $Slicepos += 12; $output_str .= "Alignment = Horizontal:" . $SliceC['AlignH'] . ", Vertical:" . $SliceC['AlignV'] . "<br>\n"; $output_str .= "Alpha Colour = " . $SliceC['Alpha'] . "<br>\n"; $output_str .= "Red = " . $SliceC['Red'] . "<br>\n"; $output_str .= "Green = " . $SliceC['Green'] . "<br>\n"; $output_str .= "Blue = " . $SliceC['Blue'] . "\n"; } $output_str .= "</td></tr>\n"; break; case 0x408: // Grid and Guides information $output_str .= "<tr class=\"Photoshop_Table_Row\"><td class=\"Photoshop_Caption_Cell\">{$Resource_Name}</td><td class=\"Photoshop_Value_Cell\">"; // Unpack the Grids info $Grid_Info = unpack("NVersion/NGridCycleH/NGridCycleV/NGuideCount", $IRB_Resource['ResData']); $output_str .= "Version = " . $Grid_Info['Version'] . "<br>\n"; $output_str .= "Grid Cycle = " . $Grid_Info['GridCycleH'] / 32 . " Pixel(s) x " . $Grid_Info['GridCycleV'] / 32 . " Pixel(s)<br>\n"; $output_str .= "Number of Guides = " . $Grid_Info['GuideCount'] . "\n"; // Cycle through the Guides for ($i = 0; $i < $Grid_Info['GuideCount']; $i++) { // Unpack the info for this guide $Guide_Info = unpack("NLocation/CDirection", substr($IRB_Resource['ResData'], 16 + $i * 5, 5)); $output_str .= "<br>Guide {$i} : Location = " . $Guide_Info['Location'] / 32 . " Pixel(s) from edge"; if ($Guide_Info['Direction'] === 0) { $output_str .= ", Vertical\n"; } else { $output_str .= ", Horizontal\n"; } } break; $output_str .= "</td></tr>\n"; case 0x406: // JPEG Quality $Qual_Info = unpack("nQuality/nFormat/nScans/Cconst", $IRB_Resource['ResData']); $output_str .= "<tr class=\"Photoshop_Table_Row\"><td class=\"Photoshop_Caption_Cell\">{$Resource_Name}</td><td class=\"Photoshop_Value_Cell\">"; switch ($Qual_Info['Quality']) { case 0xfffd: $output_str .= "Quality 1 (Low)<br>\n"; break; case 0xfffe: $output_str .= "Quality 2 (Low)<br>\n"; break; case 0xffff: $output_str .= "Quality 3 (Low)<br>\n"; break; case 0x0: $output_str .= "Quality 4 (Low)<br>\n"; break; case 0x1: $output_str .= "Quality 5 (Medium)<br>\n"; break; case 0x2: $output_str .= "Quality 6 (Medium)<br>\n"; break; case 0x3: $output_str .= "Quality 7 (Medium)<br>\n"; break; case 0x4: $output_str .= "Quality 8 (High)<br>\n"; break; case 0x5: $output_str .= "Quality 9 (High)<br>\n"; break; case 0x6: $output_str .= "Quality 10 (Maximum)<br>\n"; break; case 0x7: $output_str .= "Quality 11 (Maximum)<br>\n"; break; case 0x8: $output_str .= "Quality 12 (Maximum)<br>\n"; break; default: $output_str .= "Unknown Quality (" . $Qual_Info['Quality'] . ")<br>\n"; break; } switch ($Qual_Info['Format']) { case 0x0: $output_str .= "Standard Format\n"; break; case 0x1: $output_str .= "Optimised Format\n"; break; case 0x101: $output_str .= "Progressive Format<br>\n"; break; default: $output_str .= "Unknown Format (" . $Qual_Info['Format'] . ")\n"; break; } if ($Qual_Info['Format'] == 0x101) { switch ($Qual_Info['Scans']) { case 0x1: $output_str .= "3 Scans\n"; break; case 0x2: $output_str .= "4 Scans\n"; break; case 0x3: $output_str .= "5 Scans\n"; break; default: $output_str .= "Unknown number of scans (" . $Qual_Info['Scans'] . ")\n"; break; } } $output_str .= "</td></tr>\n"; break; case 0x409: // Thumbnail Resource // Thumbnail Resource case 0x40c: // Thumbnail Resource $thumb_data = unpack("NFormat/NWidth/NHeight/NWidthBytes/NSize/NCompressedSize/nBitsPixel/nPlanes", $IRB_Resource['ResData']); $output_str .= "<tr class=\"Photoshop_Table_Row\"><td class=\"Photoshop_Caption_Cell\">{$Resource_Name}</td><td class=\"Photoshop_Value_Cell\"><pre>\n"; $output_str .= "Format = " . ($thumb_data['Format'] == 1 ? "JPEG RGB\n" : "Raw RGB\n"); $output_str .= "Width = " . $thumb_data['Width'] . "\n"; $output_str .= "Height = " . $thumb_data['Height'] . "\n"; $output_str .= "Padded Row Bytes = " . $thumb_data['WidthBytes'] . " bytes\n"; $output_str .= "Total Size = " . $thumb_data['Size'] . " bytes\n"; $output_str .= "Compressed Size = " . $thumb_data['CompressedSize'] . " bytes\n"; $output_str .= "Bits per Pixel = " . $thumb_data['BitsPixel'] . " bits\n"; $output_str .= "Number of planes = " . $thumb_data['Planes'] . " bytes\n"; $output_str .= "Thumbnail Data:</pre><a class=\"Photoshop_Thumbnail_Link\" href=\"get_ps_thumb.php?filename={$filename}\"><img class=\"Photoshop_Thumbnail_Link\" src=\"get_ps_thumb.php?filename={$filename}\"></a>\n"; $output_str .= "</td></tr>\n"; break; case 0x414: // Document Specific ID's $output_str .= "<tr class=\"Photoshop_Table_Row\"><td class=\"Photoshop_Caption_Cell\">{$Resource_Name}</td><td class=\"Photoshop_Value_Cell\"><pre>" . hexdec(bin2hex($IRB_Resource['ResData'])) . "</pre></td></tr>\n"; break; case 0x41e: // URL List $URL_count = hexdec(bin2hex(substr($IRB_Resource['ResData'], 0, 4))); $output_str .= "<tr class=\"Photoshop_Table_Row\"><td class=\"Photoshop_Caption_Cell\">{$Resource_Name}</td><td class=\"Photoshop_Value_Cell\">\n"; $output_str .= "{$URL_count} URL's in list<br>\n"; $urlstr = substr($IRB_Resource['ResData'], 4); // TODO: Check if URL List in Photoshop IRB works for ($i = 0; $i < $URL_count; $i++) { $url_data = unpack("NLong/NID/NURLSize", $urlstr); $output_str .= "URL {$i} info: long = " . $url_data['Long'] . ", "; $output_str .= "ID = " . $url_data['ID'] . ", "; $urlstr = substr($urlstr, 12); $url = substr($urlstr, 0, $url_data['URLSize']); $output_str .= "URL = <a href=\"" . xml_UTF16_clean($url, TRUE) . "\">" . HTML_UTF16_Escape($url, TRUE) . "</a><br>\n"; } $output_str .= "</td></tr>\n"; break; case 0x3f4: // Grayscale and multichannel halftoning information. $output_str .= "<tr class=\"Photoshop_Table_Row\"><td class=\"Photoshop_Caption_Cell\">{$Resource_Name}</td><td class=\"Photoshop_Value_Cell\"><pre>\n"; $output_str .= Interpret_Halftone($IRB_Resource['ResData']); $output_str .= "</pre></td></tr>\n"; break; case 0x3f5: // Color halftoning information $output_str .= "<tr class=\"Photoshop_Table_Row\"><td class=\"Photoshop_Caption_Cell\">{$Resource_Name}</td><td class=\"Photoshop_Value_Cell\"><pre>\n"; $output_str .= "Cyan Halftoning Info:\n" . Interpret_Halftone(substr($IRB_Resource['ResData'], 0, 18)) . "\n\n"; $output_str .= "Magenta Halftoning Info:\n" . Interpret_Halftone(substr($IRB_Resource['ResData'], 18, 18)) . "\n\n"; $output_str .= "Yellow Halftoning Info:\n" . Interpret_Halftone(substr($IRB_Resource['ResData'], 36, 18)) . "\n"; $output_str .= "Black Halftoning Info:\n" . Interpret_Halftone(substr($IRB_Resource['ResData'], 54, 18)) . "\n"; $output_str .= "</pre></td></tr>\n"; break; case 0x3f7: // Grayscale and multichannel transfer function. $output_str .= "<tr class=\"Photoshop_Table_Row\"><td class=\"Photoshop_Caption_Cell\">{$Resource_Name}</td><td class=\"Photoshop_Value_Cell\"><pre>\n"; $output_str .= Interpret_Transfer_Function(substr($IRB_Resource['ResData'], 0, 28)); $output_str .= "</pre></td></tr>\n"; break; case 0x3f8: // Color transfer functions $output_str .= "<tr class=\"Photoshop_Table_Row\"><td class=\"Photoshop_Caption_Cell\">{$Resource_Name}</td><td class=\"Photoshop_Value_Cell\"><pre>\n"; $output_str .= "Red Transfer Function: \n" . Interpret_Transfer_Function(substr($IRB_Resource['ResData'], 0, 28)) . "\n\n"; $output_str .= "Green Transfer Function: \n" . Interpret_Transfer_Function(substr($IRB_Resource['ResData'], 28, 28)) . "\n\n"; $output_str .= "Blue Transfer Function: \n" . Interpret_Transfer_Function(substr($IRB_Resource['ResData'], 56, 28)) . "\n"; $output_str .= "</pre></td></tr>\n"; break; case 0x3f3: // Print Flags $output_str .= "<tr class=\"Photoshop_Table_Row\"><td class=\"Photoshop_Caption_Cell\">{$Resource_Name}</td><td class=\"Photoshop_Value_Cell\"><pre>\n"; if ($IRB_Resource['ResData'][0] == "") { $output_str .= "Labels Selected\n"; } else { $output_str .= "Labels Not Selected\n"; } if ($IRB_Resource['ResData'][1] == "") { $output_str .= "Crop Marks Selected\n"; } else { $output_str .= "Crop Marks Not Selected\n"; } if ($IRB_Resource['ResData'][2] == "") { $output_str .= "Color Bars Selected\n"; } else { $output_str .= "Color Bars Not Selected\n"; } if ($IRB_Resource['ResData'][3] == "") { $output_str .= "Registration Marks Selected\n"; } else { $output_str .= "Registration Marks Not Selected\n"; } if ($IRB_Resource['ResData'][4] == "") { $output_str .= "Negative Selected\n"; } else { $output_str .= "Negative Not Selected\n"; } if ($IRB_Resource['ResData'][5] == "") { $output_str .= "Flip Selected\n"; } else { $output_str .= "Flip Not Selected\n"; } if ($IRB_Resource['ResData'][6] == "") { $output_str .= "Interpolate Selected\n"; } else { $output_str .= "Interpolate Not Selected\n"; } if ($IRB_Resource['ResData'][7] == "") { $output_str .= "Caption Selected"; } else { $output_str .= "Caption Not Selected"; } $output_str .= "</pre></td></tr>\n"; break; case 0x2710: // Print Flags Information $PrintFlags = unpack("nVersion/CCentCrop/Cjunk/NBleedWidth/nBleedWidthScale", $IRB_Resource['ResData']); $output_str .= "<tr class=\"Photoshop_Table_Row\"><td class=\"Photoshop_Caption_Cell\">{$Resource_Name}</td><td class=\"Photoshop_Value_Cell\"><pre>\n"; $output_str .= "Version = " . $PrintFlags['Version'] . "\n"; $output_str .= "Centre Crop Marks = " . $PrintFlags['CentCrop'] . "\n"; $output_str .= "Bleed Width = " . $PrintFlags['BleedWidth'] . "\n"; $output_str .= "Bleed Width Scale = " . $PrintFlags['BleedWidthScale']; $output_str .= "</pre></td></tr>\n"; break; case 0x3ed: // Resolution Info $ResInfo = unpack("nhRes_int/nhResdec/nhResUnit/nwidthUnit/nvRes_int/nvResdec/nvResUnit/nheightUnit", $IRB_Resource['ResData']); $output_str .= "<tr class=\"Photoshop_Table_Row\"><td class=\"Photoshop_Caption_Cell\">{$Resource_Name}</td><td class=\"Photoshop_Value_Cell\"><pre>\n"; $output_str .= "Horizontal Resolution = " . ($ResInfo['hRes_int'] + $ResInfo['hResdec'] / 65536) . " pixels per Inch\n"; $output_str .= "Vertical Resolution = " . ($ResInfo['vRes_int'] + $ResInfo['vResdec'] / 65536) . " pixels per Inch\n"; if ($ResInfo['hResUnit'] == 1) { $output_str .= "Display units for Horizontal Resolution = Pixels per Inch\n"; } elseif ($ResInfo['hResUnit'] == 2) { $output_str .= "Display units for Horizontal Resolution = Pixels per Centimetre\n"; } else { $output_str .= "Display units for Horizontal Resolution = Unknown Value (" . $ResInfo['hResUnit'] . ")\n"; } if ($ResInfo['vResUnit'] == 1) { $output_str .= "Display units for Vertical Resolution = Pixels per Inch\n"; } elseif ($ResInfo['vResUnit'] == 2) { $output_str .= "Display units for Vertical Resolution = Pixels per Centimetre\n"; } else { $output_str .= "Display units for Vertical Resolution = Unknown Value (" . $ResInfo['vResUnit'] . ")\n"; } if ($ResInfo['widthUnit'] == 1) { $output_str .= "Display units for Image Width = Inches\n"; } elseif ($ResInfo['widthUnit'] == 2) { $output_str .= "Display units for Image Width = Centimetres\n"; } elseif ($ResInfo['widthUnit'] == 3) { $output_str .= "Display units for Image Width = Points\n"; } elseif ($ResInfo['widthUnit'] == 4) { $output_str .= "Display units for Image Width = Picas\n"; } elseif ($ResInfo['widthUnit'] == 5) { $output_str .= "Display units for Image Width = Columns\n"; } else { $output_str .= "Display units for Image Width = Unknown Value (" . $ResInfo['widthUnit'] . ")\n"; } if ($ResInfo['heightUnit'] == 1) { $output_str .= "Display units for Image Height = Inches"; } elseif ($ResInfo['heightUnit'] == 2) { $output_str .= "Display units for Image Height = Centimetres"; } elseif ($ResInfo['heightUnit'] == 3) { $output_str .= "Display units for Image Height = Points"; } elseif ($ResInfo['heightUnit'] == 4) { $output_str .= "Display units for Image Height = Picas"; } elseif ($ResInfo['heightUnit'] == 5) { $output_str .= "Display units for Image Height = Columns"; } else { $output_str .= "Display units for Image Height = Unknown Value (" . $ResInfo['heightUnit'] . ")"; } $output_str .= "</pre></td></tr>\n"; break; default: // All other records $output_str .= "<tr class=\"Photoshop_Table_Row\"><td class=\"Photoshop_Caption_Cell\">{$Resource_Name}</td><td class=\"Photoshop_Value_Cell\">RESOURCE DECODING NOT IMPLEMENTED YET<BR>" . strlen($IRB_Resource['ResData']) . " bytes</td></tr>\n"; } } // Add the table end to the HTML $output_str .= "</table>\n"; // Add any secondary output to the HTML $output_str .= $secondary_output_str; } // Return the HTML return $output_str; }
function interpret_IFD($IFD_array, $filename) { // Create the output string with the table tag $output_str = "<table class=\"EXIF_Table\" border=1>\n"; // Create an extra output string to receive any supplementary html // which cannot go inside the table $extra_IFD_str = ""; // Check that the IFD array is valid if ($IFD_array === FALSE || $IFD_array === NULL) { // the IFD array is NOT valid - exit return ""; } // Check if this is an EXIF IFD and if there is a makernote present if ($IFD_array['Tags Name'] === "EXIF" && !array_key_exists(37500, $IFD_array)) { // This is an EXIF IFD but NO makernote is present - Add a message to the output $extra_IFD_str .= "<h3 class=\"EXIF_Secondary_Heading\">No Makernote Present</h3>"; } // Cycle through each tag in the IFD foreach ($IFD_array as $Tag_ID => $Exif_Tag) { // Ignore the non numeric elements - they aren't tags if (!is_numeric($Tag_ID)) { // Skip Tags Name } else { if ($Exif_Tag['Decoded'] == TRUE) { // This tag has been successfully decoded // Table cells won't get drawn with nothing in them - // Ensure that at least a non breaking space exists in them if (trim($Exif_Tag['Text Value']) == "") { $Exif_Tag['Text Value'] = " "; } // Check if the tag is a sub-IFD if ($Exif_Tag['Type'] == "SubIFD") { // This is a sub-IFD tag // Add a sub-heading for the sub-IFD $extra_IFD_str .= "<h3 class=\"EXIF_Secondary_Heading\">" . $Exif_Tag['Tag Name'] . " contents</h3>"; // Cycle through each sub-IFD in the chain foreach ($Exif_Tag['Data'] as $subIFD) { // Interpret this sub-IFD and add the html to the secondary output $extra_IFD_str .= interpret_IFD($subIFD, $filename); } } else { if ($Exif_Tag['Type'] == "Maker Note") { // This is a Makernote Tag // Add a sub-heading for the Makernote $extra_IFD_str .= "<h3 class=\"EXIF_Secondary_Heading\">Maker Note Contents</h3>"; // Interpret the Makernote and add the html to the secondary output $extra_IFD_str .= Interpret_Makernote_to_HTML($Exif_Tag, $filename); } else { if ($Exif_Tag['Type'] == "IPTC") { // This is a IPTC/NAA Record, interpret it and output to the secondary html $extra_IFD_str .= "<h3 class=\"EXIF_Secondary_Heading\">Contains IPTC/NAA Embedded in EXIF</h3>"; $extra_IFD_str .= Interpret_IPTC_to_HTML($Exif_Tag['Data']); } else { if ($Exif_Tag['Type'] == "XMP") { // This is a XMP Record, interpret it and output to the secondary html $extra_IFD_str .= "<h3 class=\"EXIF_Secondary_Heading\">Contains XMP Embedded in EXIF</h3>"; $extra_IFD_str .= Interpret_XMP_to_HTML($Exif_Tag['Data']); } else { if ($Exif_Tag['Type'] == "IRB") { // This is a Photoshop IRB Record, interpret it and output to the secondary html $extra_IFD_str .= "<h3 class=\"EXIF_Secondary_Heading\">Contains Photoshop IRB Embedded in EXIF</h3>"; $extra_IFD_str .= Interpret_IRB_to_HTML($Exif_Tag['Data'], $filename); } else { if ($Exif_Tag['Type'] == "Numeric") { // Numeric Tag - Output text value as is. $output_str .= "<tr class=\"EXIF_Table_Row\"><td class=\"EXIF_Caption_Cell\">" . $Exif_Tag['Tag Name'] . "</td><td class=\"EXIF_Value_Cell\">" . $Exif_Tag['Text Value'] . "</td></tr>\n"; } else { // Other tag - Output text as preformatted $output_str .= "<tr class=\"EXIF_Table_Row\"><td class=\"EXIF_Caption_Cell\">" . $Exif_Tag['Tag Name'] . "</td><td class=\"EXIF_Value_Cell\"><pre>" . trim($Exif_Tag['Text Value']) . "</pre></td></tr>\n"; } } } } } } } else { // Tag has NOT been decoded successfully // Hence it is either an unknown tag, or one which // requires processing at the time of html construction // Table cells won't get drawn with nothing in them - // Ensure that at least a non breaking space exists in them if (trim($Exif_Tag['Text Value']) == "") { $Exif_Tag['Text Value'] = " "; } // Check if this tag is the first IFD Thumbnail if ($IFD_array['Tags Name'] == "TIFF" && $Tag_ID == 513) { // This is the first IFD thumbnail - Add html to the output // Change: as of version 1.11 - Changed to make thumbnail link portable across directories // Build the path of the thumbnail script and its filename parameter to put in a url $link_str = get_relative_path(dirname(__FILE__) . "/get_exif_thumb.php", getcwd()); $link_str .= "?filename="; $link_str .= get_relative_path($filename, dirname(__FILE__)); // Add thumbnail link to html $output_str .= "<tr class=\"EXIF_Table_Row\"><td class=\"EXIF_Caption_Cell\">" . $Exif_Tag['Tag Name'] . "</td><td class=\"EXIF_Value_Cell\"><a class=\"EXIF_First_IFD_Thumb_Link\" href=\"{$link_str}\"><img class=\"EXIF_First_IFD_Thumb\" src=\"{$link_str}\"></a></td></tr>\n"; } else { if ($Exif_Tag['Type'] == "Maker Note") { // This is the makernote, but has not been decoded // Add a message to the secondary output $extra_IFD_str .= "<h3 class=\"EXIF_Secondary_Heading\">Makernote Coding Unknown</h3>\n"; } else { // This is an Unknown Tag // Check if the user wants to hide unknown tags if ($GLOBALS['HIDE_UNKNOWN_TAGS'] === FALSE) { // User wants to display unknown tags // Check if the Data is an ascii string if ($Exif_Tag['Data Type'] == 2) { // This is a Ascii String field - add it preformatted to the output $output_str .= "<tr class=\"EXIF_Table_Row\"><td class=\"EXIF_Caption_Cell\">" . $Exif_Tag['Tag Name'] . "</td><td class=\"EXIF_Value_Cell\"><pre>" . trim($Exif_Tag['Text Value']) . "</pre></td></tr>\n"; } else { // Not an ASCII string - add it as is to the output $output_str .= "<tr class=\"EXIF_Table_Row\"><td class=\"EXIF_Caption_Cell\">" . $Exif_Tag['Tag Name'] . "</td><td class=\"EXIF_Value_Cell\">" . trim($Exif_Tag['Text Value']) . "</td></tr>\n"; } } } } } } } // Close the table in the output $output_str .= "</table>\n"; // Add the secondary output at the end of the main output $output_str .= "{$extra_IFD_str}\n"; // Return the resulting html return $output_str; }
function interpret_IFD($IFD_array, $filename) { global $mosConfig_live_site, $zoom; // Create the output string with the table tag $output_str = "<table class=\"EXIF_Table\" border=\"0\" cellspacing=\"0\" cellpadding=\"3\" width=\"70%\">\n"; // Create an extra output string to receive any supplementary html // which cannot go inside the table $extra_IFD_str = ""; // Check that the IFD array is valid if ($IFD_array === FALSE || $IFD_array === NULL) { // the IFD array is NOT valid - exit return ""; } // Check if this is an EXIF IFD and if there is a makernote present if ($IFD_array['Tags Name'] === "EXIF" && !array_key_exists(37500, $IFD_array)) { // This is an EXIF IFD but NO makernote is present - Add a message to the output $extra_IFD_str .= "<h3 class=\"EXIF_Secondary_Heading\">No Makernote Present</h3>"; } // Cycle through each tag in the IFD foreach ($IFD_array as $Tag_ID => $Exif_Tag) { // Ignore the non numeric elements - they aren't tags if (!is_numeric($Tag_ID)) { // Skip Tags Name } else { if ($Exif_Tag['Decoded'] == TRUE) { // This tag has been successfully decoded // Table cells won't get drawn with nothing in them - // Ensure that at least a non breaking space exists in them if (trim($Exif_Tag['Text Value']) == "") { $Exif_Tag['Text Value'] = " "; } // Check if the tag is a sub-IFD if ($Exif_Tag['Type'] == "SubIFD") { // This is a sub-IFD tag // Add a sub-heading for the sub-IFD $extra_IFD_str .= "<h3 class=\"EXIF_Secondary_Heading\">" . $Exif_Tag['Tag Name'] . " contents</h3>"; // Cycle through each sub-IFD in the chain foreach ($Exif_Tag['Data'] as $subIFD) { // Interpret this sub-IFD and add the html to the secondary output $extra_IFD_str .= interpret_IFD($subIFD, $filename); } } else { if ($Exif_Tag['Type'] == "Maker Note") { // This is a Makernote Tag // Add a sub-heading for the Makernote $extra_IFD_str .= "<h3 class=\"EXIF_Secondary_Heading\">Maker Note Contents</h3>"; // Interpret the Makernote and add the html to the secondary output $extra_IFD_str .= Interpret_Makernote_to_HTML($Exif_Tag, $filename); } else { if ($Exif_Tag['Type'] == "IPTC") { // This is a IPTC/NAA Record, interpret it and output to the secondary html $extra_IFD_str .= "<h3 class=\"EXIF_Secondary_Heading\">Contains IPTC/NAA Embedded in EXIF</h3>"; $extra_IFD_str .= Interpret_IPTC_to_HTML($Exif_Tag['Data']); } else { if ($Exif_Tag['Type'] == "Numeric") { // Numeric Tag - Output text value as is. $output_str .= "<tr class=\"EXIF_Table_Row\"><td class=\"EXIF_Caption_Cell\">" . $Exif_Tag['Tag Name'] . "</td><td class=\"EXIF_Value_Cell\">" . $Exif_Tag['Text Value'] . "</td></tr>\n"; } else { // Other tag - Output text as preformatted $output_str .= "<tr class=\"EXIF_Table_Row\"><td class=\"EXIF_Caption_Cell\">" . $Exif_Tag['Tag Name'] . "</td><td class=\"EXIF_Value_Cell\"><pre>" . trim($Exif_Tag['Text Value']) . "</pre></td></tr>\n"; } } } } } else { // Tag has NOT been decoded successfully // Hence it is either an unknown tag, or one which // requires processing at the time of html construction // Table cells won't get drawn with nothing in them - // Ensure that at least a non breaking space exists in them if (trim($Exif_Tag['Text Value']) == "") { $Exif_Tag['Text Value'] = " "; } // Check if this tag is the first IFD Thumbnail if ($IFD_array['Tags Name'] == "TIFF" && $Tag_ID == 513) { if ($zoom->_CONFIG['hotlinkProtection']) { $filename = $zoom->encrypt($filename); } // This is the first IFD thumbnail - Add html to the output $output_str .= "<tr class=\"EXIF_Table_Row\"><td class=\"EXIF_Caption_Cell\">" . $Exif_Tag['Tag Name'] . "</td><td class=\"EXIF_Value_Cell\"><a class=\"EXIF_First_IFD_Thumb_Link\" href=\"" . $mosConfig_live_site . "/components/com_zoom/lib/iptc/get_exif_thumb.php?filename=" . $filename . "\"><img class=\"EXIF_First_IFD_Thumb\" src=\"" . $mosConfig_live_site . "/components/com_zoom/lib/iptc/get_exif_thumb.php?filename=" . $filename . "\" alt=\"\" /></a></td></tr>\n"; } else { if ($Exif_Tag['Type'] == "Maker Note") { // This is the makernote, but has not been decoded // Add a message to the secondary output $extra_IFD_str .= "<h3 class=\"EXIF_Secondary_Heading\">Makernote Coding Unknown</h3>\n"; } else { // This is an Unknown Tag // Check if the user wants to hide unknown tags if ($GLOBALS['HIDE_UNKNOWN_TAGS'] === FALSE) { // User wants to display unknown tags // Check if the Data is an ascii string if ($Exif_Tag['Data Type'] == 2) { // This is a Ascii String field - add it preformatted to the output $output_str .= "<tr class=\"EXIF_Table_Row\"><td class=\"EXIF_Caption_Cell\">" . $Exif_Tag['Tag Name'] . "</td><td class=\"EXIF_Value_Cell\"><pre>" . trim($Exif_Tag['Text Value']) . "</pre></td></tr>\n"; } else { // Not an ASCII string - add it as is to the output $output_str .= "<tr class=\"EXIF_Table_Row\"><td class=\"EXIF_Caption_Cell\">" . $Exif_Tag['Tag Name'] . "</td><td class=\"EXIF_Value_Cell\">" . trim($Exif_Tag['Text Value']) . "</td></tr>\n"; } } } } } } } // Close the table in the output $output_str .= "</table>\n"; // Add the secondary output at the end of the main output $output_str .= "{$extra_IFD_str}\n"; // Return the resulting html return $output_str; }