exiftool_vendored 13.08.0 → 13.12.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (213) hide show
  1. checksums.yaml +4 -4
  2. data/bin/Changes +60 -2
  3. data/bin/MANIFEST +2 -0
  4. data/bin/META.json +1 -1
  5. data/bin/META.yml +1 -1
  6. data/bin/README +3 -3
  7. data/bin/exiftool +229 -158
  8. data/bin/lib/File/RandomAccess.pm +1 -1
  9. data/bin/lib/File/RandomAccess.pod +2 -2
  10. data/bin/lib/Image/ExifTool/AAC.pm +1 -1
  11. data/bin/lib/Image/ExifTool/AES.pm +1 -1
  12. data/bin/lib/Image/ExifTool/AFCP.pm +1 -1
  13. data/bin/lib/Image/ExifTool/AIFF.pm +1 -1
  14. data/bin/lib/Image/ExifTool/APE.pm +1 -1
  15. data/bin/lib/Image/ExifTool/APP12.pm +1 -1
  16. data/bin/lib/Image/ExifTool/ASF.pm +1 -1
  17. data/bin/lib/Image/ExifTool/Apple.pm +10 -8
  18. data/bin/lib/Image/ExifTool/Audible.pm +1 -1
  19. data/bin/lib/Image/ExifTool/BMP.pm +1 -1
  20. data/bin/lib/Image/ExifTool/BPG.pm +1 -1
  21. data/bin/lib/Image/ExifTool/BZZ.pm +1 -1
  22. data/bin/lib/Image/ExifTool/BigTIFF.pm +1 -1
  23. data/bin/lib/Image/ExifTool/BuildTagLookup.pm +14 -6
  24. data/bin/lib/Image/ExifTool/CBOR.pm +1 -1
  25. data/bin/lib/Image/ExifTool/Canon.pm +8 -4
  26. data/bin/lib/Image/ExifTool/CanonCustom.pm +1 -1
  27. data/bin/lib/Image/ExifTool/CanonRaw.pm +1 -1
  28. data/bin/lib/Image/ExifTool/CanonVRD.pm +1 -1
  29. data/bin/lib/Image/ExifTool/CaptureOne.pm +1 -1
  30. data/bin/lib/Image/ExifTool/Casio.pm +1 -1
  31. data/bin/lib/Image/ExifTool/Charset.pm +1 -1
  32. data/bin/lib/Image/ExifTool/DICOM.pm +1 -1
  33. data/bin/lib/Image/ExifTool/DJI.pm +96 -45
  34. data/bin/lib/Image/ExifTool/DNG.pm +1 -1
  35. data/bin/lib/Image/ExifTool/DPX.pm +1 -1
  36. data/bin/lib/Image/ExifTool/DV.pm +1 -1
  37. data/bin/lib/Image/ExifTool/DarwinCore.pm +1 -1
  38. data/bin/lib/Image/ExifTool/DjVu.pm +1 -1
  39. data/bin/lib/Image/ExifTool/EXE.pm +123 -32
  40. data/bin/lib/Image/ExifTool/Exif.pm +7 -4
  41. data/bin/lib/Image/ExifTool/FITS.pm +1 -1
  42. data/bin/lib/Image/ExifTool/FLAC.pm +1 -1
  43. data/bin/lib/Image/ExifTool/FLIF.pm +1 -1
  44. data/bin/lib/Image/ExifTool/FLIR.pm +1 -1
  45. data/bin/lib/Image/ExifTool/Fixup.pm +1 -1
  46. data/bin/lib/Image/ExifTool/Flash.pm +1 -1
  47. data/bin/lib/Image/ExifTool/FlashPix.pm +1 -1
  48. data/bin/lib/Image/ExifTool/Font.pm +1 -1
  49. data/bin/lib/Image/ExifTool/FotoStation.pm +1 -1
  50. data/bin/lib/Image/ExifTool/FujiFilm.pm +1 -1
  51. data/bin/lib/Image/ExifTool/GE.pm +1 -1
  52. data/bin/lib/Image/ExifTool/GIF.pm +1 -1
  53. data/bin/lib/Image/ExifTool/GIMP.pm +1 -1
  54. data/bin/lib/Image/ExifTool/GM.pm +1 -1
  55. data/bin/lib/Image/ExifTool/GPS.pm +1 -1
  56. data/bin/lib/Image/ExifTool/GeoTiff.pm +1 -1
  57. data/bin/lib/Image/ExifTool/Geolocation.dat +0 -0
  58. data/bin/lib/Image/ExifTool/Geolocation.pm +1 -1
  59. data/bin/lib/Image/ExifTool/Geotag.pm +1 -1
  60. data/bin/lib/Image/ExifTool/GoPro.pm +1 -1
  61. data/bin/lib/Image/ExifTool/H264.pm +1 -1
  62. data/bin/lib/Image/ExifTool/HP.pm +1 -1
  63. data/bin/lib/Image/ExifTool/HTML.pm +1 -1
  64. data/bin/lib/Image/ExifTool/HtmlDump.pm +1 -1
  65. data/bin/lib/Image/ExifTool/ICC_Profile.pm +81 -2
  66. data/bin/lib/Image/ExifTool/ICO.pm +1 -1
  67. data/bin/lib/Image/ExifTool/ID3.pm +1 -1
  68. data/bin/lib/Image/ExifTool/IPTC.pm +8 -5
  69. data/bin/lib/Image/ExifTool/ISO.pm +1 -1
  70. data/bin/lib/Image/ExifTool/ITC.pm +1 -1
  71. data/bin/lib/Image/ExifTool/Import.pm +5 -4
  72. data/bin/lib/Image/ExifTool/InDesign.pm +1 -1
  73. data/bin/lib/Image/ExifTool/InfiRay.pm +1 -1
  74. data/bin/lib/Image/ExifTool/JPEG.pm +1 -1
  75. data/bin/lib/Image/ExifTool/JPEGDigest.pm +1 -1
  76. data/bin/lib/Image/ExifTool/JSON.pm +1 -1
  77. data/bin/lib/Image/ExifTool/JVC.pm +1 -1
  78. data/bin/lib/Image/ExifTool/Jpeg2000.pm +3 -2
  79. data/bin/lib/Image/ExifTool/Kodak.pm +1 -1
  80. data/bin/lib/Image/ExifTool/KyoceraRaw.pm +1 -1
  81. data/bin/lib/Image/ExifTool/LIF.pm +1 -1
  82. data/bin/lib/Image/ExifTool/LNK.pm +1 -1
  83. data/bin/lib/Image/ExifTool/Lang/cs.pm +1 -1
  84. data/bin/lib/Image/ExifTool/Lang/de.pm +1 -1
  85. data/bin/lib/Image/ExifTool/Lang/en_ca.pm +1 -1
  86. data/bin/lib/Image/ExifTool/Lang/en_gb.pm +1 -1
  87. data/bin/lib/Image/ExifTool/Lang/es.pm +1 -1
  88. data/bin/lib/Image/ExifTool/Lang/fi.pm +1 -1
  89. data/bin/lib/Image/ExifTool/Lang/fr.pm +1 -1
  90. data/bin/lib/Image/ExifTool/Lang/it.pm +1 -1
  91. data/bin/lib/Image/ExifTool/Lang/ja.pm +1 -1
  92. data/bin/lib/Image/ExifTool/Lang/ko.pm +1 -1
  93. data/bin/lib/Image/ExifTool/Lang/nl.pm +1 -1
  94. data/bin/lib/Image/ExifTool/Lang/pl.pm +1 -1
  95. data/bin/lib/Image/ExifTool/Lang/ru.pm +1 -1
  96. data/bin/lib/Image/ExifTool/Lang/sk.pm +1 -1
  97. data/bin/lib/Image/ExifTool/Lang/sv.pm +1 -1
  98. data/bin/lib/Image/ExifTool/Lang/tr.pm +1 -1
  99. data/bin/lib/Image/ExifTool/Lang/zh_cn.pm +1 -1
  100. data/bin/lib/Image/ExifTool/Lang/zh_tw.pm +1 -1
  101. data/bin/lib/Image/ExifTool/Leaf.pm +1 -1
  102. data/bin/lib/Image/ExifTool/LigoGPS.pm +408 -0
  103. data/bin/lib/Image/ExifTool/Lytro.pm +1 -1
  104. data/bin/lib/Image/ExifTool/M2TS.pm +22 -13
  105. data/bin/lib/Image/ExifTool/MIE.pm +1 -1
  106. data/bin/lib/Image/ExifTool/MIEUnits.pod +1 -1
  107. data/bin/lib/Image/ExifTool/MIFF.pm +1 -1
  108. data/bin/lib/Image/ExifTool/MISB.pm +1 -1
  109. data/bin/lib/Image/ExifTool/MNG.pm +1 -1
  110. data/bin/lib/Image/ExifTool/MOI.pm +1 -1
  111. data/bin/lib/Image/ExifTool/MPC.pm +1 -1
  112. data/bin/lib/Image/ExifTool/MPEG.pm +1 -1
  113. data/bin/lib/Image/ExifTool/MPF.pm +1 -1
  114. data/bin/lib/Image/ExifTool/MRC.pm +1 -1
  115. data/bin/lib/Image/ExifTool/MWG.pm +1 -1
  116. data/bin/lib/Image/ExifTool/MXF.pm +1 -1
  117. data/bin/lib/Image/ExifTool/MacOS.pm +1 -1
  118. data/bin/lib/Image/ExifTool/MakerNotes.pm +1 -1
  119. data/bin/lib/Image/ExifTool/Matroska.pm +12 -4
  120. data/bin/lib/Image/ExifTool/Microsoft.pm +1 -1
  121. data/bin/lib/Image/ExifTool/Minolta.pm +1 -1
  122. data/bin/lib/Image/ExifTool/MinoltaRaw.pm +1 -1
  123. data/bin/lib/Image/ExifTool/Motorola.pm +1 -1
  124. data/bin/lib/Image/ExifTool/Nikon.pm +164 -35
  125. data/bin/lib/Image/ExifTool/NikonCapture.pm +1 -1
  126. data/bin/lib/Image/ExifTool/NikonCustom.pm +1 -1
  127. data/bin/lib/Image/ExifTool/NikonSettings.pm +1 -1
  128. data/bin/lib/Image/ExifTool/Nintendo.pm +1 -1
  129. data/bin/lib/Image/ExifTool/OOXML.pm +1 -1
  130. data/bin/lib/Image/ExifTool/Ogg.pm +1 -1
  131. data/bin/lib/Image/ExifTool/Olympus.pm +1 -1
  132. data/bin/lib/Image/ExifTool/OpenEXR.pm +1 -1
  133. data/bin/lib/Image/ExifTool/Opus.pm +1 -1
  134. data/bin/lib/Image/ExifTool/Other.pm +1 -1
  135. data/bin/lib/Image/ExifTool/PCX.pm +1 -1
  136. data/bin/lib/Image/ExifTool/PDF.pm +1 -1
  137. data/bin/lib/Image/ExifTool/PGF.pm +1 -1
  138. data/bin/lib/Image/ExifTool/PICT.pm +1 -1
  139. data/bin/lib/Image/ExifTool/PLIST.pm +3 -3
  140. data/bin/lib/Image/ExifTool/PLUS.pm +1 -1
  141. data/bin/lib/Image/ExifTool/PNG.pm +3 -2
  142. data/bin/lib/Image/ExifTool/PPM.pm +1 -1
  143. data/bin/lib/Image/ExifTool/PSP.pm +1 -1
  144. data/bin/lib/Image/ExifTool/Palm.pm +1 -1
  145. data/bin/lib/Image/ExifTool/Panasonic.pm +20 -2
  146. data/bin/lib/Image/ExifTool/PanasonicRaw.pm +1 -1
  147. data/bin/lib/Image/ExifTool/Parrot.pm +1 -1
  148. data/bin/lib/Image/ExifTool/Pentax.pm +1 -1
  149. data/bin/lib/Image/ExifTool/PhaseOne.pm +1 -1
  150. data/bin/lib/Image/ExifTool/PhotoCD.pm +1 -1
  151. data/bin/lib/Image/ExifTool/PhotoMechanic.pm +1 -1
  152. data/bin/lib/Image/ExifTool/Photoshop.pm +2 -1
  153. data/bin/lib/Image/ExifTool/PostScript.pm +1 -1
  154. data/bin/lib/Image/ExifTool/PrintIM.pm +1 -1
  155. data/bin/lib/Image/ExifTool/Protobuf.pm +24 -14
  156. data/bin/lib/Image/ExifTool/Qualcomm.pm +1 -1
  157. data/bin/lib/Image/ExifTool/QuickTime.pm +94 -26
  158. data/bin/lib/Image/ExifTool/QuickTimeStream.pl +20 -302
  159. data/bin/lib/Image/ExifTool/README +4 -0
  160. data/bin/lib/Image/ExifTool/RIFF.pm +1 -1
  161. data/bin/lib/Image/ExifTool/RSRC.pm +1 -1
  162. data/bin/lib/Image/ExifTool/RTF.pm +1 -1
  163. data/bin/lib/Image/ExifTool/Radiance.pm +1 -1
  164. data/bin/lib/Image/ExifTool/Rawzor.pm +1 -1
  165. data/bin/lib/Image/ExifTool/Real.pm +1 -1
  166. data/bin/lib/Image/ExifTool/Reconyx.pm +1 -1
  167. data/bin/lib/Image/ExifTool/Red.pm +1 -1
  168. data/bin/lib/Image/ExifTool/Ricoh.pm +1 -1
  169. data/bin/lib/Image/ExifTool/Samsung.pm +1 -1
  170. data/bin/lib/Image/ExifTool/Sanyo.pm +1 -1
  171. data/bin/lib/Image/ExifTool/Scalado.pm +1 -1
  172. data/bin/lib/Image/ExifTool/Shift.pl +1 -1
  173. data/bin/lib/Image/ExifTool/Shortcuts.pm +1 -1
  174. data/bin/lib/Image/ExifTool/Sigma.pm +1 -1
  175. data/bin/lib/Image/ExifTool/SigmaRaw.pm +1 -1
  176. data/bin/lib/Image/ExifTool/Sony.pm +1 -1
  177. data/bin/lib/Image/ExifTool/SonyIDC.pm +1 -1
  178. data/bin/lib/Image/ExifTool/Stim.pm +1 -1
  179. data/bin/lib/Image/ExifTool/TagInfoXML.pm +2 -2
  180. data/bin/lib/Image/ExifTool/TagLookup.pm +14 -5
  181. data/bin/lib/Image/ExifTool/TagNames.pod +106 -34
  182. data/bin/lib/Image/ExifTool/Text.pm +1 -1
  183. data/bin/lib/Image/ExifTool/Theora.pm +1 -1
  184. data/bin/lib/Image/ExifTool/Torrent.pm +1 -1
  185. data/bin/lib/Image/ExifTool/Unknown.pm +1 -1
  186. data/bin/lib/Image/ExifTool/VCard.pm +1 -1
  187. data/bin/lib/Image/ExifTool/Validate.pm +1 -1
  188. data/bin/lib/Image/ExifTool/Vorbis.pm +1 -1
  189. data/bin/lib/Image/ExifTool/WPG.pm +1 -1
  190. data/bin/lib/Image/ExifTool/WTV.pm +1 -1
  191. data/bin/lib/Image/ExifTool/WriteCanonRaw.pl +1 -1
  192. data/bin/lib/Image/ExifTool/WriteExif.pl +1 -1
  193. data/bin/lib/Image/ExifTool/WriteIPTC.pl +1 -1
  194. data/bin/lib/Image/ExifTool/WritePDF.pl +1 -1
  195. data/bin/lib/Image/ExifTool/WritePNG.pl +1 -1
  196. data/bin/lib/Image/ExifTool/WritePhotoshop.pl +1 -1
  197. data/bin/lib/Image/ExifTool/WritePostScript.pl +1 -1
  198. data/bin/lib/Image/ExifTool/WriteQuickTime.pl +48 -12
  199. data/bin/lib/Image/ExifTool/WriteRIFF.pl +1 -1
  200. data/bin/lib/Image/ExifTool/WriteXMP.pl +1 -1
  201. data/bin/lib/Image/ExifTool/Writer.pl +25 -13
  202. data/bin/lib/Image/ExifTool/XISF.pm +1 -1
  203. data/bin/lib/Image/ExifTool/XMP.pm +1 -1
  204. data/bin/lib/Image/ExifTool/XMP2.pl +1 -1
  205. data/bin/lib/Image/ExifTool/XMPStruct.pl +1 -1
  206. data/bin/lib/Image/ExifTool/ZIP.pm +1 -1
  207. data/bin/lib/Image/ExifTool/ZISRAW.pm +1 -1
  208. data/bin/lib/Image/ExifTool/iWork.pm +1 -1
  209. data/bin/lib/Image/ExifTool.pm +20 -11
  210. data/bin/lib/Image/ExifTool.pod +55 -40
  211. data/bin/perl-Image-ExifTool.spec +1 -1
  212. data/lib/exiftool_vendored/version.rb +1 -1
  213. metadata +3 -2
@@ -37,7 +37,7 @@ use vars qw($VERSION %leicaLensTypes);
37
37
  use Image::ExifTool qw(:DataAccess :Utils);
38
38
  use Image::ExifTool::Exif;
39
39
 
40
- $VERSION = '2.22';
40
+ $VERSION = '2.23';
41
41
 
42
42
  sub ProcessLeicaLEIC($$$);
43
43
  sub WhiteBalanceConv($;$$);
@@ -360,12 +360,16 @@ my %shootingMode = (
360
360
  '16' => 'Normal?', # (only mode for DMC-LC20)
361
361
  '16 0' => '1-area', # (FZ8)
362
362
  '16 16' => '1-area (high speed)', # (FZ8)
363
+ '16 32' => '1-area +', #forum16903 (G9M2)
364
+ '17 0' => 'Full Area', #forum16903 (G9M2)
363
365
  # '32 0' is Face Detect for FS7, and Face Detect or Focus Tracking
364
366
  # for the DMC-FZ200 (ref 17), and Auto is DMC-L1 guess,
365
367
  '32 0' => 'Tracking',
366
368
  '32 1' => '3-area (left)?', # (DMC-L1 guess)
367
369
  '32 2' => '3-area (center)?', # (DMC-L1 guess)
368
370
  '32 3' => '3-area (right)?', # (DMC-L1 guess)
371
+ '32 16' => 'Zone', #forum16903 (G9M2)
372
+ '32 18' => 'Zone (horizontal/vertical)', #forum16903 (G9M2)
369
373
  # '32 16' ? (DC-GH6)
370
374
  '64 0' => 'Face Detect',
371
375
  '64 1' => 'Face Detect (animal detect on)', #forum11194
@@ -1448,6 +1452,20 @@ my %shootingMode = (
1448
1452
  Name => 'MinimumISO',
1449
1453
  Writable => 'int32u',
1450
1454
  },
1455
+ 0xe9 => { #forum16903 (DC-G9M2)
1456
+ Name => 'AFSubjectDetection',
1457
+ Writable => 'int16u',
1458
+ PrintConv => {
1459
+ 0 => 'n/a',
1460
+ 1 => 'Human Eye/Face/Body',
1461
+ 2 => 'Animal', #PH (NC) (DC-S5 and DC-S5M2)
1462
+ 3 => 'Human Eye/Face',
1463
+ 4 => 'Animal Body',
1464
+ 5 => 'Animal Eye/Body',
1465
+ 6 => 'Car',
1466
+ 7 => 'Motorcycle',
1467
+ }
1468
+ },
1451
1469
  0xee => { #PH (DC-GH6)
1452
1470
  Name => 'DynamicRangeBoost',
1453
1471
  Writable => 'int16u',
@@ -2902,7 +2920,7 @@ Panasonic and Leica maker notes in EXIF information.
2902
2920
 
2903
2921
  =head1 AUTHOR
2904
2922
 
2905
- Copyright 2003-2024, Phil Harvey (philharvey66 at gmail.com)
2923
+ Copyright 2003-2025, Phil Harvey (philharvey66 at gmail.com)
2906
2924
 
2907
2925
  This library is free software; you can redistribute it and/or modify it
2908
2926
  under the same terms as Perl itself.
@@ -935,7 +935,7 @@ write meta information in Panasonic/Leica RAW, RW2 and RWL images.
935
935
 
936
936
  =head1 AUTHOR
937
937
 
938
- Copyright 2003-2024, Phil Harvey (philharvey66 at gmail.com)
938
+ Copyright 2003-2025, Phil Harvey (philharvey66 at gmail.com)
939
939
 
940
940
  This library is free software; you can redistribute it and/or modify it
941
941
  under the same terms as Perl itself.
@@ -825,7 +825,7 @@ timed metadata from the 'mett' frame found in Parrot drone MP4 videos.
825
825
 
826
826
  =head1 AUTHOR
827
827
 
828
- Copyright 2003-2024, Phil Harvey (philharvey66 at gmail.com)
828
+ Copyright 2003-2025, Phil Harvey (philharvey66 at gmail.com)
829
829
 
830
830
  This library is free software; you can redistribute it and/or modify it
831
831
  under the same terms as Perl itself.
@@ -6477,7 +6477,7 @@ tags, and everyone who helped contribute to the LensType values.
6477
6477
 
6478
6478
  =head1 AUTHOR
6479
6479
 
6480
- Copyright 2003-2024, Phil Harvey (philharvey66 at gmail.com)
6480
+ Copyright 2003-2025, Phil Harvey (philharvey66 at gmail.com)
6481
6481
 
6482
6482
  This library is free software; you can redistribute it and/or modify it
6483
6483
  under the same terms as Perl itself.
@@ -726,7 +726,7 @@ One maker notes.
726
726
 
727
727
  =head1 AUTHOR
728
728
 
729
- Copyright 2003-2024, Phil Harvey (philharvey66 at gmail.com)
729
+ Copyright 2003-2025, Phil Harvey (philharvey66 at gmail.com)
730
730
 
731
731
  This library is free software; you can redistribute it and/or modify it
732
732
  under the same terms as Perl itself.
@@ -484,7 +484,7 @@ information from Kodak Photo CD Image Pac (PCD) files.
484
484
 
485
485
  =head1 AUTHOR
486
486
 
487
- Copyright 2003-2024, Phil Harvey (philharvey66 at gmail.com)
487
+ Copyright 2003-2025, Phil Harvey (philharvey66 at gmail.com)
488
488
 
489
489
  This library is free software; you can redistribute it and/or modify it
490
490
  under the same terms as Perl itself.
@@ -237,7 +237,7 @@ write information written by the Camera Bits Photo Mechanic software.
237
237
 
238
238
  =head1 AUTHOR
239
239
 
240
- Copyright 2003-2024, Phil Harvey (philharvey66 at gmail.com)
240
+ Copyright 2003-2025, Phil Harvey (philharvey66 at gmail.com)
241
241
 
242
242
  This library is free software; you can redistribute it and/or modify it
243
243
  under the same terms as Perl itself.
@@ -362,6 +362,7 @@ my %unicodeString = (
362
362
  PROCESS_PROC => \&ProcessChannelOptions,
363
363
  VARS => { IS_BINARY => 1 },
364
364
  GROUPS => { 2 => 'Image' },
365
+ NOTES => 'These tags relate only to the appearance of a channel.',
365
366
  0 => {
366
367
  Name => 'ChannelColorSpace',
367
368
  Format => 'int16u',
@@ -1261,7 +1262,7 @@ be preserved when copying Photoshop information via user-defined tags.
1261
1262
 
1262
1263
  =head1 AUTHOR
1263
1264
 
1264
- Copyright 2003-2024, Phil Harvey (philharvey66 at gmail.com)
1265
+ Copyright 2003-2025, Phil Harvey (philharvey66 at gmail.com)
1265
1266
 
1266
1267
  This library is free software; you can redistribute it and/or modify it
1267
1268
  under the same terms as Perl itself.
@@ -768,7 +768,7 @@ This code reads meta information from EPS (Encapsulated PostScript), PS
768
768
 
769
769
  =head1 AUTHOR
770
770
 
771
- Copyright 2003-2024, Phil Harvey (philharvey66 at gmail.com)
771
+ Copyright 2003-2025, Phil Harvey (philharvey66 at gmail.com)
772
772
 
773
773
  This library is free software; you can redistribute it and/or modify it
774
774
  under the same terms as Perl itself.
@@ -112,7 +112,7 @@ Print Image Matching meta information.
112
112
 
113
113
  =head1 AUTHOR
114
114
 
115
- Copyright 2003-2024, Phil Harvey (philharvey66 at gmail.com)
115
+ Copyright 2003-2025, Phil Harvey (philharvey66 at gmail.com)
116
116
 
117
117
  This library is free software; you can redistribute it and/or modify it
118
118
  under the same terms as Perl itself.
@@ -17,7 +17,7 @@ use strict;
17
17
  use vars qw($VERSION);
18
18
  use Image::ExifTool qw(:DataAccess :Utils);
19
19
 
20
- $VERSION = '1.00';
20
+ $VERSION = '1.01';
21
21
 
22
22
  sub ProcessProtobuf($$$;$);
23
23
 
@@ -105,7 +105,7 @@ sub IsProtobuf($)
105
105
 
106
106
  #------------------------------------------------------------------------------
107
107
  # Process protobuf data (eg. DJI djmd timed data from Action4 videos) (ref 1)
108
- # Inputs: 0) ExifTool ref, 1) dirInfo ref with DataPt, DirName and Base,
108
+ # Inputs: 0) ExifTool ref, 1) dirInfo ref with DataPt, DataPos, DirName and Base,
109
109
  # 2) tag table ptr, 3) prefix of parent protobuf ID's
110
110
  # Returns: true on success
111
111
  sub ProcessProtobuf($$$;$)
@@ -113,27 +113,32 @@ sub ProcessProtobuf($$$;$)
113
113
  my ($et, $dirInfo, $tagTbl, $prefix) = @_;
114
114
  my $dataPt = $$dirInfo{DataPt};
115
115
  my $dirName = $$dirInfo{DirName};
116
+ my $dirStart = $$dirInfo{DirStart} || 0;
117
+ my $dirLen = $$dirInfo{DirLen} || (length($$dataPt) - $dirStart);
118
+ my $dirEnd = $dirStart + $dirLen;
119
+ my $dataPos = ($$dirInfo{Base} || 0) + ($$dirInfo{DataPos} || 0);
116
120
  my $unknown = $et->Options('Unknown') || $et->Options('Verbose');
117
121
 
118
122
  $$dirInfo{Pos} = $$dirInfo{DirStart} || 0; # initialize buffer Pos
123
+ $et->VerboseDir('Protobuf', undef, $dirLen);
119
124
 
120
125
  unless ($prefix) {
121
126
  $prefix = '';
122
- $$et{ProtocolName}{$dirName} = '*' unless defined $$et{ProtocolName}{$dirName};
127
+ $$et{ProtoPrefix}{$dirName} = '' unless defined $$et{ProtoPrefix}{$dirName};
123
128
  SetByteOrder('II');
124
129
  }
125
130
  # loop through protobuf records
126
131
  for (;;) {
127
132
  my $pos = $$dirInfo{Pos};
128
- last if $pos >= length $$dataPt;
133
+ last if $pos >= $dirEnd;
129
134
  my ($buff, $id, $type) = ReadRecord($dirInfo);
130
135
  defined $buff or $et->Warn('Protobuf format error'), last;
131
136
  if ($type == 2 and $buff =~ /\.proto$/) {
132
137
  # save protocol name separately for directory type
133
- $$et{ProtocolName}{$dirName} = substr($buff, 0, -6);
138
+ $$et{ProtoPrefix}{$dirName} = substr($buff, 0, -6) . '_';
134
139
  $et->HandleTag($tagTbl, Protocol => $buff);
135
140
  }
136
- my $tag = "$$et{ProtocolName}{$dirName}_$prefix$id";
141
+ my $tag = "$$et{ProtoPrefix}{$dirName}$prefix$id";
137
142
  my $tagInfo = $$tagTbl{$tag};
138
143
  if ($tagInfo) {
139
144
  next if $type != 2 and $$tagInfo{Unknown} and not $unknown;
@@ -168,12 +173,17 @@ sub ProcessProtobuf($$$;$)
168
173
  } elsif ($type == 1) {
169
174
  $val = '0x' . unpack('H*', $buff) . ' (double ' . GetDouble(\$buff,0) . ')';
170
175
  } elsif ($type == 2) {
171
- if ($$tagInfo{IsProtobuf}) {
172
- $et->VPrint(1, "+ Protobuf $tag (" . length($buff) . " bytes)\n");
173
- my $addr = $$dirInfo{Base} + $$dirInfo{Pos} - length($buff);
174
- $et->VerboseDump(\$buff, Addr => $addr);
175
- my %subdir = ( DataPt => \$buff, Base => $addr, DirName => $dirName );
176
+ if ($$tagInfo{SubDirectory}) {
177
+ # (fall through to process known SubDirectory)
178
+ } elsif ($$tagInfo{IsProtobuf}) {
179
+ # process Unknown protobuf directories
180
+ $et->VPrint(1, "$$et{INDENT}Protobuf $tag (" . length($buff) . " bytes) -->\n");
181
+ my $addr = $dataPos + $$dirInfo{Pos} - length($buff);
182
+ $et->VerboseDump(\$buff, Addr => $addr, Prefix => $$et{INDENT});
183
+ my %subdir = ( DataPt => \$buff, DataPos => $addr, DirName => $dirName );
184
+ $$et{INDENT} .= '| ';
176
185
  ProcessProtobuf($et, \%subdir, $tagTbl, "$prefix$id-");
186
+ $$et{INDENT} = substr($$et{INDENT}, 0, -2);
177
187
  next;
178
188
  } elsif ($buff !~ /[^\x20-\x7e]/) {
179
189
  $val = $buff; # assume this is an ASCII string
@@ -193,7 +203,7 @@ sub ProcessProtobuf($$$;$)
193
203
  my $start = $type == 0 ? $pos + 1 : $$dirInfo{Pos} - length $buff;
194
204
  $et->HandleTag($tagTbl, $tag, $val,
195
205
  DataPt => $dataPt,
196
- DataPos=> $$dirInfo{Base},
206
+ DataPos=> $dataPos,
197
207
  Start => $start,
198
208
  Size => $$dirInfo{Pos} - $start,
199
209
  Extra => ", type=$type",
@@ -201,7 +211,7 @@ sub ProcessProtobuf($$$;$)
201
211
  );
202
212
  }
203
213
  # warn if we didn't finish exactly at the end of the buffer
204
- $et->Warn('Truncated protobuf data') unless $prefix or $$dirInfo{Pos} == length $$dataPt;
214
+ $et->Warn('Truncated protobuf data') unless $prefix or $$dirInfo{Pos} == $dirEnd;
205
215
  return 1;
206
216
  }
207
217
 
@@ -222,7 +232,7 @@ information in protocol buffer (protobuf) format.
222
232
 
223
233
  =head1 AUTHOR
224
234
 
225
- Copyright 2003-2024, Phil Harvey (philharvey66 at gmail.com)
235
+ Copyright 2003-2025, Phil Harvey (philharvey66 at gmail.com)
226
236
 
227
237
  This library is free software; you can redistribute it and/or modify it
228
238
  under the same terms as Perl itself.
@@ -1331,7 +1331,7 @@ information from the APP7 Qualcomm segment in JPEG images.
1331
1331
 
1332
1332
  =head1 AUTHOR
1333
1333
 
1334
- Copyright 2003-2024, Phil Harvey (philharvey66 at gmail.com)
1334
+ Copyright 2003-2025, Phil Harvey (philharvey66 at gmail.com)
1335
1335
 
1336
1336
  This library is free software; you can redistribute it and/or modify it
1337
1337
  under the same terms as Perl itself.
@@ -48,7 +48,7 @@ use Image::ExifTool qw(:DataAccess :Utils);
48
48
  use Image::ExifTool::Exif;
49
49
  use Image::ExifTool::GPS;
50
50
 
51
- $VERSION = '3.05';
51
+ $VERSION = '3.08';
52
52
 
53
53
  sub ProcessMOV($$;$);
54
54
  sub ProcessKeys($$$);
@@ -69,8 +69,6 @@ sub Process_gps0($$$);
69
69
  sub Process_gsen($$$);
70
70
  sub Process_gdat($$$);
71
71
  sub Process_nbmt($$$);
72
- sub ProcessLigoGPS($$$;$);
73
- sub ProcessLigoJSON($$$);
74
72
  sub ProcessKenwood($$$);
75
73
  sub ProcessRIFFTrailer($$$);
76
74
  sub ProcessTTAD($$$);
@@ -253,15 +251,20 @@ my %timeInfo = (
253
251
  # Note: This value will be in UTC if generated by a system that is aware of the time zone
254
252
  # (also note: this code is duplicated for the CreateDate tag)
255
253
  RawConv => q{
256
- my $offset = (66 * 365 + 17) * 24 * 3600;
257
- return $val - $offset if $val >= $offset or $$self{OPTIONS}{QuickTimeUTC};
258
- if ($val and not $$self{IsWriting}) {
259
- $self->Warn('Patched incorrect time zero for QuickTime date/time tag',1);
254
+ if ($val) {
255
+ my $offset = (66 * 365 + 17) * 24 * 3600;
256
+ if ($val >= $offset or $$self{OPTIONS}{QuickTimeUTC}) {
257
+ $val -= $offset;
258
+ } elsif (not $$self{IsWriting}) {
259
+ $self->Warn('Patched incorrect time zero for QuickTime date/time tag',1);
260
+ }
261
+ } else {
262
+ undef $val if $self->Options('StrictDate');
260
263
  }
261
264
  return $val;
262
265
  },
263
266
  RawConvInv => q{
264
- if ($$self{FileType} eq 'CR3' and not $self->Options('QuickTimeUTC')) {
267
+ if ($val and $$self{FileType} eq 'CR3' and not $self->Options('QuickTimeUTC')) {
265
268
  # convert to UTC
266
269
  my $offset = (66 * 365 + 17) * 24 * 3600;
267
270
  $val = ConvertUnixTime($val - $offset);
@@ -274,10 +277,14 @@ my %timeInfo = (
274
277
  ValueConvInv => q{
275
278
  $val = GetUnixTime($val, $self->Options("QuickTimeUTC"));
276
279
  return undef unless defined $val;
280
+ return $val unless $val;
277
281
  return $val + (66 * 365 + 17) * 24 * 3600;
278
282
  },
279
283
  PrintConv => '$self->ConvertDateTime($val)',
280
- PrintConvInv => '$self->InverseDateTime($val)',
284
+ PrintConvInv => q{
285
+ return $val if $val eq '0000:00:00 00:00:00';
286
+ return $self->InverseDateTime($val);
287
+ }
281
288
  # (can't put Groups here because they aren't constant!)
282
289
  );
283
290
  # properties for ISO 8601 format date/time tags
@@ -590,7 +597,7 @@ my %userDefined = (
590
597
  Condition => '$$valPt =~ /^LIGOGPSINFO\0/',
591
598
  SubDirectory => {
592
599
  TagTable => 'Image::ExifTool::QuickTime::Stream',
593
- ProcessProc => \&ProcessLigoGPS,
600
+ ProcessProc => 'Image::ExifTool::LigoGPS::ProcessLigoGPS',
594
601
  },
595
602
  },
596
603
  { Name => 'Skip', Unknown => 1, Binary => 1 },
@@ -775,7 +782,7 @@ my %userDefined = (
775
782
  Condition => '$$valPt =~ /^LIGOGPSINFO \{/',
776
783
  SubDirectory => {
777
784
  TagTable => 'Image::ExifTool::QuickTime::Stream',
778
- ProcessProc => \&ProcessLigoJSON,
785
+ ProcessProc => 'Image::ExifTool::LigoGPS::ProcessLigoJSON',
779
786
  },
780
787
  },{
781
788
  Name => 'FLIRData',
@@ -1412,11 +1419,15 @@ my %userDefined = (
1412
1419
  Groups => { 2 => 'Time' },
1413
1420
  %timeInfo,
1414
1421
  RawConv => q{
1415
- my $offset = (66 * 365 + 17) * 24 * 3600;
1416
- if ($val >= $offset or $$self{OPTIONS}{QuickTimeUTC}) {
1417
- $val -= $offset;
1418
- } elsif ($val and not $$self{IsWriting}) {
1419
- $self->Warn('Patched incorrect time zero for QuickTime date/time tag',1);
1422
+ if ($val) {
1423
+ my $offset = (66 * 365 + 17) * 24 * 3600;
1424
+ if ($val >= $offset or $$self{OPTIONS}{QuickTimeUTC}) {
1425
+ $val -= $offset;
1426
+ } elsif (not $$self{IsWriting}) {
1427
+ $self->Warn('Patched incorrect time zero for QuickTime date/time tag',1);
1428
+ }
1429
+ } else {
1430
+ undef $val if $$self{OPTIONS}{StrictDate};
1420
1431
  }
1421
1432
  return $$self{CreateDate} = $val;
1422
1433
  },
@@ -2222,8 +2233,8 @@ my %userDefined = (
2222
2233
  _cx_ => { Name => 'CX', Format => 'rational64s', Unknown => 1 },
2223
2234
  _cy_ => { Name => 'CY', Format => 'rational64s', Unknown => 1 },
2224
2235
  rads => { Name => 'Rads', Format => 'rational64s', Unknown => 1 },
2225
- lvlm => { Name => 'LevelMeter', Format => 'rational64s', Unknown => 1 }, # (guess)
2226
- Lvlm => { Name => 'LevelMeter', Format => 'rational64s', Unknown => 1 }, # (guess)
2236
+ lvlm => { Name => 'LevelMeter', Format => 'rational64s', Unknown => 1 }, # (guess, Kodak proprietary)
2237
+ Lvlm => { Name => 'LevelMeter', Format => 'rational64s', Unknown => 1 }, # (guess, Kodak proprietary)
2227
2238
  pose => { Name => 'pose', SubDirectory => { TagTable => 'Image::ExifTool::Kodak::pose' } },
2228
2239
  # AMBA => Ambarella AVC atom (unknown data written by Kodak Playsport video cam)
2229
2240
  # tmlp - 1 byte: 0 (PixPro SP360/4KVR360)
@@ -2822,7 +2833,7 @@ my %userDefined = (
2822
2833
  },
2823
2834
  iinf => [{
2824
2835
  Name => 'ItemInformation',
2825
- Condition => '$$valPt =~ /^\0/', # (check for version 0)
2836
+ Condition => '$$self{LastItemID} = -1; $$valPt =~ /^\0/', # (check for version 0)
2826
2837
  SubDirectory => {
2827
2838
  TagTable => 'Image::ExifTool::QuickTime::ItemInfo',
2828
2839
  Start => 6, # (4-byte version/flags + 2-byte count)
@@ -2894,6 +2905,17 @@ my %userDefined = (
2894
2905
  %unknownInfo,
2895
2906
  },
2896
2907
  ],
2908
+ grpl => {
2909
+ Name => 'Unknown_grpl',
2910
+ SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::grpl' },
2911
+ },
2912
+ );
2913
+
2914
+ # unknown grpl container
2915
+ %Image::ExifTool::QuickTime::grpl = (
2916
+ PROCESS_PROC => \&ProcessMOV,
2917
+ GROUPS => { 2 => 'Video' },
2918
+ # altr - seen "00 00 00 00 00 00 00 41 00 00 00 02 00 00 00 42 00 00 00 2e"
2897
2919
  );
2898
2920
 
2899
2921
  # additional metadata container (ref ISO14496-12:2015)
@@ -3038,6 +3060,7 @@ my %userDefined = (
3038
3060
  );
3039
3061
 
3040
3062
  # ref https://aomediacodec.github.io/av1-spec/av1-spec.pdf
3063
+ # (NOTE: conversions are the same as Image::ExifTool::ICC_Profile::ColorRep tags)
3041
3064
  %Image::ExifTool::QuickTime::ColorRep = (
3042
3065
  PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
3043
3066
  GROUPS => { 2 => 'Video' },
@@ -3321,7 +3344,13 @@ my %userDefined = (
3321
3344
  the associations between items in the file. This information is used by
3322
3345
  ExifTool, but these entries are not extracted as tags.
3323
3346
  },
3324
- dimg => { Name => 'DerivedImageRef', RawConv => 'undef' },
3347
+ dimg => {
3348
+ Name => 'DerivedImageRef',
3349
+ # also parse these for the ID of the primary 'tmap' item
3350
+ # (tone-mapped image in HDRGainMap HEIC by iPhone 15 and 16)
3351
+ RawConv => \&ParseContentDescribes,
3352
+ WriteHook => \&ParseContentDescribes,
3353
+ },
3325
3354
  thmb => { Name => 'ThumbnailRef', RawConv => 'undef' },
3326
3355
  auxl => { Name => 'AuxiliaryImageRef', RawConv => 'undef' },
3327
3356
  cdsc => {
@@ -3339,7 +3368,8 @@ my %userDefined = (
3339
3368
  # hvc1 - HEVC image
3340
3369
  # lhv1 - L-HEVC image
3341
3370
  # infe - ItemInformationEntry
3342
- # infe types: avc1,hvc1,lhv1,Exif,xml1,iovl(overlay image),grid,mime,hvt1(tile image)
3371
+ # infe types: avc1,hvc1,lhv1,Exif,xml1,iovl(overlay image),grid,mime,tmap,hvt1(tile image)
3372
+ # ('tmap' has something to do with the new gainmap written by iPhone 15 and 16)
3343
3373
  infe => {
3344
3374
  Name => 'ItemInfoEntry',
3345
3375
  RawConv => \&ParseItemInfoEntry,
@@ -6569,7 +6599,7 @@ my %userDefined = (
6569
6599
  PROCESS_PROC => \&ProcessKeys,
6570
6600
  WRITE_PROC => \&WriteKeys,
6571
6601
  CHECK_PROC => \&CheckQTValue,
6572
- VARS => { LONG_TAGS => 8 },
6602
+ VARS => { LONG_TAGS => 9 },
6573
6603
  WRITABLE => 1,
6574
6604
  # (not PREFERRED when writing)
6575
6605
  GROUPS => { 1 => 'Keys' },
@@ -6767,6 +6797,7 @@ my %userDefined = (
6767
6797
  ValueConv => 'unpack("N", $val)',
6768
6798
  Writable => 0, # (don't make this writable because it is found in timed metadata)
6769
6799
  },
6800
+ 'full-frame-rate-playback-intent' => 'FullFrameRatePlaybackIntent', #forum16824
6770
6801
  #
6771
6802
  # seen in Apple ProRes RAW file
6772
6803
  #
@@ -8787,6 +8818,7 @@ sub PrintableTagID($;$)
8787
8818
  # ContentType - mime type of item
8788
8819
  # ContentEncoding - item encoding
8789
8820
  # URI - URI of a 'uri '-type item
8821
+ # infe - raw data for 'infe' box (when writing only) [retracted]
8790
8822
  # ipma:
8791
8823
  # Association - list of associated properties in the ipco container
8792
8824
  # Essential - list of "essential" flags for the associated properties
@@ -8937,10 +8969,18 @@ sub ParseItemInfoEntry($$)
8937
8969
  $$items{$id}{URI} = GetString(\$val, $pos);
8938
8970
  }
8939
8971
  }
8972
+ #[retracted] # save raw infe box when writing in case we need to sort items later
8973
+ #[retracted] $$items{$id}{infe} = pack('N', length($val)+8) . 'infe' . $val if $$et{IsWriting};
8940
8974
  $et->VPrint(1, "$$et{INDENT} Item $id: Type=", $$items{$id}{Type} || '',
8941
8975
  ' Name=', $$items{$id}{Name} || '',
8942
8976
  ' ContentType=', $$items{$id}{ContentType} || '',
8977
+ ($$et{PrimaryItem} and $$et{PrimaryItem} == $id) ? ' (PrimaryItem)' : '',
8943
8978
  "\n") if $verbose > 1;
8979
+ unless ($id > $$et{LastItemID}) {
8980
+ $et->Warn('Item info entries are out of order'); #[retracted] unless $$et{IsWriting};
8981
+ #[retracted] $$et{ItemsNotSorted} = 1; # set flag indicating the items weren't sorted
8982
+ }
8983
+ $$et{LastItemID} = $id;
8944
8984
  return undef;
8945
8985
  }
8946
8986
 
@@ -8961,6 +9001,7 @@ sub ParseItemPropAssoc($$)
8961
9001
  my $flg = Get32u(\$val, 0);
8962
9002
  my $num = Get32u(\$val, 4);
8963
9003
  my $pos = 8;
9004
+ my $lastID = -1;
8964
9005
  for ($i=0; $i<$num; ++$i) {
8965
9006
  if ($ver == 0) {
8966
9007
  return undef if $pos + 3 > $len;
@@ -8993,6 +9034,9 @@ sub ParseItemPropAssoc($$)
8993
9034
  $$items{$id}{Association} = \@association;
8994
9035
  $$items{$id}{Essential} = \@essential;
8995
9036
  $et->VPrint(1, "$$et{INDENT} Item $id properties: @association\n") if $verbose > 1;
9037
+ # (according to ISO/IEC 23008-12, these entries must be sorted by item ID)
9038
+ $et->Warn('Item property association entries are out of order') unless $id > $lastID;
9039
+ $lastID = $id;
8996
9040
  }
8997
9041
  return undef;
8998
9042
  }
@@ -9039,7 +9083,10 @@ sub HandleItemInfo($)
9039
9083
  }
9040
9084
  }
9041
9085
  $warn = "Can't currently decode protected $type metadata" if $$item{ProtectionIndex};
9042
- $warn = "Can't currently extract $type with construction method $$item{ConstructionMethod}" if $$item{ConstructionMethod};
9086
+ # Note: In HEIC's, these seem to indicate data in 'idat' instead of 'mdat'
9087
+ my $constMeth = $$item{ConstructionMethod} || 0;
9088
+ $warn = "Can't currently extract $type with construction method $constMeth" if $constMeth > 1;
9089
+ $warn = "No 'idat' for $type object with construction method 1" if $constMeth == 1 and not $$et{MediaDataInfo};
9043
9090
  $et->Warn($warn) if $warn and $name;
9044
9091
  $warn = 'Not this file' if $$item{DataReferenceIndex}; # (can only extract from "this file")
9045
9092
  unless (($$item{Extents} and @{$$item{Extents}}) or $warn) {
@@ -9050,7 +9097,7 @@ sub HandleItemInfo($)
9050
9097
  $et->VPrint(0, "$$et{INDENT} [not extracted] ($warn)\n") if $verbose > 2;
9051
9098
  next;
9052
9099
  }
9053
- my $base = $$item{BaseOffset} || 0;
9100
+ my $base = ($$item{BaseOffset} || 0) + ($constMeth ? $$et{MediaDataInfo}[0] : 0);
9054
9101
  if ($verbose > 2) {
9055
9102
  # do verbose hex dump
9056
9103
  my $len = 0;
@@ -9189,6 +9236,7 @@ sub HandleItemInfo($)
9189
9236
  delete $$et{DOC_NUM};
9190
9237
  }
9191
9238
  delete $$et{ItemInfo};
9239
+ delete $$et{MediaDataInfo};
9192
9240
  }
9193
9241
 
9194
9242
  #------------------------------------------------------------------------------
@@ -9771,8 +9819,10 @@ sub ProcessMOV($$;$)
9771
9819
  # save required tag sizes
9772
9820
  if ($$tagTablePtr{"$tag-size"}) {
9773
9821
  $et->HandleTag($tagTablePtr, "$tag-size", $size);
9774
- $et->HandleTag($tagTablePtr, "$tag-offset", $raf->Tell()) if $$tagTablePtr{"$tag-offset"};
9822
+ $et->HandleTag($tagTablePtr, "$tag-offset", $raf->Tell()+$dirBase) if $$tagTablePtr{"$tag-offset"};
9775
9823
  }
9824
+ # save position/size of 'idat'
9825
+ $$et{MediaDataInfo} = [ $raf->Tell() + $dirBase, $size ] if $tag eq 'idat';
9776
9826
  # stop processing at mdat/idat if -fast2 is used
9777
9827
  last if $fast > 1 and ($tag eq 'mdat' or ($tag eq 'idat' and $$et{FileType} ne 'HEIC'));
9778
9828
  # load values only if associated with a tag (or verbose) and not too big
@@ -10241,6 +10291,24 @@ sub ProcessQTIF($$)
10241
10291
  return ProcessMOV($et, $dirInfo, $table);
10242
10292
  }
10243
10293
 
10294
+ #==============================================================================
10295
+ # Autoload LigoGPS module if necessary
10296
+ # NOTE: Switches to package LigoGPS!
10297
+ #
10298
+ package Image::ExifTool::LigoGPS;
10299
+ use vars qw($AUTOLOAD);
10300
+ sub AUTOLOAD {
10301
+ require Image::ExifTool::LigoGPS;
10302
+ unless (defined &$AUTOLOAD) {
10303
+ my @caller = caller(0);
10304
+ # reproduce Perl's standard 'undefined subroutine' message:
10305
+ die "Undefined subroutine $AUTOLOAD called at $caller[1] line $caller[2]\n";
10306
+ }
10307
+ no strict 'refs';
10308
+ return &$AUTOLOAD(@_); # call the function
10309
+ }
10310
+ #==============================================================================
10311
+
10244
10312
  1; # end
10245
10313
 
10246
10314
  __END__
@@ -10260,7 +10328,7 @@ information from QuickTime and MP4 video, M4A audio, and HEIC image files.
10260
10328
 
10261
10329
  =head1 AUTHOR
10262
10330
 
10263
- Copyright 2003-2024, Phil Harvey (philharvey66 at gmail.com)
10331
+ Copyright 2003-2025, Phil Harvey (philharvey66 at gmail.com)
10264
10332
 
10265
10333
  This library is free software; you can redistribute it and/or modify it
10266
10334
  under the same terms as Perl itself.