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
  • # http://owl.phy.queensu.ca/~phil/exiftool/ExifTool.html#WriteInfo
  • # 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: , , , , , , ,

Viewing Auto Bracket Information in Lightroom

Lightroom displays the exposure compensation metadata in a field they call Exposure Bias. Unhappily, the value of this tag also contains the auto bracket metadata making it difficult to use these values in a meaningful way. In addition, Exposure Bias does not appear as Metadata criteria in the Library Filter bar.

Lightroom Keywords
Lightroom Keywords

There are many presets, templates and plugins available for Lightroom which extend the functionality but may be costly, are version dependant, or—worst case—allow you to change the labels in the metadata panel and invite you to enter values that are mapped incorrectly!

A simpler solution is to write the values of these tags to Keyword tags. The keyword tag can be read by Lightroom, Photoshop, Bridge, and Elements.

Adding Keywords to RAW files

ExifTool

ExifTool is a platform‑independent command‑line application for reading, writing, and editing meta information contained in image, audio and video files. You can download this neat little tool at http://www.sno.phy.queensu.ca/~phil/exiftool/. For help installing ExifTool on Windows, Mac OS X and Unix systems, read the instructions at http://owl.phy.queensu.ca/~phil/exiftool/install.html.

User‑defined tags can not be defined at the command line. But after you define them in the exiftool config file you can use them at the command line. The only difference in the configuration and implementation of the command (aside from the camera make) is in the use of single versus double quotes. They are critical, so copy carefully.

The Configuration File

The Easy Way

Download the appropriate config file (zipped archive):

and extract the contents of the archive (the '.ExifTool_config' file) to the same directory as the exiftool (Windows) or your home directory (Mac).

The Harder Way

Copy and paste the following into your text editor:

Nikon
%Image::ExifTool::UserDefined = (
  'Image::ExifTool::Composite' => {
    EC => {
      Require => {
        0 => 'ExposureBracketValue',
        1 => 'EXIF:ExposureCompensation',
      },
      ValueConv => '$val[1] - $val[0]',
      PrintConv => 'Image::ExifTool::Exif::ConvertFraction($val)',
    },
  },
);
1; #end
Canon
%Image::ExifTool::UserDefined = (
  'Image::ExifTool::Composite' => {
    EC => {
      Require => {
        0 => 'AEBBracketValue',
        1 => 'EXIF:ExposureCompensation',
      },
      ValueConv => '$val[1] - $val[0]',
      PrintConv => 'Image::ExifTool::Exif::ConvertFraction($val)',
    },
  },
);
1; #end

To activate this file, save it as ".ExifTool_config" in the same directory as the exiftool application (Windows) or your home directory (Mac).

Note: The Windows GUI won't let you use a file name beginning with a dot ("."), so you must first save the file with a different name (i.e., 'ExifTool_config.txt'), and then rename it using the "rename" command in a cmd shell. Alternatively, the txt file may be loaded using the ‑config option (see below).

Implementation

Caution: Do not proceed unless you already have separate backup copies of your image files. Your backup copies can safely be replaced with the keyworded version after you've confirmed that your images will open in your post‑processing software application.

Command Line Version ‑ Mac or PC
  • Open the cmd shell (Windows) or start the Terminal application (Mac).
  • Change to the photo directory. Windows or Mac: type 'cd' (without the quotes) followed by a space, drag and drop your photo directory into the window, and then press Enter.
  • Copy and paste the appropriate exiftool command (below) into the window.

Note: If you are using the txt version of the configuration file, modify the command by inserting '‑config ExifTool_config.txt ' (without the quotes) immediately before the ‑sep option.

Nikon ‑ Mac
exiftool -sep ", " '-keywords+=Bracketed, EBV: ${Nikon:ExposureBracketValue},
EC: ${EC}' -overwrite_original -if '$Nikon:ShootingMode =~ "Exposure Bracketing"'
*.NEF
Nikon ‑ PC
exiftool -sep ", " "-keywords+=Bracketed, EBV: ${Nikon:ExposureBracketValue},
EC: ${EC}" -overwrite_original -if "$Nikon:ShootingMode =~ 'Exposure Bracketing'"
*.NEF
Canon ‑ Mac
exiftool -sep ", " '-keywords+=Bracketed, EBV: ${Canon:AEBBracketValue}, EC: ${EC}'
-overwrite_original -if '$Canon:AutoExposureBracketing =~ "On"' *.CR2
Canon ‑ PC
exiftool -sep ", " "-keywords+=Bracketed, EBV: ${Canon:AEBBracketValue}, EC: ${EC}"
-overwrite_original -if "$Canon:AutoExposureBracketing =~ 'On'" *.CR2
Drag and Drop Version ‑ PC Only

Rename the exiftool(‑k).exe file you downloaded as shown below, and then drag and drop your photo file(s) or folder onto the file.

Note: If you are using the txt version of the configuration file, modify the command by inserting '‑config ExifTool_config.txt ' (without the quotes) immediately before the ‑sep option.

Nikon
exiftool(-sep ", " "-keywords+=Bracketed, EBV: ${Nikon:ExposureBracketValue},
EC: ${EC}" -overwrite_original -if "$Nikon:ShootingMode =~ 'Exposure Bracketing'"
*.NEF).exe
Canon
exiftool(-sep ", " "-keywords+=Bracketed, EBV: ${Canon:AEBBracketValue},
EC: ${EC}" -overwrite_original -if "$Canon:AutoExposureBracketing =~ 'On'"
*.CR2).exe

How it Works

The config file defines a new tag called 'EC' which takes its value from a composite of the bracket value and exposure compensation tags after subtracting one from the other. Then, if necessary, the fraction is converted. So, for example, a bracket value of '1' and a compensation value of '1 1/3' yields a corresponding EC value of '1/3.' The ValueConv expression may be any valid Perl expression—it returns the converted value given the original value ($val) of the Require'd tags. The 'EBV' value is read from the tag in the command itself.

The command options can be interpreted as follows:

  • ‑sep: Specify the separator string for items in List‑type tags. When writing metadata, this option causes values assigned to list‑type tags to be split into individual items at each substring matching the specified separator.
  • ‑keywords: The '‑keywords' operation of the command adds keywords to the original file. 'EBV' takes its value from the 'ExposureBracketValue' (Nikon) or 'AEBBracketValue' (Canon). 'EC' is calculated in the config file (described above).
  • ‑overwrite_original: Overwrite the original file (instead of preserving it by adding '_original' to the file name) when writing information to an image. Caution: This option should only be used if you already have separate backup copies of your image files. The overwrite is implemented by renaming a temporary file.
  • ‑if: Specifies the condition to be evaluated before processing each file. If the 'ShootingMode' tag includes the text 'Exposure Bracketing' (Nikon) or the 'AutoExposureBracketing' tag is 'On' (Canon), write the Bracketed, EBV and EC keywords to the file. If the condition is not met, the file is skipped.

See http://www.sno.phy.queensu.ca/~phil/exiftool/faq.html#Q17 for more on the ‑sep and ‑keywords options.

Where to Go for More Information

  • To learn more about the Extensible Metadata Platform (XMP) Specification or the Exchangeable image file format (Exif) Specification, please do a google search.

» Filed under: , , ,

array(27) {
  ["REDIRECT_STATUS"]=>
  string(3) "200"
  ["HTTP_HOST"]=>
  string(17) "blog.justagirl.us"
  ["HTTP_ACCEPT_ENCODING"]=>
  string(21) "x-gzip, gzip, deflate"
  ["HTTP_USER_AGENT"]=>
  string(39) "CCBot/2.0 (http://commoncrawl.org/faq/)"
  ["HTTP_ACCEPT_LANGUAGE"]=>
  string(28) "en-us,en-gb,en;q=0.7,*;q=0.3"
  ["HTTP_ACCEPT"]=>
  string(63) "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"
  ["PATH"]=>
  string(29) "/sbin:/usr/sbin:/bin:/usr/bin"
  ["SERVER_SIGNATURE"]=>
  string(0) ""
  ["SERVER_SOFTWARE"]=>
  string(6) "Apache"
  ["SERVER_NAME"]=>
  string(17) "blog.justagirl.us"
  ["SERVER_ADDR"]=>
  string(15) "206.188.205.172"
  ["SERVER_PORT"]=>
  string(2) "80"
  ["REMOTE_ADDR"]=>
  string(14) "54.197.218.127"
  ["DOCUMENT_ROOT"]=>
  string(53) "/var/www/vhosts/justagirl.us/subdomains/blog/httpdocs"
  ["SERVER_ADMIN"]=>
  string(23) "vurchoouhl@email-eh.com"
  ["SCRIPT_FILENAME"]=>
  string(63) "/var/www/vhosts/justagirl.us/subdomains/blog/httpdocs/index.php"
  ["REMOTE_PORT"]=>
  string(5) "50904"
  ["REDIRECT_QUERY_STRING"]=>
  string(23) "page=category/exiftool/"
  ["REDIRECT_URL"]=>
  string(19) "/category/exiftool/"
  ["GATEWAY_INTERFACE"]=>
  string(7) "CGI/1.1"
  ["SERVER_PROTOCOL"]=>
  string(8) "HTTP/1.0"
  ["REQUEST_METHOD"]=>
  string(3) "GET"
  ["QUERY_STRING"]=>
  string(23) "page=category/exiftool/"
  ["REQUEST_URI"]=>
  string(19) "/category/exiftool/"
  ["SCRIPT_NAME"]=>
  string(10) "/index.php"
  ["PHP_SELF"]=>
  string(10) "/index.php"
  ["REQUEST_TIME"]=>
  int(1406879216)
}