ExifTool Forum

ExifTool => Newbies => Topic started by: Archetyped on April 05, 2017, 05:42:31 PM

Title: Renaming file using multiple date references mixed in with other tags?
Post by: Archetyped on April 05, 2017, 05:42:31 PM
Hi, what would be the best way to rename files using differently-formatted references to DateTimeOriginal separated by other tags?

For example: 2017_Canon_12-17_080123.jpg (year_make_month-date_HMS.extension)

Since -d can only be used once, and it doesn't look like it's possible to include other tags in the date format string, what would be the best way to mix formatted date values and other tags in the new file name?

Thanks.
Title: Re: Renaming file using multiple date references mixed in with other tags?
Post by: Archetyped on April 06, 2017, 12:07:05 AM
I poked around a bit more and this is what I have so far.  I made a custom DateFMT tag that takes additional parameters to format an image's other date tags using custom formatting.  Error checking is purposefully kept at a minimum (since it was just built for my needs), but Perl is not my 1st language, so I'm sure I'm doing some things wrong.  Let me know if you see any improvements I can make.

Here's the custom tag added to ExifTool's config file:


%Image::ExifTool::UserDefined = (
  'Image::ExifTool::Composite' => {
    # Formatted Date
    DateFMT => {
      ValueConv => sub {
        use Time::Piece;
        my ($val, $tag, $fmt, $dt);
        # Clean args
        my $args = $1;
        $args =~ s/^[\'\"]+|[;\'\"]+$//g;
        @args = split(';', $args, 2);
        #Tag is defined
        if ( @args > 1 ) {
          # Get tag data
          $tag = shift(@args);
          $tag =~ s/^\s+|\s+$//g;
        }
        # Tag is not defined. Use default tag value (DateTimeOriginal)
        else {
          $tag = 'DateTimeOriginal';
        }
        # Get Tag data
        my $et = pop;
        $val = $et->GetInfo($tag);
        $val = $$val{$tag};
        # Prepare date format string
        my $fmtParse = "%Y:%m:%d %H:%M:%S";
        if ( @args > 0 ) {
          $fmt = pop(@args);
          $fmt =~ s/^[\'\"]+|[\'\"]+$//g;
        } else {
          $fmt = $fmtParse;
        }
        # Clean date: Strip Subseconds/Timezone
        $val =~ s/^(.+)[-\.]\d+.+$/$1/;
        # Parse Date
        $dt = Time::Piece->strptime($val, $fmtParse);
        return $dt->strftime($fmt);
      },
    },
  },
);


The tag can then be used on the command-line to format dates based on the parameters you give it.

By default (without passing any additional parameters), it returns DateTimeOriginal in the standard EXIF date format:

exiftool -p "${DateFMT}" File
# Example Output: 2017:03:31 16:30:29


The date can be formatted using standard date-formatting codes:
exiftool -p "${DateFMT;'%Y-%m-%d'}" File
# Example Output: 2017-03-31


You can also specify a different date tag to format:
exiftool -p "${DateFMT;'CreateDate;%Y-%m-%d_%H%M%S'}" File
# Example Output: 2017-03-31_163029


This allows me to insert formatted date strings anywhere I need to when renaming files, etc.  The example file name format in my original post would look like this:
exiftool "-filename<${DateFMT;'%Y'}_${Make}_${DateFMT;'%m-%d_%H%M%S'}.%e" image0001.jpg
# Example Output: 2017_Canon_12-17_080123.jpg

Title: Re: Renaming file using multiple date references mixed in with other tags?
Post by: Hayo Baan on April 06, 2017, 01:09:47 AM
Looking good! However, wouldn't your purpose be sufficiently serverved with the -d date format option of exiftool itself? https://exiftool.org/exiftool_pod.html#Input-output-text-formatting
Title: Re: Renaming file using multiple date references mixed in with other tags?
Post by: Archetyped on April 06, 2017, 03:43:26 AM
It's definitely possible that it could meet my needs, but I just haven't figured out how yet.  As per my original question, can the -d option contain other tags so that I can create file names where date data can be intermingled with other tags when renaming files (example file name in the original post)?  If so, how?

Thanks.
Title: Re: Renaming file using multiple date references mixed in with other tags?
Post by: StarGeek on April 06, 2017, 04:36:38 AM
I don't believe the -d can contain other tags, but there are some workarounds.

For example, you can use -d for the most complex part of the date, then directly edit the least complex using the hashtag # and regex.  For example:
exiftool -d "%m-%d_%H%M%S.%%e" "-filename<${DateTimeOriginal#;s/^(\d{4}).*/$1/}_${Make;}_${DateTimeOriginal}"

Here, ${DateTimeOriginal#;s/^(\d{4}).*/$1/} accesses the original value because of the #.  The regex that follows grabs the first four digits, i.e. the year, and saves only that part.

But for a cleaner command, a user-defined tag is better.  And you are less likely to have errors due to typos as you might with a more complex command like the one above.
Title: Re: Renaming file using multiple date references mixed in with other tags?
Post by: Phil Harvey on April 06, 2017, 08:58:57 AM
Your config file is genius!  It took me a while to figure out how you were doing this.  Very very smart.  You are obviously very good at Perl and have studied the ExifTool source code.

I have a few comments/suggestions:

1. The ValueConv relies on the value of $1 being the formatting expression.  The fact that $1 contains the expression is pure luck, and may change in future versions.  I will add an ExifTool member variable called "FMT_EXPR" in version 10.49 and guarantee that this will work for future releases.

2. As written, the optional tag name was case sensitive.  I have changed this to make it insensitive.

3. I reserve the right to add additional arguments in function calls, so I have changed "pop" to "$_[1]" to avoid future problems.

4. I have changed the code to fail gracefully if Time::Piece is missing and added better handling of strptime errors.

5. I have changed the way quotes are stripped to allow the format string to have embedded quotes at the start or end.

Attached is a new config file with these updates that will work the current and future versions of ExifTool.

- Phil

Edit:  This config file may be useful to others so I'm thinking about packaging it with the next ExifTool release.
Title: Re: Renaming file using multiple date references mixed in with other tags?
Post by: Archetyped on April 06, 2017, 02:54:48 PM
Thanks Phil!  This is actually the first time I've written Perl, but the example.config (http://"www.exiftool.org/config.html") gave me pointers on what to search for as I cobbled the custom tag together.  Finding a reference to the format expression was indeed a random discovery, but I was nonetheless happy to get access to it, and am doubly happy to know that it will be directly accessible in future updates.

Thanks for the updates to the config as well, I've now learned a few more things about Perl ;)  I did notice that if the custom tag is matched by a wildcard tag on the command-line (e.g. exiftool -Date* Image001.jpg), it will cause nothing to be output (instead of a list of matching tags and their values).  This appears to occur if $et->GetInfo($tag); is called.  Perhaps you might know why or if there is a fix?

After making this tag, it occurred to me that it would be great if simple strftime format strings could be passed to any date-based tag using the built-in advanced formatting functionality.  Basically, if the tag contains a standard EXIF date string, and the format expression was a simple string containing date formatting codes, then it would format the date accordingly.
exiftool -p ${DateTimeOriginal;'%Y'} Image001.jpg
# Outputs: 2017


Alternatively, is there a way to hook into the formatting of all tags (like a global PrintConv)?  This could be used to check the tag value for a date and format it based on the format string (if included).
Title: Re: Renaming file using multiple date references mixed in with other tags?
Post by: Phil Harvey on April 06, 2017, 10:13:20 PM
Wow.  I'm impressed that this was your first time with Perl.  Sort of miraculous actually.

Quote from: Archetyped on April 06, 2017, 02:54:48 PM
I did notice that if the custom tag is matched by a wildcard tag on the command-line (e.g. exiftool -Date* Image001.jpg), it will cause nothing to be output (instead of a list of matching tags and their values).  This appears to occur if $et->GetInfo($tag); is called.  Perhaps you might know why or if there is a fix?

I don't have time to look into this right now, but I'll post back later about this.

QuoteAfter making this tag, it occurred to me that it would be great if simple strftime format strings could be passed to any date-based tag using the built-in advanced formatting functionality.  Basically, if the tag contains a standard EXIF date string, and the format expression was a simple string containing date formatting codes, then it would format the date accordingly.

Interesting idea.  Let me think about this too.

QuoteAlternatively, is there a way to hook into the formatting of all tags (like a global PrintConv)?

There is a global API Filter option that can be used to evaluate an expression to modify the values of all tags.  But the beauty of what you did is that it allows different formatting of individual tags.

- Phil
Title: Re: Renaming file using multiple date references mixed in with other tags?
Post by: Phil Harvey on April 07, 2017, 08:32:05 AM
OK, I've had time to look at the GetInfo() problem.  You're right.  I shouldn't be calling GetInfo() recursively -- it was doing bad things.

About your idea of allowing simple strftime formatting codes in the advanced formatting:  I don't like the idea of having to parse the date and the expression before deciding whether or not to apply the format.  Instead, ExifTool could define a DateFmt() utility function that you could use like this:

exiftool -p "${datetimeoriginal;DateFmt('%Y')}" FILE

I'm thinking of adding this to the next release.

- Phil

Edit:  This could be the documentation for the new feature:

            ExifTool provides a "DateFmt" utility to simplify reformatting of
            individual date/time values.  The function acts on a standard
            EXIF-formatted date/time value in $_ and formats it according to
            the specified format string (see the -d option).  For example:

                exiftool -p "${createdate#;DateFmt('%Y-%m-%d_%H%M%S')}" a.jpg

(Compare this to the command when using your config file:)

                exiftool -p "${DateFmt;'CreateDate;%Y-%m-%d_%H%M%S'}" a.jpg
Title: Re: Renaming file using multiple date references mixed in with other tags?
Post by: Archetyped on May 12, 2017, 04:10:52 PM
Thanks Phil, does that mean GetInfo() cannot be used in any custom tags?

Thanks for the DateFmt function as well, it will make formatting dates much easier :)
Title: Re: Renaming file using multiple date references mixed in with other tags?
Post by: Phil Harvey on May 12, 2017, 10:58:21 PM
Yes.  But you can use GetValue() instead.

- Phil
Title: Re: Renaming file using multiple date references mixed in with other tags?
Post by: Archetyped on May 15, 2017, 06:25:37 PM
Ah, got it.  Thanks :)