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 get_IFD_Packed_Data($ifd_data, $IFD_offset, $Byte_Align, $Another_IFD) { $ifd_body_str = ""; $ifd_data_str = ""; $Tag_Definitions_Name = $ifd_data['Tags Name']; // Count the Tags in this IFD $tag_count = 0; foreach ($ifd_data as $key => $tag) { // Make sure we only count the Tags, not other information keys if (is_numeric($key)) { $tag_count++; } } // Add the Tag count to the packed data $packed_data = put_IFD_Data_Type($tag_count, 3, $Byte_Align); // Calculate the total length of the IFD (without the offset data) $IFD_len = 2 + $tag_count * 12 + 4; // Cycle through each tag foreach ($ifd_data as $key => $tag) { // Make sure this is a tag, not another information key if (is_numeric($key)) { // Add the tag number to the packed data $ifd_body_str .= put_IFD_Data_Type($tag['Tag Number'], 3, $Byte_Align); // Add the Data type to the packed data $ifd_body_str .= put_IFD_Data_Type($tag['Data Type'], 3, $Byte_Align); // Check if this is a Print Image Matching entry if ($tag['Type'] == "PIM") { // This is a Print Image Matching entry, // encode it $data = Encode_PIM($tag, $Byte_Align); } else { if (($Tag_Definitions_Name == "EXIF" || $Tag_Definitions_Name == "TIFF") && $tag['Tag Number'] == 33723) { // This is a IPTC/NAA Record, encode it $data = put_IPTC($tag['Data']); } else { if (($Tag_Definitions_Name == "EXIF" || $Tag_Definitions_Name == "TIFF") && $tag['Tag Number'] == 700) { // This is a XMP Record, encode it $data = write_XMP_array_to_text($tag['Data']); } else { if (($Tag_Definitions_Name == "EXIF" || $Tag_Definitions_Name == "TIFF") && $tag['Tag Number'] == 34377) { // This is a Photoshop IRB Record, encode it $data = pack_Photoshop_IRB_Data($tag['Data']); } else { if ($tag['Tag Number'] == 513 && $Tag_Definitions_Name == "TIFF") { // The Exif Thumbnail Offset is a pointer but of type Long, not Unknown // Hence we need to put the data into the packed string separately // Calculate the thumbnail offset $data_offset = $IFD_offset + $IFD_len + strlen($ifd_data_str); // Create the Offset for the IFD $data = put_IFD_Data_Type($data_offset, 4, $Byte_Align); // Store the thumbnail $ifd_data_str .= $tag['Data']; } else { if ($tag['Tag Number'] == 514 && $Tag_Definitions_Name == "TIFF") { // Encode the Thumbnail Length $data = put_IFD_Data_Type(strlen($ifd_data[513]['Data']), 4, $Byte_Align); } else { if ($tag['Type'] == "SubIFD") { // This is a Sub-IFD // Calculate the offset to the start of the Sub-IFD $data_offset = $IFD_offset + $IFD_len + strlen($ifd_data_str); // Get the packed data for the IFD chain as the data for this tag $data = get_IFD_Array_Packed_Data($tag['Data'], $data_offset, $Byte_Align); } else { // Not a special tag // Create a string to receive the data $data = ""; // Check if this is a type Unknown tag if ($tag['Data Type'] != 7) { // NOT type Unknown // Cycle through each data value and add it to the data string foreach ($tag['Data'] as $data_val) { $data .= put_IFD_Data_Type($data_val, $tag['Data Type'], $Byte_Align); } } else { // This is a type Unknown - just add the data as is to the data string $data .= $tag['Data']; } } } } } } } } // Pad the data string out to at least 4 bytes $data = str_pad($data, 4, ""); // Check if the data type is an ASCII String or type Unknown if ($tag['Data Type'] == 2 || $tag['Data Type'] == 7) { // This is an ASCII String or type Unknown // Add the Length of the string to the packed data as the Count $ifd_body_str .= put_IFD_Data_Type(strlen($data), 4, $Byte_Align); } else { // Add the array count to the packed data as the Count $ifd_body_str .= put_IFD_Data_Type(count($tag['Data']), 4, $Byte_Align); } // Check if the data is over 4 bytes long if (strlen($data) > 4) { // Data is longer than 4 bytes - it needs to be offset // Check if this entry is the Maker Note if ($Tag_Definitions_Name == "EXIF" && $tag['Tag Number'] == 37500) { // This is the makernote - It will have already been stored // at its original offset to help preserve it // all we need to do is add the Offset to the IFD packed data $data_offset = $tag['Offset']; $ifd_body_str .= put_IFD_Data_Type($data_offset, 4, $Byte_Align); } else { // This is NOT the makernote // Calculate the data offset $data_offset = $IFD_offset + $IFD_len + strlen($ifd_data_str); // Add the offset to the IFD packed data $ifd_body_str .= put_IFD_Data_Type($data_offset, 4, $Byte_Align); // Add the data to the offset packed data $ifd_data_str .= $data; } } else { // Data is less than or equal to 4 bytes - Add it to the packed IFD data as is $ifd_body_str .= $data; } } } // Assemble the IFD body onto the packed data $packed_data .= $ifd_body_str; // Check if there is another IFD after this one if ($Another_IFD === TRUE) { // There is another IFD after this // Calculate the Next-IFD offset so that it goes immediately after this IFD $next_ifd_offset = $IFD_offset + $IFD_len + strlen($ifd_data_str); } else { // There is NO IFD after this - indicate with offset=0 $next_ifd_offset = 0; } // Add the Next-IFD offset to the packed data $packed_data .= put_IFD_Data_Type($next_ifd_offset, 4, $Byte_Align); // Add the offset data to the packed data $packed_data .= $ifd_data_str; // Return the resulting packed data return $packed_data; }