ExifTool Forum

ExifTool => The Image::ExifTool API => Topic started by: alyda on September 15, 2014, 03:39:36 PM

Title: PreviewImage and SetNewValuesFromFile
Post by: alyda on September 15, 2014, 03:39:36 PM
Hi Phil,

I'm adding an additional bit of functionality to an older perl script, and it's working as desired. I'm fairly good at copying and tweaking bits and pieces I find in the Image::ExifTool Perl Library Module and this forum, but I really haven't a clue what some of it means.

Here's the new piece (copied, in part, from https://exiftool.org/forum/index.php/topic,19.msg33.html#msg33 (https://exiftool.org/forum/index.php/topic,19.msg33.html#msg33)):

  my $out = $jpg_dir . $dto . $ssto . $sc . '.jpg';
  # extract the PreviewImage tag explicitly
  my $previewInfo = $exifTool->ImageInfo($file, 'PreviewImage');
  my $val = $$previewInfo{PreviewImage};
  if ($val) {
    open OUT, ">$out";
    print OUT $$val and close OUT;
    # copy all EXIF information, preserving the original IFD
    # (without '>*.*' tags would be copied to the preferred EXIF IFD)
    my $info = $exifTool->SetNewValuesFromFile($file, 'EXIF:*>*:*');
    $exifTool->WriteInfo($out);
  }


I understand that references are commonly used when you are returning a large object or data structure (for example an array or hash) from a subroutine, and that I can also use references to subroutines and scalars. When I want to actually use the values in these variables, I need to dereference the pointer. (http://perlmeme.org/howtos/using_perl/dereferencing.html (http://perlmeme.org/howtos/using_perl/dereferencing.html))

In your reply to Janc you state, "Notice that I dereference $val because I know both JpgFromRaw and PreviewImage will return a scalar reference, but to be safe you should probably test for this."

Question 1: What do you mean by, "but to be safe you should probably test for this."

Question 2: Open, print and close feel so clumsy and old-fashioned compared to the object-oriented method of the rest of the code. Is there a 'prettier' way to write this part?

Here's the entire script:

use strict;
use Image::ExifTool;
require 'Image/ExifTool/Shift.pl';

# camera set to UTC0; will shift [-]10 for Hawaii
my $tz = 10;

my $numArgs = $#ARGV;

my $raw_dir = $ARGV[$numArgs - 1] . '/';
my $jpg_dir = $ARGV[$numArgs] . '/';

my $exifTool = new Image::ExifTool;

$exifTool->Options('DateFormat' => '%Y%m%d-%H%M%S');

foreach my $i (0..($numArgs - 2)) {
  $exifTool = new Image::ExifTool;
  # extract meta information from the image
  my $file = $ARGV[$i];
  $exifTool->ExtractInfo($file);
  # get date and time
  my $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.exiftool.org/index.html#shift
  $exifTool->SetNewValue('AllDates' => $tz, 'Shift' => -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
  my $dto = $exifTool->GetValue('DateTimeOriginal', 'ValueConv');
  Image::ExifTool::ShiftTime($dto, $tz, -1);
  $dto = $exifTool->ConvertDateTime($dto);
  # Nikon records multiple frames per second; get 'SubSecTimeOriginal' to avoid filename collision
  my $ssto = $exifTool->GetValue('SubSecTimeOriginal');
  # get shutter count
  my $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
  my $nn = $dto . $ssto . $sc . '.nef';
  # add information to source file, writing output to new file
  # https://exiftool.org/ExifTool.html#WriteInfo
  # note use of full path in filenames
  $exifTool->WriteInfo($file, $raw_dir . $nn);

  my $out = $jpg_dir . $dto . $ssto . $sc . '.jpg';
  # extract the PreviewImage tag explicitly
  my $previewInfo = $exifTool->ImageInfo($file, 'PreviewImage');
  my $val = $$previewInfo{PreviewImage};
  if ($val) {
    open OUT, ">$out";
    print OUT $$val and close OUT;
    # copy all EXIF information, preserving the original IFD
    # (without '>*.*' tags would be copied to the preferred EXIF IFD)
    my $info = $exifTool->SetNewValuesFromFile($file, 'EXIF:*>*:*');
    # overwrite file
    $exifTool->WriteInfo($out);
  }
}

Title: Re: PreviewImage and SetNewValuesFromFile
Post by: Phil Harvey on September 15, 2014, 07:37:43 PM
Quote from: alyda on September 15, 2014, 03:39:36 PM
In your reply to Janc you state, "Notice that I dereference $val because I know both JpgFromRaw and PreviewImage will return a scalar reference, but to be safe you should probably test for this."

Question 1: What do you mean by, "but to be safe you should probably test for this."

    $val = $$val if ref $val eq 'SCALAR';

QuoteQuestion 2: Open, print and close feel so clumsy and old-fashioned compared to the object-oriented method of the rest of the code. Is there a 'prettier' way to write this part?

You could maybe make it more object oriented with some other Perl library, but the open/print/close is the way I would do it (although I would do a binmode(OUT); after opening the file so the code would work on Windows platforms.

- Phil
Title: Re: PreviewImage and SetNewValuesFromFile
Post by: alyda on September 17, 2014, 02:14:10 PM
Thank you Phil!