| 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
|
|
63
|
use Image::MetaData::JPEG::data::Tables qw(:TagsAPP1_Exif); |
|
|
15
|
|
|
|
|
19
|
|
|
|
15
|
|
|
|
|
2085
|
|
|
7
|
15
|
|
|
15
|
|
83
|
no integer; |
|
|
15
|
|
|
|
|
1033
|
|
|
|
15
|
|
|
|
|
74
|
|
|
8
|
15
|
|
|
15
|
|
368
|
use strict; |
|
|
15
|
|
|
|
|
15
|
|
|
|
15
|
|
|
|
|
315
|
|
|
9
|
15
|
|
|
15
|
|
50
|
use warnings; |
|
|
15
|
|
|
|
|
15
|
|
|
|
15
|
|
|
|
|
17191
|
|
|
10
|
|
|
|
|
|
|
|
|
11
|
|
|
|
|
|
|
########################################################### |
|
12
|
|
|
|
|
|
|
# This method dumps an Exif APP1 segment. Basically, it # |
|
13
|
|
|
|
|
|
|
# dumps the identifier, the two IFDs and the thumbnail. # |
|
14
|
|
|
|
|
|
|
########################################################### |
|
15
|
|
|
|
|
|
|
sub dump_app1_exif { |
|
16
|
161
|
|
|
161
|
0
|
200
|
my ($this) = @_; |
|
17
|
|
|
|
|
|
|
# dump the identifier (not part of the TIFF header) |
|
18
|
161
|
|
|
|
|
362
|
my $identifier = $this->search_record('Identifier')->get(); |
|
19
|
161
|
|
|
|
|
485
|
$this->set_data($identifier); |
|
20
|
|
|
|
|
|
|
# dump the TIFF header; note that the offset returned by |
|
21
|
|
|
|
|
|
|
# dump_TIFF_header is the current position in the newly written |
|
22
|
|
|
|
|
|
|
# data area AFTER the identifier (i.e., the base is the base |
|
23
|
|
|
|
|
|
|
# of the TIFF header), so it does not start from zero but from the |
|
24
|
|
|
|
|
|
|
# value of $ifd0_link. Be aware that its meaning is slightly |
|
25
|
|
|
|
|
|
|
# different from $offset in the parser. |
|
26
|
161
|
|
|
|
|
398
|
my ($header, $offset, $endianness) = $this->dump_TIFF_header(); |
|
27
|
161
|
|
|
|
|
427
|
$this->set_data($header); |
|
28
|
|
|
|
|
|
|
# locally set the current endianness to what we have found. |
|
29
|
161
|
|
|
|
|
327
|
local $this->{endianness} = $endianness; |
|
30
|
|
|
|
|
|
|
# dump all the records of the 0th IFD, and update $offset to |
|
31
|
|
|
|
|
|
|
# point after the end of the current data area (with respect |
|
32
|
|
|
|
|
|
|
# to the TIFF header base). This must be done even if the IFD |
|
33
|
|
|
|
|
|
|
# itself is empty (in order to find the next one). |
|
34
|
161
|
100
|
|
|
|
371
|
my $ifd1_link = defined $this->search_record('IFD1') ? 0 : 1; |
|
35
|
161
|
|
|
|
|
467
|
$offset += $this->set_data($this->dump_ifd('IFD0', $offset, $ifd1_link)); |
|
36
|
|
|
|
|
|
|
# same thing with the 1st IFD. We don't have to worry if this |
|
37
|
|
|
|
|
|
|
# IFD is not there, because dump_ifd tests for this case. |
|
38
|
161
|
|
|
|
|
458
|
$offset += $this->set_data($this->dump_ifd('IFD1', $offset, 1)); |
|
39
|
|
|
|
|
|
|
# if there is thumbnail data in the main directory of this |
|
40
|
|
|
|
|
|
|
# segment, it is time to dump it. Use the reference, because |
|
41
|
|
|
|
|
|
|
# this can be quite large (some tens of kilobytes ....) |
|
42
|
161
|
100
|
|
|
|
456
|
if (my $th_record = $this->search_record('ThumbnailData')) { |
|
43
|
82
|
|
|
|
|
236
|
(undef, undef, undef, my $tdataref) = $th_record->get(); |
|
44
|
82
|
|
|
|
|
229
|
$this->set_data($tdataref); } |
|
45
|
|
|
|
|
|
|
} |
|
46
|
|
|
|
|
|
|
|
|
47
|
|
|
|
|
|
|
########################################################### |
|
48
|
|
|
|
|
|
|
# This method reconstructs a TIFF header and returns a # |
|
49
|
|
|
|
|
|
|
# list with all the relevant values. Nothing is written # |
|
50
|
|
|
|
|
|
|
# to the data area. Records are searched for in the # |
|
51
|
|
|
|
|
|
|
# directory specified by the second argument. # |
|
52
|
|
|
|
|
|
|
########################################################### |
|
53
|
|
|
|
|
|
|
sub dump_TIFF_header { |
|
54
|
162
|
|
|
162
|
0
|
196
|
my ($this, $dirref) = @_; |
|
55
|
|
|
|
|
|
|
# retrieve the endianness, and signature. It is not worth |
|
56
|
|
|
|
|
|
|
# setting the temporary segment endianness here, do it later. |
|
57
|
162
|
|
|
|
|
388
|
my $endianness=$this->search_record('Endianness',$dirref)->get(); |
|
58
|
162
|
|
|
|
|
431
|
my $signature =$this->search_record('Signature',$dirref)->get($endianness); |
|
59
|
|
|
|
|
|
|
# create a string containing the TIFF header (we always |
|
60
|
|
|
|
|
|
|
# choose the offset of the 0th IFD must to be 8 here). |
|
61
|
162
|
|
|
|
|
211
|
my $ifd0_len = 8; |
|
62
|
162
|
100
|
|
|
|
559
|
my $ifd0_link = pack $endianness eq $BIG_ENDIAN ? "N" : "V", $ifd0_len; |
|
63
|
162
|
|
|
|
|
317
|
my $header = $endianness . $signature . $ifd0_link; |
|
64
|
|
|
|
|
|
|
# return all relevant values in a list |
|
65
|
162
|
|
|
|
|
398
|
return ($header, $ifd0_len, $endianness); |
|
66
|
|
|
|
|
|
|
} |
|
67
|
|
|
|
|
|
|
|
|
68
|
|
|
|
|
|
|
########################################################### |
|
69
|
|
|
|
|
|
|
# This is the core of the Exif APP1 dumping method. It # |
|
70
|
|
|
|
|
|
|
# takes care to dump a whole IFD, including a special # |
|
71
|
|
|
|
|
|
|
# treatement for thumbnails and makernotes. No action is # |
|
72
|
|
|
|
|
|
|
# taken unless there is already a directory for this IFD # |
|
73
|
|
|
|
|
|
|
# in the structured data area of the segment. # |
|
74
|
|
|
|
|
|
|
# ------------------------------------------------------- # |
|
75
|
|
|
|
|
|
|
# Special treatement for tags holding an IFD offset (this # |
|
76
|
|
|
|
|
|
|
# includes makernotes); these tags are regenerated on the # |
|
77
|
|
|
|
|
|
|
# fly (since they are no more stored) and their value is # |
|
78
|
|
|
|
|
|
|
# recalculated and written to the raw data area. # |
|
79
|
|
|
|
|
|
|
# ------------------------------------------------------- # |
|
80
|
|
|
|
|
|
|
# New argument ($next), which specifies how the next_link # |
|
81
|
|
|
|
|
|
|
# pointer is to be treated: '0' --> the pointer is dumped # |
|
82
|
|
|
|
|
|
|
# with a non zero value; '1' --> the pointer is dumped # |
|
83
|
|
|
|
|
|
|
# with value set to zero; '2' -->: the pointer is ignored # |
|
84
|
|
|
|
|
|
|
########################################################### |
|
85
|
|
|
|
|
|
|
sub dump_ifd { |
|
86
|
630
|
|
|
630
|
0
|
809
|
my ($this, $dirnames, $offset, $next) = @_; |
|
87
|
|
|
|
|
|
|
# set the next link flag to zero if it is undefined |
|
88
|
630
|
50
|
|
|
|
1103
|
$next = 0 unless defined $next; |
|
89
|
|
|
|
|
|
|
# retrieve the appropriate record list (specified by a '@' separated |
|
90
|
|
|
|
|
|
|
# list of dir names in $dirnames to be interpreted in sequence). If |
|
91
|
|
|
|
|
|
|
# this fails, return immediately with a reference to an empty string |
|
92
|
630
|
|
|
|
|
1479
|
my $dirref = $this->search_record_value($dirnames); |
|
93
|
630
|
100
|
|
|
|
1346
|
return \ (my $ns = '') unless $dirref; |
|
94
|
|
|
|
|
|
|
# $short and $long are two useful format strings correctly taking |
|
95
|
|
|
|
|
|
|
# into account the IFD endianness. $format is a format string for |
|
96
|
|
|
|
|
|
|
# packing an Interoperability array |
|
97
|
575
|
100
|
|
|
|
1219
|
my $short = $this->{endianness} eq $BIG_ENDIAN ? 'n' : 'v'; |
|
98
|
575
|
100
|
|
|
|
933
|
my $long = $this->{endianness} eq $BIG_ENDIAN ? 'N' : 'V'; |
|
99
|
575
|
|
|
|
|
1599
|
my $format = $short. $short . $long; |
|
100
|
|
|
|
|
|
|
# retrieve the record list for this IFD, then eliminate the REFERENCE |
|
101
|
|
|
|
|
|
|
# records (added by the parser routine, they were not in the JPEG file). |
|
102
|
575
|
|
|
|
|
750
|
my @records = grep { $_->{type} != $REFERENCE } @$dirref; |
|
|
7246
|
|
|
|
|
9690
|
|
|
103
|
|
|
|
|
|
|
# for each reference record with a non-undef extra field, regenerate |
|
104
|
|
|
|
|
|
|
# the corresponding offset record (which can be retraced from the |
|
105
|
|
|
|
|
|
|
# "extra" field) and insert it into the @records list with a dummy |
|
106
|
|
|
|
|
|
|
# value (0). We can safely use $LONG as record type (new-style offsets). |
|
107
|
392
|
|
|
|
|
1165
|
push @records, map { |
|
108
|
7246
|
100
|
|
|
|
12091
|
my $nt = JPEG_lookup($this->{name}, $dirnames, $_->{extra}); |
|
109
|
392
|
|
|
|
|
3168
|
new Image::MetaData::JPEG::Record($nt, $LONG, \ pack($long, 0)) } |
|
110
|
575
|
|
|
|
|
743
|
grep { $_->{type} == $REFERENCE && $_->{extra} } @$dirref; |
|
111
|
|
|
|
|
|
|
# sort the accumulated records with respect to their tags (numeric). |
|
112
|
|
|
|
|
|
|
# This is not, strictly speaking mandatory, but the file looks more |
|
113
|
|
|
|
|
|
|
# polished after this (am I introducing any gratuitous incompatibility?) |
|
114
|
575
|
|
|
|
|
1573
|
@records = sort { $a->{key} <=> $b->{key} } @records; |
|
|
10965
|
|
|
|
|
10091
|
|
|
115
|
|
|
|
|
|
|
# the IFD data area is to be initialised with two bytes specifying |
|
116
|
|
|
|
|
|
|
# the number of Interoperability arrays. |
|
117
|
575
|
|
|
|
|
1253
|
my $ifd_content = pack $short, scalar @records; |
|
118
|
|
|
|
|
|
|
# Data areas too large for the Interop array will be saved in $extra; |
|
119
|
|
|
|
|
|
|
# $remote should point to its beginning (from TIFF header base), so we |
|
120
|
|
|
|
|
|
|
# must skip 12 bytes for each Interop. array, 2 bytes for the initial |
|
121
|
|
|
|
|
|
|
# count (and 4 bytes for the next IFD link, unless $next is two). |
|
122
|
575
|
|
|
|
|
1101
|
my ($remote, $extra) = ($offset + 2 + 12*@records, ''); |
|
123
|
575
|
50
|
|
|
|
1110
|
$remote += 4 unless $next == 2; |
|
124
|
|
|
|
|
|
|
# managing the thumbnail is not trivial. We want to be sure that |
|
125
|
|
|
|
|
|
|
# its declared size corresponds to the reality and correct if |
|
126
|
|
|
|
|
|
|
# this is not the case (is this a stupid idea?) |
|
127
|
575
|
100
|
100
|
|
|
1501
|
if ($dirnames eq 'IFD1' && |
|
128
|
|
|
|
|
|
|
(my $th_record = $this->search_record('ThumbnailData'))) { |
|
129
|
82
|
|
|
|
|
213
|
(undef, undef, undef, my $tdataref) = $th_record->get(); |
|
130
|
82
|
|
|
|
|
221
|
for ($THTIFF_LENGTH, $THJPEG_LENGTH) { |
|
131
|
164
|
|
|
|
|
366
|
my $th_len = $this->search_record($_, $dirref); |
|
132
|
164
|
100
|
|
|
|
570
|
$th_len->set_value(length $$tdataref) if $th_len; } } |
|
133
|
|
|
|
|
|
|
# the following tags can be found only in IFD1 in APP1, and concern |
|
134
|
|
|
|
|
|
|
# the thumbnail location. They must be dealt with in a special way. |
|
135
|
575
|
|
|
|
|
1557
|
my %th_tags = ($THTIFF_OFFSET => undef, $THJPEG_OFFSET => undef); |
|
136
|
|
|
|
|
|
|
# determine weather this IFD can have subidrectories or not; if so, |
|
137
|
|
|
|
|
|
|
# get a special mapping table from %IFD_SUBDIRS (avoid autovivification) |
|
138
|
575
|
|
|
|
|
1131
|
my $path = join '@', $this->{name}, $dirnames; |
|
139
|
575
|
100
|
|
|
|
1422
|
my $mapping = exists $IFD_SUBDIRS{$path} ? $IFD_SUBDIRS{$path} : undef; |
|
140
|
|
|
|
|
|
|
# loop on all selected records and dump them |
|
141
|
575
|
|
|
|
|
713
|
for my $record (@records) { |
|
142
|
|
|
|
|
|
|
# extract all necessary information about this |
|
143
|
|
|
|
|
|
|
# Interoperability array, with the correct endianness. |
|
144
|
7243
|
|
|
|
|
14444
|
my ($tag, $type, $count, $dataref) = $record->get($this->{endianness}); |
|
145
|
|
|
|
|
|
|
# calculate the length of the array data, and correct $count |
|
146
|
|
|
|
|
|
|
# for string-like records (it had been set to 1 during the |
|
147
|
|
|
|
|
|
|
# parsing, it must be the data length in this case). |
|
148
|
7243
|
|
|
|
|
7372
|
my $length = length $$dataref; |
|
149
|
7243
|
100
|
|
|
|
12225
|
$count = $length if $record->get_category() eq 'S'; |
|
150
|
|
|
|
|
|
|
# the last four bytes in an interoperability array are either |
|
151
|
|
|
|
|
|
|
# data or an address; prepare a variable for holding this value |
|
152
|
7243
|
|
|
|
|
6799
|
my $record_end = ''; |
|
153
|
|
|
|
|
|
|
# if this IFD1 record specifies the thumbnail location, it needs |
|
154
|
|
|
|
|
|
|
# a special treatment, since we cannot yet know where the thumbnail |
|
155
|
|
|
|
|
|
|
# will be located. Write a bogus offset now and overwrite it later. |
|
156
|
7243
|
100
|
100
|
|
|
33535
|
if ($dirnames eq 'IFD1' && exists $th_tags{$tag}) { |
|
|
|
100
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
157
|
72
|
|
|
|
|
133
|
$th_tags{$tag} = 8 + length $ifd_content; |
|
158
|
72
|
|
|
|
|
82
|
$record_end = "\000\000\000\000"; } |
|
159
|
|
|
|
|
|
|
# if this Interop array is known to correspond to a subdirectory |
|
160
|
|
|
|
|
|
|
# (use %$mapping for this), the subdirectory content is calculated |
|
161
|
|
|
|
|
|
|
# on the fly, and stored in this IFD's remote data area. Its offset |
|
162
|
|
|
|
|
|
|
# instead is saved at the end of the Interoperability array. |
|
163
|
|
|
|
|
|
|
elsif ($mapping && exists $$mapping{$tag}) { |
|
164
|
392
|
|
|
|
|
1190
|
my $is_makernote = ($tag =~ $MAKERNOTE_TAG); |
|
165
|
392
|
|
|
|
|
776
|
my $extended_dirnames = $dirnames.'@'.$$mapping{$tag}; |
|
166
|
|
|
|
|
|
|
# MakerNotes require a special treatment, including rewriting |
|
167
|
|
|
|
|
|
|
# type and count (one LONG is really many UNDEF bytes); other |
|
168
|
|
|
|
|
|
|
# subIFD's are written by a recursive dump_ifd (next link is 0). |
|
169
|
392
|
100
|
|
|
|
1165
|
my $subifd = $is_makernote ? |
|
170
|
|
|
|
|
|
|
$this->dump_makernote($extended_dirnames, $remote) : |
|
171
|
|
|
|
|
|
|
$this->dump_ifd($extended_dirnames, $remote, 1); |
|
172
|
392
|
100
|
|
|
|
777
|
$type = $UNDEF, $count = length($$subifd) if $is_makernote; |
|
173
|
392
|
|
|
|
|
647
|
$record_end = pack $long, $remote; |
|
174
|
392
|
|
|
|
|
521
|
$extra .= $$subifd; $remote += length $$subifd; } |
|
|
392
|
|
|
|
|
641
|
|
|
175
|
|
|
|
|
|
|
# if the data length is not larger than four bytes, we are ok. |
|
176
|
|
|
|
|
|
|
# $$dataref is simply appended (with padding up to 4 bytes, |
|
177
|
|
|
|
|
|
|
# AFTER $$dataref, independently of the IFD endianness). |
|
178
|
3485
|
|
|
|
|
4922
|
elsif ($length <= 4) { $record_end = $$dataref . "\000"x(4-$length); } |
|
179
|
|
|
|
|
|
|
# if $$dataref is too big, it must be packed in the $extra |
|
180
|
|
|
|
|
|
|
# section, and its pointer appended here. Remember to update |
|
181
|
|
|
|
|
|
|
# $remote for the next record of this type. |
|
182
|
3294
|
|
|
|
|
4245
|
else { $record_end = pack $long, $remote; |
|
183
|
3294
|
|
|
|
|
2770
|
$remote += $length; $extra .= $$dataref; } |
|
|
3294
|
|
|
|
|
3396
|
|
|
184
|
|
|
|
|
|
|
# the interoperability array starts with tag, type and count, |
|
185
|
|
|
|
|
|
|
# followed by $record_end (4 bytes): dump into the ifd data area |
|
186
|
7243
|
|
|
|
|
15624
|
$ifd_content .= (pack $format, $tag, $type, $count) . $record_end; } |
|
187
|
|
|
|
|
|
|
# after the Interop. arrays there can be a link to the next IFD |
|
188
|
|
|
|
|
|
|
# (this takes 4 bytes). $next = 0 --> write the next IFD offset, |
|
189
|
|
|
|
|
|
|
# = 1 --> write zero, 2 --> do not write these four bytes. |
|
190
|
575
|
100
|
|
|
|
1081
|
$ifd_content .= pack $long, $remote if $next == 0; |
|
191
|
575
|
100
|
|
|
|
1218
|
$ifd_content .= pack $long, 0 if $next == 1; |
|
192
|
|
|
|
|
|
|
# then, we save the remote data area |
|
193
|
575
|
|
|
|
|
2032
|
$ifd_content .= $extra; |
|
194
|
|
|
|
|
|
|
# if the thumbnail offset tags were found during the scan, we |
|
195
|
|
|
|
|
|
|
# need to overwrite their values with a meaningful offset now. |
|
196
|
575
|
|
|
|
|
1189
|
for (keys %th_tags) { |
|
197
|
1150
|
100
|
|
|
|
2235
|
next unless my $overwrite = $th_tags{$_}; |
|
198
|
72
|
|
|
|
|
184
|
my $tag_record = $this->search_record($_, $dirref); |
|
199
|
72
|
|
|
|
|
166
|
$tag_record->set_value($remote); |
|
200
|
72
|
|
|
|
|
191
|
my $new_offset = $tag_record->get($this->{endianness}); |
|
201
|
72
|
|
|
|
|
224
|
substr($ifd_content, $overwrite, length $new_offset) = $new_offset; } |
|
202
|
|
|
|
|
|
|
# return a reference to the scalar which holds the binary dump |
|
203
|
|
|
|
|
|
|
# of this IFD (to be saved in the caller routine, I think). |
|
204
|
575
|
|
|
|
|
2722
|
return \$ifd_content; |
|
205
|
|
|
|
|
|
|
} |
|
206
|
|
|
|
|
|
|
|
|
207
|
|
|
|
|
|
|
########################################################### |
|
208
|
|
|
|
|
|
|
# This routine dumps all kinds of makernotes. Have a look # |
|
209
|
|
|
|
|
|
|
# at parse_makernote() for further details. # |
|
210
|
|
|
|
|
|
|
########################################################### |
|
211
|
|
|
|
|
|
|
sub dump_makernote { |
|
212
|
87
|
|
|
87
|
0
|
124
|
my ($this, $dirnames, $offset) = @_; |
|
213
|
|
|
|
|
|
|
# look for a MakerNote subdirectory beginning with $dirnames: the |
|
214
|
|
|
|
|
|
|
# actual name has the format appended, e.g., MakerNoteData_Canon. |
|
215
|
87
|
|
|
|
|
751
|
$dirnames =~ s/(.*@|)([^@]*)/$1/; |
|
216
|
87
|
|
|
|
|
288
|
my $dirref = $this->search_record_value($dirnames); |
|
217
|
2201
|
|
|
|
|
4654
|
$dirnames .= $_->{key}, $dirref = $_->get_value(), last |
|
218
|
87
|
|
|
|
|
156
|
for (grep{$_->{key}=~/^$2/} @$dirref); |
|
219
|
|
|
|
|
|
|
# Also look for the subdir with special information. |
|
220
|
87
|
|
|
|
|
304
|
my $spcref = $this->search_record_value($dirnames.'@special'); |
|
221
|
|
|
|
|
|
|
# entering here without the dir and its subdir being present is an error |
|
222
|
87
|
50
|
33
|
|
|
415
|
$this->die('MakerNote subdirs not found') unless $dirref && $spcref; |
|
223
|
|
|
|
|
|
|
# read all MakerNote special values (added by the parser routine) |
|
224
|
435
|
|
|
|
|
848
|
my ($data, $signature, $endianness, $format, $error) = |
|
225
|
87
|
|
|
|
|
179
|
map { $this->search_record_value($_, $spcref) } |
|
226
|
|
|
|
|
|
|
('ORIGINAL', 'SIGNATURE', 'ENDIANNESS', 'FORMAT', 'ERROR'); |
|
227
|
|
|
|
|
|
|
# die and debug if the format record is not present |
|
228
|
87
|
50
|
|
|
|
242
|
$this->die('FORMAT not found') unless $format; |
|
229
|
|
|
|
|
|
|
# if the format is unknown or there was an error at parse time, it |
|
230
|
|
|
|
|
|
|
# is wiser to return the original, unparsed content of the MakerNote |
|
231
|
87
|
100
|
100
|
|
|
404
|
if ($format =~ /unknown/ || defined $error) { |
|
232
|
2
|
50
|
|
|
|
5
|
$this->die('ORIGINAL data not found') unless $data; return \$data; }; |
|
|
2
|
|
|
|
|
5
|
|
|
233
|
|
|
|
|
|
|
# also extract the property table for this MakerNote format |
|
234
|
85
|
|
|
|
|
226
|
my $hash = $$HASH_MAKERNOTES{$format}; |
|
235
|
|
|
|
|
|
|
# now, die if the signature or endianness is still undefined |
|
236
|
85
|
50
|
33
|
|
|
371
|
$this->die('Properties not found')unless defined $signature && $endianness; |
|
237
|
|
|
|
|
|
|
# in general, the MakerNote's next-IFD link is zero, but some |
|
238
|
|
|
|
|
|
|
# MakerNotes do not even have these four bytes: prepare the flag |
|
239
|
85
|
50
|
|
|
|
204
|
my $next_flag = exists $$hash{nonext} ? 2 : 1; |
|
240
|
|
|
|
|
|
|
# in general, MakerNote's offsets are computed from the APP1 segment |
|
241
|
|
|
|
|
|
|
# TIFF base; however, some formats compute offsets from the beginning |
|
242
|
|
|
|
|
|
|
# of the MakerNote itself: setup the offset base as required. |
|
243
|
85
|
100
|
|
|
|
221
|
$offset = length($signature) + (exists $$hash{mkntstart} ? 0 : $offset); |
|
244
|
|
|
|
|
|
|
# initialise the data area with the detected signature |
|
245
|
85
|
|
|
|
|
116
|
$data = $signature; |
|
246
|
|
|
|
|
|
|
# some MakerNotes have a TIFF header on their own, freeing them |
|
247
|
|
|
|
|
|
|
# from the relocation problem; values from this header overwrite |
|
248
|
|
|
|
|
|
|
# the previously assigned values; records are saved in $mknt_dir. |
|
249
|
85
|
100
|
|
|
|
239
|
if (exists $$hash{mkntTIFF}) { |
|
250
|
1
|
|
|
|
|
4
|
my ($TIFF_header, $TIFF_offset, $TIFF_endianness) |
|
251
|
|
|
|
|
|
|
= $this->dump_TIFF_header($spcref); |
|
252
|
1
|
50
|
|
|
|
5
|
$this->die('Endianness mismatch') if $endianness ne $TIFF_endianness; |
|
253
|
1
|
|
|
|
|
2
|
$data .= $TIFF_header; $offset = $TIFF_offset; } |
|
|
1
|
|
|
|
|
2
|
|
|
254
|
|
|
|
|
|
|
# Unstructured case: the content of the MakerNote is simply |
|
255
|
|
|
|
|
|
|
# a sequence of bytes, which must be encoded using $$hash{tags} |
|
256
|
85
|
100
|
|
|
|
200
|
if (exists $$hash{nonIFD}) { |
|
257
|
3608
|
|
|
|
|
3994
|
$data .= $this->search_record($$_[0], $dirref)->get($endianness) |
|
258
|
82
|
|
|
|
|
116
|
for map {$$hash{tags}{$_}} sort {$a <=> $b} keys %{$$hash{tags}}; } |
|
|
15172
|
|
|
|
|
10606
|
|
|
|
82
|
|
|
|
|
1024
|
|
|
259
|
|
|
|
|
|
|
# Structured case: the content of the MakerNote can be dumped |
|
260
|
|
|
|
|
|
|
# with dump_ifd (change locally the endianness value). |
|
261
|
3
|
|
|
|
|
8
|
else { local $this->{endianness} = $endianness; |
|
262
|
3
|
|
|
|
|
5
|
$data .= ${$this->dump_ifd($dirnames, $offset, $next_flag)} }; |
|
|
3
|
|
|
|
|
8
|
|
|
263
|
|
|
|
|
|
|
# return the MakerNote as a binary object |
|
264
|
85
|
|
|
|
|
687
|
return \$data; |
|
265
|
|
|
|
|
|
|
} |
|
266
|
|
|
|
|
|
|
|
|
267
|
|
|
|
|
|
|
# successful load |
|
268
|
|
|
|
|
|
|
1; |