File Coverage

blib/lib/Image/ExifTool/IPTC.pm
Criterion Covered Total %
statement 111 165 67.2
branch 70 112 62.5
condition 44 83 53.0
subroutine 9 9 100.0
pod 0 5 0.0
total 234 374 62.5


line stmt bran cond sub pod time code
1             #------------------------------------------------------------------------------
2             # File: IPTC.pm
3             #
4             # Description: Read IPTC meta information
5             #
6             # Revisions: Jan. 08/2003 - P. Harvey Created
7             # Feb. 05/2004 - P. Harvey Added support for records other than 2
8             #
9             # References: 1) http://www.iptc.org/IIM/
10             #------------------------------------------------------------------------------
11              
12             package Image::ExifTool::IPTC;
13              
14 28     28   6989 use strict;
  28         65  
  28         1363  
15 28     28   170 use vars qw($VERSION $AUTOLOAD %iptcCharset);
  28         83  
  28         2075  
16 28     28   167 use Image::ExifTool qw(:DataAccess :Utils);
  28         61  
  28         145736  
17              
18             $VERSION = '1.59';
19              
20             %iptcCharset = (
21             "\x1b%G" => 'UTF8',
22             # don't translate these (at least until we handle ISO 2022 shift codes)
23             # because the sets are only designated and not invoked
24             # "\x1b,A" => 'Latin', # G0 = ISO 8859-1 (similar to Latin1, but codes 0x80-0x9f are missing)
25             # "\x1b-A" => 'Latin', # G1 "
26             # "\x1b.A" => 'Latin', # G2
27             # "\x1b/A" => 'Latin', # G3
28             );
29              
30             sub ProcessIPTC($$$);
31             sub WriteIPTC($$$);
32             sub CheckIPTC($$$);
33             sub PrintCodedCharset($);
34             sub PrintInvCodedCharset($);
35              
36             # standard IPTC locations
37             # (MWG specifies locations only for JPEG, TIFF and PSD -- the rest are ExifTool-defined)
38             my %isStandardIPTC = (
39             'JPEG-APP13-Photoshop-IPTC' => 1,
40             'TIFF-IFD0-IPTC' => 1,
41             'PSD-IPTC' => 1,
42             'MIE-IPTC' => 1,
43             'EPS-Photoshop-IPTC' => 1,
44             'PS-Photoshop-IPTC' => 1,
45             'EXV-APP13-Photoshop-IPTC' => 1,
46             # set file types to 0 if they have a standard location
47             JPEG => 0,
48             TIFF => 0,
49             PSD => 0,
50             MIE => 0,
51             EPS => 0,
52             PS => 0,
53             EXV => 0,
54             );
55              
56             my %fileFormat = (
57             0 => 'No ObjectData',
58             1 => 'IPTC-NAA Digital Newsphoto Parameter Record',
59             2 => 'IPTC7901 Recommended Message Format',
60             3 => 'Tagged Image File Format (Adobe/Aldus Image data)',
61             4 => 'Illustrator (Adobe Graphics data)',
62             5 => 'AppleSingle (Apple Computer Inc)',
63             6 => 'NAA 89-3 (ANPA 1312)',
64             7 => 'MacBinary II',
65             8 => 'IPTC Unstructured Character Oriented File Format (UCOFF)',
66             9 => 'United Press International ANPA 1312 variant',
67             10 => 'United Press International Down-Load Message',
68             11 => 'JPEG File Interchange (JFIF)',
69             12 => 'Photo-CD Image-Pac (Eastman Kodak)',
70             13 => 'Bit Mapped Graphics File [.BMP] (Microsoft)',
71             14 => 'Digital Audio File [.WAV] (Microsoft & Creative Labs)',
72             15 => 'Audio plus Moving Video [.AVI] (Microsoft)',
73             16 => 'PC DOS/Windows Executable Files [.COM][.EXE]',
74             17 => 'Compressed Binary File [.ZIP] (PKWare Inc)',
75             18 => 'Audio Interchange File Format AIFF (Apple Computer Inc)',
76             19 => 'RIFF Wave (Microsoft Corporation)',
77             20 => 'Freehand (Macromedia/Aldus)',
78             21 => 'Hypertext Markup Language [.HTML] (The Internet Society)',
79             22 => 'MPEG 2 Audio Layer 2 (Musicom), ISO/IEC',
80             23 => 'MPEG 2 Audio Layer 3, ISO/IEC',
81             24 => 'Portable Document File [.PDF] Adobe',
82             25 => 'News Industry Text Format (NITF)',
83             26 => 'Tape Archive [.TAR]',
84             27 => 'Tidningarnas Telegrambyra NITF version (TTNITF DTD)',
85             28 => 'Ritzaus Bureau NITF version (RBNITF DTD)',
86             29 => 'Corel Draw [.CDR]',
87             );
88              
89             # main IPTC tag table
90             # Note: ALL entries in main IPTC table (except PROCESS_PROC) must be SubDirectory
91             # entries, each specifying a TagTable.
92             %Image::ExifTool::IPTC::Main = (
93             GROUPS => { 2 => 'Image' },
94             PROCESS_PROC => \&ProcessIPTC,
95             WRITE_PROC => \&WriteIPTC,
96             1 => {
97             Name => 'IPTCEnvelope',
98             SubDirectory => {
99             TagTable => 'Image::ExifTool::IPTC::EnvelopeRecord',
100             },
101             },
102             2 => {
103             Name => 'IPTCApplication',
104             SubDirectory => {
105             TagTable => 'Image::ExifTool::IPTC::ApplicationRecord',
106             },
107             },
108             3 => {
109             Name => 'IPTCNewsPhoto',
110             SubDirectory => {
111             TagTable => 'Image::ExifTool::IPTC::NewsPhoto',
112             },
113             },
114             7 => {
115             Name => 'IPTCPreObjectData',
116             SubDirectory => {
117             TagTable => 'Image::ExifTool::IPTC::PreObjectData',
118             },
119             },
120             8 => {
121             Name => 'IPTCObjectData',
122             SubDirectory => {
123             TagTable => 'Image::ExifTool::IPTC::ObjectData',
124             },
125             },
126             9 => {
127             Name => 'IPTCPostObjectData',
128             Groups => { 1 => 'IPTC#' }, #(just so this shows up in group list)
129             SubDirectory => {
130             TagTable => 'Image::ExifTool::IPTC::PostObjectData',
131             },
132             },
133             240 => {
134             Name => 'IPTCFotoStation',
135             SubDirectory => {
136             TagTable => 'Image::ExifTool::IPTC::FotoStation',
137             },
138             },
139             );
140              
141             # Record 1 -- EnvelopeRecord
142             %Image::ExifTool::IPTC::EnvelopeRecord = (
143             GROUPS => { 2 => 'Other' },
144             WRITE_PROC => \&WriteIPTC,
145             CHECK_PROC => \&CheckIPTC,
146             WRITABLE => 1,
147             0 => {
148             Name => 'EnvelopeRecordVersion',
149             Format => 'int16u',
150             Mandatory => 1,
151             },
152             5 => {
153             Name => 'Destination',
154             Flags => 'List',
155             Groups => { 2 => 'Location' },
156             Format => 'string[0,1024]',
157             },
158             20 => {
159             Name => 'FileFormat',
160             Groups => { 2 => 'Image' },
161             Format => 'int16u',
162             PrintConv => \%fileFormat,
163             },
164             22 => {
165             Name => 'FileVersion',
166             Groups => { 2 => 'Image' },
167             Format => 'int16u',
168             },
169             30 => {
170             Name => 'ServiceIdentifier',
171             Format => 'string[0,10]',
172             },
173             40 => {
174             Name => 'EnvelopeNumber',
175             Format => 'digits[8]',
176             },
177             50 => {
178             Name => 'ProductID',
179             Flags => 'List',
180             Format => 'string[0,32]',
181             },
182             60 => {
183             Name => 'EnvelopePriority',
184             Format => 'digits[1]',
185             PrintConv => {
186             0 => '0 (reserved)',
187             1 => '1 (most urgent)',
188             2 => 2,
189             3 => 3,
190             4 => 4,
191             5 => '5 (normal urgency)',
192             6 => 6,
193             7 => 7,
194             8 => '8 (least urgent)',
195             9 => '9 (user-defined priority)',
196             },
197             },
198             70 => {
199             Name => 'DateSent',
200             Groups => { 2 => 'Time' },
201             Format => 'digits[8]',
202             Shift => 'Time',
203             ValueConv => 'Image::ExifTool::Exif::ExifDate($val)',
204             ValueConvInv => 'Image::ExifTool::IPTC::IptcDate($val)',
205             PrintConvInv => 'Image::ExifTool::IPTC::InverseDateOrTime($self,$val)',
206             },
207             80 => {
208             Name => 'TimeSent',
209             Groups => { 2 => 'Time' },
210             Format => 'string[11]',
211             Shift => 'Time',
212             ValueConv => 'Image::ExifTool::Exif::ExifTime($val)',
213             ValueConvInv => 'Image::ExifTool::IPTC::IptcTime($val)',
214             PrintConvInv => 'Image::ExifTool::IPTC::InverseDateOrTime($self,$val)',
215             },
216             90 => {
217             Name => 'CodedCharacterSet',
218             Notes => q{
219             values are entered in the form "ESC X Y[, ...]". The escape sequence for
220             UTF-8 character coding is "ESC % G", but this is displayed as "UTF8" for
221             convenience. Either string may be used when writing. The value of this tag
222             affects the decoding of string values in the Application and NewsPhoto
223             records. This tag is marked as "unsafe" to prevent it from being copied by
224             default in a group operation because existing tags in the destination image
225             may use a different encoding. When creating a new IPTC record from scratch,
226             it is suggested that this be set to "UTF8" if special characters are a
227             possibility
228             },
229             Protected => 1,
230             Format => 'string[0,32]',
231             ValueConvInv => '$val =~ /^UTF-?8$/i ? "\x1b%G" : $val',
232             # convert ISO 2022 escape sequences to a more readable format
233             PrintConv => \&PrintCodedCharset,
234             PrintConvInv => \&PrintInvCodedCharset,
235             },
236             100 => {
237             Name => 'UniqueObjectName',
238             Format => 'string[14,80]',
239             },
240             120 => {
241             Name => 'ARMIdentifier',
242             Format => 'int16u',
243             },
244             122 => {
245             Name => 'ARMVersion',
246             Format => 'int16u',
247             },
248             );
249              
250             # Record 2 -- ApplicationRecord
251             %Image::ExifTool::IPTC::ApplicationRecord = (
252             GROUPS => { 2 => 'Other' },
253             WRITE_PROC => \&WriteIPTC,
254             CHECK_PROC => \&CheckIPTC,
255             WRITABLE => 1,
256             0 => {
257             Name => 'ApplicationRecordVersion',
258             Format => 'int16u',
259             Mandatory => 1,
260             },
261             3 => {
262             Name => 'ObjectTypeReference',
263             Format => 'string[3,67]',
264             },
265             4 => {
266             Name => 'ObjectAttributeReference',
267             Flags => 'List',
268             Format => 'string[4,68]',
269             },
270             5 => {
271             Name => 'ObjectName',
272             Format => 'string[0,64]',
273             },
274             7 => {
275             Name => 'EditStatus',
276             Format => 'string[0,64]',
277             },
278             8 => {
279             Name => 'EditorialUpdate',
280             Format => 'digits[2]',
281             PrintConv => {
282             '01' => 'Additional language',
283             },
284             },
285             10 => {
286             Name => 'Urgency',
287             Format => 'digits[1]',
288             PrintConv => {
289             0 => '0 (reserved)',
290             1 => '1 (most urgent)',
291             2 => 2,
292             3 => 3,
293             4 => 4,
294             5 => '5 (normal urgency)',
295             6 => 6,
296             7 => 7,
297             8 => '8 (least urgent)',
298             9 => '9 (user-defined priority)',
299             },
300             },
301             12 => {
302             Name => 'SubjectReference',
303             Flags => 'List',
304             Format => 'string[13,236]',
305             },
306             15 => {
307             Name => 'Category',
308             Format => 'string[0,3]',
309             },
310             20 => {
311             Name => 'SupplementalCategories',
312             Flags => 'List',
313             Format => 'string[0,32]',
314             },
315             22 => {
316             Name => 'FixtureIdentifier',
317             Format => 'string[0,32]',
318             },
319             25 => {
320             Name => 'Keywords',
321             Flags => 'List',
322             Format => 'string[0,64]',
323             },
324             26 => {
325             Name => 'ContentLocationCode',
326             Flags => 'List',
327             Groups => { 2 => 'Location' },
328             Format => 'string[3]',
329             },
330             27 => {
331             Name => 'ContentLocationName',
332             Flags => 'List',
333             Groups => { 2 => 'Location' },
334             Format => 'string[0,64]',
335             },
336             30 => {
337             Name => 'ReleaseDate',
338             Groups => { 2 => 'Time' },
339             Format => 'digits[8]',
340             Shift => 'Time',
341             ValueConv => 'Image::ExifTool::Exif::ExifDate($val)',
342             ValueConvInv => 'Image::ExifTool::IPTC::IptcDate($val)',
343             PrintConvInv => 'Image::ExifTool::IPTC::InverseDateOrTime($self,$val)',
344             },
345             35 => {
346             Name => 'ReleaseTime',
347             Groups => { 2 => 'Time' },
348             Format => 'string[11]',
349             Shift => 'Time',
350             ValueConv => 'Image::ExifTool::Exif::ExifTime($val)',
351             ValueConvInv => 'Image::ExifTool::IPTC::IptcTime($val)',
352             PrintConvInv => 'Image::ExifTool::IPTC::InverseDateOrTime($self,$val)',
353             },
354             37 => {
355             Name => 'ExpirationDate',
356             Groups => { 2 => 'Time' },
357             Format => 'digits[8]',
358             Shift => 'Time',
359             ValueConv => 'Image::ExifTool::Exif::ExifDate($val)',
360             ValueConvInv => 'Image::ExifTool::IPTC::IptcDate($val)',
361             PrintConvInv => 'Image::ExifTool::IPTC::InverseDateOrTime($self,$val)',
362             },
363             38 => {
364             Name => 'ExpirationTime',
365             Groups => { 2 => 'Time' },
366             Format => 'string[11]',
367             Shift => 'Time',
368             ValueConv => 'Image::ExifTool::Exif::ExifTime($val)',
369             ValueConvInv => 'Image::ExifTool::IPTC::IptcTime($val)',
370             PrintConvInv => 'Image::ExifTool::IPTC::InverseDateOrTime($self,$val)',
371             },
372             40 => {
373             Name => 'SpecialInstructions',
374             Format => 'string[0,256]',
375             },
376             42 => {
377             Name => 'ActionAdvised',
378             Format => 'digits[2]',
379             PrintConv => {
380             '' => '',
381             '01' => 'Object Kill',
382             '02' => 'Object Replace',
383             '03' => 'Object Append',
384             '04' => 'Object Reference',
385             },
386             },
387             45 => {
388             Name => 'ReferenceService',
389             Flags => 'List',
390             Format => 'string[0,10]',
391             },
392             47 => {
393             Name => 'ReferenceDate',
394             Groups => { 2 => 'Time' },
395             Flags => 'List',
396             Format => 'digits[8]',
397             Shift => 'Time',
398             ValueConv => 'Image::ExifTool::Exif::ExifDate($val)',
399             ValueConvInv => 'Image::ExifTool::IPTC::IptcDate($val)',
400             PrintConvInv => 'Image::ExifTool::IPTC::InverseDateOrTime($self,$val)',
401             },
402             50 => {
403             Name => 'ReferenceNumber',
404             Flags => 'List',
405             Format => 'digits[8]',
406             },
407             55 => {
408             Name => 'DateCreated',
409             Groups => { 2 => 'Time' },
410             Format => 'digits[8]',
411             Shift => 'Time',
412             ValueConv => 'Image::ExifTool::Exif::ExifDate($val)',
413             ValueConvInv => 'Image::ExifTool::IPTC::IptcDate($val)',
414             PrintConv => '$self->Options("DateFormat") ? $self->ConvertDateTime("$val 00:00:00") : $val',
415             PrintConvInv => 'Image::ExifTool::IPTC::InverseDateOrTime($self,$val)',
416             },
417             60 => {
418             Name => 'TimeCreated',
419             Groups => { 2 => 'Time' },
420             Format => 'string[11]',
421             Shift => 'Time',
422             ValueConv => 'Image::ExifTool::Exif::ExifTime($val)',
423             ValueConvInv => 'Image::ExifTool::IPTC::IptcTime($val)',
424             PrintConv => '$self->Options("DateFormat") ? $self->ConvertDateTime("1970:01:01 $val") : $val',
425             PrintConvInv => 'Image::ExifTool::IPTC::InverseDateOrTime($self,$val)',
426             },
427             62 => {
428             Name => 'DigitalCreationDate',
429             Groups => { 2 => 'Time' },
430             Format => 'digits[8]',
431             Shift => 'Time',
432             ValueConv => 'Image::ExifTool::Exif::ExifDate($val)',
433             ValueConvInv => 'Image::ExifTool::IPTC::IptcDate($val)',
434             PrintConv => '$self->Options("DateFormat") ? $self->ConvertDateTime("$val 00:00:00") : $val',
435             PrintConvInv => 'Image::ExifTool::IPTC::InverseDateOrTime($self,$val)',
436             },
437             63 => {
438             Name => 'DigitalCreationTime',
439             Groups => { 2 => 'Time' },
440             Format => 'string[11]',
441             Shift => 'Time',
442             ValueConv => 'Image::ExifTool::Exif::ExifTime($val)',
443             ValueConvInv => 'Image::ExifTool::IPTC::IptcTime($val)',
444             PrintConv => '$self->Options("DateFormat") ? $self->ConvertDateTime("1970:01:01 $val") : $val',
445             PrintConvInv => 'Image::ExifTool::IPTC::InverseDateOrTime($self,$val)',
446             },
447             65 => {
448             Name => 'OriginatingProgram',
449             Format => 'string[0,32]',
450             },
451             70 => {
452             Name => 'ProgramVersion',
453             Format => 'string[0,10]',
454             },
455             75 => {
456             Name => 'ObjectCycle',
457             Format => 'string[1]',
458             PrintConv => {
459             'a' => 'Morning',
460             'p' => 'Evening',
461             'b' => 'Both Morning and Evening',
462             },
463             },
464             80 => {
465             Name => 'By-line',
466             Flags => 'List',
467             Format => 'string[0,32]',
468             Groups => { 2 => 'Author' },
469             },
470             85 => {
471             Name => 'By-lineTitle',
472             Flags => 'List',
473             Format => 'string[0,32]',
474             Groups => { 2 => 'Author' },
475             },
476             90 => {
477             Name => 'City',
478             Format => 'string[0,32]',
479             Groups => { 2 => 'Location' },
480             },
481             92 => {
482             Name => 'Sub-location',
483             Format => 'string[0,32]',
484             Groups => { 2 => 'Location' },
485             },
486             95 => {
487             Name => 'Province-State',
488             Format => 'string[0,32]',
489             Groups => { 2 => 'Location' },
490             },
491             100 => {
492             Name => 'Country-PrimaryLocationCode',
493             Format => 'string[3]',
494             Groups => { 2 => 'Location' },
495             },
496             101 => {
497             Name => 'Country-PrimaryLocationName',
498             Format => 'string[0,64]',
499             Groups => { 2 => 'Location' },
500             },
501             103 => {
502             Name => 'OriginalTransmissionReference',
503             Format => 'string[0,32]',
504             Notes => 'now used as a job identifier',
505             },
506             105 => {
507             Name => 'Headline',
508             Format => 'string[0,256]',
509             },
510             110 => {
511             Name => 'Credit',
512             Groups => { 2 => 'Author' },
513             Format => 'string[0,32]',
514             },
515             115 => {
516             Name => 'Source',
517             Groups => { 2 => 'Author' },
518             Format => 'string[0,32]',
519             },
520             116 => {
521             Name => 'CopyrightNotice',
522             Groups => { 2 => 'Author' },
523             Format => 'string[0,128]',
524             },
525             118 => {
526             Name => 'Contact',
527             Flags => 'List',
528             Groups => { 2 => 'Author' },
529             Format => 'string[0,128]',
530             },
531             120 => {
532             Name => 'Caption-Abstract',
533             Format => 'string[0,2000]',
534             },
535             121 => {
536             Name => 'LocalCaption',
537             Format => 'string[0,256]', # (guess)
538             Notes => q{
539             I haven't found a reference for the format of tags 121, 184-188 and
540             225-232, so I have just make them writable as strings with
541             reasonable length. Beware that if this is wrong, other utilities
542             may not be able to read these tags as written by ExifTool
543             },
544             },
545             122 => {
546             Name => 'Writer-Editor',
547             Flags => 'List',
548             Groups => { 2 => 'Author' },
549             Format => 'string[0,32]',
550             },
551             125 => {
552             Name => 'RasterizedCaption',
553             Format => 'undef[7360]',
554             Binary => 1,
555             },
556             130 => {
557             Name => 'ImageType',
558             Groups => { 2 => 'Image' },
559             Format => 'string[2]',
560             },
561             131 => {
562             Name => 'ImageOrientation',
563             Groups => { 2 => 'Image' },
564             Format => 'string[1]',
565             PrintConv => {
566             P => 'Portrait',
567             L => 'Landscape',
568             S => 'Square',
569             },
570             },
571             135 => {
572             Name => 'LanguageIdentifier',
573             Format => 'string[2,3]',
574             },
575             150 => {
576             Name => 'AudioType',
577             Format => 'string[2]',
578             PrintConv => {
579             '1A' => 'Mono Actuality',
580             '2A' => 'Stereo Actuality',
581             '1C' => 'Mono Question and Answer Session',
582             '2C' => 'Stereo Question and Answer Session',
583             '1M' => 'Mono Music',
584             '2M' => 'Stereo Music',
585             '1Q' => 'Mono Response to a Question',
586             '2Q' => 'Stereo Response to a Question',
587             '1R' => 'Mono Raw Sound',
588             '2R' => 'Stereo Raw Sound',
589             '1S' => 'Mono Scener',
590             '2S' => 'Stereo Scener',
591             '0T' => 'Text Only',
592             '1V' => 'Mono Voicer',
593             '2V' => 'Stereo Voicer',
594             '1W' => 'Mono Wrap',
595             '2W' => 'Stereo Wrap',
596             },
597             },
598             151 => {
599             Name => 'AudioSamplingRate',
600             Format => 'digits[6]',
601             },
602             152 => {
603             Name => 'AudioSamplingResolution',
604             Format => 'digits[2]',
605             },
606             153 => {
607             Name => 'AudioDuration',
608             Format => 'digits[6]',
609             },
610             154 => {
611             Name => 'AudioOutcue',
612             Format => 'string[0,64]',
613             },
614             184 => {
615             Name => 'JobID',
616             Format => 'string[0,64]', # (guess)
617             },
618             185 => {
619             Name => 'MasterDocumentID',
620             Format => 'string[0,256]', # (guess)
621             },
622             186 => {
623             Name => 'ShortDocumentID',
624             Format => 'string[0,64]', # (guess)
625             },
626             187 => {
627             Name => 'UniqueDocumentID',
628             Format => 'string[0,128]', # (guess)
629             },
630             188 => {
631             Name => 'OwnerID',
632             Format => 'string[0,128]', # (guess)
633             },
634             200 => {
635             Name => 'ObjectPreviewFileFormat',
636             Groups => { 2 => 'Image' },
637             Format => 'int16u',
638             PrintConv => \%fileFormat,
639             },
640             201 => {
641             Name => 'ObjectPreviewFileVersion',
642             Groups => { 2 => 'Image' },
643             Format => 'int16u',
644             },
645             202 => {
646             Name => 'ObjectPreviewData',
647             Groups => { 2 => 'Preview' },
648             Format => 'undef[0,256000]',
649             Binary => 1,
650             },
651             221 => {
652             Name => 'Prefs',
653             Groups => { 2 => 'Image' },
654             Format => 'string[0,64]',
655             Notes => 'PhotoMechanic preferences',
656             PrintConv => q{
657             $val =~ s[\s*(\d+):\s*(\d+):\s*(\d+):\s*(\S*)]
658             [Tagged:$1, ColorClass:$2, Rating:$3, FrameNum:$4];
659             return $val;
660             },
661             PrintConvInv => q{
662             $val =~ s[Tagged:\s*(\d+).*ColorClass:\s*(\d+).*Rating:\s*(\d+).*FrameNum:\s*(\S*)]
663             [$1:$2:$3:$4]is;
664             return $val;
665             },
666             },
667             225 => {
668             Name => 'ClassifyState',
669             Format => 'string[0,64]', # (guess)
670             },
671             228 => {
672             Name => 'SimilarityIndex',
673             Format => 'string[0,32]', # (guess)
674             },
675             230 => {
676             Name => 'DocumentNotes',
677             Format => 'string[0,1024]', # (guess)
678             },
679             231 => {
680             Name => 'DocumentHistory',
681             Format => 'string[0,256]', # (guess)
682             ValueConv => '$val =~ s/\0+/\n/g; $val', # (have seen embedded nulls)
683             ValueConvInv => '$val',
684             },
685             232 => {
686             Name => 'ExifCameraInfo',
687             Format => 'string[0,4096]', # (guess)
688             },
689             255 => { #PH
690             Name => 'CatalogSets',
691             List => 1,
692             Format => 'string[0,256]', # (guess)
693             Notes => 'written by iView MediaPro',
694             },
695             );
696              
697             # Record 3 -- News photo
698             %Image::ExifTool::IPTC::NewsPhoto = (
699             GROUPS => { 2 => 'Image' },
700             WRITE_PROC => \&WriteIPTC,
701             CHECK_PROC => \&CheckIPTC,
702             WRITABLE => 1,
703             0 => {
704             Name => 'NewsPhotoVersion',
705             Format => 'int16u',
706             Mandatory => 1,
707             },
708             10 => {
709             Name => 'IPTCPictureNumber',
710             Format => 'string[16]',
711             Notes => '4 numbers: 1-Manufacturer ID, 2-Equipment ID, 3-Date, 4-Sequence',
712             PrintConv => 'Image::ExifTool::IPTC::ConvertPictureNumber($val)',
713             PrintConvInv => 'Image::ExifTool::IPTC::InvConvertPictureNumber($val)',
714             },
715             20 => {
716             Name => 'IPTCImageWidth',
717             Format => 'int16u',
718             },
719             30 => {
720             Name => 'IPTCImageHeight',
721             Format => 'int16u',
722             },
723             40 => {
724             Name => 'IPTCPixelWidth',
725             Format => 'int16u',
726             },
727             50 => {
728             Name => 'IPTCPixelHeight',
729             Format => 'int16u',
730             },
731             55 => {
732             Name => 'SupplementalType',
733             Format => 'int8u',
734             PrintConv => {
735             0 => 'Main Image',
736             1 => 'Reduced Resolution Image',
737             2 => 'Logo',
738             3 => 'Rasterized Caption',
739             },
740             },
741             60 => {
742             Name => 'ColorRepresentation',
743             Format => 'int16u',
744             PrintHex => 1,
745             PrintConv => {
746             0x000 => 'No Image, Single Frame',
747             0x100 => 'Monochrome, Single Frame',
748             0x300 => '3 Components, Single Frame',
749             0x301 => '3 Components, Frame Sequential in Multiple Objects',
750             0x302 => '3 Components, Frame Sequential in One Object',
751             0x303 => '3 Components, Line Sequential',
752             0x304 => '3 Components, Pixel Sequential',
753             0x305 => '3 Components, Special Interleaving',
754             0x400 => '4 Components, Single Frame',
755             0x401 => '4 Components, Frame Sequential in Multiple Objects',
756             0x402 => '4 Components, Frame Sequential in One Object',
757             0x403 => '4 Components, Line Sequential',
758             0x404 => '4 Components, Pixel Sequential',
759             0x405 => '4 Components, Special Interleaving',
760             },
761             },
762             64 => {
763             Name => 'InterchangeColorSpace',
764             Format => 'int8u',
765             PrintConv => {
766             1 => 'X,Y,Z CIE',
767             2 => 'RGB SMPTE',
768             3 => 'Y,U,V (K) (D65)',
769             4 => 'RGB Device Dependent',
770             5 => 'CMY (K) Device Dependent',
771             6 => 'Lab (K) CIE',
772             7 => 'YCbCr',
773             8 => 'sRGB',
774             },
775             },
776             65 => {
777             Name => 'ColorSequence',
778             Format => 'int8u',
779             },
780             66 => {
781             Name => 'ICC_Profile',
782             # ...could add SubDirectory support to read into this (if anybody cares)
783             Writable => 0,
784             Binary => 1,
785             },
786             70 => {
787             Name => 'ColorCalibrationMatrix',
788             Writable => 0,
789             Binary => 1,
790             },
791             80 => {
792             Name => 'LookupTable',
793             Writable => 0,
794             Binary => 1,
795             },
796             84 => {
797             Name => 'NumIndexEntries',
798             Format => 'int16u',
799             },
800             85 => {
801             Name => 'ColorPalette',
802             Writable => 0,
803             Binary => 1,
804             },
805             86 => {
806             Name => 'IPTCBitsPerSample',
807             Format => 'int8u',
808             },
809             90 => {
810             Name => 'SampleStructure',
811             Format => 'int8u',
812             PrintConv => {
813             0 => 'OrthogonalConstangSampling',
814             1 => 'Orthogonal4-2-2Sampling',
815             2 => 'CompressionDependent',
816             },
817             },
818             100 => {
819             Name => 'ScanningDirection',
820             Format => 'int8u',
821             PrintConv => {
822             0 => 'L-R, Top-Bottom',
823             1 => 'R-L, Top-Bottom',
824             2 => 'L-R, Bottom-Top',
825             3 => 'R-L, Bottom-Top',
826             4 => 'Top-Bottom, L-R',
827             5 => 'Bottom-Top, L-R',
828             6 => 'Top-Bottom, R-L',
829             7 => 'Bottom-Top, R-L',
830             },
831             },
832             102 => {
833             Name => 'IPTCImageRotation',
834             Format => 'int8u',
835             PrintConv => {
836             0 => 0,
837             1 => 90,
838             2 => 180,
839             3 => 270,
840             },
841             },
842             110 => {
843             Name => 'DataCompressionMethod',
844             Format => 'int32u',
845             },
846             120 => {
847             Name => 'QuantizationMethod',
848             Format => 'int8u',
849             PrintConv => {
850             0 => 'Linear Reflectance/Transmittance',
851             1 => 'Linear Density',
852             2 => 'IPTC Ref B',
853             3 => 'Linear Dot Percent',
854             4 => 'AP Domestic Analogue',
855             5 => 'Compression Method Specific',
856             6 => 'Color Space Specific',
857             7 => 'Gamma Compensated',
858             },
859             },
860             125 => {
861             Name => 'EndPoints',
862             Writable => 0,
863             Binary => 1,
864             },
865             130 => {
866             Name => 'ExcursionTolerance',
867             Format => 'int8u',
868             PrintConv => {
869             0 => 'Not Allowed',
870             1 => 'Allowed',
871             },
872             },
873             135 => {
874             Name => 'BitsPerComponent',
875             Format => 'int8u',
876             },
877             140 => {
878             Name => 'MaximumDensityRange',
879             Format => 'int16u',
880             },
881             145 => {
882             Name => 'GammaCompensatedValue',
883             Format => 'int16u',
884             },
885             );
886              
887             # Record 7 -- Pre-object Data
888             %Image::ExifTool::IPTC::PreObjectData = (
889             # (not actually writable, but used in BuildTagLookup to recognize IPTC tables)
890             WRITE_PROC => \&WriteIPTC,
891             10 => {
892             Name => 'SizeMode',
893             Format => 'int8u',
894             PrintConv => {
895             0 => 'Size Not Known',
896             1 => 'Size Known',
897             },
898             },
899             20 => {
900             Name => 'MaxSubfileSize',
901             Format => 'int32u',
902             },
903             90 => {
904             Name => 'ObjectSizeAnnounced',
905             Format => 'int32u',
906             },
907             95 => {
908             Name => 'MaximumObjectSize',
909             Format => 'int32u',
910             },
911             );
912              
913             # Record 8 -- ObjectData
914             %Image::ExifTool::IPTC::ObjectData = (
915             WRITE_PROC => \&WriteIPTC,
916             10 => {
917             Name => 'SubFile',
918             Flags => 'List',
919             Binary => 1,
920             },
921             );
922              
923             # Record 9 -- PostObjectData
924             %Image::ExifTool::IPTC::PostObjectData = (
925             WRITE_PROC => \&WriteIPTC,
926             10 => {
927             Name => 'ConfirmedObjectSize',
928             Format => 'int32u',
929             },
930             );
931              
932             # Record 240 -- FotoStation proprietary data (ref PH)
933             %Image::ExifTool::IPTC::FotoStation = (
934             GROUPS => { 2 => 'Other' },
935             WRITE_PROC => \&WriteIPTC,
936             CHECK_PROC => \&CheckIPTC,
937             WRITABLE => 1,
938             );
939              
940             # IPTC Composite tags
941             %Image::ExifTool::IPTC::Composite = (
942             GROUPS => { 2 => 'Image' },
943             DateTimeCreated => {
944             Description => 'Date/Time Created',
945             Groups => { 2 => 'Time' },
946             Require => {
947             0 => 'IPTC:DateCreated',
948             1 => 'IPTC:TimeCreated',
949             },
950             ValueConv => '"$val[0] $val[1]"',
951             PrintConv => '$self->ConvertDateTime($val)',
952             },
953             DigitalCreationDateTime => {
954             Description => 'Digital Creation Date/Time',
955             Groups => { 2 => 'Time' },
956             Require => {
957             0 => 'IPTC:DigitalCreationDate',
958             1 => 'IPTC:DigitalCreationTime',
959             },
960             ValueConv => '"$val[0] $val[1]"',
961             PrintConv => '$self->ConvertDateTime($val)',
962             },
963             );
964              
965             # add our composite tags
966             Image::ExifTool::AddCompositeTags('Image::ExifTool::IPTC');
967              
968              
969             #------------------------------------------------------------------------------
970             # AutoLoad our writer routines when necessary
971             #
972             sub AUTOLOAD
973             {
974 22     22   181 return Image::ExifTool::DoAutoLoad($AUTOLOAD, @_);
975             }
976              
977             #------------------------------------------------------------------------------
978             # Print conversion for CodedCharacterSet
979             # Inputs: 0) value
980             sub PrintCodedCharset($)
981             {
982 2     2 0 8 my $val = shift;
983 2 50       24 return $iptcCharset{$val} if $iptcCharset{$val};
984 0         0 $val =~ s/(.)/ $1/g;
985 0         0 $val =~ s/ \x1b/, ESC/g;
986 0         0 $val =~ s/^,? //;
987 0         0 return $val;
988             }
989              
990             #------------------------------------------------------------------------------
991             # Handle CodedCharacterSet
992             # Inputs: 0) ExifTool ref, 1) CodedCharacterSet value
993             # Returns: IPTC character set if translation required (or 'bad' if unknown)
994             sub HandleCodedCharset($$)
995             {
996 4     4 0 20 my ($et, $val) = @_;
997 4         17 my $xlat = $iptcCharset{$val};
998 4 50       16 unless ($xlat) {
999 0 0       0 if ($val =~ /^\x1b\x25/) {
1000             # some unknown character set invoked
1001 0         0 $xlat = 'bad'; # flag unsupported coding
1002             } else {
1003 0         0 $xlat = $et->Options('CharsetIPTC');
1004             }
1005             }
1006             # no need to translate if Charset is the same
1007 4 50       21 undef $xlat if $xlat eq $et->Options('Charset');
1008 4         17 return $xlat;
1009             }
1010              
1011             #------------------------------------------------------------------------------
1012             # Encode or decode coded string
1013             # Inputs: 0) ExifTool ref, 1) value ptr, 2) IPTC charset (or 'bad') ref
1014             # 3) flag set to decode (read) value from IPTC
1015             # Updates value on return
1016             sub TranslateCodedString($$$$)
1017             {
1018 5     5 0 19 my ($et, $valPtr, $xlatPtr, $read) = @_;
1019 5 50       38 if ($$xlatPtr eq 'bad') {
    100          
    50          
1020 0         0 $et->Warn('Some IPTC characters not converted (unsupported CodedCharacterSet)');
1021 0         0 undef $$xlatPtr;
1022             } elsif (not $read) {
1023 2         19 $$valPtr = $et->Decode($$valPtr, undef, undef, $$xlatPtr);
1024             } elsif ($$valPtr !~ /[\x14\x15\x1b]/) {
1025 3         18 $$valPtr = $et->Decode($$valPtr, $$xlatPtr);
1026             } else {
1027             # don't yet support reading ISO 2022 shifted character sets
1028 0         0 $et->Warn('Some IPTC characters not converted (ISO 2022 shifting not supported)');
1029             }
1030             }
1031              
1032             #------------------------------------------------------------------------------
1033             # Is this IPTC in a standard location?
1034             # Inputs: 0) Current metadata path string
1035             # Returns: true if path is standard, 0 if file type doesn't have standard IPTC,
1036             # or undef if IPTC is non-standard
1037             sub IsStandardIPTC($)
1038             {
1039 154     154 0 328 my $path = shift;
1040 154 100       831 return 1 if $isStandardIPTC{$path};
1041 70 100 66     780 return 0 unless $path =~ /^(\w+)/ and defined $isStandardIPTC{$1};
1042 44         122 return undef; # non-standard
1043             }
1044              
1045             #------------------------------------------------------------------------------
1046             # get IPTC info
1047             # Inputs: 0) ExifTool object reference, 1) dirInfo reference
1048             # 2) reference to tag table
1049             # Returns: 1 on success, 0 otherwise
1050             sub ProcessIPTC($$$)
1051             {
1052 178     178 0 607 my ($et, $dirInfo, $tagTablePtr) = @_;
1053 178         537 my $dataPt = $$dirInfo{DataPt};
1054 178   100     978 my $pos = $$dirInfo{DirStart} || 0;
1055 178   50     761 my $dirLen = $$dirInfo{DirLen} || 0;
1056 178         437 my $dirEnd = $pos + $dirLen;
1057 178         959 my $verbose = $et->Options('Verbose');
1058 178         611 my $validate = $et->Options('Validate');
1059 178         491 my $success = 0;
1060 178         395 my ($lastRec, $recordPtr, $recordName, %seen);
1061              
1062 178 50 33     795 $verbose and $dirInfo and $et->VerboseDir('IPTC', 0, $$dirInfo{DirLen});
1063              
1064 178 100       848 if ($tagTablePtr eq \%Image::ExifTool::IPTC::Main) {
1065 153         753 my $path = $et->MetadataPath();
1066 153         677 my $isStd = IsStandardIPTC($path);
1067 153 100 66     1027 if (defined $isStd and not $$et{DIR_COUNT}{STD_IPTC}) {
1068             # set flag to ensure we only have one family 1 "IPTC" group
1069 109         468 $$et{DIR_COUNT}{STD_IPTC} = 1;
1070             # calculate MD5 if Digest::MD5 is available (truly standard IPTC only)
1071 109 100       433 if ($isStd) {
1072 83         192 my $md5;
1073 83 50       210 if (eval { require Digest::MD5 }) {
  83         970  
1074 83 100 66     454 if ($pos or $dirLen != length($$dataPt)) {
1075 71         873 $md5 = Digest::MD5::md5(substr $$dataPt, $pos, $dirLen);
1076             } else {
1077 12         90 $md5 = Digest::MD5::md5($$dataPt);
1078             }
1079             } else {
1080             # a zero digest indicates IPTC exists but we don't have Digest::MD5
1081 0         0 $md5 = "\0" x 16;
1082             }
1083 83         522 $et->FoundTag('CurrentIPTCDigest', $md5);
1084             }
1085             } else {
1086 44 100 66     319 if (($Image::ExifTool::MWG::strict or $validate) and
      66        
1087             $$et{FILE_TYPE} =~ /^(JPEG|TIFF|PSD)$/)
1088             {
1089 4 50       8 if ($Image::ExifTool::MWG::strict) {
1090             # ignore non-standard IPTC while in strict MWG compatibility mode
1091 4         22 $et->Warn("Ignored non-standard IPTC at $path");
1092 4         11 return 1;
1093             } else {
1094 0         0 $et->Warn("Non-standard IPTC at $path", 1);
1095             }
1096             }
1097             # extract non-standard IPTC
1098 40   100     265 my $count = ($$et{DIR_COUNT}{IPTC} || 0) + 1; # count non-standard IPTC
1099 40         113 $$et{DIR_COUNT}{IPTC} = $count;
1100 40         116 $$et{LOW_PRIORITY_DIR}{IPTC} = 1; # lower priority of non-standard IPTC
1101 40         187 $$et{SET_GROUP1} = '+' . ($count + 1); # add number to family 1 group name
1102             }
1103             }
1104             # begin by assuming default IPTC encoding
1105 174         672 my $xlat = $et->Options('CharsetIPTC');
1106 174 50       669 undef $xlat if $xlat eq $et->Options('Charset');
1107              
1108             # quick check for improperly byte-swapped IPTC
1109 174 50 33     1401 if ($dirLen >= 4 and substr($$dataPt, $pos, 1) ne "\x1c" and
      33        
1110             substr($$dataPt, $pos + 3, 1) eq "\x1c")
1111             {
1112 0         0 $et->Warn('IPTC data was improperly byte-swapped');
1113 0         0 my $newData = pack('N*', unpack('V*', substr($$dataPt, $pos, $dirLen) . "\0\0\0"));
1114 0         0 $dataPt = \$newData;
1115 0         0 $pos = 0;
1116 0         0 $dirEnd = $pos + $dirLen;
1117             # NOTE: MUST NOT access $dirInfo DataPt, DirStart or DataLen after this!
1118             }
1119             # extract IPTC as a block if specified
1120 174 100 66     1683 if ($$et{REQ_TAG_LOOKUP}{iptc} or ($$et{TAGS_FROM_FILE} and
      100        
1121             not $$et{EXCL_TAG_LOOKUP}{iptc}))
1122             {
1123 35 100 66     201 if ($pos or $dirLen != length($$dataPt)) {
1124 17         148 $et->FoundTag('IPTC', substr($$dataPt, $pos, $dirLen));
1125             } else {
1126 18         71 $et->FoundTag('IPTC', $$dataPt);
1127             }
1128             }
1129 174         822 while ($pos + 5 <= $dirEnd) {
1130 2493         5332 my $buff = substr($$dataPt, $pos, 5);
1131 2493         8401 my ($id, $rec, $tag, $len) = unpack("CCCn", $buff);
1132 2493 100       6075 unless ($id == 0x1c) {
1133 3 50       14 unless ($id) {
1134             # scan the rest of the data an give warning unless all zeros
1135             # (iMatch pads the IPTC block with nulls for some reason)
1136 3         14 my $remaining = substr($$dataPt, $pos, $dirEnd - $pos);
1137 3 50       18 last unless $remaining =~ /[^\0]/;
1138             }
1139 0         0 $et->Warn(sprintf('Bad IPTC data tag (marker 0x%x)',$id));
1140 0         0 last;
1141             }
1142 2490         4068 $pos += 5; # step to after field header
1143             # handle extended IPTC entry if necessary
1144 2490 50       5646 if ($len & 0x8000) {
1145 0         0 my $n = $len & 0x7fff; # get num bytes in length field
1146 0 0 0     0 if ($pos + $n > $dirEnd or $n > 8) {
1147 0         0 $et->VPrint(0, "Invalid extended IPTC entry (dataset $rec:$tag, len $len)\n");
1148 0         0 $success = 0;
1149 0         0 last;
1150             }
1151             # determine length (a big-endian, variable sized int)
1152 0         0 for ($len = 0; $n; ++$pos, --$n) {
1153 0         0 $len = $len * 256 + ord(substr($$dataPt, $pos, 1));
1154             }
1155             }
1156 2490 50       5320 if ($pos + $len > $dirEnd) {
1157 0         0 $et->VPrint(0, "Invalid IPTC entry (dataset $rec:$tag, len $len)\n");
1158 0         0 $success = 0;
1159 0         0 last;
1160             }
1161 2490 100 100     8885 if (not defined $lastRec or $lastRec != $rec) {
1162 177 0 33     650 if ($validate and defined $lastRec and $rec < $lastRec) {
      33        
1163 0         0 $et->Warn("IPTC doesn't conform to spec: Records out of sequence",1)
1164             }
1165 177         590 my $tableInfo = $tagTablePtr->{$rec};
1166 177 50       566 unless ($tableInfo) {
1167 0         0 $et->Warn("Unrecognized IPTC record $rec (ignored)");
1168 0         0 $pos += $len;
1169 0         0 next; # ignore this entry
1170             }
1171 177         624 my $tableName = $tableInfo->{SubDirectory}->{TagTable};
1172 177 50       591 unless ($tableName) {
1173 0         0 $et->Warn("No table for IPTC record $rec!");
1174 0         0 last; # this shouldn't happen
1175             }
1176 177         498 $recordName = $$tableInfo{Name};
1177 177         665 $recordPtr = Image::ExifTool::GetTagTable($tableName);
1178 177         1457 $et->VPrint(0,$$et{INDENT},"-- $recordName record --\n");
1179 177         496 $lastRec = $rec;
1180             }
1181 2490         5664 my $val = substr($$dataPt, $pos, $len);
1182              
1183             # add tagInfo for all unknown tags:
1184 2490 100       7784 unless ($$recordPtr{$tag}) {
1185             # - no Format so format is auto-detected
1186             # - no Name so name is generated automatically with decimal tag number
1187 22         76 AddTagToTable($recordPtr, $tag, { Unknown => 1 });
1188             }
1189 2490         9366 my $tagInfo = $et->GetTagInfo($recordPtr, $tag);
1190 2490 0 33     6320 if ($validate and not $$tagInfo{List} and not $$tagInfo{Unknown}) {
      33        
1191 0 0       0 $et->Warn("Multiple IPTC $$tagInfo{Name} tags") if $seen{$tagInfo};
1192 0         0 $seen{$tagInfo} = 1;
1193             }
1194 2490         3599 my $format;
1195             # (could use $$recordPtr{FORMAT} if no Format below, but don't do this to
1196             # be backward compatible with improperly written PhotoMechanic tags)
1197 2490 100       6753 $format = $$tagInfo{Format} if $tagInfo;
1198 2490 100       6404 if (not $format) {
    50          
1199             # guess at "int" format if not specified
1200 230 100 66     1586 $format = 'int' if $len <= 4 and $len != 3 and $val =~ /[\0-\x08]/;
      100        
1201             } elsif ($validate) {
1202 0         0 my ($fmt,$min,$max);
1203 0 0       0 if ($format =~ /(.*)\[(\d+)(,(\d+))?\]/) {
1204 0         0 $fmt = $1;
1205 0         0 $min = $2;
1206 0   0     0 $max = $4 || $2;
1207             } else {
1208 0         0 $fmt = $format;
1209 0         0 $min = $max = 1;
1210             }
1211 0   0     0 my $siz = Image::ExifTool::FormatSize($fmt) || 1;
1212 0         0 $min *= $siz; $max *= $siz;
  0         0  
1213 0 0 0     0 if ($len < $min or $len > $max) {
1214 0 0       0 my $should = ($min == $max) ? $min : ($len < $min ? "$min min" : "$max max");
    0          
1215 0 0       0 my $what = ($len < $siz * $min) ? 'short' : 'long';
1216 0         0 $et->Warn("IPTC $$tagInfo{Name} too $what ($len bytes; should be $should)", 1);
1217             }
1218             }
1219 2490 100       5249 if ($format) {
1220 2435 100       8726 if ($format =~ /^int/) {
    100          
    100          
    50          
1221 335 100       936 if ($len <= 8) { # limit integer conversion to 8 bytes long
1222 331         585 $val = 0;
1223 331         819 my $i;
1224 331         1008 for ($i=0; $i<$len; ++$i) {
1225 1012         2707 $val = $val * 256 + ord(substr($$dataPt, $pos+$i, 1));
1226             }
1227             }
1228             } elsif ($format =~ /^string/) {
1229             # some braindead softwares add null terminators
1230 1908 50 33     5439 if ($val =~ s/\0+$// and $validate) {
1231 0         0 $et->Warn("IPTC $$tagInfo{Name} improperly terminated", 1);
1232             }
1233 1908 100 66     11754 if ($rec == 1) {
    100 100        
1234             # handle CodedCharacterSet tag
1235 2 50       30 $xlat = HandleCodedCharset($et, $val) if $tag == 90;
1236             # translate characters if necessary and special characters exist
1237             } elsif ($xlat and $rec < 7 and $val =~ /[\x80-\xff]/) {
1238             # translate to specified character set
1239 3         18 TranslateCodedString($et, \$val, \$xlat, 1);
1240             }
1241             } elsif ($format =~ /^digits/) {
1242 190 50 33     758 if ($val =~ s/\0+$// and $validate) {
1243 0         0 $et->Warn("IPTC $$tagInfo{Name} improperly terminated", 1);
1244             }
1245             } elsif ($format !~ /^undef/) {
1246 0         0 warn("Invalid IPTC format: $format"); # (this would be a programming error)
1247             }
1248             }
1249             $verbose and $et->VerboseInfo($tag, $tagInfo,
1250             Table => $tagTablePtr,
1251             Value => $val,
1252             DataPt => $dataPt,
1253             DataPos => $$dirInfo{DataPos},
1254 2490 50       5300 Size => $len,
1255             Start => $pos,
1256             Extra => ", $recordName record",
1257             Format => $format,
1258             );
1259 2490 100       9726 $et->FoundTag($tagInfo, $val) if $tagInfo;
1260 2490         4175 $success = 1;
1261              
1262 2490         7620 $pos += $len; # increment to next field
1263             }
1264 174         524 delete $$et{SET_GROUP1};
1265 174         524 delete $$et{LOW_PRIORITY_DIR}{IPTC};
1266 174         815 return $success;
1267             }
1268              
1269             1; # end
1270              
1271              
1272             __END__