You are here

exif.module in Exif 5

Same filename and directory in other branches
  1. 8.2 exif.module
  2. 8 exif.module
  3. 6 exif.module
  4. 7 exif.module

File

exif.module
View source
<?php

/**
 * Implementation of hook_menu().
 */
function exif_menu($may_cache) {
  $items = array();
  if ($may_cache) {
    $items[] = array(
      'path' => '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.'),
    );
  }
  return $items;
}

/**
 * Implementation of hook_nodeapi().
 */
function exif_nodeapi(&$node, $op, $teaser) {
  if ($teaser || $node->type != 'image') {
    return;
  }
  switch ($op) {
    case 'insert':
    case 'update':
      $file = db_fetch_object(db_query("SELECT * FROM {files} WHERE filepath = '%s'", $node->images[IMAGE_ORIGINAL]));
      _update_exif_data($file);
      break;
    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;
  }
}

/**
 * Update exif data for a given file.
 */
function _update_exif_data($file) {
  $data = _exif_read_exif($file->filepath);
  db_query('DELETE FROM {exif} WHERE fid = %d', $file->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')", $file->fid, $ifd, $tag, $value);
    }
  }
}

/**
 * Administration page callback.
 */
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;
}
function exif_admin_settings_form_submit($form_id, $values) {
  $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.'));
  }
}

/**
 * Fetch exif data.
 */
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;
    }
  }
  return $data;
}

/**
 * Reads exif data from a file.
 */
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;
  }
  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 $data;
}

/**
 * Return an array containing only the tags that were enabled.
 */
function exif_get_enabled_tags() {
  static $tags = array();
  if (!count($tags)) {
    $result = db_query('SELECT * FROM {exif_tags} WHERE status = 1');
    while ($tag = db_fetch_object($result)) {
      $tags[] = $tag;
    }
    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 $tags;
}

/**
 * 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_tags}');
  while ($tag = db_fetch_object($result)) {
    $tags["{$tag->ifd}_{$tag->tag}"] = $tag;
  }
  usort($tags, '_exif_compare_tags');
  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();
}
function exif_reset_settings() {
  db_query('DELETE FROM {exif_tags}');
}

/**
 * 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;
  $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;
}

/**
 * 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 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 $a->ifd - $b->ifd;
  }
  else {
    return $a->ifd - $b->ifd;
  }
}
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;
    }
  }
  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';
}

Functions

Namesort descending Description
exif_admin_settings_form Administration page callback.
exif_admin_settings_form_submit
exif_get_default_settings Return an array with all the valid tags, with some useful default settings.
exif_get_enabled_tags Return an array containing only the tags that were enabled.
exif_get_valid_tags Helper function to return all the valid tags (well, at least those this module cares about).
exif_load_settings Return an array with all the valid tags and their settings.
exif_menu Implementation of hook_menu().
exif_nodeapi Implementation of hook_nodeapi().
exif_reset_settings
exif_save_settings
theme_exif_admin_settings_form
theme_exif_table
_exif_bootstrap
_exif_compare_tags
_exif_get_exif Fetch exif data.
_exif_get_valid_ifd_tags
_exif_read_exif Reads exif data from a file.
_update_exif_data Update exif data for a given file.