Adding custom tags with Image::ExifTool
Posted on 2008-03-19 14:56:14-07 by sparkie
hi all This is going well! Got Perl installed, got ExifTool installed. Tested a few calls to ImageInfo. What a treat - up pops all the metadata for my jpeg. Right, what I now need is to be able to add custom tags to my JPEGS. If I understand Phil's post from yesterday correctly, custom means XMP? I thought SetNewValue was the one, but this method seems to be for writing new values to existing tags. So, a wee code snippet where a custom (brand new) tag is added to file would see me right. What a fab tool set! Thanks again, Mark
Posted on 2008-03-19 15:38:50-07 by exiftool in response to 7404
Hi Mark,
From the Image::ExifTool documentation:
User-defined tags can be added via the ExifTool configuration file or by defining the %Image::ExifTool::UserDefined hash before calling any ExifTool functions. See " ExifTool_config" in the ExifTool distribution for more details.
- Phil
Posted on 2008-03-19 16:49:52-07 by sparkie in response to 7405
Phil, thank you again for the quick reply. Yes, I'd started to look at the sample config file but being new to Perl the syntax got the better of me. Not your job to teach me Perl, I know! What's confusing me is the kind of hierarchy that we seem to adding to. I'd like to define, say, Mytag1, Mytag2 and Mytag3 within an XMP namespace called, say, myNs. How would the sample look? This is how far I've got. I'm not really clear on what the GROUPS element is for
%Image::ExifTool::UserDefined::myNs = ( GROUPS => { 0 => 'XMP', 1 => 'XMP-myNs', 2 => 'Image' }, # not sure what the third leve 'image' is doing here NAMESPACE => { 'myNs' => 'http://ns.myNs.com/xxx/1.0/' }, WRITABLE => 'string',
now I get stuck: Since I'm defining a tag (not its value) what else do I have to put in the curly braces. Your sample seems to add a further assoc array within the tag elements ?? Mytag1=> { }, Mytag1=> { }, Mytag1=> { }, ); Sorry to harrass but this is clearly the best tool for the job and I'm super keen to get this demoable. Thanks again. Mark
Posted on 2008-03-19 17:11:29-07 by exiftool in response to 7407
Hi Mark,
What you have done is basically correct.
The sample config file gives examples of how to set various attributes. The "2 => 'Image'" sets the family 2 group name for tags in the table (and is "Other" unless specified). This is simply used for catagorizing tags for your convenience and doesn't affect what is written.
You don't need anything inside the braces in the tag definition for simple strings in XMP. The examples show how to specify a different family 2 group name for an individual tag, and how to make a "List"-type tag. The "List" tags are written differently, and multiple may contain multiple values (like a keywords list).
If you want to do anything more complex, check lib/Image/ExifTool/XMP.pm for examples of how it is done, and read lib/Image/ExifTool/README for all the gory details. Basically though, there is almost none of this that you need to know if you just want to add simple tags with no special formatting.
Just 2 points:
1) you have given all your tags the same name, so only one tag will be defined.
2) you still need to add the new namespace to the Image::ExifTool::XMP::Main table as is done in the sample config file.
- Phil - Phil
Posted on 2008-03-19 17:18:20-07 by sparkie in response to 7409
Fantastic. Last question, I hope, for the moment: Does the namespace have to exist? Thank you. Mark
Posted on 2008-03-19 17:27:02-07 by sparkie in response to 7412
aha! I knew I'd be back. Having defined my UserDefined hash, how do write the call to WriteInfo. This doesn;t work ... alas:
$ExifTool->SetNewValue('Tag3','Val1'); $ExifTool->SetNewValue('Tag3','Val3'); $ExifTool->SetNewValue('Tag2','Val2'); $ExifTool->WriteInfo($picFile, $picFileMod);
merci mille fois
Posted on 2008-03-19 17:54:27-07 by exiftool in response to 7414
You define the namespace prefix and the namespace URI with the NAMESPACE entry. It doesn't have to exist anywhere else beforehand.
Your code should work. Check with the exiftool application and read the FAQ if you are having problems with the user-defined tags.
- Phil
Posted on 2008-03-20 10:24:51-07 by sparkie in response to 7416
Phil, is this OK for adding a namespace to the table. I'm still getting a tag does not exist error. My namespace is 'defra'
%Image::ExifTool::UserDefined = ( 'Image::ExifTool::XMP::Main' => { defra => { SubDirectory => { TagTable =< 'Image::ExifTool::UserDefined::defra', }, }, } );
Do I need to address the namespace when I call SetNewValue? Something like;
$ExifTool->SetNewValue('defra::Tag1','Val1');??? Slowly getting there... Mark
Posted on 2008-03-20 11:55:24-07 by exiftool in response to 7421
Hi Mark,
This looks good to me, but obviously something is wrong.
Could you post your full .ExifTool config file (inside a
block in this forum)?
You don't need to specify the group when you call SetNewValue, but if you do it is done like this:
$ExifTool->SetNewValue('XMP-defra:Tag1','Val1');
- Phil
Posted on 2008-03-20 12:52:36-07 by sparkie in response to 7422
Hello, Phil. Here's my code: I really appreciate this. I'm running the config code inline for now:
#!usr/bin/perl use warnings; # ============================== Load modules ==================================== #use DBI; use Image::ExifTool qw(:Public); my $picFile, $picFileMod; $picFile = 'C:\pics\pic2.jpg'; $picFileMod = 'C:\pics\pic2ModByExifTool.jpg'; #define ExifTool object; my $ExifTool = new Image::ExifTool; %$ExifTool::UserDefined::defra = ( GROUPS => { 0 => 'XMP', 1 => 'XMP-defra', 2 => 'Image' }, NAMESPACE => { 'defra' => 'http://ns.defra.com/' }, WRITABLE => 'string', Tag1 => {}, Tag2 => {}, Tag3 => {} ); %$ExifTool::UserDefined = ( # new XMP namespaces (ie. XMP-xxx) must be added to the Main XMP table: 'Image::ExifTool::XMP::Main' => { defra => { SubDirectory => { TagTable => '%$ExifTool::UserDefined::defra' }, }, } ); if(-e $picFile) { my $info = $ExifTool->ImageInfo($picFile); print '\n'; print '\n'; foreach (keys %$info) { print "$_ => $$info{$_}\n"; } $ExifTool->SetNewValue('Tag1','Val1'); $ExifTool->SetNewValue('Tag2','Val2'); $ExifTool->SetNewValue('Tag3','Val3'); $ExifTool->WriteInfo($picFile, $picFileMod); } print 'After mod=============================================== \n'; my $info = ImageInfo($picFileMod); foreach (keys %$info) { print "$_ => $$info{$_}\n"; }
Posted on 2008-03-20 13:17:49-07 by exiftool in response to 7423
Hi Mark,
It is clear you are struggling a bit with Perl. You have inserted a '$' symbol and removed the required "Image::" in the tag table names. Also the '%' isn't used when giving the table name in the value for TagTable. As well, you need brackets around your list of variables after "my", and the "\n" needs to be in double quotes because it is taken literally in single quotes. So try this:
#!/usr/bin/perl use warnings; # ============================== Load modules ==================================== #use DBI; use Image::ExifTool qw(:Public); my ($picFile, $picFileMod); $picFile = 'a.jpg'; $picFileMod = 'b.jpg'; #define ExifTool object; my $ExifTool = new Image::ExifTool; %Image::ExifTool::UserDefined::defra = ( GROUPS => { 0 => 'XMP', 1 => 'XMP-defra', 2 => 'Image' }, NAMESPACE => { 'defra' => 'http://ns.defra.com/' }, WRITABLE => 'string', Tag1 => {}, Tag2 => {}, Tag3 => {} ); %Image::ExifTool::UserDefined = ( # new XMP namespaces (ie. XMP-xxx) must be added to the Main XMP table: 'Image::ExifTool::XMP::Main' => { defra => { SubDirectory => { TagTable => 'Image::ExifTool::UserDefined::defra' }, }, } ); if(-e $picFile) { my $info = $ExifTool->ImageInfo($picFile); print "\n\n"; foreach (keys %$info) { print "$_ => $$info{$_}\n"; } $ExifTool->SetNewValue('Tag1','Val1'); $ExifTool->SetNewValue('Tag2','Val2'); $ExifTool->SetNewValue('Tag3','Val3'); $ExifTool->WriteInfo($picFile, $picFileMod); } print "After mod=============================================== \n"; my $info = ImageInfo($picFileMod); foreach (keys %$info) { print "$_ => $$info{$_}\n"; } #end
Also, you will save yourself a lot of headaches in the future if you check the return value from WriteInfo() and Error and Warning messages to see if there were any problems when writing the file. The the API documentation on WriteInfo for details.
- Phil
Posted on 2008-03-20 14:10:02-07 by sparkie in response to 7424
Rock and Roll! I see my tags in the output. Yes. Absolutely brand new to Perl and trying something a bit more ambitious than Hello World. Running before I can walk! 4 years of PHP are no help to me at all! I put the $ symbol in thinking that I could load the config to my $ExifTool object. And in that logic, we no longer need the Image:: prefix?? The config elements seem to address a static class. I had realised a Hash is designated with a %. Sorry for that one. So for my first perl script it's been a journey. The client is going to call me this afernoon to see if we can write metadata to his assets. I will now be able to answer 'Yeah. Absolute walk in the park. No bother. ' .... ;-)
Phil, thank you very much indeed. It's a brilliant tool set. Someone should actually write a book on it!
Regards Mark
Posted on 2008-12-01 16:19:25-08 by wanderingstan in response to 7425
Thanks Mark & Phil for sharing this conversation. It saved me a ton of trouble -- and saved my Perl-expert friends from incessant questioning. And thanks Phil for this incredible tool. There's no way I would have attempted my family's image-archiving project without it. -Stan
Posted on 2009-08-21 19:18:51-07 by gloubibou in response to 9471
Very interesting read!
Is it possible to achieve the same thing using exiftool at the command line?
Pierre
Posted on 2009-08-21 19:28:56-07 by exiftool in response to 11349
Hi Pierre,
User-defined tags can not be defined at the command line. But after you define them in the exiftool config file you can use them at the command line.
- Phil
(This article is based on a thread on the CPAN::Forum.)