Alyda

Just a Girl Weblog

Remembering Who I Really Am

Using Exiftool to Add Keywords to Your RAW Image File

Lightroom displays the flash EXIF metadata in a field they call Flash. Unhappily, the value of this tag is either 'Did fire' or 'Did not fire.' This tag appears as Metadata criteria in the Library Filter bar as 'Flash States,' but one is not further enlightened by filtering on this criteria.

A simple solution is to write the camera's flash metadata to Lightroom's Keyword tags.

Lightroom Keywords
Lightroom Keywords

Perl 5 ‑ Things Your Mother Didn't Teach You About Knitting

As part of my workflow, I've been using exiftool's command‑line interface to add exposure compensation keywords to my RAW image files. I made the switch to a Perl script because I couldn't think of a way to use multiple '‑if' conditions–one for exposure compensation, the others for flash compensation (i.e., ‑if '$FlashMode =~ "Fired"')–without making multiple passes.

Flash Photography ‑ Who Knew It Would Be So Complicated?

It seems there are a zillion combinations of built‑in and external flash settings (I haven't even tried flash bracketing), so I've decided to do my 'regular' flash photography as outlined below. I'm using a Nikon D300 camera and Nikon Autofocus Speedlight SB‑800 flash. My Perl script is dependant on these flash settings for appropriate tag retrieval.

  • Will not use the built‑in flash on it's own.
  • Will use SB‑800 either in the shoe or remotely.
  • Will not use command dial for compensation.
  • When SB‑800 in shoe, will set e3 to TTL and set compensation on SB‑800.
  • When SB‑800 in remote mode, will set e3 to Commander Mode then choose the mode and compensation on the camera.

Note: even if [‑ ‑] is selected for [Built‑in flash] > [Mode], the built‑in flash must be raised so that monitor pre‑flashes will be emitted. The built‑in flash does not fire, but the AF‑assist illuminator lights. The AF‑assist illuminator lights are so bright I thought the built‑in flash was firing, which certainly added to my confusion. I did some research and found this: The Nikon SG‑3IR IR Panel for Camera Built‑In Flashes attaches to the camera's flash shoe, and covers and prevents the camera's built‑in flash (pre‑flash) from influencing the exposure (http://photo.net/nikon-camera-forum/00O8yc).

Tags may differ for each camera make/model. Run this command to output a list of tags to a file (one for each image), in a subfolder named 'tags':

  • exiftool -a -u -u -g1 -H *.nef -w tags/%f_dblu.txt

For an explanation of the ‑a, ‑u, ‑g1, ‑H command‑line options, see the ExifTool Option Summary.

Acknowledgements

Many, many thanks to Phil Harvey for his extraordinary patience in helping me with this—my first ever—Perl script.

The Perl Script
  • #!/usr/bin/perl -w
  • use Time::localtime;
  • use File::Copy;
  • use Image::ExifTool;
  • require 'Image/ExifTool/Shift.pl';
  • # camera set to UTC0; will shift [-]10 for Hawaii
  • my $tz = 10;
  • my $curyr = localtime->year() + 1900;
  • my $cidir = '/Volumes/PHOTOS/CameraImport';
  • my $bdrv='/Volumes/B-PHOTOS/raw';
  • my $pat = 'nef';
  • my $bdir = "$bdrv/$pat/$curyr";
  • my $ext = '.' . $pat;
  • # this part of the camera's folder name is always the same
  • my $cpdir = '/Volumes/NIKON D300/DCIM';
  • # the subfolder name is incremented every 10,000 images but will always have 'ND300' as part of it's name
  • my $ccdir = 'ND300';
  • my $dirpat = $ccdir;
  • opendir(my $cdh, $cpdir) or die "Couldn't open $cpdir : $!";
  • my @cdirs = grep(/$dirpat/i, readdir($cdh));
  • closedir($cdh);
  • foreach $cdir(@cdirs) {
  • if(-d "$cpdir/$cdir") {
  • $imgdir = "$cpdir/$cdir";
  • last;
  • }
  • }
  • if(!defined($imgdir)) {
  • die "Couldn't open $cpdir";
  • }
  • opendir($dh, $imgdir) or die "Couldn't open $imgdir : $!";
  • # fill an array of all image files in the current directory
  • # note case-insensitive pattern match (/i)
  • @imgfiles = grep(/$pat/i, readdir($dh));
  • closedir($dh);
  • # process all the image files in our array
  • foreach $imgfile(@imgfiles) {
  • $exifTool = new Image::ExifTool;
  • # extract meta information from the image;
  • # note use of full path in filename
  • $exifTool->ExtractInfo("$imgdir/$imgfile");
  • # get date and time
  • $exifdto = $exifTool->GetValue('DateTimeOriginal');
  • # set GPS date and time stamps
  • $exifTool->SetNewValue('GPSDateStamp' => $exifdto);
  • $exifTool->SetNewValue('GPSTimeStamp' => $exifdto);
  • # camera set to UTC0, so shift the dates to reflect proper locale
  • # for convenience, a shortcut tag called AllDates has been defined to represent these three tags: DateTimeOriginal, CreateDate and ModifyDate
  • # http://www.sno.phy.queensu.ca/~phil/exiftool/#shift
  • $exifTool->SetNewValue('AllDates' => $tz, 'Shift' => -1);
  • # get flash compensation tags
  • $fm = $exifTool->GetValue('FlashMode');
  • # if the flash fired...
  • if($fm =~ /^Fired/) {
  • # get the mode
  • $fcm = $exifTool->GetValue('FlashCommanderMode');
  • # if mode is Off
  • if($fcm eq 'Off') {
  • $tag = 'ExternalFlashExposureComp';
  • }
  • # else mode is On
  • else {
  • $tag = 'FlashGroupACompensation';
  • $flashgrp = ': Group A';
  • }
  • $val = $exifTool->GetValue($tag);
  • # want decimal values here, convert fractions
  • $num = Image::ExifTool::Exif::ConvertFraction($val);
  • # round to one decimal place (i.e., '0.666666666666667' after fraction conversion)
  • $val = sprintf('%.1g', $num);
  • $fec = 'FEC: ' . $val;
  • $tn = 'Flash Exposure Compensation';
  • # $flashgrp is always defined after it's first occurrence in the loop...
  • if(defined($flashgrp)) {
  • $tn .= $flashgrp;
  • # ...so undefine the bleeping thing if you found it earlier
  • undef $flashgrp;
  • }
  • # add flash compensation keywords without replacing existing keywords in the file
  • $exifTool->SetNewValue('IPTC:Keywords' => [$tn, $fec], 'AddValue' => 1);
  • }
  • # get exposure compensation tags
  • $sm = $exifTool->GetValue('ShootingMode');
  • if($sm =~ /Exposure Bracketing/) {
  • $tn = 'Bracketing Exposure Compensation';
  • $val = $exifTool->GetValue('ExposureBracketValue');
  • $num = Image::ExifTool::Exif::ConvertFraction($val);
  • $valEBV = sprintf('%.1g', $num);
  • $ebv = 'EBV: ' . $valEBV;
  • $val = $exifTool->GetValue('ExposureCompensation');
  • $num = Image::ExifTool::Exif::ConvertFraction($val);
  • $valEC = sprintf('%.1g', $num);
  • # calculate 'actual' exposure compensation
  • $num = $valEC - $valEBV;
  • $val = sprintf('%.1g', $num);
  • $ec = 'EC: ' . $val;
  • # add exposure compensation keywords without replacing existing keywords in the file
  • $exifTool->SetNewValue('IPTC:Keywords' => [$tn, $ebv, $ec], 'AddValue' => 1);
  • }
  • # get values for use in new filename
  • # set desired date format
  • $exifTool->Options('DateFormat' => '%Y%m%d-%H%M%S');
  • # to *use* a shifted date/time value the shift must be applied to the unformatted (ValueConv) value
  • # then you must do the DateFormat conversion yourself
  • $dto = $exifTool->GetValue('DateTimeOriginal', 'ValueConv');
  • Image::ExifTool::ShiftTime($dto, $tz, -1);
  • $dto = $exifTool->ConvertDateTime($dto);
  • # Nikon records up to 6 frames per second; get 'SubSecTimeOriginal' to avoid filename collision
  • $ssto = $exifTool->GetValue('SubSecTimeOriginal');
  • # get shutter count
  • $sc = $exifTool->GetValue('ShutterCount');
  • # pad the shutter count number
  • $sc = '_' . sprintf('%07d', $sc);
  • # concatenate all the pieces of the new filename
  • # i.e., 20100126-08040600_0020213.nef
  • $nn = $dto . $ssto . $sc . $ext;
  • # add information to source file, writing output to new file
  • # note use of full path in filenames
  • $exifTool->WriteInfo("$imgdir/$imgfile", "$cidir/$nn");
  • # copy the file to backup drive
  • copy("$cidir/$nn", "$bdir/$nn");
  • }

How it Works

The Image::ExifTool library provides an extensible set of Perl modules to read and write meta information, accessed through the methods of the public interface (GetValue, SetNewValue, etc.). Note: some Image::ExifTool methods and modules should not be accessed directly because their interface may change with future versions (i.e., Image::ExifTool::Exif::ConvertFraction, Image::ExifTool::ShiftTime, etc.).

Where to Go for More Information

Filed under: , , , , , , ,