*** exif.module 2007-05-29 00:21:06.000000000 +1000 --- exif.module.new 2007-09-27 20:00:30.000000000 +1000 *************** *** 1,5 **** --- 1,6 ---- images['_original']); + if (!file_exists($file)) { + watchdog('exif', t('Image %file not found.', array('%file' => $file)), WATCHDOG_WARNING); + } + if (!is_file($file)) return FALSE; + if (exif_imagetype($file) != IMAGETYPE_JPEG) return FALSE; + + return $file; + } + + function _exif_DMS2D($entry) { + $value = $entry->getValue(); + $degrees = $value[0][0] / $value[0][1]; + $minutes = $value[1][0] / $value[1][1]; + $seconds = $value[2][0] / $value[2][1]; + + return $degrees + $minutes/60 + $seconds/3600; + } + + function _exif_fill_node_fields(&$node) { + /* + ** As we only care about location right now, don't bother if + ** that module is installed or the location seems filled. + */ + + if (!module_exists('location')) return FALSE; + if ($node->location['lat'] != 0) return FALSE; + + $file = _exif_node_file($node); + if (!$file) return; + + $jpeg = new PelJpeg($file); + $exif = $jpeg->getExif(); + if (!$exif) return FALSE; + $tiff = $exif->getTiff(); + if (!$tiff) return FALSE; + $ifd0 = $tiff->getIfd(); + if (!$ifd0) return FALSE; + $gps = $ifd0->getSubIfd(PelIfd::GPS); + if (!$gps) return FALSE; + + $entry = $gps->getEntry(PelTag::GPS_LATITUDE); + if (!$entry) return FALSE; + $GPS_LATITUDE = _exif_DMS2D($entry); + $entry = $gps->getEntry(PelTag::GPS_LATITUDE_REF); + if (!$entry) return FALSE; + if ($entry->getValue() == 'S') $GPS_LATITUDE = -$GPS_LATITUDE; + + $entry = $gps->getEntry(PelTag::GPS_LONGITUDE); + if (!$entry) return FALSE; + $GPS_LONGITUDE = _exif_DMS2D($entry); + $entry = $gps->getEntry(PelTag::GPS_LONGITUDE_REF); + if (!$entry) return FALSE; + if ($entry->getValue() == 'W') $GPS_LONGITUDE = -$GPS_LONGITUDE; + + $node->locations[0]['latitude'] = $GPS_LATITUDE; + $node->locations[0]['longitude'] = $GPS_LONGITUDE; + $node->locations['lat'] = $GPS_LATITUDE; + $node->locations['lon'] = $GPS_LONGITUDE; + + return TRUE; + } + /** * Implementation of hook_nodeapi(). */ *************** *** 36,46 **** switch ($op) { case 'view': // Access the file's EXIF data. Simply break when no EXIF data is found. ! $file = file_create_path($node->images['_original']); ! if (!file_exists($file)) { ! watchdog('exif', t('Image %file not found.', array('%file' => $file)), WATCHDOG_WARNING); ! } ! if (!is_file($file)) break; $jpeg = new PelJpeg($file); $exif = $jpeg->getExif(); if (!$exif) break; --- 105,113 ---- switch ($op) { case 'view': // Access the file's EXIF data. Simply break when no EXIF data is found. ! $file = _exif_node_file($node); ! if (!$file) break; ! $jpeg = new PelJpeg($file); $exif = $jpeg->getExif(); if (!$exif) break; *************** *** 57,63 **** } // Retrieve the desired tag values from the file ! $tags = exif_get_enabled_tags(); $rows = array(); foreach ($tags as $tag) { if (isset($ifds[$tag->ifd])) { --- 124,130 ---- } // Retrieve the desired tag values from the file ! $tags = _exif_get_enabled_tags(); $rows = array(); foreach ($tags as $tag) { if (isset($ifds[$tag->ifd])) { *************** *** 88,101 **** ); } break; ! } } /** * Administration page callback. */ function exif_admin_settings() { ! $tags = exif_load_settings(); return drupal_get_form('exif_admin_settings_form', $tags); } --- 155,174 ---- ); } break; ! ! /* For updates, extract any info from EXIF and save if none already given */ ! ! case 'update': ! _exif_fill_node_fields($node); ! break; ! } } /** * Administration page callback. */ function exif_admin_settings() { ! $tags = _exif_load_settings(); return drupal_get_form('exif_admin_settings_form', $tags); } *************** *** 126,131 **** --- 199,251 ---- $form['tags']["{$tag->ifd}_{$tag->tag}"]['#tree'] = TRUE; $form['tags']["{$tag->ifd}_{$tag->tag}"]['#weight'] = $tag->weight; } + + $form['harvest'] = array( + '#type' => 'fieldset', + '#title' => t('Node Completion'), + '#collapsible' => TRUE, + '#collapsed' => TRUE, + '#description' => t('When creating image nodes, what fields can be automatically harvested from the EXIF tags if not entered by the user.'), + ); + + /* The idea is that more than just location can be used in the future */ + $form['harvest']['location'] = array( + '#type' => 'checkbox', + '#title' => t('Location'), + '#default_value' => variable_get('exif_harvest_location', 0), + '#description' => sprintf(t('From GPS co-ordinates. Requires Location module (%s).'), + module_exists('location') ? t('enabled') + : t('disabled/missing')), + '#disabled' => !module_exists('location') + ); + + + /* Figure out the scan status */ + $scan_to = variable_get('exif_scan_to', 0); + $scan_last = variable_get('exif_scan_last', 0); + + if ($scan_last == $scan_to) { + $scan_status = sprintf(t("Finished (scanned to %d)"), $scan_to); + } else if ($scan_last < 1 && $scan_to > 0) { + $scan_status = sprintf(t("Not started (%d of %d)"), $scan_last, $scan_to); + } else if ($scan_last < $scan_to) { + $scan_status = sprintf(t("In progress (%d of %d)"), $scan_last, $scan_to); + } else { + $scan_status = t('Not started'); + } + + $form['harvest']['rescan'] = array( + '#type' => 'markup', + '#value' => t('
The Exif module can re-scan images (done as part of cron processing) and perform node completion functions based on the above rules. This is useful when the module is first installed.
') + ); + + $form['harvest']['start'] = array( + '#type' => 'checkbox', + '#title' => t('Start Scan'), + '#default_value' => FALSE, + '#description' => t('Check this box and submit to start scan. Status is currently: ') . $scan_status + ); + $form['buttons']['submit'] = array( '#type' => 'submit', '#value' => t('Save configuration') *************** *** 142,152 **** $op = isset($_POST['op']) ? $_POST['op'] : ''; 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.')); } } --- 262,272 ---- $op = isset($_POST['op']) ? $_POST['op'] : ''; 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.')); } } *************** *** 154,160 **** /** * Return an array containing only the tags that were enabled. */ ! function exif_get_enabled_tags() { static $tags = array(); if (!count($tags)) { --- 274,280 ---- /** * Return an array containing only the tags that were enabled. */ ! function _exif_get_enabled_tags() { static $tags = array(); if (!count($tags)) { *************** *** 164,170 **** } 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]); --- 284,290 ---- } 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]); *************** *** 180,187 **** /** * Return an array with all the valid tags and their settings. */ ! function exif_load_settings() { ! $tags = exif_get_default_settings(); $result = db_query('SELECT * FROM {exif}'); while ($tag = db_fetch_object($result)) { --- 300,307 ---- /** * Return an array with all the valid tags and their settings. */ ! function _exif_load_settings() { ! $tags = _exif_get_default_settings(); $result = db_query('SELECT * FROM {exif}'); while ($tag = db_fetch_object($result)) { *************** *** 192,201 **** return $tags; } ! function exif_save_settings($values) { db_lock_table('exif'); ! foreach ($values as $tag) { if (!is_array($tag) || !isset($tag['ifd'])) { continue; // Save only appropriate form values } db_query('DELETE FROM {exif} WHERE ifd = %d AND tag = %d', $tag['ifd'], $tag['tag']); --- 312,330 ---- return $tags; } ! function _exif_save_settings($values) { db_lock_table('exif'); ! foreach ($values as $name => $tag) { if (!is_array($tag) || !isset($tag['ifd'])) { + /* Handle 'standard' options */ + if ($name == 'location') { + variable_set('exif_harvest_location', $tag); + } else if ($name = 'start' && $tag) { + /* Reset vars to restart scan */ + variable_set('exif_scan_last', 0); + variable_set('exif_scan_from', 1); + variable_set('exif_scan_to', 2000); + } continue; // Save only appropriate form values } db_query('DELETE FROM {exif} WHERE ifd = %d AND tag = %d', $tag['ifd'], $tag['tag']); *************** *** 204,218 **** db_unlock_tables(); } ! function exif_reset_settings() { db_query('DELETE FROM {exif}'); } /** * Return an array with all the valid tags, with some useful default settings. */ ! 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; --- 333,347 ---- db_unlock_tables(); } ! function _exif_reset_settings() { db_query('DELETE FROM {exif}'); } /** * Return an array with all the valid tags, with some useful default settings. */ ! 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; *************** *** 234,240 **** * 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 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))); --- 363,369 ---- * 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 _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))); *************** *** 293,295 **** --- 422,453 ---- return $output; } + /** + * Cron - rescan images for location info if we've been directed to. + */ + + function exif_cron() { + /* Don't bother if we're done or not started */ + $scan_to = variable_get('exif_scan_to', 0); + $scan_last = variable_get('exif_scan_last', 0); + + if ($scan_to == 0 or $scan_last >= $scan_to) return; + + /* Continue where we left off - or start 'from' if not done before */ + if ($scan_last == 0) $scan_last = variable_get('exif_scan_from', 0); + + /* Don't be too greedy with the execution time - take one quarter */ + $time_limit = time() + ini_get("max_execution_time") / 4; + + while ($scan_last++ < $scan_to && time() < $time_limit) { + $node = node_load($scan_last); + /* If no node loaded, or not an image we don't care */ + if ($node->nid && $node->type == 'image') { + /* Save if we filled anything */ + if (_exif_fill_node_fields($node)) { + location_nodeapi($node, "update"); + } + } + variable_set('exif_scan_last', $scan_last); + } + }