| 1 |
<?php
|
| 2 |
// $Id: exif.module,v 1.4.2.6 2008/02/06 23:30:16 davidlesieur Exp $
|
| 3 |
|
| 4 |
/**
|
| 5 |
* Implementation of hook_menu().
|
| 6 |
*/
|
| 7 |
function exif_menu($may_cache) {
|
| 8 |
$items = array();
|
| 9 |
|
| 10 |
if ($may_cache) {
|
| 11 |
$items[] = array(
|
| 12 |
'path' => 'admin/settings/exif',
|
| 13 |
'title' => t('Exif'),
|
| 14 |
'callback' => 'drupal_get_form',
|
| 15 |
'callback arguments' => array('exif_admin_settings_form'),
|
| 16 |
'access' => user_access('administer site configuration'),
|
| 17 |
'description' => t('Configure what Exif tags to display.'),
|
| 18 |
);
|
| 19 |
}
|
| 20 |
|
| 21 |
return $items;
|
| 22 |
}
|
| 23 |
|
| 24 |
/**
|
| 25 |
* Implementation of hook_nodeapi().
|
| 26 |
*/
|
| 27 |
function exif_nodeapi(&$node, $op, $teaser) {
|
| 28 |
if ($teaser || $node->type != 'image') {
|
| 29 |
return;
|
| 30 |
}
|
| 31 |
|
| 32 |
switch ($op) {
|
| 33 |
case 'insert':
|
| 34 |
case 'update':
|
| 35 |
$fid = db_result(db_query("SELECT fid FROM {files} WHERE filepath = '%s'", $node->images[IMAGE_ORIGINAL]));
|
| 36 |
$file = file_create_path($node->images[IMAGE_ORIGINAL]);
|
| 37 |
$data = _exif_read_exif($file);
|
| 38 |
db_query('DELETE FROM {exif} WHERE fid = %d', $fid);
|
| 39 |
|
| 40 |
// Cache data in db.
|
| 41 |
foreach ($data as $ifd => $tags) {
|
| 42 |
foreach ($tags as $tag => $value) {
|
| 43 |
db_query("INSERT INTO {exif} (fid, ifd, tag, value) VALUES (%d, %d, %d, '%s')",
|
| 44 |
$fid, $ifd, $tag, $value);
|
| 45 |
}
|
| 46 |
}
|
| 47 |
break;
|
| 48 |
|
| 49 |
case 'load':
|
| 50 |
$fid = db_result(db_query("SELECT fid FROM {files} WHERE filepath = '%s'", $node->images[IMAGE_ORIGINAL]));
|
| 51 |
return array('exif_data' => _exif_get_exif($fid));
|
| 52 |
case 'view':
|
| 53 |
$node->content['exif'] = array(
|
| 54 |
'#value' => theme('exif_table', $node),
|
| 55 |
'#weight' => 10,
|
| 56 |
);
|
| 57 |
break;
|
| 58 |
}
|
| 59 |
}
|
| 60 |
|
| 61 |
/**
|
| 62 |
* Administration page callback.
|
| 63 |
*/
|
| 64 |
function exif_admin_settings_form() {
|
| 65 |
_exif_bootstrap();
|
| 66 |
$tags = exif_load_settings();
|
| 67 |
foreach ($tags as $tag) {
|
| 68 |
$form['tags']["{$tag->ifd}_{$tag->tag}"]['type'] = array(
|
| 69 |
'#type' => 'markup',
|
| 70 |
'#value' => PelIfd::getTypeName($tag->ifd),
|
| 71 |
);
|
| 72 |
$form['tags']["{$tag->ifd}_{$tag->tag}"]['ifd'] = array(
|
| 73 |
'#type' => 'hidden',
|
| 74 |
'#value' => $tag->ifd,
|
| 75 |
);
|
| 76 |
$form['tags']["{$tag->ifd}_{$tag->tag}"]['tag'] = array(
|
| 77 |
'#type' => 'hidden',
|
| 78 |
'#value' => $tag->tag,
|
| 79 |
);
|
| 80 |
$form['tags']["{$tag->ifd}_{$tag->tag}"]['status'] = array(
|
| 81 |
'#type' => 'checkbox',
|
| 82 |
'#title' => utf8_encode(PelTag::getTitle($tag->ifd, $tag->tag)),
|
| 83 |
'#default_value' => $tag->status,
|
| 84 |
);
|
| 85 |
$form['tags']["{$tag->ifd}_{$tag->tag}"]['weight'] = array(
|
| 86 |
'#type' => 'weight',
|
| 87 |
'#delta' => 10,
|
| 88 |
'#default_value' => $tag->weight,
|
| 89 |
);
|
| 90 |
$form['tags']["{$tag->ifd}_{$tag->tag}"]['#tree'] = TRUE;
|
| 91 |
$form['tags']["{$tag->ifd}_{$tag->tag}"]['#weight'] = $tag->weight;
|
| 92 |
}
|
| 93 |
$form['buttons']['submit'] = array(
|
| 94 |
'#type' => 'submit',
|
| 95 |
'#value' => t('Save configuration')
|
| 96 |
);
|
| 97 |
$form['buttons']['reset'] = array(
|
| 98 |
'#type' => 'submit',
|
| 99 |
'#value' => t('Reset to defaults')
|
| 100 |
);
|
| 101 |
|
| 102 |
return $form;
|
| 103 |
}
|
| 104 |
|
| 105 |
function exif_admin_settings_form_submit($form_id, $values) {
|
| 106 |
$op = isset($_POST['op']) ? $_POST['op'] : '';
|
| 107 |
|
| 108 |
if ($op == t('Reset to defaults')) {
|
| 109 |
exif_reset_settings();
|
| 110 |
drupal_set_message(t('The configuration options have been reset to their default values.'));
|
| 111 |
}
|
| 112 |
elseif ($op == t('Save configuration')) {
|
| 113 |
exif_save_settings($values);
|
| 114 |
drupal_set_message(t('The configuration options have been saved.'));
|
| 115 |
}
|
| 116 |
}
|
| 117 |
|
| 118 |
/**
|
| 119 |
* Fetch exif data.
|
| 120 |
*/
|
| 121 |
function _exif_get_exif($fid) {
|
| 122 |
$data = array();
|
| 123 |
if ($result = db_query('SELECT * FROM {exif} WHERE fid = %d', $fid)) {
|
| 124 |
while ($row = db_fetch_object($result)) {
|
| 125 |
$data[$row->ifd][$row->tag] = $row->value;
|
| 126 |
}
|
| 127 |
}
|
| 128 |
|
| 129 |
return $data;
|
| 130 |
}
|
| 131 |
|
| 132 |
/**
|
| 133 |
* Reads exif data from a file.
|
| 134 |
*/
|
| 135 |
function _exif_read_exif($file) {
|
| 136 |
_exif_bootstrap();
|
| 137 |
$data = array();
|
| 138 |
if (!file_exists($file)) {
|
| 139 |
watchdog('exif', t('Image %file not found.', array('%file' => $file)), WATCHDOG_WARNING);
|
| 140 |
return $exif;
|
| 141 |
}
|
| 142 |
if (exif_imagetype($file) != IMAGETYPE_JPEG) {
|
| 143 |
return $data;
|
| 144 |
}
|
| 145 |
$jpeg = new PelJpeg($file);
|
| 146 |
$exif = $jpeg->getExif();
|
| 147 |
if (!$exif) {
|
| 148 |
return $data;
|
| 149 |
}
|
| 150 |
$tiff = $exif->getTiff();
|
| 151 |
if (!$tiff) {
|
| 152 |
return $data;
|
| 153 |
}
|
| 154 |
$ifd0 = $tiff->getIfd();
|
| 155 |
if (!$ifd0) {
|
| 156 |
return $data;
|
| 157 |
}
|
| 158 |
$ifds[PelIfd::IFD0] = $ifd0;
|
| 159 |
if ($exif = $ifd0->getSubIfd(PelIfd::EXIF)) {
|
| 160 |
$ifds[PelIfd::EXIF] = $exif;
|
| 161 |
}
|
| 162 |
if ($gps = $ifd0->getSubIfd(PelIfd::GPS)) {
|
| 163 |
$ifds[PelIfd::GPS] = $gps;
|
| 164 |
}
|
| 165 |
$tags = exif_get_enabled_tags();
|
| 166 |
$data = array();
|
| 167 |
foreach ($tags as $tag) {
|
| 168 |
$entry = $ifds[$tag->ifd]->getEntry($tag->tag);
|
| 169 |
if ($entry) {
|
| 170 |
$row = array();
|
| 171 |
switch($tag->tag) {
|
| 172 |
case PelTag::DATE_TIME:
|
| 173 |
case PelTag::DATE_TIME_ORIGINAL:
|
| 174 |
case PelTag::DATE_TIME_DIGITIZED:
|
| 175 |
// Return a unixtimestamp. Theme will handle date formating.
|
| 176 |
$data[$tag->ifd][$tag->tag] = $entry->getValue();
|
| 177 |
break;
|
| 178 |
|
| 179 |
default:
|
| 180 |
$data[$tag->ifd][$tag->tag] = utf8_encode($entry->getText());
|
| 181 |
}
|
| 182 |
}
|
| 183 |
}
|
| 184 |
return $data;
|
| 185 |
}
|
| 186 |
|
| 187 |
/**
|
| 188 |
* Return an array containing only the tags that were enabled.
|
| 189 |
*/
|
| 190 |
function exif_get_enabled_tags() {
|
| 191 |
static $tags = array();
|
| 192 |
|
| 193 |
if (!count($tags)) {
|
| 194 |
$result = db_query('SELECT * FROM {exif_tags} WHERE status = 1');
|
| 195 |
while ($tag = db_fetch_object($result)) {
|
| 196 |
$tags[] = $tag;
|
| 197 |
}
|
| 198 |
if (!count($tags)) {
|
| 199 |
// Table is empty, get some defaults
|
| 200 |
$tags = exif_get_default_settings();
|
| 201 |
foreach ($tags as $key => $tag) {
|
| 202 |
if (!$tag->status) {
|
| 203 |
unset($tags[$key]);
|
| 204 |
}
|
| 205 |
}
|
| 206 |
}
|
| 207 |
usort($tags, '_exif_compare_tags');
|
| 208 |
}
|
| 209 |
|
| 210 |
return $tags;
|
| 211 |
}
|
| 212 |
|
| 213 |
/**
|
| 214 |
* Return an array with all the valid tags and their settings.
|
| 215 |
*/
|
| 216 |
function exif_load_settings() {
|
| 217 |
$tags = exif_get_default_settings();
|
| 218 |
|
| 219 |
$result = db_query('SELECT * FROM {exif_tags}');
|
| 220 |
while ($tag = db_fetch_object($result)) {
|
| 221 |
$tags["{$tag->ifd}_{$tag->tag}"] = $tag;
|
| 222 |
}
|
| 223 |
usort($tags, '_exif_compare_tags');
|
| 224 |
|
| 225 |
return $tags;
|
| 226 |
}
|
| 227 |
|
| 228 |
function exif_save_settings($values) {
|
| 229 |
db_lock_table('exif_tags');
|
| 230 |
foreach ($values as $tag) {
|
| 231 |
if (!is_array($tag) || !isset($tag['ifd'])) {
|
| 232 |
continue; // Save only appropriate form values
|
| 233 |
}
|
| 234 |
db_query('DELETE FROM {exif_tags} WHERE ifd = %d AND tag = %d', $tag['ifd'], $tag['tag']);
|
| 235 |
db_query('INSERT INTO {exif_tags} (ifd, tag, status, weight) VALUES (%d, %d, %d, %d)', $tag['ifd'], $tag['tag'], $tag['status'], $tag['weight']);
|
| 236 |
}
|
| 237 |
db_unlock_tables();
|
| 238 |
}
|
| 239 |
|
| 240 |
function exif_reset_settings() {
|
| 241 |
db_query('DELETE FROM {exif_tags}');
|
| 242 |
}
|
| 243 |
|
| 244 |
/**
|
| 245 |
* Return an array with all the valid tags, with some useful default settings.
|
| 246 |
*/
|
| 247 |
function exif_get_default_settings() {
|
| 248 |
$tags = exif_get_valid_tags();
|
| 249 |
$tags[PelIfd::EXIF .'_'. PelTag::DATE_TIME_ORIGINAL]->status = 1;
|
| 250 |
$tags[PelIfd::EXIF .'_'. PelTag::DATE_TIME_ORIGINAL]->weight = -10;
|
| 251 |
$tags[PelIfd::IFD0 .'_'. PelTag::MODEL]->status = 1;
|
| 252 |
$tags[PelIfd::IFD0 .'_'. PelTag::MODEL]->weight = -8;
|
| 253 |
$tags[PelIfd::EXIF .'_'. PelTag::FOCAL_LENGTH]->status = 1;
|
| 254 |
$tags[PelIfd::EXIF .'_'. PelTag::FOCAL_LENGTH]->weight = -6;
|
| 255 |
$tags[PelIfd::EXIF .'_'. PelTag::APERTURE_VALUE]->status = 1;
|
| 256 |
$tags[PelIfd::EXIF .'_'. PelTag::APERTURE_VALUE]->weight = -4;
|
| 257 |
$tags[PelIfd::EXIF .'_'. PelTag::EXPOSURE_TIME]->status = 1;
|
| 258 |
$tags[PelIfd::EXIF .'_'. PelTag::EXPOSURE_TIME]->weight = -2;
|
| 259 |
$tags[PelIfd::EXIF .'_'. PelTag::ISO_SPEED_RATINGS]->status = 1;
|
| 260 |
$tags[PelIfd::EXIF .'_'. PelTag::ISO_SPEED_RATINGS]->weight = 0;
|
| 261 |
return $tags;
|
| 262 |
}
|
| 263 |
|
| 264 |
/**
|
| 265 |
* Helper function to return all the valid tags (well, at least those this module cares about).
|
| 266 |
*
|
| 267 |
* For convenience, each tag has a key in the form: "ifd_tag", where ifd and tag
|
| 268 |
* are standard Exif ids. Those ids can be found in PelIfd.php and PelTag.php.
|
| 269 |
*/
|
| 270 |
function exif_get_valid_tags() {
|
| 271 |
$valid_tags = array();
|
| 272 |
$valid_tags = array_merge($valid_tags, _exif_get_valid_ifd_tags(PelIfd::IFD0, new PelIfd(PelIfd::IFD0)));
|
| 273 |
$valid_tags = array_merge($valid_tags, _exif_get_valid_ifd_tags(PelIfd::EXIF, new PelIfd(PelIfd::EXIF)));
|
| 274 |
$valid_tags = array_merge($valid_tags, _exif_get_valid_ifd_tags(PelIfd::GPS, new PelIfd(PelIfd::GPS)));
|
| 275 |
return $valid_tags;
|
| 276 |
}
|
| 277 |
|
| 278 |
function _exif_get_valid_ifd_tags($ifd_id, $ifd) {
|
| 279 |
$tags = array();
|
| 280 |
$pel_tags = $ifd->getValidTags();
|
| 281 |
foreach ($pel_tags as $pel_tag) {
|
| 282 |
$tag = new StdClass();
|
| 283 |
$tag->ifd = $ifd_id;
|
| 284 |
$tag->tag = $pel_tag;
|
| 285 |
$tags["{$tag->ifd}_{$tag->tag}"] = $tag;
|
| 286 |
}
|
| 287 |
return $tags;
|
| 288 |
}
|
| 289 |
|
| 290 |
function _exif_compare_tags($a, $b) {
|
| 291 |
$status = $b->status - $a->status;
|
| 292 |
// Separate enabled from disabled.
|
| 293 |
if ($status) {
|
| 294 |
return $status;
|
| 295 |
}
|
| 296 |
// Enabled tags
|
| 297 |
if ($a->status) {
|
| 298 |
$weight = $a->weight - $b->weight;
|
| 299 |
if ($weight) {
|
| 300 |
return $weight;
|
| 301 |
}
|
| 302 |
return $a->ifd - $b->ifd;
|
| 303 |
}
|
| 304 |
// Disabled tags
|
| 305 |
else {
|
| 306 |
return $a->ifd - $b->ifd;
|
| 307 |
}
|
| 308 |
}
|
| 309 |
|
| 310 |
function theme_exif_table($node) {
|
| 311 |
_exif_bootstrap();
|
| 312 |
// Retrieve the desired tag values from the file
|
| 313 |
$tags = exif_get_enabled_tags();
|
| 314 |
$rows = array();
|
| 315 |
$data = $node->exif_data;
|
| 316 |
|
| 317 |
foreach ($tags as $tag) {
|
| 318 |
if (!empty($data[$tag->ifd][$tag->tag])) {
|
| 319 |
$row = array();
|
| 320 |
$row[] = array('data' => check_plain(utf8_encode(PelTag::getTitle($tag->ifd, $tag->tag))), 'class' => 'exif-title');
|
| 321 |
$val = $data[$tag->ifd][$tag->tag];
|
| 322 |
switch($tag->tag) {
|
| 323 |
case PelTag::DATE_TIME:
|
| 324 |
case PelTag::DATE_TIME_ORIGINAL:
|
| 325 |
case PelTag::DATE_TIME_DIGITIZED:
|
| 326 |
// Use Drupal's date formatting instead of Pel's
|
| 327 |
$row[] = array('data' => format_date($val, 'medium', '', 0), 'class' => 'exif-value');
|
| 328 |
break;
|
| 329 |
|
| 330 |
default:
|
| 331 |
$row[] = array('data' => check_plain($val), 'class' => 'exif-value');
|
| 332 |
}
|
| 333 |
$rows[] = $row;
|
| 334 |
}
|
| 335 |
}
|
| 336 |
|
| 337 |
if (empty($rows)) {
|
| 338 |
return '';
|
| 339 |
}
|
| 340 |
$header = array(array('data' => t('Image information'), 'colspan' => 2));
|
| 341 |
return theme('table', $header, $rows, array('class' => 'exif'));
|
| 342 |
}
|
| 343 |
|
| 344 |
function theme_exif_admin_settings_form($form) {
|
| 345 |
$header = array(t('Tag'), t('Weight'), t('Type'));
|
| 346 |
$rows = array();
|
| 347 |
foreach (element_children($form['tags']) as $key) {
|
| 348 |
$row = array();
|
| 349 |
$row[] = drupal_render($form['tags'][$key]['status']);
|
| 350 |
$row[] = drupal_render($form['tags'][$key]['weight']);
|
| 351 |
$row[] = drupal_render($form['tags'][$key]['type']);
|
| 352 |
$rows[] = $row;
|
| 353 |
}
|
| 354 |
$output .= theme('table', $header, $rows, array('class' => 'admin-settings-exif'));
|
| 355 |
$output .= drupal_render($form);
|
| 356 |
return $output;
|
| 357 |
}
|
| 358 |
|
| 359 |
function _exif_bootstrap() {
|
| 360 |
include_once drupal_get_path('module', 'exif') .'/pel/PelJpeg.php';
|
| 361 |
}
|
| 362 |
|