SetNewValuesFromFile using XMP Template

Started by Archive, May 12, 2010, 08:53:51 AM

Previous topic - Next topic

Archive

[Originally posted by dougalcorn on 2005-10-24 16:10:17-07]

I'm writing a custom image ingest script to read images from a compact flash card and do some initial processing.  One of the things I'd like to do is apply a bunch of XMP metadata.  It seems like Image::ExifTool can handle this, I'm just not sure the best way.

Photoshop has these XMP Templates that it allows you to apply.  These templates are simply XML formatted text files.  My reading of the SetNewValuesFromFile docs is that it reads from an image.  What I'm wondering is if I can have it read the values in from that plain text file instead.

Is this one of those times when I should have just tried it instead of asking?

Archive

[Originally posted by exiftool on 2005-10-24 18:12:12-07]

I'm not sure exactly what the Photoshop XMP template files contain, but if you have a complete XMP record ("xmp.dat") you can write it using exiftool:

Code:
   exiftool -xmp'<=xmp.dat' image.jpg

The other alternative is to use a text file which contains the exiftool arguments to set the required XMP tags:

Code:
   exiftool -@ xmp.args image.jpg

Where "xmp.args" looks something like this:

Code:
   -xmp:author=Phil Harvey
    -xmp:keywords=keyword

Hopefully one of these possibilities is close to what you want.  I could give a more informed answer if I knew the exact format of the plain text files you're talking about.

Archive

[Originally posted by dougalcorn on 2005-10-24 18:28:01-07]

I think the Adobe calls an XMP template what you're calling an XMP data file.  Here's a sample.

Is there an easy way to apply that data from the Perl library?  I'm writing my own script and don't want to shell out unless I can help it.

Archive

[Originally posted by exiftool on 2005-10-24 18:41:37-07]

Thanks.  That is a complete XMP record, and can be written directly to an image file (replacing the existing XMP record) with my first example.

But if you only want to modify certain XMP tags in your image this isn't what you want to do.   I think I understand now what you wanted.  If ExifTool could extract information from a .XMP file like this, then you could use it with the -tagsfromfile option to transfer whatever information you wanted (as you were suggesting in your first post -- sorry, I'm a bit slow...).

I'll go ahead and add the ability to read and write XMP files since I think this will be a useful addition.  It shouldn't take me more than a day or so to have this added.  Look for it to appear in version 5.71.

Archive

[Originally posted by dougalcorn on 2005-10-24 18:47:06-07]

That's great; thanks!  BTW, a big thanks for Image::ExifTool.  Unquestionably, it's the best exif parser of any language.

Archive

[Originally posted by dougalcorn on 2005-10-24 18:50:42-07]

BTW, this is a DNG file I'm going to be updating.

If you care, you can see my script here.  It's fairly simple, but facilitates my workflow.  The idea is to index all the images on a compact flash card, rename them based on exif, and convert any raw images to DNG format.  I'd like to finish the process by adding my copyright, etc to the image.

Archive

[Originally posted by exiftool on 2005-10-24 20:23:02-07]

Thanks for the endorsement.

Scripts like yours to automate the workflow make life sooooo much easier for those of use who take thousands of pictures. Smiley

I was a bit quicker than I anticipated in getting adding support for the .XMP data files, and version 5.71 is available now from the exiftool web page

Archive

[Originally posted by dougalcorn on 2005-10-24 21:38:38-07]

Fantastic!  I've updated my script accordingly!

Here's my blog entry on it.  As above, you can download the script directly.

BTW Phil, I find it pretty hard to believe you don't have at least one version of something similar to my script. ;-)

Archive

[Originally posted by exiftool on 2005-10-24 23:21:50-07]

Great!  It looks like that fit in with your script nicely.  Glad I could help.  

You may consider adding an 'XMP:*' argument in your call to SetNewValuesFromFile().  Without this, ExifTool would prefer to translate as much of the information into EXIF and IPTC format as possible (since by default, EXIF and IPTC are preferred over XMP).  This may or may not be what you intended.  By specifying the XMP group explicitly, you constrain ExifTool to keep the information in the XMP group.  (Note that information may only change groups for tags which have the same name in more than one group.)

An alternative is to call SetNewGroups() to change the default group priority before calling SetNewValuesFromFile().  Then ExifTool still has the freedom to translate information between groups, but this allows you to set the preferred groups.

Archive

[Originally posted by dougalcorn on 2005-10-25 00:09:38-07]

I tried limiting to "XMP:*", but I wasn't sure how to do it.  I did SetNewValuesFromFile($file, ['XMP:*']) because I thought the second argument needed to be a list.  The result was that I didn't get any of the metadata from the .xmp file.

The other thing I was sad is that WriteInfo() couldn't work in place.  That means during ingest, I have to first convert the file and then copy it.  Makes for a bit slower ingest.  Seems like WriteInfo() should take an option to force overwrite.

Archive

[Originally posted by exiftool on 2005-10-25 11:47:06-07]

Thanks for your feedback.  I guess this is a bit confusing because the example for SetNewValues() is:

Code:
   $info = $exifTool->SetNewValuesFromFile($srcFile, @tags);

You are correct, the second argument is a list.  But in Perl, this is the same as

Code:
   $info = $exifTool->SetNewValuesFromFile($srcFile, $tag1, $tag1, ... );

What you did was pass a reference to an anonymous list, which is distinctly different than passing the list itself.  But I'm sure you see this now.

And I understand your comment about WriteInfo().  You're right, it doesn't work on a file in place.  This is a bit inconvenient I'll admit, but it doesn't affect performance at all, for two reasons:

1) The 'rename' command is very fast since all it does is update the directory -- it doesn't do any file copying.

2) ExifTool would have to create a temporary file then rename afterwards anyway.  So in effect, the only difference is that you have to do the rename yourself instead of ExifTool doing it.

I did it purposely this way to make you think twice before overwriting your files.

So I hope you can forgive me...  ;-)  If enough people feel strongly about this, I will consider changing it.

Archive

[Originally posted by tschnebeck on 2005-10-26 22:32:29-07]

:: And I understand your comment about WriteInfo().

Hi,

I also vote for an overwrite option for writeinfo() :-)

In my case I use ExifTool on an open filehandle as an info plugin for this file. There is no way to delete this file and use a simple renaming - If I loose my handle my program simply crashs so I have to use a quite complex transfer temp--+mem; delete temp; mem--+file :

Code:
if (status > 0) {
    QFile rfile( dest );
    rfile.open( IO_ReadOnly );
    QDataStream rstream( &rfile );
    QByteArray membuf( rfile.size() );
    rstream.readRawBytes( membuf.data(), membuf.size() );
    rfile.close();
    rfile.remove();
    QFile wfile( source );
    wfile.open( IO_WriteOnly );
    QDataStream wstream( &wfile );
    wstream.writeRawBytes( membuf.data(), membuf.size() );
    wfile.close();
  }
//sorry again for posting C++ in a Perl forum :o)

An overwrite option that does not delete the file but writes only a new header would be perfect and leads to a huge speed-up for my program.

Bye

  Thorsten

Archive

[Originally posted by exiftool on 2005-10-26 23:15:10-07]

Hi Thorsten,

In general, writing just a new header is not possible because if the length of any information changes the rest of the data must shift to accommodate the new size.  There are special cases of course, but I like to keep ExifTool general if possible.

As far as the open filehandle goes, it is easy to write a perl wrapper which edits a file in place if you want (by first writing the file to memory).  Here is an example of a 5-line subroutine to do this, along with script to test it out:

Code:
#!/usr/bin/perl -w
use strict;
require Image::ExifTool;

my $file = shift or die "please specify file name\n";

sub WriteFileHandleInPlace($$)
{
    my ($exifTool, $fh) = @_;
    my $buff;
    $exifTool->WriteInfo($fh, \$buff) >= 0 or return 0;
    return(seek($fh, 0, 0) and print $fh $buff);
}

open FILE, "+<$file" or die "Can't open file";
my $exifTool = new Image::ExifTool;
$exifTool->SetNewValue(Comment => 'test');
WriteFileHandleInPlace($exifTool, \*FILE) or warn "Error\n";
close FILE;

Archive

[Originally posted by exiftool on 2005-10-26 23:23:58-07]

Oops.  I missed one step.  I need to truncate the file to remove any garbage at the end if the new file is smaller.  This adds one line:

Code:
sub WriteFileHandleInPlace($$)
{
    my ($exifTool, $fh) = @_;
    my $buff;
    $exifTool->WriteInfo($fh, \$buff) >= 0 or return 0;
    seek($fh, 0, 0) and print $fh $buff or return 0;
    return truncate($fh, tell($fh));
}

Archive

[Originally posted by exiftool on 2005-10-28 18:18:26-07]

Hi again,

OK.  I gave in and added this ability to ExifTool.  You can now call WriteInfo() (version 4.72 or higher) with a single argument to write a file in place:

Code:
   $exifTool->WriteInfo($file);

Where $file is a file name, file reference, or scalar reference to an image in memory.