Ignore:
Timestamp:
2021-02-26T19:39:51+13:00 (3 years ago)
Author:
anupama
Message:

Committing the improvements to EmbeddedMetaPlugin's processing of Keywords vs other metadata fields. Keywords were literally stored as arrays of words rather than phrases in PDFs (at least in Diego's sample PDF), whereas other meta fields like Subjects and Creators stored them as arrays of phrases. To get both to work, Kathy updated EXIF to a newer version, to retrieve the actual EXIF values stored in the PDF. And Kathy and Dr Bainbridge came up with a new option that I added called apply_join_before_split_to_metafields that's a regex which can list the metadata fields to apply the join_before_split to and whcih previously always got applied to all metadata fields. Now it's applied to any *Keywords metafields by default, as that's the metafield we have experience of that behaves differently to the others, as it stores by word instead of phrases. Tested on Diego's sample PDF. Diego has double-checked it to works on his sample PDF too, setting the split char to ; and turning on the join_before_split and leaving apply_join_before_split_to_metafields at its default of .*Keywords. File changes are strings.properties for the tooltip, the plugin introducing the option and working with it and Kathy's EXIF updates affecting cpan/File and cpan/Image.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • main/trunk/greenstone2/perllib/cpan/Image/ExifTool/MWG.pm

    r24107 r34921  
    1515use Image::ExifTool qw(:DataAccess :Utils);
    1616use Image::ExifTool::Exif;
    17 
    18 $VERSION = '1.08';
    19 
    20 # enable MWG strict mode by default
    21 # (causes non-standard EXIF, IPTC and XMP to be ignored)
    22 $Image::ExifTool::MWG::strict = 1 unless defined $Image::ExifTool::MWG::strict;
     17use Image::ExifTool::XMP;
     18
     19$VERSION = '1.24';
    2320
    2421sub RecoverTruncatedIPTC($$$);
     
    2724sub OverwriteStringList($$$$);
    2825
     26my $mwgLoaded;  # flag set if we alreaded Load()ed the MWG tags
     27
    2928# MWG Composite tags
    3029%Image::ExifTool::MWG::Composite = (
    3130    GROUPS => { 0 => 'Composite', 1 => 'MWG', 2 => 'Image' },
    3231    VARS => { NO_ID => 1 },
     32    WRITE_PROC => \&Image::ExifTool::DummyWriteProc,
    3333    NOTES => q{
    34         The Metadata Working Group (MWG) recommendations provide a set of rules to
    35         allow certain overlapping EXIF, IPTC and XMP tags to be reconciled when
    36         reading, and synchronized when writing.  The ExifTool MWG module is designed
    37         to aid in the implementation of these recommendations.  (See
    38         L<http://www.metadataworkinggroup.org/> for the complete MWG technical
    39         specifications.)
    40 
    4134        The table below lists special Composite tags which are used to access other
    4235        tags based on the MWG 2.0 recommendations.  These tags are only accessible
    43         when the MWG module is loaded.  The MWG module is loaded automatically by
    44         the exiftool application if MWG is specified as a group for any tag on the
    45         command line, or manually with the C<-use MWG> option.  Via the API, the MWG
    46         module is loaded with "C<use Image::ExifTool::MWG>".
     36        when explicitly loaded, but this is done automatically by the exiftool
     37        application if MWG is specified as a group for any tag on the command line,
     38        or manually with the C<-use MWG> option.  Via the API, the MWG Composite
     39        tags are loaded by calling "C<Image::ExifTool::MWG::Load()>".
    4740
    4841        When reading, the value of each MWG tag is B<Derived From> the specified
     
    5952        tag is generated when non-standard metadata is encountered.  This feature
    6053        may be disabled by setting C<$Image::ExifTool::MWG::strict = 0> in the
    61         ExifTool config file (or from your Perl script when using the API).  Note
     54        L<ExifTool config file|../config.html> (or from your Perl script when using the API).  Note
    6255        that the behaviour when writing is not changed:  ExifTool always creates new
    6356        records only in the standard location, but writes new tags to any
    6457        EXIF/IPTC/XMP records that exist.
    6558
    66         A complication of the specification is that although the MWG:Creator
     59        Contrary to the EXIF specification, the MWG recommends that EXIF "ASCII"
     60        string values be stored as UTF-8.  To honour this, the exiftool application
     61        sets the default internal EXIF string encoding to "UTF8" when the MWG module
     62        is loaded, but via the API this must be done manually by setting the
     63        L<CharsetEXIF|../ExifTool.html#CharsetEXIF> option.
     64
     65        A complication of the MWG specification is that although the MWG:Creator
    6766        property may consist of multiple values, the associated EXIF tag
    6867        (EXIF:Artist) is only a simple string.  To resolve this discrepancy the MWG
     
    8079            3 => 'IPTCDigest',
    8180        },
    82         ValueConv => q{
     81        RawConv => q{
    8382            return $val[1] if not defined $val[2] or (defined $val[1] and
    8483                             (not defined $val[3] or $val[2] eq $val[3]));
     
    8887        WriteCheck => 'Image::ExifTool::MWG::ReconcileIPTCDigest($self)',
    8988        WriteAlso  => {
    90             # only write Keywords if IPTC exists (ie. set EditGroup option)
     89            # only write Keywords if IPTC exists (eg. set EditGroup option)
    9190            'IPTC:Keywords'  => '$opts{EditGroup} = 1; $val',
    9291            'XMP-dc:Subject' => '$val',
     
    102101            4 => 'IPTCDigest',
    103102        },
    104         ValueConv => q{
     103        RawConv => q{
    105104            return $val[0] if defined $val[0] and $val[0] !~ /^ *$/;
    106105            return $val[2] if not defined $val[3] or (defined $val[2] and
     
    119118        Description => 'Date/Time Original',
    120119        Groups => { 2 => 'Time' },
    121         Notes => '"creation date of the intellectual content being shown" - MWG',
    122         Writable => 1,
    123         Desire => {
    124             0 => 'EXIF:DateTimeOriginal',
    125             1 => 'EXIF:SubSecTimeOriginal',
     120        Notes => '"specifies when a photo was taken" - MWG',
     121        Writable => 1,
     122        Shift => 0, # don't shift this tag
     123        Desire => {
     124            0 => 'Composite:SubSecDateTimeOriginal',
     125            1 => 'EXIF:DateTimeOriginal',
    126126            2 => 'IPTC:DateCreated',
    127127            3 => 'IPTC:TimeCreated',
     
    130130            6 => 'IPTCDigest',
    131131        },
     132        # must check for validity in RawConv to avoid hiding a same-named tag,
     133        # but IPTC dates use a ValueConv so we need to derive the value there
     134        RawConv => q{
     135            (defined $val[0] or defined $val[1] or $val[2] or
     136            (defined $val[4] and (not defined $val[5] or not defined $val[6]
     137            or $val[5] eq $val[6]))) ? $val : undef
     138        },
    132139        ValueConv => q{
    133             if (defined $val[0] and $val[0] !~ /^[: ]*$/) {
    134                 return ($val[1] and $val[1] !~ /^ *$/) ? "$val[0].$val[1]" : $val[0];
    135             }
     140            return $val[0] if defined $val[0] and $val[0] !~ /^[: ]*$/;
     141            return $val[1] if defined $val[1] and $val[1] !~ /^[: ]*$/;
    136142            return $val[4] if not defined $val[5] or (defined $val[4] and
    137143                             (not defined $val[6] or $val[5] eq $val[6]));
     
    146152            # set EXIF date/time values according to PrintConv option instead
    147153            # of defaulting to Type=ValueConv to allow reformatting to be applied
    148             'EXIF:DateTimeOriginal'     => 'delete $opts{Type}; $val',
    149             'EXIF:SubSecTimeOriginal'   => 'delete $opts{Type}; $val',
    150             'IPTC:DateCreated'          => '$opts{EditGroup} = 1; $val',
    151             'IPTC:TimeCreated'          => '$opts{EditGroup} = 1; $val',
    152             'XMP-photoshop:DateCreated' => '$val',
     154            'Composite:SubSecDateTimeOriginal'  => 'delete $opts{Type}; $val',
     155            'IPTC:DateCreated'                  => '$opts{EditGroup} = 1; $val',
     156            'IPTC:TimeCreated'                  => '$opts{EditGroup} = 1; $val',
     157            'XMP-photoshop:DateCreated'         => '$val',
    153158        },
    154159    },
    155160    CreateDate => {
    156161        Groups => { 2 => 'Time' },
    157         Notes => '"creation date of the digital representation" - MWG',
    158         Writable => 1,
    159         Desire => {
    160             0 => 'EXIF:CreateDate',
    161             1 => 'EXIF:SubSecTimeDigitized',
     162        Notes => '"specifies when an image was digitized" - MWG',
     163        Writable => 1,
     164        Shift => 0, # don't shift this tag
     165        Desire => {
     166            0 => 'Composite:SubSecCreateDate',
     167            1 => 'EXIF:CreateDate',
    162168            2 => 'IPTC:DigitalCreationDate',
    163169            3 => 'IPTC:DigitalCreationTime',
     
    166172            6 => 'IPTCDigest',
    167173        },
     174        RawConv => q{
     175            (defined $val[0] or defined $val[1] or $val[2] or
     176            (defined $val[4] and (not defined $val[5] or not defined $val[6]
     177            or $val[5] eq $val[6]))) ? $val : undef
     178        },
    168179        ValueConv => q{
    169             if (defined $val[0] and $val[0] !~ /^[: ]*$/) {
    170                 return ($val[1] and $val[1] !~ /^ *$/) ? "$val[0].$val[1]" : $val[0];
    171             }
     180            return $val[0] if defined $val[0] and $val[0] !~ /^[: ]*$/;
     181            return $val[1] if defined $val[1] and $val[1] !~ /^[: ]*$/;
    172182            return $val[4] if not defined $val[5] or (defined $val[4] and
    173183                             (not defined $val[6] or $val[5] eq $val[6]));
     
    180190        WriteCheck => 'Image::ExifTool::MWG::ReconcileIPTCDigest($self)',
    181191        WriteAlso  => {
    182             'EXIF:CreateDate'          => 'delete $opts{Type}; $val',
    183             'EXIF:SubSecTimeDigitized' => 'delete $opts{Type}; $val',
    184             'IPTC:DigitalCreationDate' => '$opts{EditGroup} = 1; $val',
    185             'IPTC:DigitalCreationTime' => '$opts{EditGroup} = 1; $val',
    186             'XMP-xmp:CreateDate'       => '$val',
     192            'Composite:SubSecCreateDate' => 'delete $opts{Type}; $val',
     193            'IPTC:DigitalCreationDate'   => '$opts{EditGroup} = 1; $val',
     194            'IPTC:DigitalCreationTime'   => '$opts{EditGroup} = 1; $val',
     195            'XMP-xmp:CreateDate'         => '$val',
    187196        },
    188197    },
    189198    ModifyDate => {
    190199        Groups => { 2 => 'Time' },
    191         Notes => '"modification date of the digital image file" - MWG',
    192         Writable => 1,
    193         Desire => {
    194             0 => 'EXIF:ModifyDate',
    195             1 => 'EXIF:SubSecTime',
     200        Notes => '"specifies when a file was modified by the user" - MWG',
     201        Writable => 1,
     202        Shift => 0, # don't shift this tag
     203        Desire => {
     204            0 => 'Composite:SubSecModifyDate',
     205            1 => 'EXIF:ModifyDate',
    196206            2 => 'XMP-xmp:ModifyDate',
    197207            3 => 'CurrentIPTCDigest',
    198208            4 => 'IPTCDigest',
    199209        },
    200         ValueConv => q{
    201             if (defined $val[0] and $val[0] !~ /^[: ]*$/) {
    202                 return ($val[1] and $val[1] !~ /^ *$/) ? "$val[0].$val[1]" : $val[0];
    203             }
     210        RawConv => q{
     211            return $val[0] if defined $val[0] and $val[0] !~ /^[: ]*$/;
     212            return $val[1] if defined $val[1] and $val[1] !~ /^[: ]*$/;
    204213            return $val[2] if not defined $val[3] or not defined $val[4] or $val[3] eq $val[4];
    205214            return undef;
     
    212221        WriteCheck => '""',
    213222        WriteAlso  => {
    214             'EXIF:ModifyDate'    => 'delete $opts{Type}; $val',
    215             'EXIF:SubSecTime'    => 'delete $opts{Type}; $val',
    216             'XMP-xmp:ModifyDate' => '$val',
     223            'Composite:SubSecModifyDate' => 'delete $opts{Type}; $val',
     224            'XMP-xmp:ModifyDate'         => '$val',
    217225        },
    218226    },
     
    248256            4 => 'IPTCDigest',
    249257        },
    250         ValueConv => q{
     258        RawConv => q{
    251259            return $val[0] if defined $val[0] and $val[0] !~ /^ *$/;
    252260            return $val[2] if not defined $val[3] or (defined $val[2] and
     
    257265        WriteCheck => 'Image::ExifTool::MWG::ReconcileIPTCDigest($self)',
    258266        WriteAlso  => {
    259             'EXIF:Copyright'       => '$val',
     267            'EXIF:Copyright' => q{
     268                # encode if necessary (not automatic because Format is 'undef')
     269                my $enc = $self->Options('CharsetEXIF');
     270                if ($enc) {
     271                    my $v = $val;
     272                    $self->Encode($v,$enc);
     273                    return $v;
     274                }
     275                return $val;
     276            },
    260277            'IPTC:CopyrightNotice' => '$opts{EditGroup} = 1; $val',
    261278            'XMP-dc:Rights'        => '$val',
     
    272289            4 => 'IPTCDigest',
    273290        },
    274         ValueConv => q{
     291        RawConv => q{
    275292            return $val[0] if defined $val[0] and $val[0] !~ /^ *$/;
    276293            return $val[2] if not defined $val[3] or (defined $val[2] and
     
    292309            0 => 'IPTC:Country-PrimaryLocationName', # (64-character limit)
    293310            1 => 'XMP-photoshop:Country',
    294             2 => 'CurrentIPTCDigest',
    295             3 => 'IPTCDigest',
    296         },
    297         ValueConv => q{
    298             return $val[1] if not defined $val[2] or (defined $val[1] and
    299                              (not defined $val[3] or $val[2] eq $val[3]));
    300             return Image::ExifTool::MWG::RecoverTruncatedIPTC($val[0], $val[1], 64);
     311            2 => 'XMP-iptcExt:LocationShownCountryName',
     312            3 => 'CurrentIPTCDigest',
     313            4 => 'IPTCDigest',
     314        },
     315        RawConv => q{
     316            my $xmpVal = $val[2] || $val[1];
     317            return $xmpVal if not defined $val[3] or (defined $xmpVal and
     318                             (not defined $val[4] or $val[3] eq $val[4]));
     319            return Image::ExifTool::MWG::RecoverTruncatedIPTC($val[0], $xmpVal, 64);
    301320        },
    302321        DelCheck   => 'Image::ExifTool::MWG::ReconcileIPTCDigest($self)',
     
    304323        WriteAlso  => {
    305324            'IPTC:Country-PrimaryLocationName' => '$opts{EditGroup} = 1; $val',
    306             'XMP-photoshop:Country'            => '$val',
     325            'XMP-photoshop:Country'            => '$val', # (legacy)
     326            'XMP-iptcExt:LocationShownCountryName' => '$val',
    307327        },
    308328    },
     
    313333            0 => 'IPTC:Province-State', # (32-character limit)
    314334            1 => 'XMP-photoshop:State',
    315             2 => 'CurrentIPTCDigest',
    316             3 => 'IPTCDigest',
    317         },
    318         ValueConv => q{
    319             return $val[1] if not defined $val[2] or (defined $val[1] and
    320                              (not defined $val[3] or $val[2] eq $val[3]));
    321             return Image::ExifTool::MWG::RecoverTruncatedIPTC($val[0], $val[1], 32);
     335            2 => 'XMP-iptcExt:LocationShownProvinceState',
     336            3 => 'CurrentIPTCDigest',
     337            4 => 'IPTCDigest',
     338        },
     339        RawConv => q{
     340            my $xmpVal = $val[2] || $val[1];
     341            return $xmpVal if not defined $val[3] or (defined $xmpVal and
     342                             (not defined $val[4] or $val[3] eq $val[4]));
     343            return Image::ExifTool::MWG::RecoverTruncatedIPTC($val[0], $xmpVal, 32);
    322344        },
    323345        DelCheck   => 'Image::ExifTool::MWG::ReconcileIPTCDigest($self)',
     
    325347        WriteAlso  => {
    326348            'IPTC:Province-State' => '$opts{EditGroup} = 1; $val',
    327             'XMP-photoshop:State' => '$val',
     349            'XMP-photoshop:State' => '$val', # (legacy)
     350            'XMP-iptcExt:LocationShownProvinceState' => '$val',
    328351        },
    329352    },
     
    334357            0 => 'IPTC:City', # (32-character limit)
    335358            1 => 'XMP-photoshop:City',
    336             2 => 'CurrentIPTCDigest',
    337             3 => 'IPTCDigest',
    338         },
    339         ValueConv => q{
    340             return $val[1] if not defined $val[2] or (defined $val[1] and
    341                              (not defined $val[3] or $val[2] eq $val[3]));
    342             return Image::ExifTool::MWG::RecoverTruncatedIPTC($val[0], $val[1], 32);
     359            2 => 'XMP-iptcExt:LocationShownCity',
     360            3 => 'CurrentIPTCDigest',
     361            4 => 'IPTCDigest',
     362        },
     363        RawConv => q{
     364            my $xmpVal = $val[2] || $val[1];
     365            return $xmpVal if not defined $val[3] or (defined $xmpVal and
     366                             (not defined $val[4] or $val[3] eq $val[4]));
     367            return Image::ExifTool::MWG::RecoverTruncatedIPTC($val[0], $xmpVal, 32);
    343368        },
    344369        DelCheck   => 'Image::ExifTool::MWG::ReconcileIPTCDigest($self)',
     
    346371        WriteAlso  => {
    347372            'IPTC:City'          => '$opts{EditGroup} = 1; $val',
    348             'XMP-photoshop:City' => '$val',
     373            'XMP-photoshop:City' => '$val', # (legacy)
     374            'XMP-iptcExt:LocationShownCity' => '$val',
    349375        },
    350376    },
     
    355381            0 => 'IPTC:Sub-location', # (32-character limit)
    356382            1 => 'XMP-iptcCore:Location',
    357             2 => 'CurrentIPTCDigest',
    358             3 => 'IPTCDigest',
    359         },
    360         ValueConv => q{
    361             return $val[1] if not defined $val[2] or (defined $val[1] and
    362                              (not defined $val[3] or $val[2] eq $val[3]));
    363             return Image::ExifTool::MWG::RecoverTruncatedIPTC($val[0], $val[1], 32);
     383            2 => 'XMP-iptcExt:LocationShownSublocation',
     384            3 => 'CurrentIPTCDigest',
     385            4 => 'IPTCDigest',
     386        },
     387        RawConv => q{
     388            my $xmpVal = $val[2] || $val[1];
     389            return $xmpVal if not defined $val[3] or (defined $xmpVal and
     390                             (not defined $val[4] or $val[3] eq $val[4]));
     391            return Image::ExifTool::MWG::RecoverTruncatedIPTC($val[0], $xmpVal, 32);
    364392        },
    365393        DelCheck   => 'Image::ExifTool::MWG::ReconcileIPTCDigest($self)',
     
    367395        WriteAlso  => {
    368396            'IPTC:Sub-location'     => '$opts{EditGroup} = 1; $val',
    369             'XMP-iptcCore:Location' => '$val',
     397            'XMP-iptcCore:Location' => '$val', # (legacy)
     398            'XMP-iptcExt:LocationShownSublocation' => '$val',
    370399        },
    371400    },
    372401);
    373402
    374 unless ($Image::ExifTool::documentOnly) {
     403# MWG XMP structures
     404my %sExtensions = (
     405    STRUCT_NAME => 'MWG Extensions',
     406    NAMESPACE   => undef, # variable namespace
     407    NOTES => q{
     408        This structure may contain any top-level XMP tags, but none have been
     409        pre-defined in ExifTool.  Since no flattened tags have been pre-defined,
     410        RegionExtensions is writable only as a structure (eg.
     411        C<{xmp-dc:creator=me,rating=5}>).  Fields for this structure are identified
     412        using the standard ExifTool tag name (with optional leading group name,
     413        and/or trailing language code, and/or trailing C<#> symbol to disable print
     414        conversion).
     415    },
     416);
     417my %sRegionStruct = (
     418    STRUCT_NAME => 'MWG RegionStruct',
     419    NAMESPACE   => 'mwg-rs',
     420    Area => { Struct => \%Image::ExifTool::XMP::sArea },
     421    Type => {
     422        PrintConv => {
     423            Face => 'Face',
     424            Pet => 'Pet',
     425            Focus => 'Focus',
     426            BarCode => 'BarCode',
     427        },
     428    },
     429    Name        => { },
     430    Description => { },
     431    FocusUsage  => {
     432        PrintConv => {
     433            EvaluatedUsed => 'Evaluated, Used',
     434            EvaluatedNotUsed => 'Evaluated, Not Used',
     435            NotEvaluatedNotUsed => 'Not Evaluated, Not Used',
     436        },
     437    },
     438    BarCodeValue=> { },
     439    Extensions  => { Struct => \%sExtensions },
     440    Rotation    => { # (observed in LR6 XMP)
     441        Writable => 'real',
     442        Notes => 'not part of MWG 2.0 spec',
     443    },
     444    seeAlso => { Namespace => 'rdfs', Resource => 1 },
     445);
     446my %sKeywordStruct;
     447%sKeywordStruct = (
     448    STRUCT_NAME => 'MWG KeywordStruct',
     449    NAMESPACE   => 'mwg-kw',
     450    Keyword   => { },
     451    Applied   => { Writable => 'boolean' },
     452    Children  => { Struct => \%sKeywordStruct, List => 'Bag' },
     453);
     454
     455# MWG 2.0 XMP region namespace tags
     456%Image::ExifTool::MWG::Regions = (
     457    %Image::ExifTool::XMP::xmpTableDefaults,
     458    GROUPS => { 0 => 'XMP', 1 => 'XMP-mwg-rs', 2 => 'Image' },
     459    NAMESPACE => 'mwg-rs',
     460    NOTES => q{
     461        Image region metadata defined by the MWG 2.0 specification.  These tags
     462        may be accessed without the need to load the MWG Composite tags above.  See
     463        L<https://web.archive.org/web/20181006115950/http://www.metadataworkinggroup.org/specs/>
     464        for the official specification.
     465    },
     466    Regions => {
     467        Name => 'RegionInfo',
     468        FlatName => 'Region',
     469        Struct => {
     470            STRUCT_NAME => 'MWG RegionInfo',
     471            NAMESPACE   => 'mwg-rs',
     472            RegionList => {
     473                FlatName => 'Region',
     474                Struct => \%sRegionStruct,
     475                List => 'Bag',
     476            },
     477            AppliedToDimensions => { Struct => \%Image::ExifTool::XMP::sDimensions },
     478        },
     479    },
     480    RegionsRegionList => { Flat => 1, Name => 'RegionList' },
     481);
     482
     483# MWG 2.0 XMP hierarchical keyword namespace tags
     484%Image::ExifTool::MWG::Keywords = (
     485    %Image::ExifTool::XMP::xmpTableDefaults,
     486    GROUPS => { 0 => 'XMP', 1 => 'XMP-mwg-kw', 2 => 'Image' },
     487    NAMESPACE => 'mwg-kw',
     488    NOTES => q{
     489        Hierarchical keywords metadata defined by the MWG 2.0 specification.
     490        ExifTool unrolls keyword structures to an arbitrary depth of 6 to allow
     491        individual levels to be accessed with different tag names, and to avoid
     492        infinite recursion.  See
     493        L<https://web.archive.org/web/20181006115950/http://www.metadataworkinggroup.org/specs/>
     494        for the official specification.
     495    },
     496    # arbitrarily define only the first 6 levels of the keyword hierarchy
     497    Keywords => {
     498        Name => 'KeywordInfo',
     499        Struct => {
     500            STRUCT_NAME => 'MWG KeywordInfo',
     501            NAMESPACE   => 'mwg-kw',
     502            Hierarchy => { Struct => \%sKeywordStruct, List => 'Bag' },
     503        },
     504    },
     505    KeywordsHierarchy => { Name => 'HierarchicalKeywords', Flat => 1 },
     506    KeywordsHierarchyKeyword  => { Name => 'HierarchicalKeywords1', Flat => 1 },
     507    KeywordsHierarchyApplied  => { Name => 'HierarchicalKeywords1Applied', Flat => 1 },
     508    KeywordsHierarchyChildren => { Name => 'HierarchicalKeywords1Children', Flat => 1 },
     509    KeywordsHierarchyChildrenKeyword  => { Name => 'HierarchicalKeywords2', Flat => 1 },
     510    KeywordsHierarchyChildrenApplied  => { Name => 'HierarchicalKeywords2Applied', Flat => 1 },
     511    KeywordsHierarchyChildrenChildren => { Name => 'HierarchicalKeywords2Children', Flat => 1 },
     512    KeywordsHierarchyChildrenChildrenKeyword  => { Name => 'HierarchicalKeywords3', Flat => 1 },
     513    KeywordsHierarchyChildrenChildrenApplied  => { Name => 'HierarchicalKeywords3Applied', Flat => 1 },
     514    KeywordsHierarchyChildrenChildrenChildren => { Name => 'HierarchicalKeywords3Children', Flat => 1 },
     515    KeywordsHierarchyChildrenChildrenChildrenKeyword  => { Name => 'HierarchicalKeywords4', Flat => 1 },
     516    KeywordsHierarchyChildrenChildrenChildrenApplied  => { Name => 'HierarchicalKeywords4Applied', Flat => 1 },
     517    KeywordsHierarchyChildrenChildrenChildrenChildren => { Name => 'HierarchicalKeywords4Children', Flat => 1 },
     518    KeywordsHierarchyChildrenChildrenChildrenChildrenKeyword  => { Name => 'HierarchicalKeywords5', Flat => 1 },
     519    KeywordsHierarchyChildrenChildrenChildrenChildrenApplied  => { Name => 'HierarchicalKeywords5Applied', Flat => 1 },
     520    KeywordsHierarchyChildrenChildrenChildrenChildrenChildren => { Name => 'HierarchicalKeywords5Children', Flat => 1, NoSubStruct => 1 }, # break infinite recursion
     521    KeywordsHierarchyChildrenChildrenChildrenChildrenChildrenKeyword => { Name => 'HierarchicalKeywords6', Flat => 1 },
     522    KeywordsHierarchyChildrenChildrenChildrenChildrenChildrenApplied => { Name => 'HierarchicalKeywords6Applied', Flat => 1 },
     523);
     524
     525# MWG 2.0 XMP collections namespace tags
     526%Image::ExifTool::MWG::Collections = (
     527    %Image::ExifTool::XMP::xmpTableDefaults,
     528    GROUPS => { 0 => 'XMP', 1 => 'XMP-mwg-coll', 2 => 'Image' },
     529    NAMESPACE => 'mwg-coll',
     530    NOTES => q{
     531        Collections metadata defined by the MWG 2.0 specification.  See
     532        L<https://web.archive.org/web/20181006115950/http://www.metadataworkinggroup.org/specs/>
     533        for the official specification.
     534    },
     535    Collections => {
     536        FlatName => '',
     537        List => 'Bag',
     538        Struct => {
     539            STRUCT_NAME => 'MWG CollectionInfo',
     540            NAMESPACE   => 'mwg-coll',
     541            CollectionName => { },
     542            CollectionURI  => { },
     543        },
     544    },
     545);
     546
     547
     548#------------------------------------------------------------------------------
     549# Load the MWG Composite tags
     550sub Load()
     551{
     552    return if $mwgLoaded;
     553
    375554    # add our composite tags
    376555    Image::ExifTool::AddCompositeTags('Image::ExifTool::MWG');
     
    379558    Image::ExifTool::AddTagsToLookup(\%Image::ExifTool::MWG::Composite,
    380559                                     'Image::ExifTool::Composite');
    381 }
    382 
    383 # modify EXIF:Artist to behave as a List-type tag
    384 {
     560
     561    # modify EXIF:Artist to behave as a list-type tag
    385562    my $artist = $Image::ExifTool::Exif::Main{0x13b};
    386563    $$artist{List} = 1;
    387564    $$artist{IsOverwriting} = \&OverwriteStringList;
    388565    $$artist{RawConv} = \&StringToList;
     566
     567    # enable MWG strict mode if not set already
     568    # (causes non-standard EXIF, IPTC and XMP to be ignored)
     569    $Image::ExifTool::MWG::strict = 1 unless defined $Image::ExifTool::MWG::strict;
     570
     571    $mwgLoaded = 1;
    389572}
    390573
     
    414597sub StringToList($$)
    415598{
    416     my ($str, $exifTool) = @_;
     599    my ($str, $et) = @_;
    417600    my (@vals, $inQuotes);
    418601    my @t = split '; ', $str, -1;
     
    433616        }
    434617    }
    435     $exifTool->Warn('Incorrectly quoted MWG string-list value') if $inQuotes;
     618    $et->Warn('Incorrectly quoted MWG string-list value') if $inQuotes;
    436619    return @vals > 1 ? \@vals : $vals[0];
    437620}
     
    439622#------------------------------------------------------------------------------
    440623# Handle logic for overwriting EXIF string-type list tag
    441 # Inputs: 0) new value hash ref, 1) new value hash ref,
     624# Inputs: 0) ExifTool ref, 1) new value hash ref,
    442625#         2) old string value (or undef if it didn't exist), 3) new value ref
    443626# Returns: 1 and sets the new value for the tag
     
    445628{
    446629    local $_;
    447     my ($exifTool, $nvHash, $val, $newValuePt) = @_;
     630    my ($et, $nvHash, $val, $newValuePt) = @_;
    448631    my (@new, $delIndex);
     632    my $writeMode = $et->Options('WriteMode');
     633    if ($writeMode ne 'wcg') {
     634        if (defined $val) {
     635            $writeMode =~ /w/i or return 0;
     636        } else {
     637            $writeMode =~ /c/i or return 0;
     638        }
     639    }
    449640    if ($$nvHash{DelValue} and defined $val) {
    450641        # preserve specified old values
    451         my $old = StringToList($val, $exifTool);
     642        my $old = StringToList($val, $et);
    452643        my @old = ref $old eq 'ARRAY' ? @$old : $old;
    453644        if (@{$$nvHash{DelValue}}) {
     
    485676sub ReconcileIPTCDigest($)
    486677{
    487     my $exifTool = shift;
     678    my $et = shift;
    488679
    489680    # set new value for IPTCDigest if not done already
    490681    unless ($Image::ExifTool::Photoshop::iptcDigestInfo and
    491             $exifTool->{NEW_VALUE}{$Image::ExifTool::Photoshop::iptcDigestInfo})
     682            $$et{NEW_VALUE}{$Image::ExifTool::Photoshop::iptcDigestInfo})
    492683    {
    493684        # write new IPTCDigest only if it doesn't exist or
    494685        # is the same as the digest of the original IPTC
    495686        my @a; # (capture warning messages)
    496         @a = $exifTool->SetNewValue('Photoshop:IPTCDigest', 'old', Protected => 1, DelValue => 1);
    497         @a = $exifTool->SetNewValue('Photoshop:IPTCDigest', 'new', Protected => 1);
     687        @a = $et->SetNewValue('Photoshop:IPTCDigest', 'old', Protected => 1, DelValue => 1);
     688        @a = $et->SetNewValue('Photoshop:IPTCDigest', 'new', Protected => 1);
    498689    }
    499690    return '';
     
    516707        }
    517708        return \@vals;
    518     } elsif (defined $iptc and length $iptc == $limit) {   
     709    } elsif (defined $iptc and length $iptc == $limit) {
    519710        $xmp = $$xmp[0] if ref $xmp;    # take first element of list
    520711        return $xmp if length $xmp > $limit and $iptc eq substr($xmp, 0, $limit);
     
    533724=head1 SYNOPSIS
    534725
    535     # enable MWG tags (strict mode enabled by default)
     726    # enable MWG Composite tags
    536727    use Image::ExifTool::MWG;
     728    Image::ExifTool::MWG::Load();
     729
     730    # enable MWG strict mode
     731    $Image::ExifTool::MWG::strict = 1;
    537732
    538733    # disable MWG strict mode
     
    541736=head1 DESCRIPTION
    542737
    543 The MWG module contains tag definitions which are designed to simplify
    544 implementation of the Metadata Working Group guidelines.  These special MWG
    545 composite tags are enabled simply by loading this module:
     738The MWG module contains Composite tag definitions which are designed to
     739simplify implementation of the Metadata Working Group guidelines.  These
     740special MWG Composite tags are enabled by calling the Load() method:
    546741
    547742    use Image::ExifTool::MWG;
    548 
    549 When the MWG module is loaded, "strict MWG conformance" is enabled by
    550 default.  In this mode, ExifTool will generate a Warning tag instead of
    551 extracting EXIF, IPTC and XMP from non-standard locations.  The strict mode
    552 may be disabled by setting the MWG "strict" flag to zero (either before or
    553 after loading the MWG module):
     743    Image::ExifTool::MWG::Load();
     744
     745By default, loading the MWG Composite tags enables "strict MWG conformance"
     746unless previously enabled or disabled by the user.  In this mode, ExifTool
     747will generate a Warning instead of extracting EXIF, IPTC and XMP from
     748non-standard locations.  The strict mode may be disabled or enabled at any
     749time by setting the MWG "strict" flag to 0 or 1.  eg)
    554750
    555751    $Image::ExifTool::MWG::strict = 0;
    556752
     753This module also contains the MWG XMP tags which are loaded automatically by
     754ExifTool as required, and are independent of the MWG Composite tags which
     755must be loaded explicitly as described above.
     756
    557757=head1 AUTHOR
    558758
    559 Copyright 2003-2011, Phil Harvey (phil at owl.phy.queensu.ca)
     759Copyright 2003-2021, Phil Harvey (philharvey66 at gmail.com)
    560760
    561761This library is free software; you can redistribute it and/or modify it
Note: See TracChangeset for help on using the changeset viewer.