Recognizing list-type fields

Started by yosh, May 17, 2017, 11:19:47 AM

Previous topic - Next topic

yosh

Hey, I'm trying to make an action that handles all possible IPTC moves (from single record to single, single to list-type, list-type to single (joined) and list-type to list-type). The problem is when I try to move one list-type record into another list-type record that has only one value, i.e. put all keywords into by-line tags. So in fact I want to change all 2:25 (1C 02 19) to 2.80 (1C 02 50).

Is there a fast way to tell if the destination record is of list-type by standard, and not check it's current values?

Currently trying something like this but the destination isn't always of type 'ARRAY'.

if (ref $record_from eq 'ARRAY' && ref $record_to eq 'ARRAY') {
       foreach (@$record_from) {
     $exifTool->SetNewValue($record_too, $_, AddValue => 1);
     $exifTool->SetNewValue($record_from, $_, DelValue => 1);
       }
}


Or maybe there is a better way and I don't have to check the type of source and destination fields? :)

Also, bonus question.... Is it safe to use this solution to get tag names by number?

my $record = 2;
my $number = 80;
my $tagname = Image::ExifTool::GetTagTable( $Image::ExifTool::IPTC::Main{$record}{SubDirectory}{TagTable} )->{$number}{Name}; #= By-line


Thanks in advance!

Phil Harvey

How are you joining the lists?  If you can join them so they can be split again, you can just do this:

$exifTool->Options(List => 0);
$exifTool->Options(ListSep => ', ');
$exifTool->Options(ListSplit => ', ');
# then just do this for all tags:
$exifTool->SetNewValue($tag, $val);


If it is a List-type tag, then the value will be split apart again.

For the bonus:  It really isn't safe in that you are accessing private ExifTool data structures, but these aren't likely to change so your code should work for the foreseeable future.

You shouldn't, however, use a table without calling GetTagTable() first.  So you should do this:

my $record = 2;
my $number = 80;
my $iptcTable = Image::ExifTool::GetTagTable('Image::ExifTool::IPTC::Main');
my $tagname = Image::ExifTool::GetTagTable( $iptcTable{$record}{SubDirectory}{TagTable} )->{$number}{Name}; #= By-line


- Phil
...where DIR is the name of a directory/folder containing the images.  On Mac/Linux/PowerShell, use single quotes (') instead of double quotes (") around arguments containing a dollar sign ($).

yosh

Thank you! I am testing it now and it seems to work great.

I have another question though. Is there a method like "commit" or "update" that updates the metadata in memory before writing it to file?

I allow users to define a list of actions to perform. For example:

1) Delete keywords
$exifTool->SetNewValue('Keywords');
2) Set new keyword
$exifTool->SetNewValue('Keywords', 'word1');
3) Add new keyword
$exifTool->SetNewValue('Keywords', 'word2', AddValue=>1);

This results in all the previously deleted keywords being brought back. Is there any sync/update method to call? SaveNewValues() called after each action doesn't seem to do that.

Also fixed the IptcTable to include calling that method, thanks!

Phil Harvey

I think you are confused about the function of AddValue.  This is only used to preserve existing entries in the file.

If you want to replace existing keywords with "word1", "word2", just do this:

$exifTool->SetNewValue(Keywords => 'word1');
$exifTool->SetNewValue(Keywords => 'word2');


- Phil
...where DIR is the name of a directory/folder containing the images.  On Mac/Linux/PowerShell, use single quotes (') instead of double quotes (") around arguments containing a dollar sign ($).

yosh

No, I understand how AddValue works.
Just hoped I could do something to use it without bringing back previously deleted content of that record.

This is great, thank you!

Phil Harvey

If you want to delete a specific value, then use DelValue.  If you want to replace all existing list values from a file, then you don't use either DelValue or AddValue.

- Phil
...where DIR is the name of a directory/folder containing the images.  On Mac/Linux/PowerShell, use single quotes (') instead of double quotes (") around arguments containing a dollar sign ($).