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 = "&nbsp;";
                        }
                        // 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;
}
Exemple #6
0
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;
}