function put_photoshop_file_info($jpeg_header_data, $new_ps_file_info_array, $Old_Exif_array, $Old_XMP_array, $Old_IRB_array) { /*******************************************/ // PREPROCESSING // Check that the date is in the correct format (YYYY-MM-DD) // Explode the date into pieces using the - symbol $date_pieces = explode("-", $new_ps_file_info_array['date']); // If there are not 3 pieces to the date, it is invalid if (count($date_pieces) != 3) { // INVALID DATE echo "Invalid Date - must be YYYY-MM-DD format<br>"; return FALSE; } // Cycle through each piece of the date foreach ($date_pieces as $piece) { // If the piece is not numeric, then the date is invalid. if (!is_numeric($piece)) { // INVALID DATE echo "Invalid Date - must be YYYY-MM-DD format<br>"; return FALSE; } } // Make a unix timestamp at midnight on the date specified $date_stamp = mktime(0, 0, 0, $date_pieces[1], $date_pieces[2], $date_pieces[0]); // Create a translation table to remove carriage return characters $trans = array("\r" => ""); // Cycle through each of the File Info elements foreach ($new_ps_file_info_array as $valkey => $val) { // If the element is 'Keywords' or 'Supplemental Categories', then // it is an array, and needs to be treated as one if ($valkey != 'supplementalcategories' && $valkey != 'keywords') { // Not Keywords or Supplemental Categories // Convert escaped HTML characters to UTF8 and remove carriage returns $new_ps_file_info_array[$valkey] = strtr(HTML_UTF8_UnEscape($val), $trans); } else { // Either Keywords or Supplemental Categories // Cycle through the array, foreach ($val as $subvalkey => $subval) { // Convert escaped HTML characters to UTF8 and remove carriage returns $new_ps_file_info_array[$valkey][$subvalkey] = strtr(HTML_UTF8_UnEscape($subval), $trans); } } } /*******************************************/ // EXIF Processing // Check if the EXIF array exists if ($Old_Exif_array == FALSE) { // EXIF Array doesn't exist - create a new one $new_Exif_array = array('Byte_Align' => "MM", 'Makernote_Tag' => false, 'Tags Name' => "TIFF", 0 => array("Tags Name" => "TIFF")); } else { // EXIF Array Does Exist - use it $new_Exif_array = $Old_Exif_array; } // Update the EXIF Image Description Tag with the new value $new_Exif_array[0][270] = array("Tag Name" => $GLOBALS["IFD_Tag_Definitions"]['TIFF'][270]['Name'], "Tag Number" => 270, "Data Type" => 2, "Type" => $GLOBALS["IFD_Tag_Definitions"]['TIFF'][270]['Type'], "Data" => array(HTML_UTF8_Escape($new_ps_file_info_array['caption']))); // Update the EXIF Artist Name Tag with the new value $new_Exif_array[0][315] = array("Tag Name" => $GLOBALS["IFD_Tag_Definitions"]['TIFF'][315]['Name'], "Tag Number" => 315, "Data Type" => 2, "Type" => $GLOBALS["IFD_Tag_Definitions"]['TIFF'][315]['Type'], "Data" => array(HTML_UTF8_Escape($new_ps_file_info_array['author']))); // Update the EXIF Copyright Information Tag with the new value $new_Exif_array[0][33432] = array("Tag Name" => $GLOBALS["IFD_Tag_Definitions"]['TIFF'][33432]['Name'], "Tag Number" => 33432, "Data Type" => 2, "Type" => $GLOBALS["IFD_Tag_Definitions"]['TIFF'][33432]['Type'], "Data" => array(HTML_UTF8_Escape($new_ps_file_info_array['copyrightnotice']))); // Photoshop checks if the "Date and Time of Original" and "Date and Time when Digitized" tags exist // If they don't exist, it means that the EXIF date may be wiped out if it is changed, so Photoshop // copies the EXIF date to these two tags if (array_key_exists(306, $new_Exif_array[0]) && array_key_exists(34665, $new_Exif_array[0]) && array_key_exists(0, $new_Exif_array[0][34665])) { // Replace "Date and Time of Original" if it doesn't exist if (!array_key_exists(36867, $new_Exif_array[0][34665][0])) { $new_Exif_array[0][34665][0][36867] = array("Tag Name" => $GLOBALS["IFD_Tag_Definitions"]['EXIF'][36867]['Name'], "Tag Number" => 36867, "Data Type" => 2, "Type" => $GLOBALS["IFD_Tag_Definitions"]['EXIF'][36867]['Type'], "Data" => $new_Exif_array[0][306]['Data']); } // Replace "Date and Time when Digitized" if it doesn't exist if (!array_key_exists(36868, $new_Exif_array[0][34665][0])) { $new_Exif_array[0][34665][0][36868] = array("Tag Name" => $GLOBALS["IFD_Tag_Definitions"]['EXIF'][36868]['Name'], "Tag Number" => 36868, "Data Type" => 2, "Type" => $GLOBALS["IFD_Tag_Definitions"]['EXIF'][36868]['Type'], "Data" => $new_Exif_array[0][306]['Data']); } } // Photoshop changes the EXIF date Tag (306) to the current date, not the date that was entered in File Info $exif_date = date("Y:m:d H:i:s"); // Update the EXIF Date and Time Tag with the new value $new_Exif_array[0][306] = array("Tag Name" => $GLOBALS["IFD_Tag_Definitions"]['TIFF'][306]['Name'], "Tag Number" => 306, "Data Type" => 2, "Type" => $GLOBALS["IFD_Tag_Definitions"]['TIFF'][306]['Type'], "Data" => array($exif_date)); // Photoshop replaces the EXIF Software or Firmware Tag with "Adobe Photoshop ..." // This toolkit instead preserves existing value and appends the toolkit name to the end of it // Check if the EXIF Software or Firmware Tag exists if (array_key_exists(305, $new_Exif_array[0])) { // An existing EXIF Software or Firmware Tag was found // Check if the existing Software or Firmware Tag already contains the Toolkit's name if (stristr($new_Exif_array[0][305]['Data'][0], $GLOBALS["Software Name"]) == FALSE) { // Toolkit Name string not found in the existing Software/Firmware string - append it. $firmware_str = $new_Exif_array[0][305]['Data'][0] . " " . $GLOBALS["Software Name"]; } else { // Toolkit name already exists in Software/Firmware string - don't put another copy in the string $firmware_str = $new_Exif_array[0][305]['Data'][0]; } } else { // No Software/Firmware string exists - create one $firmware_str = $GLOBALS["Software Name"]; } // Update the EXIF Software/Firmware Tag with the new value $new_Exif_array[0][305] = array("Tag Name" => $GLOBALS["IFD_Tag_Definitions"]['TIFF'][305]['Name'], "Tag Number" => 305, "Data Type" => 2, "Type" => $GLOBALS["IFD_Tag_Definitions"]['TIFF'][305]['Type'], "Data" => array(HTML_UTF8_Escape($firmware_str))); /*******************************************/ // Photoshop IRB Processing // Check if there is an existing Photoshop IRB array if ($Old_IRB_array == FALSE) { // No existing IRB array - create one $new_IRB_array = array(); } else { // There is an existing Photoshop IRB array - use it $new_IRB_array = $Old_IRB_array; } // Remove any existing Copyright Flag, URL, or IPTC resources - these will be re-written foreach ($new_IRB_array as $resno => $res) { if ($res['ResID'] == 0x40a || $res['ResID'] == 0x40b || $res['ResID'] == 0x404) { array_splice($new_IRB_array, $resno, 1); } } // Add a new Copyright Flag resource if ($new_ps_file_info_array['copyrightstatus'] == "Copyrighted Work") { $PS_copyright_flag = ""; // Copyrighted } else { $PS_copyright_flag = ""; // Public domain or Unmarked } $new_IRB_array[] = array('ResID' => 0x40a, 'ResName' => $GLOBALS["Photoshop_ID_Names"][0x40a], 'ResDesc' => $GLOBALS["Photoshop_ID_Descriptions"][0x40a], 'ResEmbeddedName' => "", 'ResData' => $PS_copyright_flag); // Add a new URL resource $new_IRB_array[] = array('ResID' => 0x40b, 'ResName' => $GLOBALS["Photoshop_ID_Names"][0x40b], 'ResDesc' => $GLOBALS["Photoshop_ID_Descriptions"][0x40b], 'ResEmbeddedName' => "", 'ResData' => $new_ps_file_info_array['ownerurl']); // Create IPTC resource // IPTC requires date to be in the following format YYYYMMDD $iptc_date = date("Ymd", $date_stamp); // Create the new IPTC array $new_IPTC_array = array(0 => array('IPTC_Type' => '2:00', 'RecName' => $GLOBALS["IPTC_Entry_Names"]['2:00'], 'RecDesc' => $GLOBALS["IPTC_Entry_Descriptions"]['2:00'], 'RecData' => ""), 1 => array('IPTC_Type' => '2:120', 'RecName' => $GLOBALS["IPTC_Entry_Names"]['2:120'], 'RecDesc' => $GLOBALS["IPTC_Entry_Descriptions"]['2:120'], 'RecData' => substr(HTML_UTF8_Escape($new_ps_file_info_array['caption']), 0, 2000)), 2 => array('IPTC_Type' => '2:122', 'RecName' => $GLOBALS["IPTC_Entry_Names"]['2:122'], 'RecDesc' => $GLOBALS["IPTC_Entry_Descriptions"]['2:122'], 'RecData' => substr(HTML_UTF8_Escape($new_ps_file_info_array['captionwriter']), 0, 32)), 3 => array('IPTC_Type' => '2:105', 'RecName' => $GLOBALS["IPTC_Entry_Names"]['2:105'], 'RecDesc' => $GLOBALS["IPTC_Entry_Descriptions"]['2:105'], 'RecData' => substr(HTML_UTF8_Escape($new_ps_file_info_array['headline']), 0, 256)), 4 => array('IPTC_Type' => '2:40', 'RecName' => $GLOBALS["IPTC_Entry_Names"]['2:40'], 'RecDesc' => $GLOBALS["IPTC_Entry_Descriptions"]['2:40'], 'RecData' => substr(HTML_UTF8_Escape($new_ps_file_info_array['instructions']), 0, 256)), 5 => array('IPTC_Type' => '2:80', 'RecName' => $GLOBALS["IPTC_Entry_Names"]['2:80'], 'RecDesc' => $GLOBALS["IPTC_Entry_Descriptions"]['2:80'], 'RecData' => substr(HTML_UTF8_Escape($new_ps_file_info_array['author']), 0, 32)), 6 => array('IPTC_Type' => '2:85', 'RecName' => $GLOBALS["IPTC_Entry_Names"]['2:85'], 'RecDesc' => $GLOBALS["IPTC_Entry_Descriptions"]['2:85'], 'RecData' => substr(HTML_UTF8_Escape($new_ps_file_info_array['authorsposition']), 0, 32)), 7 => array('IPTC_Type' => '2:110', 'RecName' => $GLOBALS["IPTC_Entry_Names"]['2:110'], 'RecDesc' => $GLOBALS["IPTC_Entry_Descriptions"]['2:110'], 'RecData' => substr(HTML_UTF8_Escape($new_ps_file_info_array['credit']), 0, 32)), 8 => array('IPTC_Type' => '2:115', 'RecName' => $GLOBALS["IPTC_Entry_Names"]['2:115'], 'RecDesc' => $GLOBALS["IPTC_Entry_Descriptions"]['2:115'], 'RecData' => substr(HTML_UTF8_Escape($new_ps_file_info_array['source']), 0, 32)), 9 => array('IPTC_Type' => '2:05', 'RecName' => $GLOBALS["IPTC_Entry_Names"]['2:05'], 'RecDesc' => $GLOBALS["IPTC_Entry_Descriptions"]['2:05'], 'RecData' => substr(HTML_UTF8_Escape($new_ps_file_info_array['title']), 0, 64)), 10 => array('IPTC_Type' => '2:55', 'RecName' => $GLOBALS["IPTC_Entry_Names"]['2:55'], 'RecDesc' => $GLOBALS["IPTC_Entry_Descriptions"]['2:55'], 'RecData' => "{$iptc_date}"), 11 => array('IPTC_Type' => '2:90', 'RecName' => $GLOBALS["IPTC_Entry_Names"]['2:90'], 'RecDesc' => $GLOBALS["IPTC_Entry_Descriptions"]['2:90'], 'RecData' => substr(HTML_UTF8_Escape($new_ps_file_info_array['city']), 0, 32)), 12 => array('IPTC_Type' => '2:95', 'RecName' => $GLOBALS["IPTC_Entry_Names"]['2:95'], 'RecDesc' => $GLOBALS["IPTC_Entry_Descriptions"]['2:95'], 'RecData' => substr(HTML_UTF8_Escape($new_ps_file_info_array['state']), 0, 32)), 13 => array('IPTC_Type' => '2:101', 'RecName' => $GLOBALS["IPTC_Entry_Names"]['2:101'], 'RecDesc' => $GLOBALS["IPTC_Entry_Descriptions"]['2:101'], 'RecData' => substr(HTML_UTF8_Escape($new_ps_file_info_array['country']), 0, 64)), 14 => array('IPTC_Type' => '2:103', 'RecName' => $GLOBALS["IPTC_Entry_Names"]['2:103'], 'RecDesc' => $GLOBALS["IPTC_Entry_Descriptions"]['2:103'], 'RecData' => substr(HTML_UTF8_Escape($new_ps_file_info_array['transmissionreference']), 0, 32)), 15 => array('IPTC_Type' => '2:15', 'RecName' => $GLOBALS["IPTC_Entry_Names"]['2:15'], 'RecDesc' => $GLOBALS["IPTC_Entry_Descriptions"]['2:15'], 'RecData' => substr(HTML_UTF8_Escape($new_ps_file_info_array['category']), 0, 3)), 21 => array('IPTC_Type' => '2:116', 'RecName' => $GLOBALS["IPTC_Entry_Names"]['2:10'], 'RecDesc' => $GLOBALS["IPTC_Entry_Descriptions"]['2:10'], 'RecData' => substr(HTML_UTF8_Escape($new_ps_file_info_array['copyrightnotice']), 0, 128))); // Check the value of urgency is valid if ($new_ps_file_info_array['urgency'] > 0 && $new_ps_file_info_array['urgency'] < 9) { // Add the Urgency item to the IPTC array $new_IPTC_array[] = array('IPTC_Type' => '2:10', 'RecName' => $GLOBALS["IPTC_Entry_Names"]['2:10'], 'RecDesc' => $GLOBALS["IPTC_Entry_Descriptions"]['2:10'], 'RecData' => substr(HTML_UTF8_Escape($new_ps_file_info_array['urgency']), 0, 1)); } // Cycle through the Supplemental Categories, foreach ($new_ps_file_info_array['supplementalcategories'] as $supcat) { // Add this Supplemental Category to the IPTC array $new_IPTC_array[] = array('IPTC_Type' => '2:20', 'RecName' => $GLOBALS["IPTC_Entry_Names"]['2:20'], 'RecDesc' => $GLOBALS["IPTC_Entry_Descriptions"]['2:20'], 'RecData' => HTML_UTF8_Escape($supcat)); } // Cycle through the Keywords, foreach ($new_ps_file_info_array['keywords'] as $keyword) { // Add this Keyword to the IPTC array $new_IPTC_array[] = array('IPTC_Type' => '2:25', 'RecName' => $GLOBALS["IPTC_Entry_Names"]['2:25'], 'RecDesc' => $GLOBALS["IPTC_Entry_Descriptions"]['2:25'], 'RecData' => $keyword); } /***********************************/ // XMP Processing // Check if XMP existed previously if ($Old_XMP_array == FALSE) { // XMP didn't exist - create a new one based on a blank structure $new_XMP_array = XMP_Check($GLOBALS['Blank XMP Structure'], array()); } else { // XMP does exist // Some old XMP processors used x:xapmeta, check for this if ($Old_XMP_array[0]['tag'] == 'x:xapmeta') { // x:xapmeta found - change it to x:xmpmeta $Old_XMP_array[0]['tag'] = 'x:xmpmeta'; } // Ensure that the existing XMP has all required fields, and add any that are missing $new_XMP_array = XMP_Check($GLOBALS['Blank XMP Structure'], $Old_XMP_array); } // Process the XMP Photoshop block // Find the Photoshop Information within the XMP block $photoshop_block =& find_XMP_block($new_XMP_array, "photoshop"); // The Photoshop CaptionWriter tag contains captionwriter - Find it and Update the value $Item =& find_XMP_item($photoshop_block, "photoshop:CaptionWriter"); $Item['value'] = $new_ps_file_info_array['captionwriter']; // The Photoshop Category tag contains category - Find it and Update the value $Item =& find_XMP_item($photoshop_block, "photoshop:Category"); $Item['value'] = $new_ps_file_info_array['category']; // The Photoshop DateCreated tag contains date - Find it and Update the value $Item =& find_XMP_item($photoshop_block, "photoshop:DateCreated"); $Item['value'] = $new_ps_file_info_array['date']; // The Photoshop City tag contains city - Find it and Update the value $Item =& find_XMP_item($photoshop_block, "photoshop:City"); $Item['value'] = $new_ps_file_info_array['city']; // The Photoshop State tag contains state - Find it and Update the value $Item =& find_XMP_item($photoshop_block, "photoshop:State"); $Item['value'] = $new_ps_file_info_array['state']; // The Photoshop Country tag contains country - Find it and Update the value $Item =& find_XMP_item($photoshop_block, "photoshop:Country"); $Item['value'] = $new_ps_file_info_array['country']; // The Photoshop AuthorsPosition tag contains authorsposition - Find it and Update the value $Item =& find_XMP_item($photoshop_block, "photoshop:AuthorsPosition"); $Item['value'] = $new_ps_file_info_array['authorsposition']; // The Photoshop Credit tag contains credit - Find it and Update the value $Item =& find_XMP_item($photoshop_block, "photoshop:Credit"); $Item['value'] = $new_ps_file_info_array['credit']; // The Photoshop Source tag contains source - Find it and Update the value $Item =& find_XMP_item($photoshop_block, "photoshop:Source"); $Item['value'] = $new_ps_file_info_array['source']; // The Photoshop Headline tag contains headline - Find it and Update the value $Item =& find_XMP_item($photoshop_block, "photoshop:Headline"); $Item['value'] = $new_ps_file_info_array['headline']; // The Photoshop Instructions tag contains instructions - Find it and Update the value $Item =& find_XMP_item($photoshop_block, "photoshop:Instructions"); $Item['value'] = $new_ps_file_info_array['instructions']; // The Photoshop TransmissionReference tag contains transmissionreference - Find it and Update the value $Item =& find_XMP_item($photoshop_block, "photoshop:TransmissionReference"); $Item['value'] = $new_ps_file_info_array['transmissionreference']; // The Photoshop Urgency tag contains urgency - Find it and Update the value $Item =& find_XMP_item($photoshop_block, "photoshop:Urgency"); $Item['value'] = $new_ps_file_info_array['urgency']; // The Photoshop SupplementalCategories tag contains supplementalcategories - Find it $Item =& find_XMP_item($photoshop_block, "photoshop:SupplementalCategories"); // Create an array to receive the XML list items for the Supplemental Categories $new_supcat_array = array(); // Cycle through the Supplemental Categories foreach ($new_ps_file_info_array['supplementalcategories'] as $sup_category) { // Add a new list item for this Supplemental Category $new_supcat_array[] = array('tag' => 'rdf:li', 'value' => $sup_category); } // Add the array of Supplemental Category List Items to the Photoshop SupplementalCategories tag $Item['children'][0]['children'] = $new_supcat_array; // Process the XMP XAP block // Find the XAP Information within the XMP block $XAP_block =& find_XMP_block($new_XMP_array, "xap"); // The XAP CreateDate tag contains date XMP was first created - Find it and Update the value $Item =& find_XMP_item($XAP_block, "xap:CreateDate"); // Check if the CreateDate is blank if ($Item['value'] == "") { // CreateDate is blank - we must have just added it - set it to the current date $Item['value'] = date("Y-m-d\\TH:i:s"); $Item['value'] .= get_Local_Timezone_Offset(); } // The XAP ModifyDate tag contains last resource change date - Find it and Update the value to the current date $Item =& find_XMP_item($XAP_block, "xap:ModifyDate"); $Item['value'] = date("Y-m-d\\TH:i:s"); $Item['value'] .= get_Local_Timezone_Offset(); // The XAP ModifyDate tag contains last XMP change date - Find it and Update the value to the current date $Item =& find_XMP_item($XAP_block, "xap:MetadataDate"); $Item['value'] = date("Y-m-d\\TH:i:s"); $Item['value'] .= get_Local_Timezone_Offset(); // The XAP CreatorTool tag contains name of the software editor - Find it $Item =& find_XMP_item($XAP_block, "xap:CreatorTool"); // Photoshop replaces the CreatorTool with "Adobe Photoshop ..." // This toolkit instead preserves existing value and appends the toolkit name to the end of it // Check if a CreatorTool already exists if ($Item['value'] != "") { // An existing CreatorTool was found // Check if the existing CreatorTool already contains the Toolkit's name if (stristr($Item['value'], $GLOBALS["Software Name"]) == FALSE) { // Toolkit Name string not found in the existing CreatorTool string - append it. $Item['value'] = $Item['value'] . " " . $GLOBALS["Software Name"]; } else { // Toolkit name already exists in CreatorTool string - leave as is } } else { // No CreatorTool string exists - create one $Item['value'] = $GLOBALS["Software Name"]; } // Process the XMP Basic Job Information block // Find the XAP Basic Job Information within the XMP block $XAPBJ_block =& find_XMP_block($new_XMP_array, "xapBJ"); // The XAP Basic Job JobRef tag contains urgency - Find it and Update the value $Item =& find_XMP_item($XAPBJ_block, "xapBJ:JobRef"); $Item['children'][0]['children'] = array(array('tag' => 'rdf:li', 'attributes' => array('rdf:parseType' => 'Resource'), 'children' => array(0 => array('tag' => 'stJob:name', 'value' => $new_ps_file_info_array['jobname'])))); // Process the XMP XAP Rights Information block // Find the XAP Rights Information within the XMP block $XAPRights_block =& find_XMP_block($new_XMP_array, "xapRights"); // The XAP Rights Marked tag should only be present if copyrightstatus is 'Copyrighted Work' or 'Public Domain' // If copyrightstatus 'Unmarked' or anything else, the XAP Rights Marked tag should be missing // Remove any existing XAP Rights Marked tags - they will be replaced foreach ($XAPRights_block as $tagno => $tag) { if ($tag['tag'] == "xapRights:Marked") { array_splice($XAPRights_block, $tagno, 1); } } // Check the value of the copyrightstatus flag if ($new_ps_file_info_array['copyrightstatus'] == "Copyrighted Work") { // Copyrighted - add the tag $XAPRights_block[] = array('tag' => 'xapRights:Marked', 'value' => 'True'); } else { if ($new_ps_file_info_array['copyrightstatus'] == "Public Domain") { // Public domain - add the tag $XAPRights_block[] = array('tag' => 'xapRights:Marked', 'value' => 'False'); } else { // Unmarked or Other - Do nothing - don't add a Marked tag } } // The XAP Rights WebStatement tag contains ownerurl - Find it and Update the value $Item =& find_XMP_item($XAPRights_block, "xapRights:WebStatement"); $Item['value'] = $new_ps_file_info_array['ownerurl']; // Process the XMP Dublin Core block // Find the Dublin Core Information within the XMP block $DC_block =& find_XMP_block($new_XMP_array, "dc"); // The Dublin Core description tag contains caption - Find it and Update the value $Item =& find_XMP_item($DC_block, "dc:description"); $Item['children'][0]['children'] = array(array('tag' => "rdf:li", 'value' => $new_ps_file_info_array['caption'], 'attributes' => array('xml:lang' => "x-default"))); // The Dublin Core title tag contains title - Find it and Update the value $Item =& find_XMP_item($DC_block, "dc:title"); $Item['children'][0]['children'] = array(array('tag' => "rdf:li", 'value' => $new_ps_file_info_array['title'], 'attributes' => array('xml:lang' => "x-default"))); // The Dublin Core rights tag contains copyrightnotice - Find it and Update the value $Item =& find_XMP_item($DC_block, "dc:rights"); $Item['children'][0]['children'] = array(array('tag' => "rdf:li", 'value' => $new_ps_file_info_array['copyrightnotice'], 'attributes' => array('xml:lang' => "x-default"))); // The Dublin Core creator tag contains author - Find it and Update the value $Item =& find_XMP_item($DC_block, "dc:creator"); $Item['children'][0]['children'] = array(array('tag' => "rdf:li", 'value' => $new_ps_file_info_array['author'])); // The Dublin Core subject tag contains keywords - Find it $Item =& find_XMP_item($DC_block, "dc:subject"); // Create an array to receive the Keywords List Items $new_keywords_array = array(); // Cycle through each keyword foreach ($new_ps_file_info_array['keywords'] as $keyword) { // Add a List item for this keyword $new_keywords_array[] = array('tag' => "rdf:li", 'value' => $keyword); } // Add the Keywords List Items array to the Dublin Core subject tag $Item['children'][0]['children'] = $new_keywords_array; /***************************************/ // FINISHED UPDATING VALUES // Insert the new IPTC array into the Photoshop IRB array $new_IRB_array = put_Photoshop_IPTC($new_IRB_array, $new_IPTC_array); // Write the EXIF array to the JPEG header $jpeg_header_data = put_EXIF_JPEG($new_Exif_array, $jpeg_header_data); // Convert the XMP array to XMP text $xmp_text = write_XMP_array_to_text($new_XMP_array); // Write the XMP text to the JPEG Header $jpeg_header_data = put_XMP_text($jpeg_header_data, $xmp_text); // Write the Photoshop IRB array to the JPEG header $jpeg_header_data = put_Photoshop_IRB($jpeg_header_data, $new_IRB_array); return $jpeg_header_data; }
function Interpret_XMP_to_HTML($XMP_array) { // Create a string to receive the output html $output = ""; // Check if the XMP tree structure array is valid if ($XMP_array !== FALSE) { // Check if there is a rdf:RDF tag at either the first or second level if ($XMP_array[0]['tag'] == "x:xapmeta" && $XMP_array[0]['children'][0]['tag'] == "rdf:RDF") { // RDF found at second level - Save it's position $RDF_Contents =& $XMP_array[0]['children'][0]['children']; } else { if ($XMP_array[0]['tag'] == "x:xmpmeta" && $XMP_array[0]['children'][0]['tag'] == "rdf:RDF") { // RDF found at second level - Save it's position $RDF_Contents =& $XMP_array[0]['children'][0]['children']; } else { if ($XMP_array[0]['tag'] == "rdf:RDF") { // RDF found at first level - Save it's position $RDF_Contents =& $XMP_array[0]['children']; } else { // RDF section not found - abort return ""; } } } // Add heading to html output $output .= "<h2 class=\"XMP_Main_Heading\">Contains Extensible Metadata Platform (XMP) / Resource Description Framework (RDF) Information</h2>\n"; // Cycle through each of the items in the RDF tree array, and process them foreach ($RDF_Contents as $RDF_Item) { // Check if the item is a rdf:Description tag - these are the only ones that can be processed if ($RDF_Item['tag'] == "rdf:Description" && array_key_exists('children', $RDF_Item)) { // Item is a rdf:Description tag. // Cycle through each of the attributes for this tag, looking // for a xmlns: attribute, which tells us what Namespace the // sub-items will be in. foreach ($RDF_Item['attributes'] as $key => $val) { // Check for the xmlns: namespace attribute if (substr($key, 0, 6) == "xmlns:") { // Found a xmlns: attribute // Extract the namespace string // Add heading to the HTML according to which Namespace the RDF items have switch (substr($key, 6)) { case "photoshop": $output .= "<h3 class=\"XMP_Secondary_Heading\">Photoshop RDF Segment</h3>\n"; break; case "xapBJ": $output .= "<h3 class=\"XMP_Secondary_Heading\">Basic Job Ticket RDF Segment</h3>\n"; break; case "xapMM": $output .= "<h3 class=\"XMP_Secondary_Heading\">Media Management RDF Segment</h3>\n"; break; case "xapRights": $output .= "<h3 class=\"XMP_Secondary_Heading\">Rights Management RDF Segment</h3>\n"; break; case "dc": $output .= "<h3 class=\"XMP_Secondary_Heading\">Dublin Core Metadata Initiative RDF Segment</h3>\n"; break; case "xmp": case "xap": $output .= "<h3 class=\"XMP_Secondary_Heading\">XMP Basic Segment</h3>\n"; break; case "xmpTPg": $output .= "<h3 class=\"XMP_Secondary_Heading\">XMP Paged-Text Segment</h3>\n"; break; case "xmpTPg": $output .= "<h3 class=\"XMP_Secondary_Heading\">Adobe PDF Segment</h3>\n"; break; case "tiff": $output .= "<h3 class=\"XMP_Secondary_Heading\">XMP - embedded TIFF Segment</h3>\n"; break; case "exif": $output .= "<h3 class=\"XMP_Secondary_Heading\">XMP - embedded EXIF Segment</h3>\n"; break; case "xapGImg": // Sub Category - Do nothing break; case "stDim": // Sub Category - Do nothing break; case "stEvt": // Sub Category - Do nothing break; case "stRef": // Sub Category - Do nothing break; case "stVer": // Sub Category - Do nothing break; case "stJob": // Sub Category - Do nothing break; default: $output .= "<h3 class=\"XMP_Secondary_Heading\">Unknown RDF Segment '" . substr($key, 6) . "'</h3>\n"; break; } } } // Add the start of the table to the HTML output $output .= "\n<table class=\"XMP_Table\" border=\"0\" cellspacing=\"0\" cellpadding=\"3\">\n"; // Check if this element has sub-items if (array_key_exists('children', $RDF_Item)) { // Cycle through each of the sub-items foreach ($RDF_Item['children'] as $child_item) { // Get an interpretation of the sub-item's caption and value list($tag_caption, $value_str) = Interpret_RDF_Item($child_item); // Escape the text of the caption for html $tag_caption = HTML_UTF8_Escape($tag_caption); // Escape the text of the value for html and turn newlines to <br> $value_str = nl2br(HTML_UTF8_Escape($value_str)); // Check if the value is empty - if it is, put a no-break-space in // to ensure the table cell gets drawn if ($value_str == "") { $value_str = " "; } // Add the table row to the output html $output .= "<tr class=\"XMP_Table_Row\"><td class=\"XMP_Caption_Cell\">" . $tag_caption . ":</td><td class=\"XMP_Value_Cell\">" . $value_str . "</td></tr>\n"; } } // Add the end of the table to the html $output .= "\n</table>\n"; } else { // Don't know how to process tags other than rdf:Description - do nothing } } } // Return the resulting HTML return $output; }
function get_Ricoh_Text_Value($Exif_Tag, $Tag_Definitions_Name) { // Check that this tag uses the Ricoh tags, otherwise it can't be decoded here if ($Tag_Definitions_Name == "Ricoh") { // Process the tag acording to it's tag number, to produce a text value if ($Exif_Tag['Tag Number'] == 0x2) { $tmp = implode("", $Exif_Tag['Data']); return "\"" . HTML_UTF8_Escape($tmp) . "\" (" . bin2hex($tmp) . " hex)"; } } // Unknown tag or tag definitions return FALSE; }
function get_Nikon_Text_Value($Exif_Tag, $Tag_Definitions_Name) { // Check that this tag uses the Nikon tags, otherwise it can't be interpreted here // And check which variety of tags if ($Tag_Definitions_Name == "Nikon Type 1") { // No special tags for Nikon type 1 so far return FALSE; } else { if ($Tag_Definitions_Name == "Nikon Type 3") { // Nikon Type 3 special tag // Process tag according to it's tag number if ($Exif_Tag['Tag Number'] == 1) { return "\"" . HTML_UTF8_Escape($Exif_Tag['Data']) . "\" (" . bin2hex($Exif_Tag['Data']) . " hex)"; } else { if ($Exif_Tag['Tag Number'] == 2 || $Exif_Tag['Tag Number'] == 19) { // ISO speed settings - should be the second of two values if (count($Exif_Tag['Data']) == 2) { // There are two values - display the second return $Exif_Tag['Data'][1] . " " . $Exif_Tag['Units']; } else { // There is not two values - display generic version of values return get_IFD_value_as_text($Exif_Tag['Data']) . " " . $Exif_Tag['Units']; } } else { if ($Exif_Tag['Tag Number'] == 137) { // Add shooting mode to output from first two bits switch ($Exif_Tag['Data'][0] & 0x3) { case 0x0: $outputstr = "Shooting Mode: Single Frame\n"; break; case 0x1: $outputstr = "Shooting Mode: Continuous\n"; break; case 0x2: $outputstr = "Shooting Mode: Self Timer\n"; break; case 0x3: $outputstr = "Shooting Mode: Remote??\n"; break; default: $outputstr = "Shooting Mode: Unknown\n"; break; } // Add flash bracketing to output from fifth bit if (($Exif_Tag['Data'][0] & 0x10) == 0x10) { $outputstr .= "AE/Flash Bracketing On\n"; } else { $outputstr .= "AE/Flash Bracketing Off\n"; } // Add white balance bracketing to output from seventh bit if (($Exif_Tag['Data'][0] & 0x40) == 0x40) { $outputstr .= "White Balance Bracketing On\n"; } else { $outputstr .= "White Balance Bracketing Off\n"; } // Return the output return $outputstr; } else { if ($Exif_Tag['Tag Number'] == 136) { // Create a string to receive the output $outputstr = ""; // If all zeros, this could be manual focus if ($Exif_Tag['Data'] == "") { $outputstr .= "Manual Focus, or\n"; } // Add AF mode according to the first byte switch (ord($Exif_Tag['Data'][0])) { case 0x0: $outputstr .= "Auto Focus Mode: Single Area\n"; break; case 0x1: $outputstr .= "Auto Focus Mode: Dynamic Area\n"; break; case 0x2: $outputstr .= "Auto Focus Mode: Closest Subject\n"; break; default: $outputstr .= "Auto Focus Mode: Unknown AF Mode\n"; break; } // Add AF area according to second byte switch (ord($Exif_Tag['Data'][1])) { case 0x0: $outputstr .= "Auto Focus Area Selected: Centre\n"; break; case 0x1: $outputstr .= "Auto Focus Area Selected: Top\n"; break; case 0x2: $outputstr .= "Auto Focus Area Selected: Bottom\n"; break; case 0x3: $outputstr .= "Auto Focus Area Selected: Left\n"; break; case 0x4: $outputstr .= "Auto Focus Area Selected: Right\n"; break; } // Add properly focused areas to output according to byte 3 bits $outputstr .= "Properly Focused Area(s): "; if (ord($Exif_Tag['Data'][3]) == 0x0) { $outputstr .= "None"; } if ((ord($Exif_Tag['Data'][3]) & 0x1) == 0x1) { $outputstr .= "Centre "; } if ((ord($Exif_Tag['Data'][3]) & 0x2) == 0x2) { $outputstr .= "Top "; } if ((ord($Exif_Tag['Data'][3]) & 0x4) == 0x4) { $outputstr .= "Bottom "; } if ((ord($Exif_Tag['Data'][3]) & 0x8) == 0x8) { $outputstr .= "Left "; } if ((ord($Exif_Tag['Data'][3]) & 0x10) == 0x10) { $outputstr .= "Right "; } $outputstr .= "\n"; // return the string return $outputstr; } else { // Unknown special tag return FALSE; } } } } } } return FALSE; }
function Interpret_IPTC_to_HTML($IPTC_info) { // Create a string to receive the HTML $output_str = ""; // Check if the IPTC if ($IPTC_info !== FALSE) { // Add Heading to HTML $output_str .= "<h3 class=\"IPTC_Main_Heading\">IPTC-NAA Record</h3>\n"; // Add Table to HTML $output_str .= "\n<table class=\"IPTC_Table\" border=1>\n"; // Cycle through each of the IPTC-NAA IIM records foreach ($IPTC_info as $IPTC_Record) { // Check if the record is a known IPTC field $Record_Name = $IPTC_Record['RecName']; if ($Record_Name == "") { // Record is an unknown field - add message to HTML $output_str .= "<tr class=\"IPTC_Table_Row\"><td class=\"IPTC_Caption_Cell\">Unknown IPTC field '" . htmlentities($IPTC_Record['IPTC_Type']) . "' :</td><td class=\"IPTC_Value_Cell\">" . nl2br(HTML_UTF8_Escape($IPTC_Record['RecData'])) . "</td></tr>\n"; } else { // Record is a recognised IPTC field - Process it accordingly switch ($IPTC_Record['IPTC_Type']) { case "1:00": // Envelope Record:Model Version // Envelope Record:Model Version case "1:22": // Envelope Record:File Format Version $output_str .= "<tr class=\"IPTC_Table_Row\"><td class=\"IPTC_Caption_Cell\">{$Record_Name}</td><td class=\"IPTC_Value_Cell\">" . hexdec(bin2hex($IPTC_Record['RecData'])) . "</td></tr>\n"; break; case "1:90": // Envelope Record:Coded Character Set $output_str .= "<tr class=\"IPTC_Table_Row\"><td class=\"IPTC_Caption_Cell\">{$Record_Name}</td><td class=\"IPTC_Value_Cell\">Decoding not yet implemented<br>\n (Hex Data: " . bin2hex($IPTC_Record['RecData']) . ")</td></tr>\n"; break; // TODO: Implement decoding of IPTC record 1:90 // TODO: Implement decoding of IPTC record 1:90 case "1:20": // Envelope Record:File Format $formatno = hexdec(bin2hex($IPTC_Record['RecData'])); // Lookup file format from lookup-table if (array_key_exists($formatno, $GLOBALS["IPTC_File Formats"])) { // Entry was found in lookup table - add it to HTML $output_str .= "<tr class=\"IPTC_Table_Row\"><td class=\"IPTC_Caption_Cell\">File Format</td><td class=\"IPTC_Value_Cell\">" . $GLOBALS["IPTC_File Formats"][$formatno] . "</td></tr>\n"; } else { // No matching entry was found in lookup table - add message to html $output_str .= "<tr class=\"IPTC_Table_Row\"><td class=\"IPTC_Caption_Cell\">File Format</td><td class=\"IPTC_Value_Cell\">Unknown File Format ({$formatno})</td></tr>\n"; } break; case "2:00": // Application Record:Record Version $output_str .= "<tr class=\"IPTC_Table_Row\"><td class=\"IPTC_Caption_Cell\">IPTC Version</td><td class=\"IPTC_Value_Cell\">" . hexdec(bin2hex($IPTC_Record['RecData'])) . "</td></tr>\n"; break; case "2:42": // Application Record: Action Advised // Looup Action if ($IPTC_Record['RecData'] == "01") { $output_str .= "<tr class=\"IPTC_Table_Row\"><td class=\"IPTC_Caption_Cell\">{$Record_Name}</td><td class=\"IPTC_Value_Cell\">Kill</td></tr>\n"; } elseif ($IPTC_Record['RecData'] == "02") { $output_str .= "<tr class=\"IPTC_Table_Row\"><td class=\"IPTC_Caption_Cell\">{$Record_Name}</td><td class=\"IPTC_Value_Cell\">Replace</td></tr>\n"; } elseif ($IPTC_Record['RecData'] == "03") { $output_str .= "<tr class=\"IPTC_Table_Row\"><td class=\"IPTC_Caption_Cell\">{$Record_Name}</td><td class=\"IPTC_Value_Cell\">Append</td></tr>\n"; } elseif ($IPTC_Record['RecData'] == "04") { $output_str .= "<tr class=\"IPTC_Table_Row\"><td class=\"IPTC_Caption_Cell\">{$Record_Name}</td><td class=\"IPTC_Value_Cell\">Reference</td></tr>\n"; } else { // Unknown Action $output_str .= "<tr class=\"IPTC_Table_Row\"><td class=\"IPTC_Caption_Cell\">{$Record_Name}</td><td class=\"IPTC_Value_Cell\">Unknown : " . nl2br(HTML_UTF8_Escape($IPTC_Record['RecData'])) . "</td></tr>\n"; } break; case "2:08": // Application Record:Editorial Update if ($IPTC_Record['RecData'] == "01") { // Additional Language $output_str .= "<tr class=\"IPTC_Table_Row\"><td class=\"IPTC_Caption_Cell\">{$Record_Name}</td><td class=\"IPTC_Value_Cell\">Additional language</td></tr>\n"; } else { // Unknown Value $output_str .= "<tr class=\"IPTC_Table_Row\"><td class=\"IPTC_Caption_Cell\">{$Record_Name}</td><td class=\"IPTC_Value_Cell\">Unknown : " . nl2br(HTML_UTF8_Escape($IPTC_Record['RecData'])) . "</td></tr>\n"; } break; case "2:30": // Application Record:Release Date // Application Record:Release Date case "2:37": // Application Record:Expiration Date // Application Record:Expiration Date case "2:47": // Application Record:Reference Date // Application Record:Reference Date case "2:55": // Application Record:Date Created // Application Record:Date Created case "2:62": // Application Record:Digital Creation Date // Application Record:Digital Creation Date case "1:70": // Envelope Record:Date Sent $date_array = unpack("a4Year/a2Month/A2Day", $IPTC_Record['RecData']); $output_str .= "<tr class=\"IPTC_Table_Row\"><td class=\"IPTC_Caption_Cell\">{$Record_Name}</td><td class=\"IPTC_Value_Cell\">" . nl2br(HTML_UTF8_Escape($date_array['Day'] . "/" . $date_array['Month'] . "/" . $date_array['Year'])) . "</td></tr>\n"; break; case "2:35": // Application Record:Release Time // Application Record:Release Time case "2:38": // Application Record:Expiration Time // Application Record:Expiration Time case "2:60": // Application Record:Time Created // Application Record:Time Created case "2:63": // Application Record:Digital Creation Time // Application Record:Digital Creation Time case "1:80": // Envelope Record:Time Sent $time_array = unpack("a2Hour/a2Minute/A2Second/APlusMinus/A4Timezone", $IPTC_Record['RecData']); $output_str .= "<tr class=\"IPTC_Table_Row\"><td class=\"IPTC_Caption_Cell\">{$Record_Name}</td><td class=\"IPTC_Value_Cell\">" . nl2br(HTML_UTF8_Escape($time_array['Hour'] . ":" . $time_array['Minute'] . ":" . $time_array['Second'] . " " . $time_array['PlusMinus'] . $time_array['Timezone'])) . "</td></tr>\n"; break; case "2:75": // Application Record:Object Cycle // Lookup Value if ($IPTC_Record['RecData'] == "a") { $output_str .= "<tr class=\"IPTC_Table_Row\"><td class=\"IPTC_Caption_Cell\">{$Record_Name}</td><td class=\"IPTC_Value_Cell\">Morning</td></tr>\n"; } elseif ($IPTC_Record['RecData'] == "p") { $output_str .= "<tr class=\"IPTC_Table_Row\"><td class=\"IPTC_Caption_Cell\">{$Record_Name}</td><td class=\"IPTC_Value_Cell\">Evening</td></tr>\n"; } elseif ($IPTC_Record['RecData'] == "b") { $output_str .= "<tr class=\"IPTC_Table_Row\"><td class=\"IPTC_Caption_Cell\">{$Record_Name}</td><td class=\"IPTC_Value_Cell\">Both Morning and Evening</td></tr>\n"; } else { // Unknown Value $output_str .= "<tr class=\"IPTC_Table_Row\"><td class=\"IPTC_Caption_Cell\">{$Record_Name}</td><td class=\"IPTC_Value_Cell\">Unknown : " . nl2br(HTML_UTF8_Escape($IPTC_Record['RecData'])) . "</td></tr>\n"; } break; case "2:125": // Application Record:Rasterised Caption $output_str .= "<tr class=\"IPTC_Table_Row\"><td class=\"IPTC_Caption_Cell\">{$Record_Name}</td><td class=\"IPTC_Value_Cell\">460x128 pixel black and white caption image</td></tr>\n"; break; // TODO: Display Rasterised Caption for IPTC record 2:125 // TODO: Display Rasterised Caption for IPTC record 2:125 case "2:130": // Application Record:Image Type // Lookup Number of Components if ($IPTC_Record['RecData'][0] == "0") { $output_str .= "<tr class=\"IPTC_Table_Row\"><td class=\"IPTC_Caption_Cell\">{$Record_Name}</td><td class=\"IPTC_Value_Cell\">No Objectdata"; } elseif ($IPTC_Record['RecData'][0] == "9") { $output_str .= "<tr class=\"IPTC_Table_Row\"><td class=\"IPTC_Caption_Cell\">{$Record_Name}</td><td class=\"IPTC_Value_Cell\">Supplemental objects related to other objectdata"; } else { $output_str .= "<tr class=\"IPTC_Table_Row\"><td class=\"IPTC_Caption_Cell\">{$Record_Name}</td><td class=\"IPTC_Value_Cell\">Number of Colour Components : " . nl2br(HTML_UTF8_Escape($IPTC_Record['RecData'][0])); } // Lookup current objectdata colour if ($GLOBALS['ImageType_Names'][$IPTC_Record['RecData'][1]] == "") { $output_str .= ", Unknown : " . nl2br(HTML_UTF8_Escape($IPTC_Record['RecData'][1])); } else { $output_str .= ", " . nl2br(HTML_UTF8_Escape($GLOBALS['ImageType_Names'][$IPTC_Record['RecData'][1]])); } $output_str .= "</td></tr>\n"; break; case "2:131": // Application Record:Image Orientation // Lookup value if ($IPTC_Record['RecData'] == "L") { $output_str .= "<tr class=\"IPTC_Table_Row\"><td class=\"IPTC_Caption_Cell\">{$Record_Name}</td><td class=\"IPTC_Value_Cell\">Landscape</td></tr>\n"; } elseif ($IPTC_Record['RecData'] == "P") { $output_str .= "<tr class=\"IPTC_Table_Row\"><td class=\"IPTC_Caption_Cell\">{$Record_Name}</td><td class=\"IPTC_Value_Cell\">Portrait</td></tr>\n"; } elseif ($IPTC_Record['RecData'] == "S") { $output_str .= "<tr class=\"IPTC_Table_Row\"><td class=\"IPTC_Caption_Cell\">{$Record_Name}</td><td class=\"IPTC_Value_Cell\">Square</td></tr>\n"; } else { // Unknown Orientation Value $output_str .= "<tr class=\"IPTC_Table_Row\"><td class=\"IPTC_Caption_Cell\">{$Record_Name}</td><td class=\"IPTC_Value_Cell\">Unknown : " . nl2br(HTML_UTF8_Escape($IPTC_Record['RecData'])) . "</td></tr>\n"; } break; default: // All other records $output_str .= "<tr class=\"IPTC_Table_Row\"><td class=\"IPTC_Caption_Cell\">{$Record_Name}</td><td class=\"IPTC_Value_Cell\">" . nl2br(HTML_UTF8_Escape($IPTC_Record['RecData'])) . "</td></tr>\n"; break; } } } // Add Table End to HTML $output_str .= "</table><br>\n"; } // Return HTML return $output_str; }
function Interpret_App12_Pic_Info_to_HTML($jpeg_header_data) { // Create a string to receive the output $output = ""; // read the App12 Picture Info segment $PI = get_jpeg_App12_Pic_Info($jpeg_header_data); // Check if the Picture Info segment was valid if ($PI !== array(FALSE, FALSE)) { // Picture Info exists - add it to the output $output .= "<h2 class=\"Picture_Info_Main_Heading\">Picture Info Text</h2>\n"; $output .= "<p><span class=\"Picture_Info_Caption_Text\">Header: </span><span class=\"Picture_Info_Value_Text\">" . HTML_UTF8_Escape($PI['Header']) . "</span></p>\n"; $output .= "<p class=\"Picture_Info_Caption_Text\">Picture Info Text:</p><pre class=\"Picture_Info_Value_Text\">" . HTML_UTF8_Escape($PI['Picture Info']) . "</pre>\n"; } // Return the result return $output; }
function put_photoshop_file_info($jpeg_header_data, $new_ps_file_info_array) { /*******************************************/ // PREPROCESSING // Check that the date is in the correct format (YYYY-MM-DD) // Explode the date into pieces using the - symbol $date_pieces = explode("-", $new_ps_file_info_array['date']); // If there are not 3 pieces to the date, it is invalid if (count($date_pieces) != 3) { // INVALID DATE echo "Invalid Date - must be YYYY-MM-DD format<br>"; return FALSE; } // Cycle through each piece of the date foreach ($date_pieces as $piece) { // If the piece is not numeric, then the date is invalid. if (!is_numeric($piece)) { // INVALID DATE echo "Invalid Date - must be YYYY-MM-DD format<br>"; return FALSE; } } // Make a unix timestamp at midnight on the date specified $date_stamp = mktime(0, 0, 0, $date_pieces[1], $date_pieces[2], $date_pieces[0]); // Create a translation table to remove carriage return characters $trans = array("\r" => ""); // Cycle through each of the File Info elements foreach ($new_ps_file_info_array as $valkey => $val) { // If the element is 'Keywords' or 'Supplemental Categories', then // it is an array, and needs to be treated as one if ($valkey != 'supplementalcategories' && $valkey != 'keywords') { // Not Keywords or Supplemental Categories // Convert escaped HTML characters to UTF8 and remove carriage returns $new_ps_file_info_array[$valkey] = strtr(HTML_UTF8_UnEscape($val), $trans); } else { // Either Keywords or Supplemental Categories // Cycle through the array, foreach ($val as $subvalkey => $subval) { // Convert escaped HTML characters to UTF8 and remove carriage returns $new_ps_file_info_array[$valkey][$subvalkey] = strtr(HTML_UTF8_UnEscape($subval), $trans); } } } // Photoshop IRB Processing $new_IRB_array = array(); // Remove any existing Copyright Flag, URL, or IPTC resources - these will be re-written foreach ($new_IRB_array as $resno => $res) { if ($res['ResID'] == 0x40a || $res['ResID'] == 0x40b || $res['ResID'] == 0x404) { array_splice($new_IRB_array, $resno, 1); } } // Add a new Copyright Flag resource if ($new_ps_file_info_array['copyrightstatus'] == "Copyrighted Work") { $PS_copyright_flag = ""; // Copyrighted } else { $PS_copyright_flag = ""; // Public domain or Unmarked } $new_IRB_array[] = array('ResID' => 0x40a, 'ResName' => $GLOBALS["Photoshop_ID_Names"][0x40a], 'ResDesc' => $GLOBALS["Photoshop_ID_Descriptions"][0x40a], 'ResEmbeddedName' => "", 'ResData' => $PS_copyright_flag); // Add a new URL resource $new_IRB_array[] = array('ResID' => 0x40b, 'ResName' => $GLOBALS["Photoshop_ID_Names"][0x40b], 'ResDesc' => $GLOBALS["Photoshop_ID_Descriptions"][0x40b], 'ResEmbeddedName' => "", 'ResData' => $new_ps_file_info_array['ownerurl']); // Create IPTC resource // IPTC requires date to be in the following format YYYYMMDD $iptc_date = date("Ymd", $date_stamp); // Create the new IPTC array $new_IPTC_array = array(0 => array('IPTC_Type' => '2:00', 'RecName' => $GLOBALS["IPTC_Entry_Names"]['2:00'], 'RecDesc' => $GLOBALS["IPTC_Entry_Descriptions"]['2:00'], 'RecData' => ""), 2 => array('IPTC_Type' => '2:122', 'RecName' => $GLOBALS["IPTC_Entry_Names"]['2:122'], 'RecDesc' => $GLOBALS["IPTC_Entry_Descriptions"]['2:122'], 'RecData' => substr(HTML_UTF8_Escape($new_ps_file_info_array['captionwriter']), 0, 32)), 5 => array('IPTC_Type' => '2:80', 'RecName' => $GLOBALS["IPTC_Entry_Names"]['2:80'], 'RecDesc' => $GLOBALS["IPTC_Entry_Descriptions"]['2:80'], 'RecData' => substr(HTML_UTF8_Escape($new_ps_file_info_array['author']), 0, 32)), 10 => array('IPTC_Type' => '2:55', 'RecName' => $GLOBALS["IPTC_Entry_Names"]['2:55'], 'RecDesc' => $GLOBALS["IPTC_Entry_Descriptions"]['2:55'], 'RecData' => "{$iptc_date}")); // FINISHED UPDATING VALUES // Insert the new IPTC array into the Photoshop IRB array $new_IRB_array = put_Photoshop_IPTC($new_IRB_array, $new_IPTC_array); // Write the Photoshop IRB array to the JPEG header $jpeg_header_data = put_Photoshop_IRB($jpeg_header_data, $new_IRB_array); return $jpeg_header_data; }