File Coverage

blib/lib/Image/ExifTool/IPTC.pm
Criterion Covered Total %
statement 110 162 67.9
branch 70 108 64.8
condition 42 77 54.5
subroutine 9 9 100.0
pod 0 5 0.0
total 231 361 63.9


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 27     27   4896 use strict;
  27         84  
  27         1118  
15 27     27   153 use vars qw($VERSION $AUTOLOAD %iptcCharset);
  27         72  
  27         1801  
16 27     27   207 use Image::ExifTool qw(:DataAccess :Utils);
  27         60  
  27         110396  
17              
18             $VERSION = '1.58';
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 21     21   315 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       15 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 15 my ($et, $val) = @_;
997 4         18 my $xlat = $iptcCharset{$val};
998 4 50       13 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       19 undef $xlat if $xlat eq $et->Options('Charset');
1008 4         15 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 3     3 0 8 my ($et, $valPtr, $xlatPtr, $read) = @_;
1019 3 50       22 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 1         7 $$valPtr = $et->Decode($$valPtr, undef, undef, $$xlatPtr);
1024             } elsif ($$valPtr !~ /[\x14\x15\x1b]/) {
1025 2         15 $$valPtr = $et->Decode($$valPtr, $$xlatPtr);
1026             } else {
1027             # don't yet support reading ISO 2022 shifted character sets
1028 0         0 $et->WarnOnce('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 151     151 0 356 my $path = shift;
1040 151 100       705 return 1 if $isStandardIPTC{$path};
1041 70 100 66     833 return 0 unless $path =~ /^(\w+)/ and defined $isStandardIPTC{$1};
1042 44         141 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 175     175 0 614 my ($et, $dirInfo, $tagTablePtr) = @_;
1053 175         486 my $dataPt = $$dirInfo{DataPt};
1054 175   100     1014 my $pos = $$dirInfo{DirStart} || 0;
1055 175   50     623 my $dirLen = $$dirInfo{DirLen} || 0;
1056 175         380 my $dirEnd = $pos + $dirLen;
1057 175         706 my $verbose = $et->Options('Verbose');
1058 175         920 my $validate = $et->Options('Validate');
1059 175         511 my $success = 0;
1060 175         482 my ($lastRec, $recordPtr, $recordName);
1061              
1062 175 50 33     880 $verbose and $dirInfo and $et->VerboseDir('IPTC', 0, $$dirInfo{DirLen});
1063              
1064 175 100       758 if ($tagTablePtr eq \%Image::ExifTool::IPTC::Main) {
1065 150         637 my $path = $et->MetadataPath();
1066 150         746 my $isStd = IsStandardIPTC($path);
1067 150 100 66     1001 if (defined $isStd and not $$et{DIR_COUNT}{STD_IPTC}) {
1068             # set flag to ensure we only have one family 1 "IPTC" group
1069 106         613 $$et{DIR_COUNT}{STD_IPTC} = 1;
1070             # calculate MD5 if Digest::MD5 is available (truly standard IPTC only)
1071 106 100       358 if ($isStd) {
1072 80         152 my $md5;
1073 80 50       198 if (eval { require Digest::MD5 }) {
  80         937  
1074 80 100 66     492 if ($pos or $dirLen != length($$dataPt)) {
1075 68         812 $md5 = Digest::MD5::md5(substr $$dataPt, $pos, $dirLen);
1076             } else {
1077 12         124 $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 80         466 $et->FoundTag('CurrentIPTCDigest', $md5);
1084             }
1085             } else {
1086 44 100 66     3583 if (($Image::ExifTool::MWG::strict or $et->Options('Validate')) and
      66        
1087             $$et{FILE_TYPE} =~ /^(JPEG|TIFF|PSD)$/)
1088             {
1089 4 50       16 if ($Image::ExifTool::MWG::strict) {
1090             # ignore non-standard IPTC while in strict MWG compatibility mode
1091 4         25 $et->Warn("Ignored non-standard IPTC at $path");
1092 4         21 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     275 my $count = ($$et{DIR_COUNT}{IPTC} || 0) + 1; # count non-standard IPTC
1099 40         133 $$et{DIR_COUNT}{IPTC} = $count;
1100 40         116 $$et{LOW_PRIORITY_DIR}{IPTC} = 1; # lower priority of non-standard IPTC
1101 40         170 $$et{SET_GROUP1} = '+' . ($count + 1); # add number to family 1 group name
1102             }
1103             }
1104             # begin by assuming default IPTC encoding
1105 171         901 my $xlat = $et->Options('CharsetIPTC');
1106 171 50       892 undef $xlat if $xlat eq $et->Options('Charset');
1107              
1108             # quick check for improperly byte-swapped IPTC
1109 171 50 33     1614 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 171 100 66     1394 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     205 if ($pos or $dirLen != length($$dataPt)) {
1124 17         109 $et->FoundTag('IPTC', substr($$dataPt, $pos, $dirLen));
1125             } else {
1126 18         73 $et->FoundTag('IPTC', $$dataPt);
1127             }
1128             }
1129 171         738 while ($pos + 5 <= $dirEnd) {
1130 2465         4881 my $buff = substr($$dataPt, $pos, 5);
1131 2465         7312 my ($id, $rec, $tag, $len) = unpack("CCCn", $buff);
1132 2465 100       5659 unless ($id == 0x1c) {
1133 3 50       25 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         15 my $remaining = substr($$dataPt, $pos, $dirEnd - $pos);
1137 3 50       60 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 2462         3625 $pos += 5; # step to after field header
1143             # handle extended IPTC entry if necessary
1144 2462 50       4948 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 2462 50       4855 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 2462 100 100     7997 if (not defined $lastRec or $lastRec != $rec) {
1162 174 0 33     683 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 174         561 my $tableInfo = $tagTablePtr->{$rec};
1166 174 50       571 unless ($tableInfo) {
1167 0         0 $et->WarnOnce("Unrecognized IPTC record $rec (ignored)");
1168 0         0 $pos += $len;
1169 0         0 next; # ignore this entry
1170             }
1171 174         648 my $tableName = $tableInfo->{SubDirectory}->{TagTable};
1172 174 50       523 unless ($tableName) {
1173 0         0 $et->Warn("No table for IPTC record $rec!");
1174 0         0 last; # this shouldn't happen
1175             }
1176 174         442 $recordName = $$tableInfo{Name};
1177 174         583 $recordPtr = Image::ExifTool::GetTagTable($tableName);
1178 174         1468 $et->VPrint(0,$$et{INDENT},"-- $recordName record --\n");
1179 174         473 $lastRec = $rec;
1180             }
1181 2462         5693 my $val = substr($$dataPt, $pos, $len);
1182              
1183             # add tagInfo for all unknown tags:
1184 2462 100       7875 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         107 AddTagToTable($recordPtr, $tag, { Unknown => 1 });
1188             }
1189              
1190 2462         6431 my $tagInfo = $et->GetTagInfo($recordPtr, $tag);
1191 2462         3876 my $format;
1192             # (could use $$recordPtr{FORMAT} if no Format below, but don't do this to
1193             # be backward compatible with improperly written PhotoMechanic tags)
1194 2462 100       7659 $format = $$tagInfo{Format} if $tagInfo;
1195 2462 100       5679 if (not $format) {
    50          
1196             # guess at "int" format if not specified
1197 230 100 66     1513 $format = 'int' if $len <= 4 and $len != 3 and $val =~ /[\0-\x08]/;
      100        
1198             } elsif ($validate) {
1199 0         0 my ($fmt,$min,$max);
1200 0 0       0 if ($format =~ /(.*)\[(\d+)(,(\d+))?\]/) {
1201 0         0 $fmt = $1;
1202 0         0 $min = $2;
1203 0   0     0 $max = $4 || $2;
1204             } else {
1205 0         0 $fmt = $format;
1206 0         0 $min = $max = 1;
1207             }
1208 0   0     0 my $siz = Image::ExifTool::FormatSize($fmt) || 1;
1209 0         0 $min *= $siz; $max *= $siz;
  0         0  
1210 0 0 0     0 if ($len < $min or $len > $max) {
1211 0 0       0 my $should = ($min == $max) ? $min : ($len < $min ? "$min min" : "$max max");
    0          
1212 0 0       0 my $what = ($len < $siz * $min) ? 'short' : 'long';
1213 0         0 $et->Warn("IPTC $$tagInfo{Name} too $what ($len bytes; should be $should)", 1);
1214             }
1215             }
1216 2462 100       4548 if ($format) {
1217 2407 100       9766 if ($format =~ /^int/) {
    100          
    100          
    50          
1218 332 100       943 if ($len <= 8) { # limit integer conversion to 8 bytes long
1219 328         589 $val = 0;
1220 328         483 my $i;
1221 328         889 for ($i=0; $i<$len; ++$i) {
1222 1006         2560 $val = $val * 256 + ord(substr($$dataPt, $pos+$i, 1));
1223             }
1224             }
1225             } elsif ($format =~ /^string/) {
1226             # some braindead softwares add null terminators
1227 1885 50 33     5096 if ($val =~ s/\0+$// and $validate) {
1228 0         0 $et->Warn("IPTC $$tagInfo{Name} improperly terminated", 1);
1229             }
1230 1885 100 66     9807 if ($rec == 1) {
    100 100        
1231             # handle CodedCharacterSet tag
1232 2 50       15 $xlat = HandleCodedCharset($et, $val) if $tag == 90;
1233             # translate characters if necessary and special characters exist
1234             } elsif ($xlat and $rec < 7 and $val =~ /[\x80-\xff]/) {
1235             # translate to specified character set
1236 2         9 TranslateCodedString($et, \$val, \$xlat, 1);
1237             }
1238             } elsif ($format =~ /^digits/) {
1239 188 50 33     746 if ($val =~ s/\0+$// and $validate) {
1240 0         0 $et->Warn("IPTC $$tagInfo{Name} improperly terminated", 1);
1241             }
1242             } elsif ($format !~ /^undef/) {
1243 0         0 warn("Invalid IPTC format: $format"); # (this would be a programming error)
1244             }
1245             }
1246             $verbose and $et->VerboseInfo($tag, $tagInfo,
1247             Table => $tagTablePtr,
1248             Value => $val,
1249             DataPt => $dataPt,
1250             DataPos => $$dirInfo{DataPos},
1251 2462 50       4942 Size => $len,
1252             Start => $pos,
1253             Extra => ", $recordName record",
1254             Format => $format,
1255             );
1256 2462 100       8325 $et->FoundTag($tagInfo, $val) if $tagInfo;
1257 2462         3941 $success = 1;
1258              
1259 2462         6235 $pos += $len; # increment to next field
1260             }
1261 171         723 delete $$et{SET_GROUP1};
1262 171         472 delete $$et{LOW_PRIORITY_DIR}{IPTC};
1263 171         636 return $success;
1264             }
1265              
1266             1; # end
1267              
1268              
1269             __END__