exiftool_vendored 12.50.0 → 12.52.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -12,7 +12,7 @@ meta information extracted from or written to a file.
12
12
  =head1 TAG TABLES
13
13
 
14
14
  The tables listed below give the names of all tags recognized by ExifTool.
15
- They contain a total of 26027 tags, with 16663 unique tag names.
15
+ They contain a total of 26197 tags, with 16717 unique tag names.
16
16
 
17
17
  B<Tag ID>, B<Index#> or B<Sequence> is given in the first column of each
18
18
  table. A B<Tag ID> is the computer-readable equivalent of a tag name, and
@@ -14436,6 +14436,8 @@ These tags are extracted from encrypted data in images from the Z9.
14436
14436
  60143 PitchAngle fixed32u
14437
14437
  60147 YawAngle fixed32u
14438
14438
  60491 MenuSettingsZ9 Nikon MenuSettingsZ9
14439
+ -
14440
+ Nikon MenuSettingsZ9Firmware3
14439
14441
 
14440
14442
  =head3 Nikon MenuSettingsZ9 Tags
14441
14443
 
@@ -14513,6 +14515,79 @@ These tags are used by the Z9.
14513
14515
  1636 USBPowerDelivery? int8u
14514
14516
  1645 SensorShield? int8u
14515
14517
 
14518
+ =head3 Nikon MenuSettingsZ9Firmware3 Tags
14519
+
14520
+ These tags are used by the Z9 firmware 3.00.
14521
+
14522
+ Index1 Tag Name Writable
14523
+ --------------- --------
14524
+ 154 MultipleExposureMode int8u
14525
+ 156 MultiExposureShots int8u
14526
+ 204 Intervals int32u
14527
+ 208 ShotsPerInterval int32u
14528
+ 248 FocusShiftNumberShots int8u
14529
+ 252 FocusShiftStepWidth int8u
14530
+ 256 FocusShiftInterval int8u~
14531
+ 260 FocusShiftExposureLock? int8u
14532
+ 290 PhotoShootingMenuBank int8u
14533
+ 292 ExtendedMenuBanks int8u
14534
+ 328 PhotoShootingMenuBankImageArea int8u
14535
+ 342 AutoISO int8u
14536
+ 344 ISOAutoHiLimit? int16u
14537
+ 346 ISOAutoFlashLimit? int16u
14538
+ 354 ISOAutoShutterTime no
14539
+ 436 MovieVignetteControl? int8u
14540
+ 438 DiffractionCompensation int8u
14541
+ 440 FlickerReductionShooting int8u
14542
+ 548 AFAreaMode int8u
14543
+ 550 VRMode int8u
14544
+ 554 BracketSet int8u
14545
+ 556 BracketProgram int8u
14546
+ 558 BracketIncrement int8u
14547
+ 576 SecondarySlotFunction int8u
14548
+ 592 DXCropAlert int8u
14549
+ 594 SubjectDetection int8u
14550
+ 636 HighFrequencyFlickerReductionShooting? int8u
14551
+ 646 MovieImageArea? int8u & 0x01
14552
+ 656 MovieType? int8u
14553
+ 658 MovieISOAutoHiLimit? int16u
14554
+ 660 MovieISOAutoControlManualMode? int8u
14555
+ 662 MovieISOAutoManualMode? int16u
14556
+ 736 MovieActiveD-Lighting? int8u
14557
+ 738 MovieHighISONoiseReduction? int8u
14558
+ 744 MovieFlickerReduction int8u
14559
+ 746 MovieMeteringMode? int8u
14560
+ 748 MovieFocusMode? int8u
14561
+ 750 MovieAFAreaMode int8u
14562
+ 752 MovieVRMode? int8u
14563
+ 756 MovieElectronicVR? int8u
14564
+ 758 MovieSoundRecording? int8u
14565
+ 760 MicrophoneSensitivity? int8u
14566
+ 762 MicrophoneAttenuator? int8u
14567
+ 764 MicrophoneFrequencyResponse? int8u
14568
+ 766 WindNoiseReduction? int8u
14569
+ 788 MovieToneMap? int8u
14570
+ 794 MovieFrameSize? int8u
14571
+ 796 MovieFrameRate? int8u
14572
+ 802 MicrophoneJackPower? int8u
14573
+ 803 MovieDXCropAlert? int8u
14574
+ 804 MovieSubjectDetection? int8u
14575
+ 812 MovieHighResZoom? int8u
14576
+ 847 CustomSettingsZ9 NikonCustom SettingsZ9
14577
+ 1474 Language? int8u
14578
+ 1476 TimeZone int8u
14579
+ 1482 MonitorBrightness? int8u
14580
+ 1504 AFFineTune? int8u
14581
+ 1600 HDMIOutputResolution int8u
14582
+ 1613 SetClockFromLocationData? int8u
14583
+ 1620 AirplaneMode? int8u
14584
+ 1621 EmptySlotRelease? int8u
14585
+ 1656 EnergySavingMode? int8u
14586
+ 1680 RecordLocationData? int8u
14587
+ 1684 USBPowerDelivery? int8u
14588
+ 1693 SensorShield? int8u
14589
+ 1754 FocusShiftAutoReset? int8u
14590
+
14516
14591
  =head3 Nikon ShotInfo Tags
14517
14592
 
14518
14593
  This information is encrypted for ShotInfoVersion 02xx, and some tags are
@@ -16306,7 +16381,9 @@ Custom settings for the Z9.
16306
16381
  191 UseDialWithoutHold? int8u
16307
16382
  193 ReverseIndicators? int8u
16308
16383
  195 MovieFunc1Button int8u
16384
+ 199 MovieFunc2Button int8u
16309
16385
  203 MovieAF-OnButton int8u
16386
+ 215 MovieLensControlRing int8u
16310
16387
  217 MovieMultiSelector? int8u
16311
16388
  221 MovieAFSpeed int8u
16312
16389
  223 MovieAFSpeedApply int8u
@@ -23588,6 +23665,7 @@ writes only EXIF, IPTC and XMP tags in Jpeg2000 images.
23588
23665
  'bfil' BinaryFilter no
23589
23666
  'bidb' BinaryData no
23590
23667
  'bpcc' BitsPerComponent no
23668
+ 'c2sh' C2PASaltHash no
23591
23669
  'cbor' CBORData CBOR
23592
23670
  'cdef' ComponentDefinition no
23593
23671
  'cgrp' ColorGroup no
@@ -25710,6 +25788,7 @@ check if speed is more of a concern.
25710
25788
  'acTL' AnimationControl PNG AnimationControl
25711
25789
  'bKGD' BackgroundColor no
25712
25790
  'cHRM' PrimaryChromaticities PNG PrimaryChromaticities
25791
+ 'caBX' JUMBF Jpeg2000
25713
25792
  'dSIG' DigitalSignature no
25714
25793
  'eXIf' eXIf EXIF
25715
25794
  'fRAc' FractalParameters no
@@ -27543,64 +27622,64 @@ View Camera Motion Metadata of MP4 videos. See
27543
27622
  L<https://developers.google.com/streetview/publish/camm-spec> for the
27544
27623
  specification.
27545
27624
 
27546
- Index1 Tag Name Writable
27625
+ Tag ID Tag Name Writable
27547
27626
  ------ -------- --------
27548
- 4 AngleAxis no
27627
+ 0x0004 AngleAxis no
27549
27628
 
27550
27629
  =head3 QuickTime camm1 Tags
27551
27630
 
27552
- Index1 Tag Name Writable
27631
+ Tag ID Tag Name Writable
27553
27632
  ------ -------- --------
27554
- 4 PixelExposureTime no
27555
- 8 RollingShutterSkewTime no
27633
+ 0x0004 PixelExposureTime no
27634
+ 0x0008 RollingShutterSkewTime no
27556
27635
 
27557
27636
  =head3 QuickTime camm2 Tags
27558
27637
 
27559
- Index1 Tag Name Writable
27638
+ Tag ID Tag Name Writable
27560
27639
  ------ -------- --------
27561
- 4 AngularVelocity no
27640
+ 0x0004 AngularVelocity no
27562
27641
 
27563
27642
  =head3 QuickTime camm3 Tags
27564
27643
 
27565
- Index1 Tag Name Writable
27644
+ Tag ID Tag Name Writable
27566
27645
  ------ -------- --------
27567
- 4 Acceleration no
27646
+ 0x0004 Acceleration no
27568
27647
 
27569
27648
  =head3 QuickTime camm4 Tags
27570
27649
 
27571
- Index1 Tag Name Writable
27650
+ Tag ID Tag Name Writable
27572
27651
  ------ -------- --------
27573
- 4 Position no
27652
+ 0x0004 Position no
27574
27653
 
27575
27654
  =head3 QuickTime camm5 Tags
27576
27655
 
27577
- Index1 Tag Name Writable
27656
+ Tag ID Tag Name Writable
27578
27657
  ------ -------- --------
27579
- 4 GPSLatitude no
27580
- 12 GPSLongitude no
27581
- 20 GPSAltitude no
27658
+ 0x0004 GPSLatitude no
27659
+ 0x000c GPSLongitude no
27660
+ 0x0014 GPSAltitude no
27582
27661
 
27583
27662
  =head3 QuickTime camm6 Tags
27584
27663
 
27585
- Index1 Tag Name Writable
27664
+ Tag ID Tag Name Writable
27586
27665
  ------ -------- --------
27587
- 4 GPSDateTime no
27588
- 12 GPSMeasureMode no
27589
- 16 GPSLatitude no
27590
- 24 GPSLongitude no
27591
- 32 GPSAltitude no
27592
- 36 GPSHorizontalAccuracy no
27593
- 40 GPSVerticalAccuracy no
27594
- 44 GPSVelocityEast no
27595
- 48 GPSVelocityNorth no
27596
- 52 GPSVelocityUp no
27597
- 56 GPSSpeedAccuracy no
27666
+ 0x0004 GPSDateTime no
27667
+ 0x000c GPSMeasureMode no
27668
+ 0x0010 GPSLatitude no
27669
+ 0x0018 GPSLongitude no
27670
+ 0x0020 GPSAltitude no
27671
+ 0x0024 GPSHorizontalAccuracy no
27672
+ 0x0028 GPSVerticalAccuracy no
27673
+ 0x002c GPSVelocityEast no
27674
+ 0x0030 GPSVelocityNorth no
27675
+ 0x0034 GPSVelocityUp no
27676
+ 0x0038 GPSSpeedAccuracy no
27598
27677
 
27599
27678
  =head3 QuickTime camm7 Tags
27600
27679
 
27601
- Index1 Tag Name Writable
27680
+ Tag ID Tag Name Writable
27602
27681
  ------ -------- --------
27603
- 4 MagneticField no
27682
+ 0x0004 MagneticField no
27604
27683
 
27605
27684
  =head3 QuickTime marl Tags
27606
27685
 
@@ -27880,7 +27959,7 @@ QuickTimeHandler option may be set to 0 to avoid this.
27880
27959
  'pcst' Podcast int8s
27881
27960
  'perf' Performer string
27882
27961
  'pgap' PlayGap int8s
27883
- 'plID' PlayListID int32s[0.25]
27962
+ 'plID' PlayListID int32s[2]
27884
27963
  'prID' ProductID string
27885
27964
  'purd' PurchaseDate string
27886
27965
  'purl' PodcastURL string
@@ -30319,7 +30398,7 @@ Matroska specification.
30319
30398
  0x037e ChapterCountry no
30320
30399
  0x0444 SegmentFamily? no
30321
30400
  0x0461 DateTimeOriginal no
30322
- 0x047a TagLanguage no
30401
+ 0x047a TagLanguageBCP47 no
30323
30402
  0x0484 TagDefault no
30324
30403
  0x0485 TagBinary no
30325
30404
  0x0487 TagString no
@@ -30377,10 +30456,10 @@ Matroska specification.
30377
30456
  0x23a2 CodecPrivate? no
30378
30457
  0x23c0 Targets Matroska
30379
30458
  0x23c3 ChapterPhysicalEquivalent no
30380
- 0x23c4 TagChapterUID? no
30381
- 0x23c5 TagTrackUID? no
30382
- 0x23c6 TagAttachmentUID? no
30383
- 0x23c9 TagEditionUID? no
30459
+ 0x23c4 TagChapterUID no
30460
+ 0x23c5 TagTrackUID no
30461
+ 0x23c6 TagAttachmentUID no
30462
+ 0x23c9 TagEditionUID no
30384
30463
  0x23ca TargetType no
30385
30464
  0x2532 SignedElement? no
30386
30465
  0x2624 TrackTranslate Matroska
@@ -30408,7 +30487,7 @@ Matroska specification.
30408
30487
  0x3384 SegmentFileName no
30409
30488
  0x33a4 SegmentUID? no
30410
30489
  0x33c4 ChapterUID? no
30411
- 0x33c5 TrackUID? no
30490
+ 0x33c5 TrackUID no
30412
30491
  0x3446 TrackAttachmentUID no
30413
30492
  0x35a1 BlockAdditions Matroska
30414
30493
  0x38b5 OutputAudioSampleRate no
@@ -30468,6 +30547,116 @@ for the specification.
30468
30547
  0x7674 ProjectionPosePitch no
30469
30548
  0x7675 ProjectionPoseRoll no
30470
30549
 
30550
+ =head3 Matroska Tags
30551
+
30552
+ Standardized Matroska tags (see
30553
+ L<https://www.matroska.org/technical/tagging.html>).
30554
+
30555
+ Tag ID Tag Name Writable
30556
+ ------ -------- --------
30557
+ 'ACCOMPANIMENT' Accompaniment no
30558
+ 'ACTOR' Actor no
30559
+ 'ADDRESS' Address no
30560
+ 'ARRANGER' Arranger no
30561
+ 'ARTIST' Artist no
30562
+ 'ART_DIRECTOR' ArtDirector no
30563
+ 'ASSISTANT_DIRECTOR' AssistantDirector no
30564
+ 'BARCODE' Barcode no
30565
+ 'BPM' BPM no
30566
+ 'BPS' BPS no
30567
+ 'CATALOG_NUMBER' CatalogNumber no
30568
+ 'CHARACTER' Character no
30569
+ 'CHOREGRAPHER' Choregrapher no
30570
+ 'COMMENT' Comment no
30571
+ 'COMPOSER' Composer no
30572
+ 'COMPOSER_NATIONALITY' ComposerNationality no
30573
+ 'COMPOSITION_LOCATION' CompositionLocation no
30574
+ 'CONDUCTOR' Conductor no
30575
+ 'CONTENT_TYPE' ContentType no
30576
+ 'COPRODUCER' Coproducer no
30577
+ 'COPYRIGHT' Copyright no
30578
+ 'COSTUME_DESIGNER' CostumeDesigner no
30579
+ 'COUNTRY' Country no
30580
+ 'DATE_DIGITIZED' CreateDate no
30581
+ 'DATE_ENCODED' DateEncoded no
30582
+ 'DATE_PURCHASED' DatePurchased no
30583
+ 'DATE_RECORDED' DateTimeOriginal no
30584
+ 'DATE_RELEASED' DateReleased no
30585
+ 'DATE_TAGGED' DateTagged no
30586
+ 'DATE_WRITTEN' DateWritten no
30587
+ 'DESCRIPTION' Description no
30588
+ 'DIRECTOR' Director no
30589
+ 'DIRECTOR_OF_PHOTOGRAPHY'
30590
+ DirectorOfPhotography no
30591
+ 'DISTRIBUTED_BY' DistributedBy no
30592
+ 'EDITED_BY' EditedBy no
30593
+ 'EMAIL' Email no
30594
+ 'ENCODED_BY' EncodedBy no
30595
+ 'ENCODER' Encoder no
30596
+ 'ENCODER_SETTINGS' EncoderSettings no
30597
+ 'EXECUTIVE_PRODUCER' ExecutiveProducer no
30598
+ 'FAX' FAX no
30599
+ 'FPS' FPS no
30600
+ 'GENRE' Genre no
30601
+ 'IMDB' IMDB no
30602
+ 'INITIAL_KEY' InitialKey no
30603
+ 'INSTRUMENTS' Instruments no
30604
+ 'ISBN' ISBN no
30605
+ 'ISRC' ISRC no
30606
+ 'KEYWORDS' Keywords no
30607
+ 'LABEL' Label no
30608
+ 'LABEL_CODE' LabelCode no
30609
+ 'LAW_RATING' LawRating no
30610
+ 'LCCN' Lccn no
30611
+ 'LEAD_PERFORMER' LeadPerformer no
30612
+ 'LICENSE' License no
30613
+ 'LYRICIST' Lyricist no
30614
+ 'LYRICS' Lyrics no
30615
+ 'MASTERED_BY' MasteredBy no
30616
+ 'MCDI' MCDI no
30617
+ 'MEASURE' Measure no
30618
+ 'MIXED_BY' MixedBy no
30619
+ 'MOOD' Mood no
30620
+ 'ORIGINAL' Original no
30621
+ 'ORIGINAL_MEDIA_TYPE' OriginalMediaType no
30622
+ 'PART_NUMBER' PartNumber no
30623
+ 'PART_OFFSET' PartOffset no
30624
+ 'PERIOD' Period no
30625
+ 'PHONE' Phone no
30626
+ 'PLAY_COUNTER' PlayCounter no
30627
+ 'PRODUCER' Producer no
30628
+ 'PRODUCTION_COPYRIGHT' ProductionCopyright no
30629
+ 'PRODUCTION_DESIGNER' ProductionDesigner no
30630
+ 'PRODUCTION_STUDIO' ProductionStudio no
30631
+ 'PUBLISHER' Publisher no
30632
+ 'PURCHASE_CURRENCY' PurchaseCurrency no
30633
+ 'PURCHASE_INFO' PurchaseInfo no
30634
+ 'PURCHASE_ITEM' PurchaseItem no
30635
+ 'PURCHASE_OWNER' PurchaseOwner no
30636
+ 'PURCHASE_PRICE' PurchasePrice no
30637
+ 'RATING' Rating no
30638
+ 'RECORDING_LOCATION' RecordingLocation no
30639
+ 'REMIXED_BY' RemixedBy no
30640
+ 'REPLAYGAIN_GAIN' ReplaygainGain no
30641
+ 'REPLAYGAIN_PEAK' ReplaygainPeak no
30642
+ 'SAMPLE' Sample no
30643
+ 'SCREENPLAY_BY' ScreenplayBy no
30644
+ 'SORT_WITH' SortWith no
30645
+ 'SOUND_ENGINEER' SoundEngineer no
30646
+ 'SUBJECT' Subject no
30647
+ 'SUBTITLE' Subtitle no
30648
+ 'SUMMARY' Summary no
30649
+ 'SYNOPSIS' Synopsis no
30650
+ 'TERMS_OF_USE' TermsOfUse no
30651
+ 'THANKS_TO' ThanksTo no
30652
+ 'TITLE' Title no
30653
+ 'TMDB' TMDB no
30654
+ 'TOTAL_PARTS' TotalParts no
30655
+ 'TUNING' Tuning no
30656
+ 'TVDB' TVDB no
30657
+ 'URL' URL no
30658
+ 'WRITTEN_BY' WrittenBy no
30659
+
30471
30660
  =head2 MOI Tags
30472
30661
 
30473
30662
  MOI files store information about associated MOD or TOD files, and are
@@ -37487,6 +37676,7 @@ FileName.
37487
37676
  ProcessingTime ExifTool no
37488
37677
  RAFVersion File no
37489
37678
  ResourceForkSize System no
37679
+ SphericalVideoXML GSpherical yes!
37490
37680
  SymLink - yes!
37491
37681
  TestName - yes!
37492
37682
  ThumbnailImage File no
@@ -306,14 +306,17 @@ sub CheckQTValue($$$)
306
306
 
307
307
  #------------------------------------------------------------------------------
308
308
  # Format QuickTime value for writing
309
- # Inputs: 0) ExifTool ref, 1) value ref, 2) Format (or undef), 3) Writable (or undef)
310
- # Returns: Flags for QT data type, and reformats value as required
309
+ # Inputs: 0) ExifTool ref, 1) value ref, 2) tagInfo ref, 3) Format (or undef)
310
+ # Returns: Flags for QT data type, and reformats value as required (sets to undef on error)
311
311
  sub FormatQTValue($$;$$)
312
312
  {
313
- my ($et, $valPt, $format, $writable) = @_;
313
+ my ($et, $valPt, $tagInfo, $format) = @_;
314
+ my $writable = $$tagInfo{Writable};
315
+ my $count = $$tagInfo{Count};
314
316
  my $flags;
317
+ $format or $format = $$tagInfo{Format};
315
318
  if ($format and $format ne 'string' or not $format and $writable and $writable ne 'string') {
316
- $$valPt = WriteValue($$valPt, $format || $writable);
319
+ $$valPt = WriteValue($$valPt, $format || $writable, $count);
317
320
  if ($writable and $qtFormat{$writable}) {
318
321
  $flags = $qtFormat{$writable};
319
322
  } else {
@@ -329,6 +332,7 @@ sub FormatQTValue($$;$$)
329
332
  $flags = 0x01; # UTF8
330
333
  $$valPt = $et->Encode($$valPt, 'UTF8');
331
334
  }
335
+ defined $$valPt or $et->WarnOnce("Error converting value for $$tagInfo{Name}");
332
336
  return $flags;
333
337
  }
334
338
 
@@ -1139,7 +1143,7 @@ sub WriteQuickTime($$$)
1139
1143
  my $newVal = $et->GetNewValue($nvHash);
1140
1144
  next unless defined $newVal;
1141
1145
  my $prVal = $newVal;
1142
- my $flags = FormatQTValue($et, \$newVal, $format, $$tagInfo{Writable});
1146
+ my $flags = FormatQTValue($et, \$newVal, $tagInfo, $format);
1143
1147
  next unless defined $newVal;
1144
1148
  my ($ctry, $lang) = (0, 0);
1145
1149
  if ($$ti{LangCode}) {
@@ -1220,7 +1224,8 @@ sub WriteQuickTime($$$)
1220
1224
  }
1221
1225
  my $prVal = $newVal;
1222
1226
  # format new value for writing (and get new flags)
1223
- $flags = FormatQTValue($et, \$newVal, $format, $$tagInfo{Writable});
1227
+ $flags = FormatQTValue($et, \$newVal, $tagInfo, $format);
1228
+ next unless defined $newVal;
1224
1229
  my $grp = $et->GetGroup($langInfo, 1);
1225
1230
  $et->VerboseValue("- $grp:$$langInfo{Name}", $val);
1226
1231
  $et->VerboseValue("+ $grp:$$langInfo{Name}", $prVal);
@@ -1463,7 +1468,7 @@ sub WriteQuickTime($$$)
1463
1468
  my $newVal = $et->GetNewValue($nvHash);
1464
1469
  next unless defined $newVal;
1465
1470
  my $prVal = $newVal;
1466
- my $flags = FormatQTValue($et, \$newVal, $$tagInfo{Format}, $$tagInfo{Writable});
1471
+ my $flags = FormatQTValue($et, \$newVal, $tagInfo);
1467
1472
  next unless defined $newVal;
1468
1473
  my ($ctry, $lang) = (0, 0);
1469
1474
  # handle alternate languages
@@ -561,7 +561,21 @@ sub AddStructType($$$$;$)
561
561
  }
562
562
 
563
563
  #------------------------------------------------------------------------------
564
- # Hack to use XMP writer for SphericalVideoXML
564
+ # Process SphericalVideoXML (see XMP-GSpherical tags documentation)
565
+ # Inputs: 0) ExifTool ref, 1) dirInfo ref, 2) tag table ref
566
+ # Returns: SphericalVideoXML data
567
+ sub ProcessGSpherical($$$)
568
+ {
569
+ my ($et, $dirInfo, $tagTablePtr) = @_;
570
+ # extract SphericalVideoXML as a block if requested
571
+ if ($$et{REQ_TAG_LOOKUP}{sphericalvideoxml}) {
572
+ $et->FoundTag(SphericalVideoXML => substr(${$$dirInfo{DataPt}}, 16));
573
+ }
574
+ return Image::ExifTool::XMP::ProcessXMP($et, $dirInfo, $tagTablePtr);
575
+ }
576
+
577
+ #------------------------------------------------------------------------------
578
+ # Hack to use XMP writer for SphericalVideoXML (see XMP-GSpherical tags documentation)
565
579
  # Inputs: 0) ExifTool ref, 1) dirInfo ref, 2) tag table ref
566
580
  # Returns: SphericalVideoXML data
567
581
  sub WriteGSpherical($$$)
@@ -707,9 +707,13 @@ TAG: foreach $tagInfo (@matchingTags) {
707
707
  $writeGroup or $writeGroup = $group0;
708
708
  # get priority for this group
709
709
  unless ($priority) {
710
- $priority = $$self{WRITE_PRIORITY}{lc($writeGroup)};
711
- unless ($priority) {
712
- $priority = $$self{WRITE_PRIORITY}{lc($group0)} || 0;
710
+ if ($$tagInfo{Avoid} and $$tagInfo{WriteAlso}) {
711
+ $priority = 0;
712
+ } else {
713
+ $priority = $$self{WRITE_PRIORITY}{lc($writeGroup)};
714
+ unless ($priority) {
715
+ $priority = $$self{WRITE_PRIORITY}{lc($group0)} || 0;
716
+ }
713
717
  }
714
718
  }
715
719
  # adjust priority based on Preferred level for this tag
@@ -830,6 +834,8 @@ TAG: foreach $tagInfo (@matchingTags) {
830
834
  $tag = $$tagInfo{Name}; # get tag name for warnings
831
835
  my $lcTag = lc $tag;
832
836
  my $pref = $preferred{$lcTag} || { };
837
+ # don't write Avoid-ed tags with side effect unless preferred
838
+ next if not $$pref{$tagInfo} and $$tagInfo{Avoid} and $$tagInfo{WriteAlso};
833
839
  my $shift = $options{Shift};
834
840
  my $addValue = $options{AddValue};
835
841
  if (defined $shift) {
@@ -971,6 +977,7 @@ TAG: foreach $tagInfo (@matchingTags) {
971
977
  $self->GetNewValueHash($tagInfo, $writeGroup, 'delete', $options{ProtectSaved});
972
978
  # also delete related tag previous new values
973
979
  if ($$tagInfo{WriteAlso}) {
980
+ $$self{INDENT2} = '+';
974
981
  my ($wgrp, $wtag);
975
982
  if ($$tagInfo{WriteGroup} and $$tagInfo{WriteGroup} eq 'All' and $writeGroup) {
976
983
  $wgrp = $writeGroup . ':';
@@ -981,6 +988,7 @@ TAG: foreach $tagInfo (@matchingTags) {
981
988
  my ($n,$e) = $self->SetNewValue($wgrp . $wtag, undef, Replace=>2);
982
989
  $numSet += $n;
983
990
  }
991
+ $$self{INDENT2} = '';
984
992
  }
985
993
  $options{Replace} == 2 and ++$numSet, next;
986
994
  }
@@ -1022,7 +1030,7 @@ TAG: foreach $tagInfo (@matchingTags) {
1022
1030
  require 'Image/ExifTool/XMPStruct.pl';
1023
1031
  $_ = Image::ExifTool::XMP::SerializeStruct($_);
1024
1032
  }
1025
- print $out "$verb $wgrp1:$tag$fromList if value is '${_}'\n";
1033
+ print $out "$$self{INDENT2}$verb $wgrp1:$tag$fromList if value is '${_}'\n";
1026
1034
  }
1027
1035
  }
1028
1036
  }
@@ -1086,15 +1094,25 @@ TAG: foreach $tagInfo (@matchingTags) {
1086
1094
  push @{$$nvHash{Value}}, ref $val eq 'ARRAY' ? @$val : $val;
1087
1095
  }
1088
1096
  if ($verbose > 1) {
1089
- my $ifExists = $$nvHash{IsCreating} ? ( $createOnly ?
1090
- ($$nvHash{IsCreating} == 2 ?
1091
- " if $writeGroup exists and tag doesn't" :
1092
- " if tag doesn't exist") :
1093
- ($$nvHash{IsCreating} == 2 ? " if $writeGroup exists" : '')) :
1097
+ my $ifExists;
1098
+ if ($$tagInfo{IsComposite}) {
1099
+ # (composite tags don't technically exist in the file)
1100
+ if ($$tagInfo{WriteAlso}) {
1101
+ $ifExists = ' (+' . join(',+',sort keys %{$$tagInfo{WriteAlso}}) . '):';
1102
+ } else {
1103
+ $ifExists = '';
1104
+ }
1105
+ } else {
1106
+ $ifExists = $$nvHash{IsCreating} ? ( $createOnly ?
1107
+ ($$nvHash{IsCreating} == 2 ?
1108
+ " if $writeGroup exists and tag doesn't" :
1109
+ " if tag doesn't exist") :
1110
+ ($$nvHash{IsCreating} == 2 ? " if $writeGroup exists" : '')) :
1094
1111
  (($$nvHash{DelValue} and @{$$nvHash{DelValue}}) ?
1095
- ' if tag was deleted' : ' if tag exists');
1112
+ ' if tag was deleted' : ' if tag exists');
1113
+ }
1096
1114
  my $verb = ($shift ? 'Shifting' : ($addValue ? 'Adding' : 'Writing'));
1097
- print $out "$verb $wgrp1:$tag$ifExists\n";
1115
+ print $out "$$self{INDENT2}$verb $wgrp1:$tag$ifExists\n";
1098
1116
  }
1099
1117
  }
1100
1118
  } elsif ($permanent) {
@@ -1109,7 +1127,7 @@ TAG: foreach $tagInfo (@matchingTags) {
1109
1127
  $self->GetNewValueHash($tagInfo, $writeGroup, 'delete');
1110
1128
  my $nvHash = $self->GetNewValueHash($tagInfo, $writeGroup, 'create');
1111
1129
  $$nvHash{WantGroup} = $wantGroup;
1112
- $verbose > 1 and print $out "Deleting $wgrp1:$tag\n";
1130
+ $verbose > 1 and print $out "$$self{INDENT2}Deleting $wgrp1:$tag\n";
1113
1131
  }
1114
1132
  $$setTags{$tagInfo} = 1 if $setTags;
1115
1133
  $prioritySet = 1 if $$pref{$tagInfo};
@@ -1118,6 +1136,7 @@ WriteAlso:
1118
1136
  # also write related tags
1119
1137
  my $writeAlso = $$tagInfo{WriteAlso};
1120
1138
  if ($writeAlso) {
1139
+ $$self{INDENT2} = '+'; # indicate related tag with a leading "+"
1121
1140
  my ($wgrp, $wtag, $n);
1122
1141
  if ($$tagInfo{WriteGroup} and $$tagInfo{WriteGroup} eq 'All' and $writeGroup) {
1123
1142
  $wgrp = $writeGroup . ':';
@@ -1137,7 +1156,7 @@ WriteAlso:
1137
1156
  SetTags => \%alsoWrote, # remember tags already written
1138
1157
  );
1139
1158
  undef $evalWarning;
1140
- #### eval WriteAlso ($val)
1159
+ #### eval WriteAlso ($val,%opts)
1141
1160
  my $v = eval $$writeAlso{$wtag};
1142
1161
  # we wanted to do the eval in case there are side effect, but we
1143
1162
  # don't want to write a value for a tag that is being deleted:
@@ -1159,6 +1178,7 @@ WriteAlso:
1159
1178
  }
1160
1179
  }
1161
1180
  }
1181
+ $$self{INDENT2} = '';
1162
1182
  }
1163
1183
  }
1164
1184
  # print warning if we couldn't set our priority tag
@@ -19,7 +19,7 @@ use strict;
19
19
  use vars qw($VERSION $warnString);
20
20
  use Image::ExifTool qw(:DataAccess :Utils);
21
21
 
22
- $VERSION = '1.27';
22
+ $VERSION = '1.28';
23
23
 
24
24
  sub WarnProc($) { $warnString = $_[0]; }
25
25
 
@@ -385,6 +385,18 @@ sub HandleMember($$;$)
385
385
  $et->HandleTag($tagTablePtr, '_com', $com) if defined $com and length $com;
386
386
  }
387
387
 
388
+ #------------------------------------------------------------------------------
389
+ # Extract file from ZIP archive
390
+ # Inputs: 0) ExifTool ref, 1) Zip object ref, 2) file name
391
+ # Returns: zip member or undef it it didn't exist
392
+ sub ExtractFile($$$)
393
+ {
394
+ my ($et, $zip, $file) = @_;
395
+ my $result = $zip->memberNamed($file);
396
+ $et->VPrint(1, " (Extracting '${file}' from zip archive)\n");
397
+ return $result;
398
+ }
399
+
388
400
  #------------------------------------------------------------------------------
389
401
  # Extract information from a ZIP file
390
402
  # Inputs: 0) ExifTool object reference, 1) dirInfo reference
@@ -460,7 +472,7 @@ sub ProcessZIP($$)
460
472
  # check for an Office Open file (DOCX, etc)
461
473
  # --> read '[Content_Types].xml' to determine the file type
462
474
  my ($mime, @members);
463
- my $cType = $zip->memberNamed('[Content_Types].xml');
475
+ my $cType = ExtractFile($et, $zip, '[Content_Types].xml');
464
476
  if ($cType) {
465
477
  ($buff, $status) = $zip->contents($cType);
466
478
  if (not $status and (
@@ -501,7 +513,7 @@ sub ProcessZIP($$)
501
513
  }
502
514
 
503
515
  # check for an Open Document, IDML or EPUB file
504
- my $mType = $zip->memberNamed('mimetype');
516
+ my $mType = ExtractFile($et, $zip, 'mimetype');
505
517
  if ($mType) {
506
518
  ($mime, $status) = $zip->contents($mType);
507
519
  if (not $status and $mime =~ /([\x21-\xfe]+)/s) {
@@ -510,9 +522,9 @@ sub ProcessZIP($$)
510
522
  $et->SetFileType($openDocType{$mime} || 'ZIP', $mime);
511
523
  $et->Warn("Unrecognized MIMEType $mime") unless $openDocType{$mime};
512
524
  # extract Open Document metadata from "meta.xml"
513
- my $meta = $zip->memberNamed('meta.xml');
525
+ my $meta = ExtractFile($et, $zip, 'meta.xml');
514
526
  # IDML files have metadata in a different place (ref 6)
515
- $meta or $meta = $zip->memberNamed('META-INF/metadata.xml');
527
+ $meta or $meta = ExtractFile($et, $zip, 'META-INF/metadata.xml');
516
528
  if ($meta) {
517
529
  ($buff, $status) = $zip->contents($meta);
518
530
  unless ($status) {
@@ -532,7 +544,7 @@ sub ProcessZIP($$)
532
544
  # process rootfile of EPUB container if applicable
533
545
  for (;;) {
534
546
  last if $meta and $mime ne 'application/epub+zip';
535
- my $container = $zip->memberNamed('META-INF/container.xml');
547
+ my $container = ExtractFile($et, $zip, 'META-INF/container.xml');
536
548
  ($buff, $status) = $zip->contents($container);
537
549
  last if $status;
538
550
  $buff =~ /<rootfile\s+[^>]*?\bfull-path=(['"])(.*?)\1/s or last;
@@ -570,7 +582,7 @@ sub ProcessZIP($$)
570
582
  my $type;
571
583
  my %tag = ( jpg => 'PreviewImage', png => 'PreviewPNG' );
572
584
  foreach $type ('jpg', 'png') {
573
- my $thumb = $zip->memberNamed("Thumbnails/thumbnail.$type");
585
+ my $thumb = ExtractFile($et, $zip, "Thumbnails/thumbnail.$type");
574
586
  next unless $thumb;
575
587
  ($buff, $status) = $zip->contents($thumb);
576
588
  $et->FoundTag($tag{$type}, $buff) unless $status;