ExifTool Forum

ExifTool => The "exiftool" Application => Topic started by: msbc on January 16, 2017, 12:38:50 AM

Title: Checking for TAG in pair of files
Post by: msbc on January 16, 2017, 12:38:50 AM
I'd like to check for the existence or otherwise of a tag in a RAW file and an XMP sidecar at the same time. So, if a folder contains 5 NEF files and their XMP sidecars I want to determine if a particular tag exists in each NEF and/or the associated XMP. Ideally the test would print the filename if the tag is not present in either the NEF or XMP. If the tag is present in either, or both then no action would be taken.

Is this possible ?

Thanks,
Mark
Title: Re: Checking for TAG in pair of files
Post by: Hayo Baan on January 16, 2017, 03:50:05 AM
Hi Mark,

So you are looking for a solution that shows the name of the file IF both it and the matching XMP do not have a certain tag?

Well, yes, but it not easily. A solution a can think of would be to use a custom tag which calls exiftool again on the accompanying file and checks to see if that tag is present there.

Another solution would be to just use a little bit of scripting checking the output of an exiftool call on both files (if you're on a Mac/Linux this is really simply done).

What is the name of the tag you are looking for?
Title: Re: Checking for TAG in pair of files
Post by: msbc on January 16, 2017, 04:59:29 PM
Hi, I need an efficient solution as I will be running the command on many folders, some with 400+ NEF/XMP pairs.

Scripting is fine - I'm on a Mac. I already have a script I developed that checks all my image folders and reports if certain tags, conditions pass/fail. I'll be augmenting the script to add this new check - hopefully :-)

As background to what I'm trying to do - I want to check all my image files and report if they have/don't have GPS information. I have images from many different cameras. Most of my images I've added GPS data after shooting to the XMP. But some of my NEFs have GPS in the NEF as I've used a GPS device on my camera. So some RAW files - Sony, Canon, Panasonic, Olympus - have GPS in XMP. Some NEFs have GPS in the NEF, some in the XMP (when I didn't use the on-camera GPS) and some files have not yet been geo-tagged.

My test would be to look for gpslatitude tag in the RAW/XMP pair and print out the filename if neither had that tag.

Your suggestion about using a custom tag sounds interesting - since I don't want to have to execute the exiftool cmd twice, once for XMP and again for the RAW.
Title: Re: Checking for TAG in pair of files
Post by: Hayo Baan on January 16, 2017, 05:46:32 PM
I'll see if I can find some time tomorrow to give you a first solution.
Title: Re: Checking for TAG in pair of files
Post by: Stephen Marsh on January 16, 2017, 05:57:41 PM
It should be possible to use the one command on a directory/subdirectories by adding the extension filter to specifically process the required file types, such as:

exiftool -r -tagname -ext .cr2 -ext .xmp DIR
Title: Re: Checking for TAG in pair of files
Post by: Hayo Baan on January 17, 2017, 05:24:57 AM
Quote from: Stephen Marsh on January 16, 2017, 05:57:41 PM
It should be possible to use the one command on a directory/subdirectories by adding the extension filter to specifically process the required file types, such as:

exiftool -r -tagname -ext .cr2 -ext .xmp DIR
Stephen, that's not exactly what Mark wants: he only wants to see those files that have the GPS info set in either the raw file or the xmp. Your command will show the info for all files.
Title: Re: Checking for TAG in pair of files
Post by: Hayo Baan on January 17, 2017, 06:11:38 AM
Hi Mark,

I've created a composite tag GPSIsSet that indicates whether or not the file (1) or the xmp (2) has GPSLatitude set.

Using exiftool's -if function you can then easily accomplish what you want: exiftool -config gps_isset_config -T -filepath -if '$GPSIsSet'

Enjoy.

File: gps_isset_config
%Image::ExifTool::UserDefined = (
    'Image::ExifTool::Composite' => {
        GPSIsSet => {
            Require => {
                0 => 'Directory',
                1 => 'FileName',
            },
            Desire => {
                2 => 'GPSLatitude',
            },
            RawConv => q{
                return 1 if defined $val[2];
                if ($val[1] !~ /\.xmp$/i) {
                    require File::Spec;
                    my $xmp = File::Spec->catfile($val[0], $val[1]);
                    $xmp =~ s/\.[^.]+$/.xmp/;
                    if (-f $xmp) {
                        my $et = Image::ExifTool->new;
                        $et->ExtractInfo($xmp);
                        return 2 if defined $et->GetValue('GPSLatitude');
                    }
                }
                return 0;
            },
        }
    },
);

1;
Title: Re: Checking for TAG in pair of files
Post by: Phil Harvey on January 17, 2017, 07:51:25 AM
Sweet.
Title: Re: Checking for TAG in pair of files
Post by: Hayo Baan on January 17, 2017, 08:01:07 AM
Quote from: Phil Harvey on January 17, 2017, 07:51:25 AM
Sweet.
:)

I think this is the most elegant and efficient way since it doesn't involve loading exiftool a second time (another "simpler" solution could have been to use the backtick operator to call exiftool another time, or otherwise some shell logic).

It's actually a similar technique I use in my own library. There I gather and merge (additional) information (for .mov files) from .xmp files as well.
Title: Re: Checking for TAG in pair of files
Post by: Stephen Marsh on January 17, 2017, 03:08:40 PM
Quote from: Hayo Baan on January 17, 2017, 05:24:57 AM
Quote from: Stephen Marsh on January 16, 2017, 05:57:41 PM
It should be possible to use the one command on a directory/subdirectories by adding the extension filter to specifically process the required file types, such as:

exiftool -r -tagname -ext .cr2 -ext .xmp DIR
Stephen, that's not exactly what Mark wants: he only wants to see those files that have the GPS info set in either the raw file or the xmp. Your command will show the info for all files.

Thanks Hayo, I did test before posting and the TIF file was filtered out and only the CR2 and XMP were reported. I'll test again...

EDIT: OK I see what you mean, either CR2 or XMP – not both at the same time (and there may be more than one raw file format).
Title: Re: Checking for TAG in pair of files
Post by: msbc on January 17, 2017, 06:54:45 PM
Hayo,

Just confirming my understanding of your composite tag - I have merged it into my .Exiftool-config file:
If I execute exiftool -GPSIsSet -ext NEF . then the three output possibilities for each file would be:
0 - no GPSLatitude in NEF or XMP
1 - GPSLaitude in NEF
2 - GPSLaitude in XMP
Title: Re: Checking for TAG in pair of files
Post by: Hayo Baan on January 18, 2017, 01:30:20 AM
Quote from: msbc on January 17, 2017, 06:54:45 PM
Hayo,

Just confirming my understanding of your composite tag - I have merged it into my .Exiftool-config file:
If I execute exiftool -GPSIsSet -ext NEF . then the three output possibilities for each file would be:
0 - no GPSLatitude in NEF or XMP
1 - GPSLaitude in NEF
2 - GPSLaitude in XMP
Exactly :)
Note: no checking of XMP is done once it is determined the nef has it. It's easy to extend the code to allow for this too (e.g. 3 is both have it), but it will make checking slower and I didn't think you needed it anyway.
Title: Re: Checking for TAG in pair of files
Post by: msbc on January 18, 2017, 01:50:22 AM
Great - thanks so much for working this out :-)

I'm thinking that since the majority of my images don't have the GPS in the RAW it would be more efficient to test the XMP first and try the RAW if that fails. What modification would be needed to achieve that? I think GPSIsSet would need an argument that would be the filetype since it could be anything, not just NEF.
Title: Re: Checking for TAG in pair of files
Post by: StarGeek on January 18, 2017, 03:58:19 AM
The GPSIsSet tag will accept any file type, the NEF limitation was in the -ext NEF option on the command line.  Remove that for any file or change it to limit it.

Changing it to check XMP first might be more difficult to do.  Easier to check to see if an XMP file exists rather than checking to see if a jpeg, png, tiff, nef, cr2, etc, exists that matches the XMP file.
Title: Re: Checking for TAG in pair of files
Post by: msbc on January 18, 2017, 05:14:08 PM
The XMP will always be present - I only shoot RAW so there is always a RAW/XMP pair.
Title: Re: Checking for TAG in pair of files
Post by: Hayo Baan on January 19, 2017, 04:13:18 AM
Sorry it took a while but I have come up with a solution that works in all cases now. You can now provide either a non-xmp file or an xmp file and it will work if the gps is set.
I also changed the return value, instead of a number, it will now return the name of the file in which the gps data was found (still allowing the -if trick).

The toughest trick was actually to prevent internal looping of the metadata extraction calls (looking for the metadata in a mov file would trigger looking for the data in the xmp which would also look into the mov which would then look into the xmp, etc.). I fixed this by no longer extracting composite tags for the secondary files (which is also going to slightly faster). I therefore needed to also look for the GPSCoordinates tag instead of just the GPSLatitude tag as e.g. quicktime movies store the info there.

Here's the new code:
#!/usr/bin/perl

%Image::ExifTool::UserDefined = (
    'Image::ExifTool::Composite' => {
        GPSIsSet => {
            Require => {
                0 => 'Directory',
                1 => 'FileName',
            },
            Desire => {
                2 => 'GPSLatitude',
                3 => 'GPSCoordinates',
            },
            RawConv => q{
                require File::Spec;
                my $file = File::Spec->catfile($val[0], $val[1]);
                return $file if defined $val[2] or defined $val[3];
                my $base = File::Spec->catfile($val[0], $val[1]);
                $base =~ s/\.[^.]+$//;
                my @files = grep { ($val[1] =~ /\.xmp$/i) ^ /\.xmp$/i } glob(qq("$base.*"));
                for my $file (@files) {
                    if (-f $file) {
                        my $et = Image::ExifTool->new;
                        $et->ExtractInfo($file, { Composite => 0, Duplicates => 0 });
                        return $file if defined $et->GetValue('GPSLatitude') or defined $et->GetValue('GPSCoordinates');
                    }
                }
                return '';
            },
        },
    },
);

1;
Title: Re: Checking for TAG in pair of files
Post by: Phil Harvey on January 19, 2017, 06:29:56 AM
Very smart.
Title: Re: Checking for TAG in pair of files
Post by: Hayo Baan on January 19, 2017, 08:09:57 AM
Quote from: Phil Harvey on January 19, 2017, 06:29:56 AM
Very smart.
;D
Actually I noticed it can be done slightly shorter even (without the extra $base variable that I needed in a different approach to prevent the file loading-loop):
#!/usr/bin/perl

%Image::ExifTool::UserDefined = (
    'Image::ExifTool::Composite' => {
        GPSIsSet => {
            Require => {
                0 => 'Directory',
                1 => 'FileName',
            },
            Desire => {
                2 => 'GPSLatitude',
                3 => 'GPSCoordinates',
            },
            RawConv => q{
                require File::Spec;
                my $file = File::Spec->catfile($val[0], $val[1]);
                return $file if defined $val[2] or defined $val[3];
                $file =~ s/\.[^.]+$//;
                my @files = grep { ($val[1] =~ /\.xmp$/i) ^ /\.xmp$/i } glob(qq("$file.*"));
                for my $file (@files) {
                    if (-f $file) {
                        my $et = Image::ExifTool->new;
                        $et->ExtractInfo($file, { Composite => 0, Duplicates => 0 });
                        return $file if defined $et->GetValue('GPSLatitude') or defined $et->GetValue('GPSCoordinates');
                    }
                }
                return '';
            },
        },
    },
);

1;

(I left the single use of @files in as that improves readability)
Title: Re: Checking for TAG in pair of files
Post by: msbc on January 20, 2017, 02:02:41 AM
Hayo,

Is GPSCoordinates a composite tag you defined? It's not in my NEFs.

I'm going to optimise your code for my use-case, i'll post a version back here when I can.

Thanks,
Mark
Title: Re: Checking for TAG in pair of files
Post by: Hayo Baan on January 20, 2017, 03:05:29 AM
Quote from: msbc on January 20, 2017, 02:02:41 AM
Is GPSCoordinates a composite tag you defined? It's not in my NEFs.
No, it's the tag that gets the gps info in movie files (at least when from an iPhone, but perhaps also from a Nikon camera with gps module). To allow for this, I added the tag.

Quote from: msbc on January 20, 2017, 02:02:41 AM
I'm going to optimise your code for my use-case, i'll post a version back here when I can.
OK! (Though not testing for the additional tag is probably not that costly)