File Coverage

blib/lib/Image/MetaData/JPEG/parsers/app2.pl
Criterion Covered Total %
statement 97 97 100.0
branch 24 32 75.0
condition n/a
subroutine 8 8 100.0
pod 0 4 0.0
total 129 141 91.4


line stmt bran cond sub pod time code
1             ###########################################################
2             # A Perl package for showing/modifying JPEG (meta)data. #
3             # Copyright (C) 2004,2005,2006 Stefano Bettelli #
4             # See the COPYING and LICENSE files for license terms. #
5             ###########################################################
6 15     15   67 use Image::MetaData::JPEG::data::Tables qw(:TagsAPP2);
  15         24  
  15         2117  
7 15     15   80 no integer;
  15         19  
  15         82  
8 15     15   254 use strict;
  15         20  
  15         340  
9 15     15   52 use warnings;
  15         75  
  15         14399  
10              
11             ###########################################################
12             # This is the entry point for parsing APP2 segments. Such #
13             # application segments can host at least two formats (see #
14             # the called subroutines for more details): #
15             # 1) Flashpix conversion information ("FPXR"). #
16             # 2) ICC profiles data. #
17             # This method decides among the various formats and then #
18             # calls a specific parser. An error is issued if the #
19             # metadata format is not recognised. #
20             #=========================================================#
21             # Ref: "Exchangeable image file format for digital still #
22             # cameras: Exif Version 2.2", JEITA CP-3451, Apr2002 #
23             # Jap.Electr.Industry Develop.Assoc. (JEIDA), pag. 65 #
24             ###########################################################
25             sub parse_app2 {
26 25     25 0 46 my ($this) = @_;
27             # If the data area begins with "FPXR\000", it contains Flashpix data
28 25 100       97 return $this->parse_app2_flashpix()
29             if $this->data(0, length $APP2_FPXR_TAG) eq $APP2_FPXR_TAG;
30             # If it starts with "ICC_PROFILE", well, guess it ....
31 21 100       82 return $this->parse_app2_ICC_profiles()
32             if $this->data(0, length $APP2_ICC_TAG) eq $APP2_ICC_TAG;
33             # if the segment type is unknown, generate an error
34 1         4 $this->die('Incorrect identifier (' . $this->data(0, 6) . ')');
35             }
36              
37             ###########################################################
38             # This method parses an APP2 Flashpix extension segment, #
39             # and is not really reliable, since I have only one exam- #
40             # ple and very badly written documentation. The FPXR #
41             # structure, the worst I have ever seen, is as follows: #
42             #---------------------------------------------------------#
43             # 5 bytes identifier ("FPXR\000" = 0x4650585200) #
44             # 1 byte version (always zero?, it is a binary value) #
45             # 1 byte type (1=Cont. List, 2=Stream Data, 3=reserved)#
46             #--- Contents List Segment -------------------------------#
47             # 2 bytes Interoperability count (the list size ...) #
48             # ---------- multiple times -------------------------- #
49             # 4 bytes Entity size (0xffffffff for a storage (?)) #
50             # ... Storage/Stream name (null termin., Unicode) #
51             # 16 bytes Entity class ID (for storages) (var. size ?) #
52             #--- Stream Data Segment ---------------------------------#
53             # 2 bytes index in the Contents List #
54             # 4 bytes offset to the first byte in the stream (?) #
55             # ... the actual data stream (to the end?) #
56             #=========================================================#
57             # Ref: "Exchangeable image file format for digital still #
58             # cameras: Exif Version 2.2", JEITA CP-3451, Apr2002 #
59             # Jap.Electr.Industry Develop.Assoc.(JEIDA), pag.65-67 #
60             ###########################################################
61             sub parse_app2_flashpix {
62 4     4 0 5 my ($this) = @_;
63 4         6 my $offset = 0;
64             # at least 7 bytes for the identifier, its version and its type
65 4         10 $this->test_size(7, "FPXR header too small");
66             # decode the identifier (get its length from $APP2_FPXR_TAG)
67 4         12 my $identifier = $this->store_record
68             ('Identifier', $ASCII, $offset, length $APP2_FPXR_TAG)->get_value();
69             # die if it is not correct
70 4 50       8 $this->die("Incorrect identifier ($identifier)")
71             if $identifier ne $APP2_FPXR_TAG;
72             # decode the version number (is this always zero?) and the data type
73 4         10 $this->store_record('Version', $BYTE, $offset);
74 4         11 my $type = $this->store_record('FPXR_type', $BYTE, $offset)->get_value();
75             # data type equal to 1 means we are dealing with a Contents List
76             # structure, listing the storages and streams for the Flashpix image.
77 4 100       15 if ($type == 1) {
    100          
    100          
78             # the first two bytes select the number of entries in the list
79 1         4 my $count = $this->read_record($SHORT, $offset);
80 1         4 for (1..$count) {
81             # create a separate subdir for each entry (stupid ?), then
82             # get the entity size and default value (the size refers to
83             # what we are going to find in future APP2 segments!).
84 2         8 my $subdir = $this->provide_subdirectory('Entity_' . $_);
85 2         10 my $size = $this->store_record($subdir, 'Size', $LONG, $offset);
86 2         6 $this->store_record($subdir, 'DefaultValue', $BYTE, $offset);
87             # the following entry is a Unicode string (16 bits --> 1 char)
88             # in little endian format. It terminates with a Unicode null
89             # char, i.e., "\000\000". Find its length, then store it. The
90             # string is invalid if it does not begin with Unicode "/".
91 2         3 my $pos=0; $pos+=2 while $this->data($offset+$pos,2) ne "\000\000";
  2         5  
92 2 50       5 $this->die('Invalid Storage/Stream name (not beginning with /)')
93             if $this->data($offset, 2) ne "/\000";
94 2         6 $this->store_record($subdir, 'Name', $ASCII, $offset, $pos+2);
95             # if $size is 0xffffffff, we are dealing with a Storage
96             # Interoperability Field; I don't know what this means, but
97             # at this point there should be an "Entity class ID" (16 bytes)
98 2 50       10 $this->store_record($subdir, 'Class_ID', $UNDEF, $offset, 16)
99             if $size == 0xffffffff;
100             } }
101             # data type equal to 2 means we are dealing with a Stream Data
102             # segment (there can be more than one such segments).
103             elsif ($type == 2) {
104 1         3 $this->store_record('ContentsIndex', $SHORT, $offset);
105 1         3 $this->store_record('StreamOffset', $LONG, $offset);
106 1         4 $this->store_record('Data', $UNDEF, $offset, $this->size() - $offset);
107             }
108             # type 3 is reserved for the future (let me know ...)
109             elsif ($type == 3) {
110 1         4 $this->store_record('Unknown', $UNDEF, $offset,$this->size()-$offset);}
111             # a type different from 1, 2 or 3 is not valid.
112 1         4 else { $this->die("Unknown FPXR type ($type)"); }
113             # check that there are no spurious data in the segment
114 3         10 $this->test_size(-$offset, "unknown data at segment end");
115             }
116              
117             ###########################################################
118             # This method parses an APP2 ICC_PROFILE segment. The #
119             # profile is defined as a header followed by a tag table #
120             # followed by a series of tagged elements. This routine #
121             # parses the overall structure and the profile header, #
122             # the other tags are read by parse_app2_ICC_tags(). The #
123             # ICC segment structure is as follows: #
124             #---------------------------------------------------------#
125             # 5 bytes identifier ("FPXR\000" = 0x4650585200) #
126             # 1 byte sequence number of the chunck (starting at 1) #
127             # 1 byte total number of chunks #
128             #------- Profile header ----------------------------------#
129             # 4 bytes profile size (this includes header and data) #
130             # 4 bytes CMM type signature #
131             # 4 bytes profile version number #
132             # 4 bytes profile/device class signature #
133             # 4 bytes color space signature #
134             # 4 bytes profile connection space (PCS) signature #
135             # 12 bytes date and time this profile was created #
136             # 4 bytes profile file signature #
137             # 4 bytes profile primary platform signature #
138             # 4 bytes flags for CMM profile options #
139             # 4 bytes device manifacturer signature #
140             # 4 bytes device model signature #
141             # 8 bytes device attributes #
142             # 4 bytes rendering intent #
143             # 12 bytes XYZ values of the illuminant of the PCS #
144             # 4 bytes profile creator signature #
145             # 16 bytes profile ID checksum #
146             # 28 bytes reserved for future expansion (must be zero) #
147             #------- Tag table ---------------------------------------#
148             # see parse_app2_ICC_tags() #
149             #=========================================================#
150             # Since ICC profile data can easily exceed 64KB, there is #
151             # a mechanism to divide the profile into smaller chunks. #
152             # This is the sequence number; every chunk must show the #
153             # same value for the total number of chunks. #
154             #=========================================================#
155             # Ref: "Specification ICC.1:2003-09, File Format for Co- #
156             # lor Profiles (ver. 4.1.0)", Intern.Color Consort. #
157             ###########################################################
158             sub parse_app2_ICC_profiles {
159 20     20 0 30 my ($this) = @_;
160 20         39 my $offset = 0;
161             # get the length of the APP2 ICC identifier; then calculate
162             # the profile header offset (there are two more bytes)
163 20         36 my $id_size = length $APP2_ICC_TAG;
164 20         39 my $header_base = $id_size + 2;
165             # at least $header_base + 128 bytes (profile header) to start
166 20         68 $this->test_size($header_base + 128, "ICC profile header too small");
167             # decode the identifier (get its length from $APP2_FPXR_TAG)
168 20         81 my $identifier = $this->store_record
169             ('Identifier', $ASCII, $offset, $id_size)->get_value();
170             # die if it is not correct
171 20 50       127 $this->die("Incorrect identifier ($identifier)")
172             if $identifier ne $APP2_ICC_TAG;
173             # read the sequence number and the total number of chunks
174 20         179 $this->store_record('SequenceNumber', $BYTE, $offset);
175 20         63 $this->store_record('TotalNumber', $BYTE, $offset);
176             # read the profile size and check with the real size
177             # remember to include the (identifier + chunks) bytes
178 20         58 my $size = $this->read_record($LONG, $offset);
179 20         105 $this->test_size(-($size + $header_base), "Incorrect ICC data size");
180             # prepare a subdirectory for the profile header
181 20         66 my $sd = $this->provide_subdirectory('ProfileHeader');
182             # read all other entries in the profile header
183 20         68 $this->store_record($sd, 'CMM_TypeSignature', $ASCII, $offset, 4 );
184 20         67 $this->store_record($sd, 'ProfileVersionNumber', $UNDEF, $offset, 4 );
185 20         63 $this->store_record($sd, 'ClassSignature', $ASCII, $offset, 4 );
186 20         64 $this->store_record($sd, 'ColorSpaceSignature', $ASCII, $offset, 4 );
187 20         60 $this->store_record($sd, 'ConnectionSpaceSignature', $ASCII, $offset, 4 );
188 20         67 $this->store_record($sd, 'Year', $SHORT, $offset );
189 20         59 $this->store_record($sd, 'Month', $SHORT, $offset );
190 20         59 $this->store_record($sd, 'Day', $SHORT, $offset );
191 20         50 $this->store_record($sd, 'Hour', $SHORT, $offset );
192 20         58 $this->store_record($sd, 'Minute', $SHORT, $offset );
193 20         62 $this->store_record($sd, 'Second', $SHORT, $offset );
194 20         61 $this->store_record($sd, 'ProfileFileSignature', $ASCII, $offset, 4 );
195 20         59 $this->store_record($sd, 'PrimaryPlatformSignature', $ASCII, $offset, 4 );
196 20         67 $this->store_record($sd, 'CMM_ProfileFlags', $LONG, $offset );
197 20         59 $this->store_record($sd, 'DeviceManifactSignature', $ASCII, $offset, 4 );
198 20         60 $this->store_record($sd, 'DeviceModelSignature', $ASCII, $offset, 4 );
199 20         81 $this->store_record($sd, 'DeviceAttributes', $UNDEF, $offset, 8 );
200 20         65 $this->store_record($sd, 'RenderingIntent', $LONG, $offset );
201 20         1065 $this->store_record($sd, 'XYZ_PCS_Illuminant', $UNDEF, $offset, 12);
202 20         65 $this->store_record($sd, 'ProfileCreatorSignature', $ASCII, $offset, 4 );
203 20         59 $this->store_record($sd, 'ProfileID_Checksum', $UNDEF, $offset, 16);
204             # the last 28 bytes in the profile header are reserved for
205             # future use, and should contain only zero.
206 20         68 my $reserved = $this->read_record($UNDEF, $offset, 28);
207 20 50       83 $this->die('Non-zero reserved bytes in profile header')
208             if $reserved ne "\000" x 28;
209             # call another method knowing how to read the remaining tags
210             # (it only needs to know the current offset and where is the
211             # beginning of the profile header)
212 20         69 return $this->parse_app2_ICC_tags($offset, $header_base);
213             }
214              
215             ###########################################################
216             # This method parses the tag table of an APP2 ICC_PROFILE #
217             # segment (it complements parse_app2_ICC_profiles()). See #
218             # that routine for more details. The arguments are the #
219             # current offset in the segment data area and the start #
220             # of the profile header with respect to the beginning of #
221             # the segment data area. There are no checks on the over- #
222             # all size, since it is assumed that this was already #
223             # controlled by the calling routine. The tag table #
224             # structure is as follows: #
225             #---------------------------------------------------------#
226             # 4 bytes tag count #
227             # ---------- multiple times ------------------- #
228             # 4 bytes tag signature (a unique number) #
229             # 4 bytes tag offset from the profile header start #
230             # 4 bytes tag size #
231             #------ Data area of a tag -------------------------------#
232             # 4 bytes ICC tag type (an ASCII string) #
233             # 4 bytes reserved for the future ("\000\000\000\000") #
234             # .... real data area (various encodings). #
235             #---------------------------------------------------------#
236             # The first tag data area must immediately follow the tag #
237             # table. All tagged element data must be padded with #
238             # nulls by no more than three pad bytes to reach a four #
239             # bytes boundary. We only store the final part of the tag #
240             # data area in the record (the ICC type is saved in its #
241             # extra field). See the code for more details. #
242             #=========================================================#
243             # Ref: "Specification ICC.1:2003-09, File Format for Co- #
244             # lor Profiles (ver. 4.1.0)", Intern.Color Consort. #
245             ###########################################################
246             sub parse_app2_ICC_tags {
247 20     20 0 857 my ($this, $offset, $header_base) = @_;
248             # read the number of tags in the tag table (don't store it)
249 20         928 my $tags = $this->read_record($LONG, $offset);
250             # prepare a subdirectory for the tag table
251 20         909 my $tag_table = $this->provide_subdirectory('TagTable');
252             # repeat the tag-reading algorithm $tags time
253 20         63 for (1..$tags) {
254             # the 12 bytes in the tag table entry contain the tag code
255             # (which we are going to use as record key), the pointer to
256             # the tag data with respect to the profile header beginning
257             # and the size of this data area. Read and don't store.
258 340         2255 my $tag_code = $this->read_record($LONG, $offset);
259 340         1007 my $tag_offset = $this->read_record($LONG, $offset);
260 340         963 my $tag_size = $this->read_record($LONG, $offset);
261             # the first 8 bytes in the tag data area are special; the first
262             # 4 bytes specify the "ICC type", the following 4 must be zero.
263             # Read, check the condition, but don't store.
264 340         1085 my $tag_desc = $this->data($header_base + $tag_offset , 4);
265 340         693 my $tag_pad = $this->data($header_base + $tag_offset + 4, 4);
266 340 50       581 $this->die('Non-zero padding in ICC tag')
267             if $tag_pad ne "\000\000\000\000";
268             # adjust the tag size and offset to reflect the 8 bytes we read.
269             # also adjust the offset by adding the profile header base
270 340         327 $tag_size -= 8; $tag_offset += 8 + $header_base;
  340         260  
271             # a few ICC tag types can be shown with something more
272             # specific than the UNDEF type (which remains the default)
273 340         880 my $tag_type = $UNDEF;
274 340 100       934 $tag_type = $ASCII if $tag_desc =~ /text|sig /;
275 340 50       624 $tag_type = $BYTE if $tag_desc =~ /ui08/;
276 340 50       641 $tag_type = $SHORT if $tag_desc =~ /ui16|dtim/;
277 340 100       828 $tag_type = $LONG if $tag_desc =~ /ui32|XYZ |view/;
278             # depending on the tag type, calculate its length in bytes and
279             # therefore the number of elements in the data area (the count).
280             # If the type is variable-length (i.e., if get_size returns
281             # zero), $tag_count must be indeed equal to $tag_size.
282 340         768 my $tag_length = Image::MetaData::JPEG::Record->get_size($tag_type, 1);
283 340 100       562 my $tag_count = ($tag_length == 0)? $tag_size : $tag_size/$tag_length;
284             # now, store the content of the tag data area (minus the first
285             # 8 bytes) as a record of given key, type and count. Store the
286             # record in the tag table subdirectory.
287 340         632 $this->store_record($tag_table, $tag_code, $tag_type,
288             \ $this->data($tag_offset, $tag_size), $tag_count);
289             # also store the ICC tag type in the record "extra" field
290 340         747 $this->search_record('LAST_RECORD', $tag_table)->{extra} = $tag_desc;
291             }
292             }
293              
294             # successful load
295             1;