/* * This php file provides an interface for adding IPTC keywords (aka "tags") and captions to a photo. * * The form at the end of the file submits to itself (bad practice, I'm sure) so this file handles both the reading * and writing of photo data */ // Include libraries that do the heavy lifting. Available on the web if you search for "Photoshop_IRB.php". include("/var/www/iptc/JPEG.php"); include("/var/www/iptc/Photoshop_IRB.php"); // // Some config stuff. Probably doesn't belong here // // A text file containing the paths of all my photos. I choose a random photo later from this list. // The list gets rebuilt every night via cron job. I had it as a byproduct from another project $PHOTO_FILE_FULL_PATH = "/var/www/slideshow/photos.txt"; // Where to backup files before saving them with tags, in case the tagging goes badly. $BACKUP_PATH = "/mnt/storage/photo_tagging_backups/"; // Where to save all the tags used so far, for reference, and for autocomplete $TAG_FILE = "./tags.txt"; $TAG_FILE_JS = "./scripts/list"; // Redundant to keep two lists, but I'm lazy // End config // Not sure if I need this function, really function trim_value(&$value) { $value = trim($value); } // Read previously entered tags for all photos $tags = array(); if (file_exists($TAG_FILE)) { $tag_str = file_get_contents($TAG_FILE); if ($tag_str) { $tags = split("\n", $tag_str); //array_walk($tags, 'trim_value'); } } // Default IPTC data. Since we may be inserted IPTC to a photo for the first time, we need to // have a valid header. This array creates a basic header of the format used by the IPTC libraries $default_iptc_data = array( array('RecName' => 'Caption/Abstract', 'ReDesc' => 'Caption/Abstract - Max 2000 Characters', 'IPTC_Type' => '2:120', 'RecData' => ''), array('RecName' => 'Keywords', 'RecDesc' => 'Keywords - Max 64 characters', 'IPTC_Type' => '2:25', 'RecData' => '') ); // IPTC data is embedded within Photoshop_IRB data, whatever that is. So here's a default set of that $default_photoshop_data= array(array('ResID' => '1028', 'ResName' => 'IPTC-NAA record', 'ResDesc' => 'IPTC-NAA record. This contains the File Info... information. See the IIMV4.pdf document.', 'ResEmbeddedName' => '', 'ResData' => ''));; // A function which opens the text file listing of my photos, and chooses one at random function pick_random_photo() { global $PHOTO_FILE_FULL_PATH; $photo_listing = file_get_contents($PHOTO_FILE_FULL_PATH); $all_photos = array('hi'); $file = ""; if ($photo_listing){ $photo_lines = array(); $photo_lines = explode("\n", $photo_listing); $photo_index = rand(0, count($photo_lines)); $photo_line = $photo_lines[$photo_index]; // The file also contains the time the photo was taken, since my other project used that. // We don't need it for tagging, so it gets ignored list($file, $time) = explode("|", $photo_line, 2); } return $file; } function fix_file_chars($path) { return str_replace("\\'", "'", $path); } // Choose a photo. Either read it from the querystring, or pick one at random $image = (isset($_REQUEST["image"])) ? fix_file_chars($_REQUEST["image"]) : pick_random_photo(); $image_path = "/album/photos" . $image; // Where the file is local to the docroot. $image_full_path = $_SERVER["DOCUMENT_ROOT"] . $image_path; // Where the file is on my machine // I'm using phpAlbum for the thumbnails, so convert the image name to the phpAlbum image name $phpAlbum_path = preg_replace("/^\//", "", $image); // Where to back up photos before saving tags to them, in case saving corrupts the file $backup_full_path = $BACKUP_PATH . $image; $tmp_image_full_path = str_replace("\\'", "'", $image_full_path); // Read existing IPTC data $header = get_jpeg_header_data ($image_full_path); $photoshop_data = get_Photoshop_IRB($header); if (!$photoshop_data) { $photoshop_data = $default_photoshop_data; } $iptc = get_Photoshop_IPTC($photoshop_data); if (!$iptc) { $iptc = $default_iptc_data; } // New IPTC data goes into this array. This is eventually what we'll write to the photo $newIPTC = array(); // Copy existing IPTC data to new IPTC data if ($iptc) { foreach ($iptc as $hItem) { if ($hItem['RecName'] == "Caption/Abstract" && isset($_REQUEST['caption'])) { $captionObject = array(); $captionObject['RecName'] = $hItem['RecName']; $captionObject['RecData'] = $_REQUEST['caption']; $captionObject['IPTC_Type'] = $hItem['IPTC_Type']; $captionObject['RecDesc'] = $hItem['RecDesc']; // Overwrite the existing caption $captionObject['RecData'] = trim($_REQUEST['caption']); $newIPTC[] = $captionObject; } elseif ($hItem['RecName'] == "Keywords" && isset($_REQUEST['keywords'])) { // If we're going to save new keywords, don't read the existing ones, // or we end up with dups } else { // If it's not a caption or a keyword, copy it as-is $newIPTC[] = $hItem; } } } // If we're adding keywords... if (isset($_REQUEST['keywords'])) { // .. read keywords from request $keywords = split(",", strtolower($_REQUEST['keywords'])); array_walk($keywords, 'trim_value'); // ... prep them for IPTC foreach ($keywords as $keyword) { $keyword = trim($keyword); $newIPTC[] = array('IPTC_Type' => '2:25', 'RecName' => 'Keywords', 'RecDesc' => 'Keywords - Max 64 characters', 'RecData' => $keyword); } // Add the new tags to the list of previously used tags $tags = array_merge($tags, $keywords); sort($tags); $tags = array_unique($tags); // We don't want dups // Save the list of all tags for reference, and for autocomplete file_put_contents($TAG_FILE, join("\n", $tags)); file_put_contents($TAG_FILE_JS, "[{text:\"" . join("\"}, {text:\"", $tags) . "\"}]"); // Prep the JPEG header $iptc = $newIPTC; $photoshop_data = put_Photoshop_IPTC($photoshop_data, $iptc); $header = put_Photoshop_IRB($header, $photoshop_data); // Back it up. Beep.. Beep.. Beep.. Beep.. $backup_full_path = str_replace("\\'", "'", $backup_full_path); if (!file_exists($backup_full_path)) { $file_parts = explode("/", $backup_full_path); $file = array_pop($file_parts); $img_dir = implode("/", $file_parts); if (!file_exists($img_dir)) { mkdir($img_dir, 0775, true); } copy($image_full_path, $img_dir . "/" . $file); } // Write the header to the photo $result = put_jpeg_header_data ($image_full_path, $image_full_path, $header); } // On success, redirect, so refreshing the page won't resubmit the data // Also, it's a lazy way to pick a new photo // TODO: error display if ($result === TRUE) { header("Location: /tag_photo/?prev_image=" . urlencode($image)); } // If there was a problem, or no data was submitted, show the form ?>