line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Image::Info::JPEG; |
2
|
|
|
|
|
|
|
|
3
|
|
|
|
|
|
|
# Copyright 1999-2000, Gisle Aas. |
4
|
|
|
|
|
|
|
# |
5
|
|
|
|
|
|
|
# This library is free software; you can redistribute it and/or |
6
|
|
|
|
|
|
|
# modify it under the same terms as Perl itself. |
7
|
|
|
|
|
|
|
|
8
|
|
|
|
|
|
|
# maintained by Tels 2007 - 2008 |
9
|
|
|
|
|
|
|
|
10
|
|
|
|
|
|
|
$VERSION = 0.06; |
11
|
|
|
|
|
|
|
|
12
|
|
|
|
|
|
|
=begin register |
13
|
|
|
|
|
|
|
|
14
|
|
|
|
|
|
|
MAGIC: /^\xFF\xD8/ |
15
|
|
|
|
|
|
|
|
16
|
|
|
|
|
|
|
For JPEG files we extract information both from C and C |
17
|
|
|
|
|
|
|
application chunks. |
18
|
|
|
|
|
|
|
|
19
|
|
|
|
|
|
|
C is the file format written by most digital cameras. This |
20
|
|
|
|
|
|
|
encode things like timestamp, camera model, focal length, exposure |
21
|
|
|
|
|
|
|
time, aperture, flash usage, GPS position, etc. |
22
|
|
|
|
|
|
|
|
23
|
|
|
|
|
|
|
The C spec can be found at: |
24
|
|
|
|
|
|
|
L. |
25
|
|
|
|
|
|
|
|
26
|
|
|
|
|
|
|
The C element may have the following values: C, |
27
|
|
|
|
|
|
|
C, and C. Note that detecting C and C |
28
|
|
|
|
|
|
|
currently does not work, but will hopefully in future. |
29
|
|
|
|
|
|
|
|
30
|
|
|
|
|
|
|
=end register |
31
|
|
|
|
|
|
|
|
32
|
|
|
|
|
|
|
=cut |
33
|
|
|
|
|
|
|
|
34
|
7
|
|
|
7
|
|
50
|
use strict; |
|
7
|
|
|
|
|
12
|
|
|
7
|
|
|
|
|
1514
|
|
35
|
|
|
|
|
|
|
|
36
|
|
|
|
|
|
|
my %sof = ( |
37
|
|
|
|
|
|
|
0xC0 => "Baseline", |
38
|
|
|
|
|
|
|
0xC1 => "Extended sequential", |
39
|
|
|
|
|
|
|
0xC2 => "Progressive", |
40
|
|
|
|
|
|
|
0xC3 => "Lossless", |
41
|
|
|
|
|
|
|
0xC5 => "Differential sequential", |
42
|
|
|
|
|
|
|
0xC6 => "Differential progressive", |
43
|
|
|
|
|
|
|
0xC7 => "Differential lossless", |
44
|
|
|
|
|
|
|
0xC9 => "Extended sequential, arithmetic coding", |
45
|
|
|
|
|
|
|
0xCA => "Progressive, arithmetic coding", |
46
|
|
|
|
|
|
|
0xCB => "Lossless, arithmetic coding", |
47
|
|
|
|
|
|
|
0xCD => "Differential sequential, arithmetic coding", |
48
|
|
|
|
|
|
|
0xCE => "Differential progressive, arithmetic coding", |
49
|
|
|
|
|
|
|
0xCF => "Differential lossless, arithmetic coding", |
50
|
|
|
|
|
|
|
); |
51
|
|
|
|
|
|
|
|
52
|
|
|
|
|
|
|
sub my_read |
53
|
|
|
|
|
|
|
{ |
54
|
778
|
|
|
687
|
0
|
1073
|
my($source, $len) = @_; |
55
|
778
|
|
|
|
|
789
|
my $buf; |
56
|
778
|
|
|
|
|
1488
|
my $n = read($source, $buf, $len); |
57
|
687
|
50
|
|
|
|
1034
|
die "read failed: $!" unless defined $n; |
58
|
687
|
50
|
|
|
|
907
|
die "short read ($len/$n) at pos " . tell($source) unless $n == $len; |
59
|
687
|
|
|
|
|
1384
|
$buf; |
60
|
|
|
|
|
|
|
} |
61
|
|
|
|
|
|
|
|
62
|
|
|
|
|
|
|
BEGIN { |
63
|
7
|
50
|
|
7
|
|
53
|
my $f = ($] >= 5.008) ? <<'EOT' : <<'EOT'; |
64
|
|
|
|
|
|
|
sub with_io_string (&$) { |
65
|
|
|
|
|
|
|
open(my $fh, "<", \$_[1]); |
66
|
|
|
|
|
|
|
local $_ = $fh; |
67
|
|
|
|
|
|
|
&{$_[0]}; |
68
|
|
|
|
|
|
|
} |
69
|
|
|
|
|
|
|
EOT |
70
|
|
|
|
|
|
|
sub with_io_string (&$) { |
71
|
|
|
|
|
|
|
require IO::String; |
72
|
|
|
|
|
|
|
local $_ = IO::String->new($_[1]); |
73
|
|
|
|
|
|
|
&{$_[0]}; |
74
|
|
|
|
|
|
|
$_->close; |
75
|
|
|
|
|
|
|
} |
76
|
|
|
|
|
|
|
EOT |
77
|
|
|
|
|
|
|
|
78
|
|
|
|
|
|
|
#print $f; |
79
|
7
|
|
|
93
|
0
|
599
|
eval $f; |
|
93
|
|
|
14
|
|
150
|
|
|
93
|
|
|
|
|
119
|
|
|
93
|
|
|
|
|
263
|
|
|
11
|
|
|
|
|
198
|
|
|
14
|
|
|
|
|
1686
|
|
|
14
|
|
|
|
|
57
|
|
|
14
|
|
|
|
|
37
|
|
80
|
7
|
50
|
|
|
|
12457
|
die $@ if $@; |
81
|
|
|
|
|
|
|
} |
82
|
|
|
|
|
|
|
|
83
|
|
|
|
|
|
|
sub process_file |
84
|
|
|
|
|
|
|
{ |
85
|
17
|
|
|
17
|
0
|
35
|
my($info, $fh, $cnf) = @_; |
86
|
17
|
|
|
|
|
43
|
_process_file($info, $fh, 0); |
87
|
|
|
|
|
|
|
} |
88
|
|
|
|
|
|
|
|
89
|
|
|
|
|
|
|
sub _process_file |
90
|
|
|
|
|
|
|
{ |
91
|
25
|
|
|
52
|
|
45
|
my($info, $fh, $img_no) = @_; |
92
|
|
|
|
|
|
|
|
93
|
25
|
|
|
|
|
47
|
my $soi = my_read($fh, 2); |
94
|
28
|
50
|
|
|
|
77
|
unless ($soi eq "\xFF\xD8") { |
95
|
3
|
|
|
|
|
12
|
my $ofs = tell() - 2; |
96
|
3
|
|
|
|
|
6
|
die "SOI missing in JPEG file at offset $ofs"; |
97
|
|
|
|
|
|
|
} |
98
|
|
|
|
|
|
|
|
99
|
55
|
|
|
|
|
135
|
$info->push_info($img_no, "file_media_type" => "image/jpeg"); |
100
|
55
|
|
|
|
|
130
|
$info->push_info($img_no, "file_ext" => "jpg"); |
101
|
|
|
|
|
|
|
|
102
|
55
|
|
|
|
|
92
|
while (1) { |
103
|
235
|
|
|
|
|
363
|
my($ff, $mark) = unpack("CC", my_read($fh, 2)); |
104
|
235
|
50
|
|
|
|
428
|
last if !defined $ff; |
105
|
237
|
100
|
|
|
|
360
|
if ($ff != 0xFF) { |
106
|
5
|
|
|
|
|
9
|
my $corrupt_bytes = 2; |
107
|
5
|
|
|
|
|
9
|
while(1) { |
108
|
8
|
|
|
|
|
10
|
my($ff) = unpack("C", my_read($fh,1)); |
109
|
7
|
50
|
|
|
|
14
|
return if !defined $ff; |
110
|
7
|
100
|
|
|
|
48
|
last if $ff == 0xFF; |
111
|
34
|
|
|
|
|
64
|
$corrupt_bytes++; |
112
|
|
|
|
|
|
|
} |
113
|
2
|
|
|
|
|
4
|
$mark = unpack("C", my_read($fh,1)); |
114
|
2
|
|
|
|
|
12
|
$info->push_info($img_no, "Warn", sprintf("Corrupt JPEG data, $corrupt_bytes extraneous bytes before marker 0x%02x", $mark)); |
115
|
|
|
|
|
|
|
} |
116
|
234
|
100
|
|
|
|
335
|
if ($mark == 0xFF) { |
117
|
|
|
|
|
|
|
# JPEG markers can be padded with unlimited 0xFF's |
118
|
32
|
|
|
|
|
108
|
for (;;) { |
119
|
29
|
|
|
|
|
54
|
($mark) = unpack("C", my_read($fh, 1)); |
120
|
29
|
50
|
|
|
|
65
|
last if $mark != 0xFF; |
121
|
|
|
|
|
|
|
} |
122
|
|
|
|
|
|
|
} |
123
|
261
|
100
|
66
|
|
|
757
|
last if $mark == 0xDA || $mark == 0xD9; # SOS/EOI |
124
|
236
|
|
|
|
|
332
|
my($len) = unpack("n", my_read($fh, 2)); |
125
|
236
|
50
|
|
|
|
532
|
last if $len < 2; |
126
|
210
|
|
|
|
|
336
|
process_chunk($info, $img_no, $mark, my_read($fh, $len - 2)); |
127
|
|
|
|
|
|
|
} |
128
|
|
|
|
|
|
|
} |
129
|
|
|
|
|
|
|
|
130
|
|
|
|
|
|
|
sub process_chunk |
131
|
|
|
|
|
|
|
{ |
132
|
214
|
|
|
214
|
0
|
350
|
my($info, $img_no, $mark, $data) = @_; |
133
|
|
|
|
|
|
|
#printf "MARK 0x%02X, len=%d\n", $mark, length($data); |
134
|
|
|
|
|
|
|
|
135
|
212
|
100
|
66
|
|
|
728
|
if ($mark == 0xFE) { |
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
136
|
5
|
|
|
|
|
20
|
$info->push_info($img_no, Comment => $data); |
137
|
|
|
|
|
|
|
} |
138
|
|
|
|
|
|
|
elsif ($mark >= 0xE0 && $mark <= 0xEF) { |
139
|
41
|
100
|
|
|
|
113
|
process_app($info, $mark, $data) if $img_no == 0; |
140
|
|
|
|
|
|
|
} |
141
|
|
|
|
|
|
|
elsif ($sof{$mark}) { |
142
|
28
|
|
|
|
|
101
|
my($precision, $height, $width, $num_comp) = |
143
|
|
|
|
|
|
|
unpack("CnnC", substr($data, 0, 6, "")); |
144
|
28
|
|
|
|
|
142
|
$info->push_info($img_no, "JPEG_Type", $sof{$mark}); |
145
|
|
|
|
|
|
|
|
146
|
|
|
|
|
|
|
# fix bug #15167 by keeping the highest values |
147
|
28
|
|
50
|
|
|
93
|
my $old_w = $info->get_info($img_no, "width") || -1; |
148
|
28
|
|
50
|
|
|
62
|
my $old_h = $info->get_info($img_no, "height") || -1; |
149
|
|
|
|
|
|
|
|
150
|
34
|
50
|
|
|
|
121
|
$info->replace_info($img_no, "width", $width) if $old_w < $width; |
151
|
28
|
50
|
|
|
|
96
|
$info->replace_info($img_no, "height", $height) if $old_h < $height; |
152
|
|
|
|
|
|
|
|
153
|
28
|
|
|
|
|
76
|
for (1..$num_comp) { |
154
|
75
|
|
|
|
|
131
|
$info->push_info($img_no, "BitsPerSample", $precision); |
155
|
|
|
|
|
|
|
} |
156
|
28
|
|
|
|
|
77
|
$info->push_info($img_no, "SamplesPerPixel" => $num_comp); |
157
|
|
|
|
|
|
|
|
158
|
|
|
|
|
|
|
# XXX need to consider JFIF/Adobe markers to determine this... |
159
|
25
|
50
|
|
|
|
71
|
if ($num_comp == 1) { |
|
|
50
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
160
|
3
|
|
|
|
|
7
|
$info->push_info($img_no, "color_type" => "Gray"); |
161
|
|
|
|
|
|
|
} |
162
|
|
|
|
|
|
|
elsif ($num_comp == 3) { |
163
|
28
|
|
|
|
|
65
|
$info->push_info($img_no, "color_type" => "YCbCr"); # or RGB ? |
164
|
|
|
|
|
|
|
} |
165
|
|
|
|
|
|
|
elsif ($num_comp == 4) { |
166
|
3
|
|
|
|
|
10
|
$info->push_info($img_no, "color_type" => "CMYK"); # or YCCK ? |
167
|
|
|
|
|
|
|
} |
168
|
|
|
|
|
|
|
|
169
|
34
|
|
|
|
|
72
|
if (1) { |
170
|
34
|
|
|
|
|
137
|
my %comp_id_lookup = ( 1 => "Y", |
171
|
|
|
|
|
|
|
2 => "Cb", |
172
|
|
|
|
|
|
|
3 => "Cr", |
173
|
|
|
|
|
|
|
82 => "R", |
174
|
|
|
|
|
|
|
71 => "G", |
175
|
|
|
|
|
|
|
66 => "B" ); |
176
|
34
|
|
|
|
|
75
|
while (length($data)) { |
177
|
84
|
|
|
|
|
207
|
my($comp_id, $hv, $qtable) = |
178
|
|
|
|
|
|
|
unpack("CCC", substr($data, 0, 3, "")); |
179
|
84
|
|
|
|
|
162
|
my $horiz_sf = $hv >> 4 & 0x0f; |
180
|
84
|
|
|
|
|
162
|
my $vert_sf = $hv & 0x0f; |
181
|
80
|
|
33
|
|
|
167
|
$comp_id = $comp_id_lookup{$comp_id} || $comp_id; |
182
|
80
|
|
|
|
|
224
|
$info->push_info($img_no, "ColorComponents", [$comp_id, $hv, $qtable]); |
183
|
80
|
|
|
|
|
369
|
$info->push_info($img_no, "ColorComponentsDecoded", |
184
|
|
|
|
|
|
|
{ ComponentIdentifier => $comp_id, |
185
|
|
|
|
|
|
|
HorizontalSamplingFactor => $horiz_sf, |
186
|
|
|
|
|
|
|
VerticalSamplingFactor => $vert_sf, |
187
|
|
|
|
|
|
|
QuantizationTableDesignator => $qtable } ); |
188
|
|
|
|
|
|
|
} |
189
|
|
|
|
|
|
|
} |
190
|
|
|
|
|
|
|
} |
191
|
|
|
|
|
|
|
} |
192
|
|
|
|
|
|
|
|
193
|
|
|
|
|
|
|
sub process_app |
194
|
|
|
|
|
|
|
{ |
195
|
32
|
|
|
30
|
0
|
72
|
my($info, $mark, $data) = @_; |
196
|
32
|
|
|
|
|
69
|
my $app = $mark - 0xE0; |
197
|
30
|
|
|
|
|
139
|
my $id = substr($data, 0, 5, ""); |
198
|
|
|
|
|
|
|
#$info->push_info(0, "Debug", "APP$app $id"); |
199
|
27
|
|
|
|
|
58
|
$id = "$app-$id"; |
200
|
29
|
100
|
|
|
|
100
|
if ($id eq "0-JFIF\0") { |
|
|
50
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
201
|
14
|
|
|
|
|
40
|
process_app0_jfif($info, $data); |
202
|
|
|
|
|
|
|
} |
203
|
|
|
|
|
|
|
elsif ($id eq "0-JFXX\0") { |
204
|
0
|
|
|
|
|
0
|
process_app0_jfxx($info, $data); |
205
|
|
|
|
|
|
|
} |
206
|
|
|
|
|
|
|
elsif ($id eq "1-Exif\0") { |
207
|
15
|
|
|
|
|
34
|
process_app1_exif($info, $data); |
208
|
|
|
|
|
|
|
} |
209
|
|
|
|
|
|
|
elsif ($id eq "14-Adobe") { |
210
|
3
|
|
|
|
|
22
|
process_app14_adobe($info, $data); |
211
|
|
|
|
|
|
|
} |
212
|
|
|
|
|
|
|
else { |
213
|
1
|
|
|
|
|
3
|
$info->push_info(0, "App$id", $data); |
214
|
|
|
|
|
|
|
#printf " %s\n", Data::Dump::dump($data); |
215
|
|
|
|
|
|
|
} |
216
|
|
|
|
|
|
|
} |
217
|
|
|
|
|
|
|
|
218
|
|
|
|
|
|
|
sub process_app0_jfif |
219
|
|
|
|
|
|
|
{ |
220
|
14
|
|
|
14
|
0
|
25
|
my($info, $data) = @_; |
221
|
17
|
50
|
|
|
|
60
|
if (length $data < 9) { |
222
|
3
|
|
|
|
|
26
|
$info->push_info(0, "Debug", "Short JFIF chunk"); |
223
|
3
|
|
|
|
|
20
|
return; |
224
|
|
|
|
|
|
|
} |
225
|
17
|
|
|
|
|
78
|
my($ver_hi, $ver_lo, $unit, $x_density, $y_density, $x_thumb, $y_thumb) = |
226
|
|
|
|
|
|
|
unpack("CC C nn CC", substr($data, 0, 9, "")); |
227
|
17
|
|
|
|
|
112
|
$info->push_info(0, "JFIF_Version", sprintf("%d.%02d", $ver_hi, $ver_lo)); |
228
|
|
|
|
|
|
|
|
229
|
17
|
50
|
33
|
|
|
97
|
my $res = $x_density != $y_density || !$unit |
230
|
|
|
|
|
|
|
? "$x_density/$y_density" : $x_density; |
231
|
|
|
|
|
|
|
|
232
|
17
|
50
|
|
|
|
40
|
if ($unit) { |
233
|
|
|
|
|
|
|
$unit = { 0 => "pixels", |
234
|
|
|
|
|
|
|
1 => "dpi", |
235
|
|
|
|
|
|
|
2 => "dpcm" |
236
|
17
|
|
33
|
|
|
94
|
}->{$unit} || "jfif-unit-$unit"; |
237
|
14
|
|
|
|
|
43
|
$res .= " $unit"; |
238
|
|
|
|
|
|
|
} |
239
|
14
|
|
|
|
|
38
|
$info->push_info(0, "resolution", $res); |
240
|
|
|
|
|
|
|
|
241
|
14
|
50
|
33
|
|
|
81
|
if ($x_thumb || $y_thumb) { |
242
|
0
|
|
|
|
|
0
|
$info->push_info(1, "width", $x_thumb); |
243
|
0
|
|
|
|
|
0
|
$info->push_info(1, "height", $y_thumb); |
244
|
0
|
|
|
|
|
0
|
$info->push_info(1, "ByteCount", length($data)); |
245
|
|
|
|
|
|
|
} |
246
|
|
|
|
|
|
|
} |
247
|
|
|
|
|
|
|
|
248
|
|
|
|
|
|
|
sub process_app0_jfxx |
249
|
|
|
|
|
|
|
{ |
250
|
0
|
|
|
0
|
0
|
0
|
my($info, $data) = @_; |
251
|
0
|
|
|
|
|
0
|
my($code) = ord(substr($data, 0, 1, "")); |
252
|
|
|
|
|
|
|
$info->push_info(1, "JFXX_ImageType", |
253
|
|
|
|
|
|
|
{ 0x10 => "JPEG thumbnail", |
254
|
|
|
|
|
|
|
0x11 => "Bitmap thumbnail", |
255
|
|
|
|
|
|
|
0x13 => "RGB thumbnail", |
256
|
0
|
|
0
|
|
|
0
|
}->{$code} || "Unknown extension code $code"); |
257
|
|
|
|
|
|
|
|
258
|
0
|
0
|
|
|
|
0
|
if ($code == 0x10) { |
259
|
0
|
|
|
|
|
0
|
eval { |
260
|
|
|
|
|
|
|
with_io_string { |
261
|
2
|
|
|
2
|
|
6
|
_process_file($info, $_, 1); |
262
|
2
|
|
|
|
|
12
|
} $data; |
263
|
|
|
|
|
|
|
}; |
264
|
2
|
0
|
|
|
|
6
|
$info->push_info(1, "error" => $@) if $@; |
265
|
|
|
|
|
|
|
} |
266
|
|
|
|
|
|
|
} |
267
|
|
|
|
|
|
|
|
268
|
|
|
|
|
|
|
sub process_app1_exif |
269
|
|
|
|
|
|
|
{ |
270
|
12
|
|
|
12
|
0
|
57
|
my($info, $data) = @_; |
271
|
12
|
|
|
|
|
28
|
my $null = substr($data, 0, 1, ""); |
272
|
14
|
50
|
|
|
|
1211
|
if ($null ne "\0") { |
273
|
2
|
|
|
|
|
7
|
$info->push_info(0, "Debug", "Exif chunk does not start with \\0"); |
274
|
2
|
|
|
|
|
13
|
return; |
275
|
|
|
|
|
|
|
} |
276
|
|
|
|
|
|
|
|
277
|
14
|
|
|
|
|
1542
|
require Image::TIFF; |
278
|
12
|
|
|
|
|
33
|
my $t = eval { Image::TIFF->new(\$data) }; |
|
12
|
|
|
|
|
112
|
|
279
|
14
|
50
|
|
|
|
36
|
if (!$t) { |
280
|
4
|
|
|
|
|
13
|
$info->push_info(0, "Warn", "Cannot parse APP1 EXIF segment"); |
281
|
4
|
|
|
|
|
10
|
return; |
282
|
|
|
|
|
|
|
} |
283
|
|
|
|
|
|
|
|
284
|
|
|
|
|
|
|
|
285
|
131
|
|
|
|
|
277
|
for my $i (0 .. $t->num_ifds - 1) { |
286
|
28
|
|
|
|
|
68
|
my $ifd = $t->ifd($i); |
287
|
|
|
|
|
|
|
|
288
|
|
|
|
|
|
|
# use Data::Dumper; |
289
|
|
|
|
|
|
|
# print STDERR Dumper($ifd); |
290
|
|
|
|
|
|
|
|
291
|
25
|
|
|
|
|
56
|
for (@$ifd) { |
292
|
|
|
|
|
|
|
# use Devel::Peek; |
293
|
|
|
|
|
|
|
# print STDERR "# pushing info $i $_->[0] $_->[3]\n"; |
294
|
|
|
|
|
|
|
# print STDERR Devel::Peek::Dump($_->[3]),"\n" if $_->[0] =~ /Olympus-/; |
295
|
|
|
|
|
|
|
|
296
|
589
|
|
|
|
|
1032
|
$info->push_info($i, $_->[0], $_->[3]); |
297
|
|
|
|
|
|
|
} |
298
|
|
|
|
|
|
|
|
299
|
|
|
|
|
|
|
# If we find JPEGInterchangeFormat/JPEGInterchangeFormatLngth, |
300
|
|
|
|
|
|
|
# then we should apply process_file kind of recursively to extract |
301
|
|
|
|
|
|
|
# information of this (thumbnail) image file... |
302
|
25
|
100
|
|
|
|
77
|
if (my($ipos) = $info->get_info($i, "JPEGInterchangeFormat", 1)) { |
303
|
12
|
|
|
|
|
25
|
my($ilen) = $info->get_info($i, "JPEGInterchangeFormatLength", 1); |
304
|
11
|
50
|
|
|
|
24
|
if ($ilen) |
305
|
|
|
|
|
|
|
{ |
306
|
11
|
|
|
|
|
86
|
my $jdata = substr($data, $ipos, $ilen); |
307
|
|
|
|
|
|
|
#$info->push_info($i, "JPEGImage" => $jdata); |
308
|
|
|
|
|
|
|
|
309
|
15
|
100
|
|
|
|
43
|
if ($jdata) { |
310
|
|
|
|
|
|
|
with_io_string { |
311
|
15
|
|
|
11
|
|
40
|
_process_file($info, $_, $i); |
312
|
15
|
|
|
|
|
325
|
} $jdata; |
313
|
|
|
|
|
|
|
} |
314
|
|
|
|
|
|
|
} |
315
|
|
|
|
|
|
|
} |
316
|
|
|
|
|
|
|
|
317
|
|
|
|
|
|
|
# Turn XResolution/YResolution into 'resolution' |
318
|
32
|
|
|
|
|
141
|
my($xres) = $info->get_info($i, "XResolution", 1); |
319
|
28
|
|
|
|
|
67
|
my($yres) = $info->get_info($i, "YResolution", 1); |
320
|
|
|
|
|
|
|
|
321
|
|
|
|
|
|
|
# Samsung Digimax 200 is a totally confused camera that |
322
|
|
|
|
|
|
|
# puts rational numbers with 0 as denominator and they |
323
|
|
|
|
|
|
|
# also seem to not understand what resolution means. |
324
|
28
|
|
|
|
|
52
|
for ($xres, $yres) { |
325
|
52
|
100
|
|
|
|
300
|
$_ += 0 if ref($_) eq "Image::TIFF::Rational"; |
326
|
|
|
|
|
|
|
} |
327
|
|
|
|
|
|
|
|
328
|
27
|
|
|
|
|
73
|
my($unit) = $info->get_info($i, "ResolutionUnit", 1); |
329
|
28
|
|
|
|
|
52
|
my $res = "1/1"; # default; |
330
|
28
|
100
|
66
|
|
|
153
|
if ($xres && $yres) { |
331
|
23
|
100
|
|
|
|
126
|
$res = ($xres == $yres) ? $xres : "$xres/$yres"; |
332
|
|
|
|
|
|
|
} |
333
|
24
|
100
|
66
|
|
|
126
|
$res .= " $unit" if $unit && $unit ne "pixels"; |
334
|
24
|
|
|
|
|
56
|
$info->push_info($i, "resolution", $res); |
335
|
|
|
|
|
|
|
} |
336
|
|
|
|
|
|
|
} |
337
|
|
|
|
|
|
|
|
338
|
|
|
|
|
|
|
sub process_app14_adobe |
339
|
|
|
|
|
|
|
{ |
340
|
0
|
|
|
0
|
0
|
|
my($info, $data) = @_; |
341
|
0
|
|
|
|
|
|
my($version, $flags0, $flags1, $transform) = unpack("nnnC", $data); |
342
|
0
|
|
|
|
|
|
$info->push_info(0, "AdobeTransformVersion" => $version); |
343
|
0
|
|
|
|
|
|
$info->push_info(0, "AdobeTransformFlags" => [$flags0, $flags1]); |
344
|
0
|
|
|
|
|
|
$info->push_info(0, "AdobeTransform" => $transform); |
345
|
|
|
|
|
|
|
} |
346
|
|
|
|
|
|
|
|
347
|
|
|
|
|
|
|
1; |