From ca7d08e2b8124353bc56f8dbdfc3ea32da669b7e Mon Sep 17 00:00:00 2001 From: Silvio Date: Thu, 7 Oct 2010 18:44:31 -0300 Subject: CVS update --- exif.module | 566 ++++++++++++++++++++++++++++++++---------------------------- 1 file changed, 299 insertions(+), 267 deletions(-) (limited to 'exif.module') diff --git a/exif.module b/exif.module index 7d955f1..2f41afb 100755 --- a/exif.module +++ b/exif.module @@ -1,61 +1,50 @@ 'admin/settings/exif', + 'title' => t('Exif'), + 'callback' => 'drupal_get_form', + 'callback arguments' => array('exif_admin_settings_form'), + 'access' => user_access('administer site configuration'), + 'description' => t('Configure what Exif tags to display.'), + ); + } -function exif_menu() { - $items['admin/settings/exif'] = array( - 'title' => 'Exif', - 'page callback' => 'exif_admin_settings', - 'access arguments' => array('administer site configuration'), - 'description' => t('Display available fields'), - 'access callback' => 'user_access', - 'file' => 'exif.admin.inc', - 'type' => MENU_NORMAL_ITEM, - ); - $items['admin/settings/exif/general'] = array( - 'title' => 'Exif', - 'page callback' => 'exif_admin_settings', - 'access arguments' => array('administer site configuration'), - 'description' => t('Display available fields'), - 'access callback' => 'user_access', - 'file' => 'exif.admin.inc', - 'type' => MENU_DEFAULT_LOCAL_TASK, - ); - $items['admin/settings/exif/config'] = array( - 'title' => 'Config', - 'page callback' => 'drupal_get_form', - 'page arguments' => array('exif_admin_settings_form'), - 'access arguments' => array('administer site configuration'), - 'description' => t('Some Settings'), - 'access callback' => 'user_access', - 'file' => 'exif.admin.inc', - 'type' => MENU_LOCAL_TASK, - ); return $items; } /** - * implementation of hook_nodeapi + * Implementation of hook_nodeapi(). */ -function exif_nodeapi(&$node, $op, $teaser = NULL, $page = NULL) { - - if ($teaser) { +function exif_nodeapi(&$node, $op, $teaser) { + if ($teaser || $node->type != 'image') { return; } switch ($op) { - + case 'insert': case 'update': - //we are only going to update if we have said so - if (!variable_get('exif_update', TRUE)) { - break; + $fid = db_result(db_query("SELECT fid FROM {files} WHERE filepath = '%s'", $node->images[IMAGE_ORIGINAL])); + $file = file_create_path($node->images[IMAGE_ORIGINAL]); + $data = _exif_read_exif($file); + db_query('DELETE FROM {exif} WHERE fid = %d', $fid); + + // Cache data in db. + foreach ($data as $ifd => $tags) { + foreach ($tags as $tag => $value) { + db_query("INSERT INTO {exif} (fid, ifd, tag, value) VALUES (%d, %d, %d, '%s')", + $fid, $ifd, $tag, $value); + } } +<<<<<<< exif.module case 'insert': if (! _exif_check_for_exif_data($node->type)) { return; @@ -67,282 +56,325 @@ function exif_nodeapi(&$node, $op, $teaser = NULL, $page = NULL) { //get all the fields that will be filled with exif data $ar_exif_fields = $exif->getExifFields($fields); - - //get the path to the image - $image_path = _exif_get_image_path($fields, $node); - - $fid = db_result(db_query("SELECT fid FROM {files} WHERE filepath = '%s'", $image_path)); - $file = file_create_path($image_path); - - $data1 = _exif_reformat($exif->readExifTags($file, $ar_exif_fields)); - $data2 = $exif->readIPTCTags($file, $ar_exif_fields); - - if (class_exists('SXMPFiles')) { - $data3 = $exif->readXMPTags($file, $ar_exif_fields); - $data = array_merge($data1, $data2, $data3); - } - else { - $data = array_merge($data1, $data2); - } - - // Loop through every exif enabled field and set its value to the - // corresponding exif value. If no exif value was found, set the field - // value to NULL, to avoid strange behaviour in other field modules - // (date). - foreach ($ar_exif_fields as $ar_exif_field) { - $exif_name = $ar_exif_field['section'] .'_'. $ar_exif_field['tag']; - $exif_value = isset($data[$exif_name]) ? $data[$exif_name] : NULL; - - $field_name = 'field_'. $exif_name; - if (! $exif_value) { - if (variable_get('exif_empty_values', TRUE)) { - $node->{$field_name}[0]['value'] = NULL; - } - continue; - } - $field = $fields[$field_name]; - - // Setup the field value array for delta = 0. - switch ($exif_name) { - case 'exif_datetimeoriginal': - case 'exif_datetimedigitized': - case 'ifd0_datetime': - $first_delta = _exif_date_handler($field, $exif_value); - break; - default: - $first_delta = array('value' => $data[$exif_name]); - break; - } - $node->{$field_name}[0] = $first_delta; - } +======= + break; +>>>>>>> 1.9 + + case 'load': + $fid = db_result(db_query("SELECT fid FROM {files} WHERE filepath = '%s'", $node->images[IMAGE_ORIGINAL])); + return array('exif_data' => _exif_get_exif($fid)); + case 'view': + $node->content['exif'] = array( + '#value' => theme('exif_table', $node), + '#weight' => 10, + ); break; } } /** - * Date API hook. - * - * Make exif a date format in Date API. This makes it possible to alter the - * format exif dates is parsed as. + * Administration page callback. */ -function exif_date_format_types() { - return array('exif' => 'EXIF'); -} - -/** - * Date API hook. - * - * Make the EXIF date format default for the 'exif' date type. - */ -function exif_date_formats() { - return array( - array( - 'type' => 'exif', - 'format' => 'Y:m:d H:i:s', - ), +function exif_admin_settings_form() { + _exif_bootstrap(); + $tags = exif_load_settings(); + foreach ($tags as $tag) { + $form['tags']["{$tag->ifd}_{$tag->tag}"]['type'] = array( + '#type' => 'markup', + '#value' => PelIfd::getTypeName($tag->ifd), + ); + $form['tags']["{$tag->ifd}_{$tag->tag}"]['ifd'] = array( + '#type' => 'hidden', + '#value' => $tag->ifd, + ); + $form['tags']["{$tag->ifd}_{$tag->tag}"]['tag'] = array( + '#type' => 'hidden', + '#value' => $tag->tag, + ); + $form['tags']["{$tag->ifd}_{$tag->tag}"]['status'] = array( + '#type' => 'checkbox', + '#title' => utf8_encode(PelTag::getTitle($tag->ifd, $tag->tag)), + '#default_value' => $tag->status, + ); + $form['tags']["{$tag->ifd}_{$tag->tag}"]['weight'] = array( + '#type' => 'weight', + '#delta' => 10, + '#default_value' => $tag->weight, + ); + $form['tags']["{$tag->ifd}_{$tag->tag}"]['#tree'] = TRUE; + $form['tags']["{$tag->ifd}_{$tag->tag}"]['#weight'] = $tag->weight; + } + $form['buttons']['submit'] = array( + '#type' => 'submit', + '#value' => t('Save configuration') + ); + $form['buttons']['reset'] = array( + '#type' => 'submit', + '#value' => t('Reset to defaults') ); + + return $form; } -/** - * Helper function to handle all date values from exif header. This is - * designed for the date_api and date modules, but is compatible if these - * aren't enabled. - * - * @param array $field - * The field definition for the matcing exif date - * @param string $exif_date - * The date extracted from exif header. - * @return array - * The field value array for delta = 0 - */ -function _exif_date_handler($field, $exif_date) { - if (! module_exists('date_api')) { - // Don't bother doing anything if the webmaster doesn't ... - return array('value' => $exif_date); - } +function exif_admin_settings_form_submit($form_id, $values) { + $op = isset($_POST['op']) ? $_POST['op'] : ''; - require_once drupal_get_path('module', 'date_api') .'/date_api_elements.inc'; - $date_datetime = date_convert_from_custom($exif_date, variable_get('date_format_exif', 'Y:m:d H:i:s')); - if (! in_array($field['type'], array('date', 'datetime', 'datestamp'))) { - // Field is not a date field type, so we return a ISO-8601 representation - return array('value' => date_convert($date_datetime, DATE_DATETIME, DATE_ISO)); + if ($op == t('Reset to defaults')) { + exif_reset_settings(); + drupal_set_message(t('The configuration options have been reset to their default values.')); + } + elseif ($op == t('Save configuration')) { + exif_save_settings($values); + drupal_set_message(t('The configuration options have been saved.')); } - - // Exif doesn't handles timezones, so we assume the exif date is in the - // timezone configured for this date field. This means the exif date needs - // to be converted to UTC before it's stored. - $timezone = date_get_timezone($field['tz_handling']); - $date = date_make_date($date_datetime, $timezone, DATE_DATETIME, $field['granularity']); - - // Store date offset before converting to UTC as this is lost when setting - // timezone to 'UTC'. - $offset = date_offset_get($date); - date_timezone_set($date, timezone_open('UTC')); - - // Finally, convert the date object in UTC to a date according to the field - // type: DATE_ISO, DATE_DATETIME or DATE_UNIX. - $date_field = date_convert($date, DATE_OBJECT, $field['type']); - return array( - 'value' => $date_field, - 'value2' => $date_field, - 'timezone' => $timezone, - 'offset' => $offset, - 'offset2' => $offset, - ); } /** - * Let's check if this node type contains an image field. - * - * @param $fields fields from this content type - * @return boolean + * Fetch exif data. */ -function _exif_check_for_exif_data($node_type) { - - $new_types = array(); - //fill up array with checked nodetypes - foreach (variable_get('exif_nodetypes', array()) as $type) { - if ($type != "0" ) { - $new_types[] = $type; +function _exif_get_exif($fid) { + $data = array(); + if ($result = db_query('SELECT * FROM {exif} WHERE fid = %d', $fid)) { + while ($row = db_fetch_object($result)) { + $data[$row->ifd][$row->tag] = $row->value; } } - if (in_array($node_type, $new_types)) { - return TRUE; - } - return FALSE; + + return $data; } /** - * From a given node we are going to get the imagepath of the image. if it's an image node - * it's just going to be images[IMAGE_ORIGINAL]. If it's an imagefield node, we have to go - * through the fields and look if there is an imagefield and then return the path - * - * @param $fields - * @param $node - * @return unknown_type + * Reads exif data from a file. */ -function _exif_get_image_path($fields, &$node) { - if ($node->type == 'image') { - return $node->images[IMAGE_ORIGINAL]; +function _exif_read_exif($file) { + _exif_bootstrap(); + $data = array(); + if (!file_exists($file)) { + watchdog('exif', t('Image %file not found.', array('%file' => $file)), WATCHDOG_WARNING); + return $exif; } - - foreach ($fields as $field) { - if ($field['type'] == 'filefield') { - $tmp = $node->$field['field_name']; - return $tmp[0]['filepath']; + if (exif_imagetype($file) != IMAGETYPE_JPEG) { + return $data; + } + $jpeg = new PelJpeg($file); + $exif = $jpeg->getExif(); + if (!$exif) { + return $data; + } + $tiff = $exif->getTiff(); + if (!$tiff) { + return $data; + } + $ifd0 = $tiff->getIfd(); + if (!$ifd0) { + return $data; + } + $ifds[PelIfd::IFD0] = $ifd0; + if ($exif = $ifd0->getSubIfd(PelIfd::EXIF)) { + $ifds[PelIfd::EXIF] = $exif; + } + if ($gps = $ifd0->getSubIfd(PelIfd::GPS)) { + $ifds[PelIfd::GPS] = $gps; + } + $tags = exif_get_enabled_tags(); + $data = array(); + foreach ($tags as $tag) { + $entry = $ifds[$tag->ifd]->getEntry($tag->tag); + if ($entry) { + $row = array(); + switch($tag->tag) { + case PelTag::DATE_TIME: + case PelTag::DATE_TIME_ORIGINAL: + case PelTag::DATE_TIME_DIGITIZED: + // Return a unixtimestamp. Theme will handle date formating. + $data[$tag->ifd][$tag->tag] = $entry->getValue(); + break; + + default: + $data[$tag->ifd][$tag->tag] = utf8_encode($entry->getText()); + } } } - return NULL; + return $data; } - /** - * Helper function to reformat fields where required. - * - * Some values (lat/lon) break down into structures, not strings. + * Return an array containing only the tags that were enabled. */ -function _exif_reformat($data) { - $date_array = array('datetimeoriginal', 'datetime', 'datetimedigitized'); +function exif_get_enabled_tags() { + static $tags = array(); - // Make the key lowercase as CCK field names must be - $data = array_change_key_case($data, CASE_LOWER); - - foreach ($data as $key => &$value) { - if (is_array($value)) { - $value = array_change_key_case($value, CASE_LOWER); + if (!count($tags)) { + $result = db_query('SELECT * FROM {exif_tags} WHERE status = 1'); + while ($tag = db_fetch_object($result)) { + $tags[] = $tag; } - - // Check for individual keys - switch ($key) { - case 'gpslatitude': - $value = _exif_DMS2D($value, $data['gpslatituderef']); - break; - - case 'gpslongitude': - $value = _exif_DMS2D($value, $data['gpslongituderef']); - break; - - case 'gps_gpslatitude': - $value = _exif_DMS2D($value, $data['gps_gpslatituderef']); - break; - - case 'gps_gpslongitude': - $value = _exif_DMS2D($value, $data['gps_gpslongituderef']); - break; - + if (!count($tags)) { + // Table is empty, get some defaults + $tags = exif_get_default_settings(); + foreach ($tags as $key => $tag) { + if (!$tag->status) { + unset($tags[$key]); + } + } } + usort($tags, '_exif_compare_tags'); } - return $data; + + return $tags; } /** - * Helper function to change GPS co-ords into decimals. + * Return an array with all the valid tags and their settings. */ -function _exif_DMS2D($value, $ref) { - $parts = split('/', $value[0]); - $dec = (float) ((float) $parts[0] / (float) $parts[1]); +function exif_load_settings() { + $tags = exif_get_default_settings(); - $parts = split('/', $value[1]); - $dec += (float) (((float) $parts[0] / (float) $parts[1]) / 60); + $result = db_query('SELECT * FROM {exif_tags}'); + while ($tag = db_fetch_object($result)) { + $tags["{$tag->ifd}_{$tag->tag}"] = $tag; + } + usort($tags, '_exif_compare_tags'); - $parts = split('/', $value[2]); - $dec += (float) (((float) $parts[0] / (float) $parts[1]) / 3600); + return $tags; +} + +function exif_save_settings($values) { + db_lock_table('exif_tags'); + foreach ($values as $tag) { + if (!is_array($tag) || !isset($tag['ifd'])) { + continue; // Save only appropriate form values + } + db_query('DELETE FROM {exif_tags} WHERE ifd = %d AND tag = %d', $tag['ifd'], $tag['tag']); + db_query('INSERT INTO {exif_tags} (ifd, tag, status, weight) VALUES (%d, %d, %d, %d)', $tag['ifd'], $tag['tag'], $tag['status'], $tag['weight']); + } + db_unlock_tables(); +} - if ($ref == 'S' || $ref == 'W') $dec *= -1; - return $dec; +function exif_reset_settings() { + db_query('DELETE FROM {exif_tags}'); } /** - * Helper function to get the exif class - * @return Exif + * Return an array with all the valid tags, with some useful default settings. */ -function _exif_get_class() { - include_once drupal_get_path('module', 'exif') .'/exif.class.php'; - $exif = Exif::getInstance(); - return $exif; +function exif_get_default_settings() { + $tags = exif_get_valid_tags(); + $tags[PelIfd::EXIF .'_'. PelTag::DATE_TIME_ORIGINAL]->status = 1; + $tags[PelIfd::EXIF .'_'. PelTag::DATE_TIME_ORIGINAL]->weight = -10; + $tags[PelIfd::IFD0 .'_'. PelTag::MODEL]->status = 1; + $tags[PelIfd::IFD0 .'_'. PelTag::MODEL]->weight = -8; + $tags[PelIfd::EXIF .'_'. PelTag::FOCAL_LENGTH]->status = 1; + $tags[PelIfd::EXIF .'_'. PelTag::FOCAL_LENGTH]->weight = -6; + $tags[PelIfd::EXIF .'_'. PelTag::APERTURE_VALUE]->status = 1; + $tags[PelIfd::EXIF .'_'. PelTag::APERTURE_VALUE]->weight = -4; + $tags[PelIfd::EXIF .'_'. PelTag::EXPOSURE_TIME]->status = 1; + $tags[PelIfd::EXIF .'_'. PelTag::EXPOSURE_TIME]->weight = -2; + $tags[PelIfd::EXIF .'_'. PelTag::ISO_SPEED_RATINGS]->status = 1; + $tags[PelIfd::EXIF .'_'. PelTag::ISO_SPEED_RATINGS]->weight = 0; + return $tags; } /** - * Implementation of hook_hoken_list - * @param array $type + * Helper function to return all the valid tags (well, at least those this module cares about). + * + * For convenience, each tag has a key in the form: "ifd_tag", where ifd and tag + * are standard Exif ids. Those ids can be found in PelIfd.php and PelTag.php. */ -function fast_gallery_token_list($type = 'node') { - if ($type == 'node') { - $exif = _exif_get_class(); - $ar_iptc = $exif->getHumanReadableIPTCkey(); - foreach ($ar_iptc as $iptc) { - $tokens['iptc']['iptc_' . $iptc] = 'IPTC Field: ' . $iptc; +function exif_get_valid_tags() { + $valid_tags = array(); + $valid_tags = array_merge($valid_tags, _exif_get_valid_ifd_tags(PelIfd::IFD0, new PelIfd(PelIfd::IFD0))); + $valid_tags = array_merge($valid_tags, _exif_get_valid_ifd_tags(PelIfd::EXIF, new PelIfd(PelIfd::EXIF))); + $valid_tags = array_merge($valid_tags, _exif_get_valid_ifd_tags(PelIfd::GPS, new PelIfd(PelIfd::GPS))); + return $valid_tags; +} + +function _exif_get_valid_ifd_tags($ifd_id, $ifd) { + $tags = array(); + $pel_tags = $ifd->getValidTags(); + foreach ($pel_tags as $pel_tag) { + $tag = new StdClass(); + $tag->ifd = $ifd_id; + $tag->tag = $pel_tag; + $tags["{$tag->ifd}_{$tag->tag}"] = $tag; + } + return $tags; +} + +function _exif_compare_tags($a, $b) { + $status = $b->status - $a->status; + // Separate enabled from disabled. + if ($status) { + return $status; + } + // Enabled tags + if ($a->status) { + $weight = $a->weight - $b->weight; + if ($weight) { + return $weight; } - return $tokens; + return $a->ifd - $b->ifd; + } + // Disabled tags + else { + return $a->ifd - $b->ifd; } } -/** - * implementation of hook_token_values - * @param unknown_type $type - * @param unknown_type $object - * @param unknown_type $options - */ -function fast_gallery_token_values($type, $object = NULL, $options = array()) { - if ($type == 'node') { - $node = $object; - $exif = _exif_get_class(); - $ar_iptc = $exif->getHumanReadableIPTCkey(); - - $info = content_types($node->type); - $fields = $info['fields']; - //get the path to the image - $image_path = _exif_get_image_path($fields, $node); - - //dsm("start reading"); - $iptc_values = $exif->readIPTCTags($image_path, array(), array('style' => 'fullSmall')); - //dsm($iptc_values); - - // TODO: needs to be finished - foreach ($iptc_values as $key => $iptc) { - $tokens['iptc_' . $key] = 'IPTC Field: ' . utf8_encode($iptc); +function theme_exif_table($node) { + _exif_bootstrap(); + // Retrieve the desired tag values from the file + $tags = exif_get_enabled_tags(); + $rows = array(); + $data = $node->exif_data; + + foreach ($tags as $tag) { + if (!empty($data[$tag->ifd][$tag->tag])) { + $row = array(); + $row[] = array('data' => check_plain(utf8_encode(PelTag::getTitle($tag->ifd, $tag->tag))), 'class' => 'exif-title'); + $val = $data[$tag->ifd][$tag->tag]; + switch($tag->tag) { + case PelTag::DATE_TIME: + case PelTag::DATE_TIME_ORIGINAL: + case PelTag::DATE_TIME_DIGITIZED: + // Use Drupal's date formatting instead of Pel's + $row[] = array('data' => format_date($val, 'medium', '', 0), 'class' => 'exif-value'); + break; + + default: + $row[] = array('data' => check_plain($val), 'class' => 'exif-value'); + } + $rows[] = $row; } - //dsm($tokens); - return $tokens; } +<<<<<<< exif.module +} +======= + + if (empty($rows)) { + return ''; + } + $header = array(array('data' => t('Image information'), 'colspan' => 2)); + return theme('table', $header, $rows, array('class' => 'exif')); } + +function theme_exif_admin_settings_form($form) { + $header = array(t('Tag'), t('Weight'), t('Type')); + $rows = array(); + foreach (element_children($form['tags']) as $key) { + $row = array(); + $row[] = drupal_render($form['tags'][$key]['status']); + $row[] = drupal_render($form['tags'][$key]['weight']); + $row[] = drupal_render($form['tags'][$key]['type']); + $rows[] = $row; + } + $output .= theme('table', $header, $rows, array('class' => 'admin-settings-exif')); + $output .= drupal_render($form); + return $output; +} + +function _exif_bootstrap() { + include_once drupal_get_path('module', 'exif') .'/pel/PelJpeg.php'; +} + +>>>>>>> 1.9 -- cgit v1.2.3