Duplicate tags (Nikon:FlashExposureComp) return different values

Started by alyda, June 24, 2010, 03:07:55 PM

Previous topic - Next topic

alyda

Hi Phil,

I had some help from you a while back (2010-02-03) on writing exposure compensation values into keywords if I was shooting in Exposure Bracketing mode.

Command line:
exiftool -sep ", " '-keywords+<EBV: ${Nikon:ExposureBracketValue}, EC: ${EC}' -overwrite_original - +if '$Nikon:ShootingMode =~ "Exposure Bracketing"' *.nef

My .ExifTool_config file looks like this:
%Image::ExifTool::UserDefined = (
'Image::ExifTool::Composite' => {
    FN => {
      Require => 'Nikon:FileNumber',
      PrintConv => 'sprintf("%07d",$val)',
    },
    SC => {
      Require => 'Nikon:ShutterCount',
      PrintConv => 'sprintf("%07d",$val)',
    },
    EC => {
      Require => {
        0 => 'ExposureBracketValue',
        1 => 'EXIF:ExposureCompensation',
      },
      ValueConv => '$val[1] - $val[0]',
      PrintConv => 'Image::ExifTool::Exif::ConvertFraction($val)',
    },
    FEC => {
      Require => 'Nikon:FlashExposureComp',
      PrintConv => 'Image::ExifTool::Exif::ConvertFraction($val)',
    },
  },
); #end


I'm making the switch to a perl script because I can't think of a way to use two '-if' conditions--one for exposure compensation, the other for flash compensation (-if 'not $ExifIFD:Flash =~ "No Flash"')--without making two passes.

It looks like I can get where I want to go if I take advantage of the GetValue, SetNewValue and WriteInfo methods of the Image::ExifTool module: 'SetNewValue - Set the new value for a tag. The routine may be called multiple times to set the values of many tags before using "WriteInfo" to write the new values to an image.'

The problem is that I'm seeing duplicate tags for 'Nikon:FlashExposureComp' and they return different values.

Code:
#!/usr/bin/perl
use Image::ExifTool;
my $exifTool = new Image::ExifTool;
my $filename = '20100619-14320274_0025637_3092117.nef';
my $tag1 = 'ExifIFD:Flash'; #! line 86; looking for 'On, Return detected'
my $tag2 = 'Nikon:FlashMode'; #! line 153; looking for 'Fired, TTL Mode'
my $tag3 = 'Nikon:FlashExposureComp'; #! line 118: -1, line 120: 0, line 187: -1; returning duplicate tags with different values
my $flash = $exifTool->ImageInfo($filename, $tag1, $tag2, $tag3);
foreach (keys %$flash) {
  print "$_ => $$flash{$_}\n";
}


Returns:
FlashExposureComp (1) => -5/3
FlashExposureComp (2) => -5/3
FlashExposureComp => 0
FlashMode => Fired, TTL Mode
Flash => On, Return detected


I've been unable to attach the RAW file to this post so I've zipped it and made it available for download at http://www.justagirl.us/downloads/20100619-14320274_0025637_3092117.zip. File size: 20.4MB.

Please note: My server is scheduled for upgrade and will not be available between 9:00pm ET Thursday, June 24, 2010, and 3:00am ET Friday, June 25, 2010.


Phil Harvey

Thanks for the sample.  (It was over the 10MB limit of this forum -- that's why it couldn't be uploaded here.)


exiftool 20100619-14320274_0025637_3092117.nef -flashexposurecomp -flashmode -H
0x0012 Flash Exposure Compensation     : -5/3
0x0017 Flash Exposure Compensation     : 0
0x000a Flash Exposure Compensation     : -5/3
0x0087 Flash Mode                      : Fired, TTL Mode


It is the version with tag ID 0x0017 which is the problem.  This tag is a relatively recent addition and it could be that we don't yet fully understand its meaning.  Perhaps this tag is related to the external flash only, in which case it should be renamed to ExternalFlashExposureComp.  Do you have an external flash that you could test this with?  If so, we should be able to sort this out.

- Phil
...where DIR is the name of a directory/folder containing the images.  On Mac/Linux/PowerShell, use single quotes (') instead of double quotes (") around arguments containing a dollar sign ($).

alyda

I do have an external flash, thanks for asking.

Updated perl (filename):
#!/usr/bin/perl
use Image::ExifTool;
my $exifTool = new Image::ExifTool;
my $filename = '20100625-04330525_0026017_3092117.nef';
my $tag1 = 'ExifIFD:Flash';
my $tag2 = 'Nikon:FlashMode';
my $tag3 = 'Nikon:FlashExposureComp';
my $flash = $exifTool->ImageInfo($filename, $tag1, $tag2, $tag3);
foreach (keys %$flash) {
  print "$_ => $$flash{$_}\n";
}


Returns:
FlashExposureComp (1) => -4/3
FlashExposureComp (2) => 0
FlashExposureComp => 0
FlashMode => Fired, External
Flash => On, Return detected


RAW file: http://www.justagirl.us/downloads/20100625-04330525_0026017_3092117.zip



Phil Harvey

Great, thanks!:


exiftool 20100625-04330525_0026017_3092117.nef  -flashexposurecomp -flashmode -H
0x0012 Flash Exposure Compensation     : -4/3
0x0017 Flash Exposure Compensation     : 0
0x000a Flash Exposure Compensation     : 0
0x0087 Flash Mode                      : Fired, External


So only 0x0012 is valid for the ExternalFlash.  Then it must be that 0x0017 has some other meaning for the D300.  In light of this, maybe the tags should be renamed as follows:

0x0012 => 'FlashExposureComp' (no change)
0x0017 => 'FlashExposureComp2' (until we figure out what this means)
0x000a => 'InternalFlashExposureComp' (not sure about this one)

Note that 0x0012 still has the odd behaviour that it is set even if the flash didn't fire (in which case it should be ignored).

If you want to run some more tests, be my guest.  It would be interesting to know how these tags are set if you fire both flashes together (is this possible?  And if so, it it possible to set the compensation differently for each flash -- probably not I would imagine), or if you use the external flash as a remote by triggering it using the internal flash as a commander.

Also, you don't need to upload the whole NEF.  Just the EXIF information will do.  An EXIF file can be produced with this command line:

exiftool SRC.nef -o DST.exif

- Phil
...where DIR is the name of a directory/folder containing the images.  On Mac/Linux/PowerShell, use single quotes (') instead of double quotes (") around arguments containing a dollar sign ($).

alyda

Wow! You ask really interesting questions. I'm a geek (note to self: must get housekeeper), so I ran a few more tests.

I've attached the EXIF information for the all the photos below (exif.zip), along with a couple of other files you may like to refer to.

SB-800 External Flash in Remote Mode, Built-In Flash in Commander Mode

20100625-06552859_0026042_3092117.nef
Camera's flash compensation (command dial; see attached commandDials.jpg): -4/3
SB-800 flash compensation: -2

FlashExposureComp (1) => -4/3
FlashExposureComp (2) => -2
FlashExposureComp => -2
FlashMode => Fired, External
Flash => On, Return detected


20100625-06560568_0026043_3092117.nef
Camera's flash compensation (command dial): 0
SB-800 flash compensation: -2

FlashExposureComp (1) => 0
FlashExposureComp (2) => -2
FlashExposureComp => -2
FlashMode => Fired, External
Flash => On, Return detected


20100625-06564594_0026044_3092117.nef
Camera's flash compensation (command dial): 0
SB-800 flash compensation: 0

FlashExposureComp (1) => 0
FlashExposureComp (2) => 0
FlashExposureComp => 0
FlashMode => Fired, External
Flash => On, Return detected


20100625-06571293_0026045_3092117.nef
Camera's flash compensation (command dial): 0
SB-800 flash compensation: 0

FlashExposureComp (1) => 0
FlashExposureComp (2) => 0
FlashExposureComp => 0
FlashMode => Fired, External
Flash => On, Return detected


20100625-08441707_0026062_3092117.nef
Camera's flash compensation (command dial): 0
SB-800 flash compensation: 0

FlashExposureComp (1) => -1
FlashExposureComp (2) => -1
FlashExposureComp => 0
FlashMode => Fired, TTL Mode
Flash => On, Return not detected


20100625-08444889_0026063_3092117.nef
Camera's flash compensation (command dial): 0
SB-800 flash compensation: 0

FlashExposureComp (1) => -4/3
FlashExposureComp (2) => -4/3
FlashExposureComp => 0
FlashMode => Fired, TTL Mode
Flash => On, Return not detected


From Nikon D300 manual: Use the built-in flash as a master flash controlling one or more remote optional SB-800, SB-600, or SB-R200 flash units in up to two groups (A and B) using advanced wireless lighting (e3 menu item on camera). See attached manualNikonD300_FlashControlForBuilt-inFlash.pdf

20100625-09015843_0026069_3092117.nef
Camera's flash compensation (command dial): -2/3
SB-800 flash compensation: 0
e3 Flash cntrl - Built-in flash compensation: -4/3
e3 Flash cntrl - Group A (SB-800?) compensation: -1/3

FlashExposureComp (1) => -2
FlashExposureComp (2) => -2
FlashExposureComp => 0
FlashMode => Fired, TTL Mode
Flash => On, Return not detected


20100625-09022351_0026070_3092117.nef
Camera's flash compensation (command dial): -1
SB-800 flash compensation: 0
e3 Flash cntrl - Built-in flash compensation: -4/3
e3 Flash cntrl - Group A (SB-800?) compensation: -1/3

FlashExposureComp (1) => -7/3
FlashExposureComp (2) => -7/3
FlashExposureComp => 0
FlashMode => Fired, TTL Mode
Flash => On, Return not detected


20100625-09025925_0026071_3092117.nef
Camera's flash compensation (command dial): -1
SB-800 flash compensation: 0
e3 Flash cntrl - Built-in flash compensation: 0
e3 Flash cntrl - Group A (SB-800?) compensation: -1/3


FlashExposureComp (1) => -1
FlashExposureComp (2) => -1
FlashExposureComp => 0
FlashMode => Fired, TTL Mode
Flash => On, Return not detected


SB-800 External Flash in Hot Shoe

20100625-07403416_0026055_3092117.nef
Camera's flash compensation (command dial): 0
SB-800 flash compensation: 0

FlashExposureComp (1) => 0
FlashExposureComp (2) => 0
FlashExposureComp => 0
FlashMode => Fired, External
Flash => On, Return detected


20100625-07405452_0026056_3092117.nef
Camera's flash compensation (command dial): -1/3
SB-800 flash compensation: 0

FlashExposureComp (1) => -1/3
FlashExposureComp (2) => 0
FlashExposureComp => 0
FlashMode => Fired, External
Flash => On, Return detected


20100625-07411100_0026057_3092117.nef
Camera's flash compensation (command dial): -1/3
SB-800 flash compensation: -1

FlashExposureComp (1) => -1/3
FlashExposureComp (2) => -1
FlashExposureComp => -1
FlashMode => Fired, External
Flash => On, Return detected


20100625-07413350_0026058_3092117.nef
Camera's flash compensation (command dial): 0
SB-800 flash compensation: -1

FlashExposureComp (1) => 0
FlashExposureComp (2) => -1
FlashExposureComp => -1
FlashMode => Fired, External
Flash => On, Return detected


No Flash

20100625-07535149_0026059_3092117.nef
Camera's flash compensation (command dial): 0
FlashExposureComp (1) => 0
FlashExposureComp (2) => 0
FlashExposureComp => 0
FlashMode => Did Not Fire
Flash => No Flash


20100625-07540806_0026060_3092117.nef
Camera's flash compensation (command dial): -5/3
FlashExposureComp (1) => -5/3
FlashExposureComp (2) => 0
FlashExposureComp => 0
FlashMode => Did Not Fire
Flash => No Flash


Phil Harvey

Excellent!  Thanks for running these tests.

This is starting to make a bit of sense.  The camera controls either the internal or external flash depending on the mode.  Here is what I think is going on:

FlashExposureComp (1) = 0x0012: The flash compensation set in the camera.  Controls either the internal or external flash depending on the mode.

FlashExposureComp (2) = 0x000a: The flash compensation actually applied?

FlashExposureComp = 0x0017: The compensation set on the external flash.

The things I don't understand are:

1) 20100625-08441707_0026062_3092117.nef and 20100625-08444889_0026063_3092117.nef:  It seems you must have set the compensation in the e3 custom setting here, but you didn't mention this.

2) For all of the images taken with the SB-800 on the hot shoe, tag 0x000a reflects the SB-800 setting and not the camera setting.  In this mode, which setting is actually applied?

- Phil
...where DIR is the name of a directory/folder containing the images.  On Mac/Linux/PowerShell, use single quotes (') instead of double quotes (") around arguments containing a dollar sign ($).

alyda

Hi Phil,

I'm sorry about the confusion.

Quote from: Phil Harvey on June 26, 2010, 07:30:18 AM
The things I don't understand are:

1) 20100625-08441707_0026062_3092117.nef and 20100625-08444889_0026063_3092117.nef:  It seems you must have set the compensation in the e3 custom setting here, but you didn't mention this.

I've checked my notes and don't see anything for the e3 custom setting. I may have forgotten to jot it down or values weren't set. I have no idea which.

Quote from: Phil Harvey on June 26, 2010, 07:30:18 AM
2) For all of the images taken with the SB-800 on the hot shoe, tag 0x000a reflects the SB-800 setting and not the camera setting.  In this mode, which setting is actually applied?

I'm sorry, I don't understand the question.

I played with the settings some more this morning and have become even more confused. You refer to Tag ID (0x0012, 0x000a, etc.). I don't see them when I do testing:

exiftool *.nef -o %f.exif
exiftool -a -u -g1 *.exif


Is there another command I can use? I'd like to spend more time on it and, hopefully, become enlightened.

---
Alyda



Phil Harvey

Hi Alyda,

Quote
I'm sorry, I don't understand the question.

With the SB-800 on the hot shoe, does the flash output change when a) the command dial setting is changed, or b) when the compensation is adjusted in the SB-800, or both?

The tag ID's are shown with the -H option.

This is very interesting.  I think my idea of calling 0x0017 ExternalFlashExposureComp was good since this is the value you actually set on the SB-800.  But I'm still wondering about how to clear up the confusion between the other two tags.

- Phil
...where DIR is the name of a directory/folder containing the images.  On Mac/Linux/PowerShell, use single quotes (') instead of double quotes (") around arguments containing a dollar sign ($).

alyda

Confirmed:

"e3: Flash Cntrl for Built-in Flash" settings completely ignored when SB-800 is in hot shoe (makes sense given the name).

With the SB-800 in the hot shoe the actual flash output is a combination of the command dial and SB-800 compensation settings.

So, if the SB-800 is in the hot shoe, "FlashExposureComp (2) = 0x000a" should be the flash compensation actually applied.

I still need to run more tests with the SB-800 in remote mode.

Phil Harvey

Hi Alyda,

Thanks for your effort in helping to figure this out.

Quote from: alyda on June 26, 2010, 08:18:03 PM
"e3: Flash Cntrl for Built-in Flash" settings completely ignored when SB-800 is in hot shoe (makes sense given the name).

It's always nice when something makes sense. :)

Quote
With the SB-800 in the hot shoe the actual flash output is a combination of the command dial and SB-800 compensation settings.

So, if the SB-800 is in the hot shoe, "FlashExposureComp (2) = 0x000a" should be the flash compensation actually applied.

I still don't understand this.  For example, 20100625-07405452_0026056_3092117.nef has a command-dial setting of -1/3 and an SB-800 setting of 0, but 0x000a is 0 for this image.  It is the hot shoe tests that I am having the most trouble with because 0x000a seems to follow the SB-800 setting, which isn't what I would have expected.

- Phil
...where DIR is the name of a directory/folder containing the images.  On Mac/Linux/PowerShell, use single quotes (') instead of double quotes (") around arguments containing a dollar sign ($).

alyda

Hi Phil,

With SB-800 in remote mode, the camera must be set to commander mode in e3 menu. Exposure compensation adjustments can be made in one of four places in this mode: one at the command dial and three in the e3 menu--Built-in, Group A and Group B Group B is irrelevant here and I don't have another flash for testing). In remote mode, the SB-800 can be set to Group A, B or C. It's been set to Group A for all of the images I've taken so far. In this set, I verified visually on the camera's monitor that each of the compensation settings affect the brightness of the image.

SB-800 set to Group A
20100626-16231614_0026337_3092117.nef
command dial set to 0, e3 Built-in set to 0, Group A set to 0, Group B set to 0
20100626-16234363_0026338_3092117.nef
command dial set to -1, e3 Built-in set to 0, Group A set to 0, Group B set to 0
20100626-16244094_0026339_3092117.nef
command dial set to -1, e3 Built-in set to -1, Group A set to 0, Group B set to 0
20100626-16250186_0026340_3092117.nef
command dial set to -1, e3 Built-in set to -1, Group A set to -1, Group B set to 0

SB-800 set to Group B
20100626-17233668_0026345_3092117.nef
command dial set to -1, e3 Built-in set to -1, Group A set to -1, Group B set to -1

SB-800 set to Group C - SB-800 did not fire but the Built-in flash did
20100626-17234860_0026346_3092117.nef
command dial set to -1, e3 Built-in set to -1, Group A set to -1, Group B set to -1

There's a very brief discussion of flash modes and compensation in each of the three PDF attachments to this post. Maybe you'll get more out of it than I did.

I think part of the answer may lie in one or more of these tags:

0x0009 Flash Type
0x0011 Flash Group A Control Mode
0x0012 Flash Group B Control Mode
0x0012 Flash Group C Control Mode
0x0013 Flash Group A Exposure Comp
0x0014 Flash Group B Exposure Comp
0x0015 Flash Group C Exposure Comp

Perhaps Group A should be named Built-in, and then groups B and C become A and B? I feel a bit silly making this suggestion since I know so little about how your fabulous tool works. I hope you're not offended.

Quote from: Phil Harvey on June 26, 2010, 08:57:38 PM
I still don't understand this.  For example, 20100625-07405452_0026056_3092117.nef has a command-dial setting of -1/3 and an SB-800 setting of 0, but 0x000a is 0 for this image.  It is the hot shoe tests that I am having the most trouble with because 0x000a seems to follow the SB-800 setting, which isn't what I would have expected.

I'm not sure if I agree with this based on new findings above.

---
Alyda


Phil Harvey

Hi Alyda,

Quote from: alyda on June 27, 2010, 12:04:10 AM
With SB-800 in remote mode, the camera must be set to commander mode in e3 menu. Exposure compensation adjustments can be made in one of four places in this mode:

Actually I think 5 places:  You forgot about the compensation on the SB-800, which was 0 for all of these tests.

Quote
There's a very brief discussion of flash modes and compensation in each of the three PDF attachments to this post. Maybe you'll get more out of it than I did.

I have downloaded the full D300 and SB-800 manuals myself and read through them too.  Like you, I find that they don't answer all of my questions.

Quote
Perhaps Group A should be named Built-in, and then groups B and C become A and B?

I will to look into this, thanks for pointing out this problem.  It seems that other models may have different meanings for the same tags.  If so, we may just have to live with this because it would get messy for me to change the names of all of these tags depending on the camera model.

Quote
I hope you're not offended.

Absolutely not!  You don't have to worry about offending me.  I don't claim to have all of the answers, and with your help I have learned a lot that I didn't know before.

Quote
Quote from: Phil Harvey on June 26, 2010, 08:57:38 PM
It is the hot shoe tests that I am having the most trouble with because 0x000a seems to follow the SB-800 setting, which isn't what I would have expected.

I'm not sure if I agree with this based on new findings above.

The difference is that in the above tests your FlashType was "Built-in,TTL&Comdr.".  In any type of "Built-in" flash 0x000a follows the command dial.  However, for all of your previous hot-shoe tests the FlashType was "Optional,TTL", and in this mode 0x000a seems to follow the SB-800 setting (also for your previous tests in commander mode with the built-in flash off).

So for me this part is starting to make a bit more sense.

- Phil
...where DIR is the name of a directory/folder containing the images.  On Mac/Linux/PowerShell, use single quotes (') instead of double quotes (") around arguments containing a dollar sign ($).

alyda

Hi Phil,

Quote from: Phil Harvey on June 27, 2010, 07:16:32 AM
Actually I think 5 places:  You forgot about the compensation on the SB-800, which was 0 for all of these tests.

I'd be delighted to be wrong about this but I think it's four (4) places. In remote mode, the SB-800 is completely slaved to the camera. The only selectable options in this mode are channel and group. Flash compensation values on the SB-800 can be set while it's in the hot shoe. So...while in TTL/TTL-BL mode (in the hot shoe) I set the compensation to -1. Then I took it off the hot shoe, switched to remote mode and shot an image with these settings:

SB-800 set to Group A
20100627-04292994_0026362_3092117.nef
command dial set to -1, e3 Built-in set to -1, Group A set to -1, Group B set to -1

I'm not seeing anything different in the output.

Quote from: Phil Harvey on June 27, 2010, 07:16:32 AM
Quote
Perhaps Group A should be named Built-in, and then groups B and C become A and B?

I will to look into this, thanks for pointing out this problem.  It seems that other models may have different meanings for the same tags.  If so, we may just have to live with this because it would get messy for me to change the names of all of these tags depending on the camera model.

No problem. So...if we focus for a moment on my desire to write flash output level compensation values as keywords to the RAW file...can you suggest a workaround?

Here's some [maybe] helpful background: I took an online HDR photography class early this year and some us found comparing exposure compensation metadata in Lightroom to be painfully slow. With your help in February, I wrote an article on adding keywords to the RAW files before import into Lightroom and shared it with my classmates (http://www.justagirl.us/keywords.php).

Here's the command I currently use for that:
exiftool -sep ", " '-keywords+<EBV: ${Nikon:ExposureBracketValue}, EC: ${EC}' -overwrite_original -if '$Nikon:ShootingMode =~ "Exposure Bracketing"' *.NEF

I'll need to specify one or more conditions to be evaluated before processing each file. My thought is to use some magic combination of flash mode, type and compensation, and then do some math with the values of the compensation tags, but it makes my head hurt when I start to write it down. Maybe a beer would help; it's 5:00 somewhere, right? I'm going to print this post, and the tag/value output from a couple of photos, and start making some notes.

I've been told I have a very logical mind and strong abstract conceptualization skills. I'm not really sure how to phrase this question, but is there something you could share about how your software accesses the manufacturer-specific metadata from the image file, and how you interpret the context of the information found? How do you see an image file in your mind?

---
Alyda

Phil Harvey

Hi Alyda,

Quote from: alyda on June 27, 2010, 03:09:15 PM
I'd be delighted to be wrong about this but I think it's four (4) places.

I understand.  Thanks for explaining.

Quote
No problem. So...if we focus for a moment on my desire to write flash output level compensation values as keywords to the RAW file...can you suggest a workaround?

Here's the command I currently use for that:
exiftool -sep ", " '-keywords+<EBV: ${Nikon:ExposureBracketValue}, EC: ${EC}' -overwrite_original -if '$Nikon:ShootingMode =~ "Exposure Bracketing"' *.NEF

I'll need to specify one or more conditions to be evaluated before processing each file. My thought is to use some magic combination of flash mode, type and compensation, and then do some math with the values of the compensation tags, but it makes my head hurt when I start to write it down.

If you can define exactly what you want to do, this can be done in a user-defined Composite tag.  Of course it can also be done by writing a Perl script and calling the ExifTool functions as you are doing.  If you can write down the algorithm you want to use I can help with this.  Sorry to get distracted by the FlashExposureComp problem.  Until I get this fixed you can select the specific FlashExposureComp tag you want by specifying a copy number.  For instance, the 0x0012 value is Copy1:FlashExposureComp.

Quote
I've been told I have a very logical mind and strong abstract conceptualization skills. I'm not really sure how to phrase this question, but is there something you could share about how your software accesses the manufacturer-specific metadata from the image file, and how you interpret the context of the information found? How do you see an image file in your mind?

Visualizing something is very important to me, and to this end I created the -htmlDump option which is the best visualization tool I know for seeing the structure of the metadata in a JPEG or TIFF image (including TIFF-based raw formats like NEF).  This is very close to the way I visualize things in my mind when thinking of the binary structure.

- Phil
...where DIR is the name of a directory/folder containing the images.  On Mac/Linux/PowerShell, use single quotes (') instead of double quotes (") around arguments containing a dollar sign ($).

Phil Harvey

I was thinking about something like this when I mentioned the user-defined tags:


%Image::ExifTool::UserDefined = (
'Image::ExifTool::Composite' => {
    MyKeywords => {
      Require => {
        0 => 'Nikon:FileNumber',
      },
      Desire => {
        1 => 'Nikon:ShutterCount',
        2 => 'ExposureBracketValue',
        3 => 'EXIF:ExposureCompensation',
        4 => 'FlashMode',
        5 => 'Copy1:FlashExposureComp',
      },
      ValueConv => q{
        my @a;
        push @a, "FN: $val[0]";
        push @a, 'EC: ' . Image::ExifTool::Exif::ConvertFraction($val[3] - ($val[2] || 0)) if defined $val[3];
        push @a, 'FEC: ' . Image::ExifTool::Exif::ConvertFraction($val[5]) if defined $val[5] and $val[4] and $val[4] =~ /Fired/;
        return \@a;
      },
    },
  },
);
1; #end


And this command:

exiftool "-keywords+<mykeywords" FILE

- Phil
...where DIR is the name of a directory/folder containing the images.  On Mac/Linux/PowerShell, use single quotes (') instead of double quotes (") around arguments containing a dollar sign ($).