line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
#------------------------------------------------------------------------------ |
2
|
|
|
|
|
|
|
# File: CanonRaw.pm |
3
|
|
|
|
|
|
|
# |
4
|
|
|
|
|
|
|
# Description: Read Canon RAW (CRW) meta information |
5
|
|
|
|
|
|
|
# |
6
|
|
|
|
|
|
|
# Revisions: 11/25/2003 - P. Harvey Created |
7
|
|
|
|
|
|
|
# 12/02/2003 - P. Harvey Completely reworked and figured out many |
8
|
|
|
|
|
|
|
# more tags |
9
|
|
|
|
|
|
|
# |
10
|
|
|
|
|
|
|
# References: 1) http://www.cybercom.net/~dcoffin/dcraw/ |
11
|
|
|
|
|
|
|
# 2) http://www.wonderland.org/crw/ |
12
|
|
|
|
|
|
|
# 3) http://xyrion.org/ciff/CIFFspecV1R04.pdf |
13
|
|
|
|
|
|
|
# 4) Dave Nicholson private communication (PowerShot S30) |
14
|
|
|
|
|
|
|
#------------------------------------------------------------------------------ |
15
|
|
|
|
|
|
|
|
16
|
|
|
|
|
|
|
package Image::ExifTool::CanonRaw; |
17
|
|
|
|
|
|
|
|
18
|
20
|
|
|
20
|
|
4537
|
use strict; |
|
20
|
|
|
|
|
52
|
|
|
20
|
|
|
|
|
852
|
|
19
|
20
|
|
|
20
|
|
121
|
use vars qw($VERSION $AUTOLOAD %crwTagFormat); |
|
20
|
|
|
|
|
55
|
|
|
20
|
|
|
|
|
1403
|
|
20
|
20
|
|
|
20
|
|
148
|
use Image::ExifTool qw(:DataAccess :Utils); |
|
20
|
|
|
|
|
51
|
|
|
20
|
|
|
|
|
5051
|
|
21
|
20
|
|
|
20
|
|
1484
|
use Image::ExifTool::Exif; |
|
20
|
|
|
|
|
125
|
|
|
20
|
|
|
|
|
615
|
|
22
|
20
|
|
|
20
|
|
14054
|
use Image::ExifTool::Canon; |
|
20
|
|
|
|
|
321
|
|
|
20
|
|
|
|
|
55436
|
|
23
|
|
|
|
|
|
|
|
24
|
|
|
|
|
|
|
$VERSION = '1.60'; |
25
|
|
|
|
|
|
|
|
26
|
|
|
|
|
|
|
sub WriteCRW($$); |
27
|
|
|
|
|
|
|
sub ProcessCanonRaw($$$); |
28
|
|
|
|
|
|
|
sub WriteCanonRaw($$$); |
29
|
|
|
|
|
|
|
sub CheckCanonRaw($$$); |
30
|
|
|
|
|
|
|
sub InitMakerNotes($); |
31
|
|
|
|
|
|
|
sub SaveMakerNotes($); |
32
|
|
|
|
|
|
|
sub BuildMakerNotes($$$$$$); |
33
|
|
|
|
|
|
|
|
34
|
|
|
|
|
|
|
# formats for CRW tag types (($tag >> 8) & 0x38) |
35
|
|
|
|
|
|
|
# Note: don't define format for undefined types |
36
|
|
|
|
|
|
|
%crwTagFormat = ( |
37
|
|
|
|
|
|
|
0x00 => 'int8u', |
38
|
|
|
|
|
|
|
0x08 => 'string', |
39
|
|
|
|
|
|
|
0x10 => 'int16u', |
40
|
|
|
|
|
|
|
0x18 => 'int32u', |
41
|
|
|
|
|
|
|
# 0x20 => 'undef', |
42
|
|
|
|
|
|
|
# 0x28 => 'undef', |
43
|
|
|
|
|
|
|
# 0x30 => 'undef', |
44
|
|
|
|
|
|
|
); |
45
|
|
|
|
|
|
|
|
46
|
|
|
|
|
|
|
# Canon raw file tag table |
47
|
|
|
|
|
|
|
# Note: Tag ID's have upper 2 bits set to zero, since these 2 bits |
48
|
|
|
|
|
|
|
# just specify the location of the information |
49
|
|
|
|
|
|
|
%Image::ExifTool::CanonRaw::Main = ( |
50
|
|
|
|
|
|
|
GROUPS => { 0 => 'MakerNotes', 2 => 'Camera' }, |
51
|
|
|
|
|
|
|
PROCESS_PROC => \&ProcessCanonRaw, |
52
|
|
|
|
|
|
|
WRITE_PROC => \&WriteCanonRaw, |
53
|
|
|
|
|
|
|
CHECK_PROC => \&CheckCanonRaw, |
54
|
|
|
|
|
|
|
WRITABLE => 1, |
55
|
|
|
|
|
|
|
0x0000 => { Name => 'NullRecord', Writable => 'undef' }, #3 |
56
|
|
|
|
|
|
|
0x0001 => { #3 |
57
|
|
|
|
|
|
|
Name => 'FreeBytes', |
58
|
|
|
|
|
|
|
Format => 'undef', |
59
|
|
|
|
|
|
|
Binary => 1, |
60
|
|
|
|
|
|
|
}, |
61
|
|
|
|
|
|
|
0x0032 => { Name => 'CanonColorInfo1', Writable => 0 }, |
62
|
|
|
|
|
|
|
0x0805 => [ |
63
|
|
|
|
|
|
|
# this tag is found in more than one directory... |
64
|
|
|
|
|
|
|
{ |
65
|
|
|
|
|
|
|
Condition => '$self->{DIR_NAME} eq "ImageDescription"', |
66
|
|
|
|
|
|
|
Name => 'CanonFileDescription', |
67
|
|
|
|
|
|
|
Writable => 'string[32]', |
68
|
|
|
|
|
|
|
}, |
69
|
|
|
|
|
|
|
{ |
70
|
|
|
|
|
|
|
Name => 'UserComment', |
71
|
|
|
|
|
|
|
Writable => 'string[256]', |
72
|
|
|
|
|
|
|
}, |
73
|
|
|
|
|
|
|
], |
74
|
|
|
|
|
|
|
0x080a => { |
75
|
|
|
|
|
|
|
Name => 'CanonRawMakeModel', |
76
|
|
|
|
|
|
|
Writable => 0, |
77
|
|
|
|
|
|
|
SubDirectory => { TagTable => 'Image::ExifTool::CanonRaw::MakeModel' }, |
78
|
|
|
|
|
|
|
}, |
79
|
|
|
|
|
|
|
0x080b => { Name => 'CanonFirmwareVersion', Writable => 'string[32]' }, |
80
|
|
|
|
|
|
|
0x080c => { Name => 'ComponentVersion', Writable => 'string' }, #3 |
81
|
|
|
|
|
|
|
0x080d => { Name => 'ROMOperationMode', Writable => 'string[8]' }, #3 |
82
|
|
|
|
|
|
|
0x0810 => { Name => 'OwnerName', Writable => 'string[32]' }, |
83
|
|
|
|
|
|
|
0x0815 => { Name => 'CanonImageType', Writable => 'string[32]' }, |
84
|
|
|
|
|
|
|
0x0816 => { Name => 'OriginalFileName', Writable => 'string[32]' }, |
85
|
|
|
|
|
|
|
0x0817 => { Name => 'ThumbnailFileName', Writable => 'string[32]' }, |
86
|
|
|
|
|
|
|
0x100a => { #3 |
87
|
|
|
|
|
|
|
Name => 'TargetImageType', |
88
|
|
|
|
|
|
|
Writable => 'int16u', |
89
|
|
|
|
|
|
|
PrintConv => { |
90
|
|
|
|
|
|
|
0 => 'Real-world Subject', |
91
|
|
|
|
|
|
|
1 => 'Written Document', |
92
|
|
|
|
|
|
|
}, |
93
|
|
|
|
|
|
|
}, |
94
|
|
|
|
|
|
|
0x1010 => { #3 |
95
|
|
|
|
|
|
|
Name => 'ShutterReleaseMethod', |
96
|
|
|
|
|
|
|
Writable => 'int16u', |
97
|
|
|
|
|
|
|
PrintConv => { |
98
|
|
|
|
|
|
|
0 => 'Single Shot', |
99
|
|
|
|
|
|
|
2 => 'Continuous Shooting', |
100
|
|
|
|
|
|
|
}, |
101
|
|
|
|
|
|
|
}, |
102
|
|
|
|
|
|
|
0x1011 => { #3 |
103
|
|
|
|
|
|
|
Name => 'ShutterReleaseTiming', |
104
|
|
|
|
|
|
|
Writable => 'int16u', |
105
|
|
|
|
|
|
|
PrintConv => { |
106
|
|
|
|
|
|
|
0 => 'Priority on shutter', |
107
|
|
|
|
|
|
|
1 => 'Priority on focus', |
108
|
|
|
|
|
|
|
}, |
109
|
|
|
|
|
|
|
}, |
110
|
|
|
|
|
|
|
0x1016 => { Name => 'ReleaseSetting', Writable => 'int16u' }, #3 |
111
|
|
|
|
|
|
|
0x101c => { Name => 'BaseISO', Writable => 'int16u' }, #3 |
112
|
|
|
|
|
|
|
0x1028=> { #PH |
113
|
|
|
|
|
|
|
Name => 'CanonFlashInfo', |
114
|
|
|
|
|
|
|
Writable => 'int16u', |
115
|
|
|
|
|
|
|
Count => 4, |
116
|
|
|
|
|
|
|
Unknown => 1, |
117
|
|
|
|
|
|
|
}, |
118
|
|
|
|
|
|
|
0x1029 => { |
119
|
|
|
|
|
|
|
Name => 'CanonFocalLength', |
120
|
|
|
|
|
|
|
Writable => 0, |
121
|
|
|
|
|
|
|
SubDirectory => { TagTable => 'Image::ExifTool::Canon::FocalLength' }, |
122
|
|
|
|
|
|
|
}, |
123
|
|
|
|
|
|
|
0x102a => { |
124
|
|
|
|
|
|
|
Name => 'CanonShotInfo', |
125
|
|
|
|
|
|
|
Writable => 0, |
126
|
|
|
|
|
|
|
SubDirectory => { TagTable => 'Image::ExifTool::Canon::ShotInfo' }, |
127
|
|
|
|
|
|
|
}, |
128
|
|
|
|
|
|
|
0x102c => { |
129
|
|
|
|
|
|
|
Name => 'CanonColorInfo2', |
130
|
|
|
|
|
|
|
Writable => 0, |
131
|
|
|
|
|
|
|
# for the S30, the following information has been decoded: (ref 4) |
132
|
|
|
|
|
|
|
# offset 66: int32u - shutter half press time in ms |
133
|
|
|
|
|
|
|
# offset 70: int32u - image capture time in ms |
134
|
|
|
|
|
|
|
# offset 74: int16u - custom white balance flag (0=Off, 512=On) |
135
|
|
|
|
|
|
|
}, |
136
|
|
|
|
|
|
|
0x102d => { |
137
|
|
|
|
|
|
|
Name => 'CanonCameraSettings', |
138
|
|
|
|
|
|
|
Writable => 0, |
139
|
|
|
|
|
|
|
SubDirectory => { TagTable => 'Image::ExifTool::Canon::CameraSettings' }, |
140
|
|
|
|
|
|
|
}, |
141
|
|
|
|
|
|
|
0x1030 => { #4 |
142
|
|
|
|
|
|
|
Name => 'WhiteSample', |
143
|
|
|
|
|
|
|
Writable => 0, |
144
|
|
|
|
|
|
|
SubDirectory => { |
145
|
|
|
|
|
|
|
Validate => 'Image::ExifTool::Canon::Validate($dirData,$subdirStart,$size)', |
146
|
|
|
|
|
|
|
TagTable => 'Image::ExifTool::CanonRaw::WhiteSample', |
147
|
|
|
|
|
|
|
}, |
148
|
|
|
|
|
|
|
}, |
149
|
|
|
|
|
|
|
0x1031 => { |
150
|
|
|
|
|
|
|
Name => 'SensorInfo', |
151
|
|
|
|
|
|
|
Writable => 0, |
152
|
|
|
|
|
|
|
SubDirectory => { TagTable => 'Image::ExifTool::Canon::SensorInfo' }, |
153
|
|
|
|
|
|
|
}, |
154
|
|
|
|
|
|
|
# this tag has only be verified for the 10D in CRW files, but the D30 and D60 |
155
|
|
|
|
|
|
|
# also produce CRW images and have CustomFunction information in their JPEG's |
156
|
|
|
|
|
|
|
0x1033 => [ |
157
|
|
|
|
|
|
|
{ |
158
|
|
|
|
|
|
|
Name => 'CustomFunctions10D', |
159
|
|
|
|
|
|
|
Condition => '$self->{Model} =~ /EOS 10D/', |
160
|
|
|
|
|
|
|
SubDirectory => { |
161
|
|
|
|
|
|
|
Validate => 'Image::ExifTool::Canon::Validate($dirData,$subdirStart,$size)', |
162
|
|
|
|
|
|
|
TagTable => 'Image::ExifTool::CanonCustom::Functions10D', |
163
|
|
|
|
|
|
|
}, |
164
|
|
|
|
|
|
|
}, |
165
|
|
|
|
|
|
|
{ |
166
|
|
|
|
|
|
|
Name => 'CustomFunctionsD30', |
167
|
|
|
|
|
|
|
Condition => '$self->{Model} =~ /EOS D30\b/', |
168
|
|
|
|
|
|
|
SubDirectory => { |
169
|
|
|
|
|
|
|
Validate => 'Image::ExifTool::Canon::Validate($dirData,$subdirStart,$size)', |
170
|
|
|
|
|
|
|
TagTable => 'Image::ExifTool::CanonCustom::FunctionsD30', |
171
|
|
|
|
|
|
|
}, |
172
|
|
|
|
|
|
|
}, |
173
|
|
|
|
|
|
|
{ |
174
|
|
|
|
|
|
|
Name => 'CustomFunctionsD60', |
175
|
|
|
|
|
|
|
Condition => '$self->{Model} =~ /EOS D60\b/', |
176
|
|
|
|
|
|
|
SubDirectory => { |
177
|
|
|
|
|
|
|
# the stored size in the D60 apparently doesn't include the size word: |
178
|
|
|
|
|
|
|
Validate => 'Image::ExifTool::Canon::Validate($dirData,$subdirStart,$size-2,$size)', |
179
|
|
|
|
|
|
|
# (D60 custom functions are basically the same as D30) |
180
|
|
|
|
|
|
|
TagTable => 'Image::ExifTool::CanonCustom::FunctionsD30', |
181
|
|
|
|
|
|
|
}, |
182
|
|
|
|
|
|
|
}, |
183
|
|
|
|
|
|
|
{ |
184
|
|
|
|
|
|
|
Name => 'CustomFunctionsUnknown', |
185
|
|
|
|
|
|
|
SubDirectory => { |
186
|
|
|
|
|
|
|
Validate => 'Image::ExifTool::Canon::Validate($dirData,$subdirStart,$size)', |
187
|
|
|
|
|
|
|
TagTable => 'Image::ExifTool::CanonCustom::FuncsUnknown', |
188
|
|
|
|
|
|
|
}, |
189
|
|
|
|
|
|
|
}, |
190
|
|
|
|
|
|
|
], |
191
|
|
|
|
|
|
|
0x1038 => { |
192
|
|
|
|
|
|
|
Name => 'CanonAFInfo', |
193
|
|
|
|
|
|
|
Writable => 0, |
194
|
|
|
|
|
|
|
SubDirectory => { TagTable => 'Image::ExifTool::Canon::AFInfo' }, |
195
|
|
|
|
|
|
|
}, |
196
|
|
|
|
|
|
|
0x1093 => { |
197
|
|
|
|
|
|
|
Name => 'CanonFileInfo', |
198
|
|
|
|
|
|
|
SubDirectory => { |
199
|
|
|
|
|
|
|
Validate => 'Image::ExifTool::Canon::Validate($dirData,$subdirStart,$size)', |
200
|
|
|
|
|
|
|
TagTable => 'Image::ExifTool::Canon::FileInfo', |
201
|
|
|
|
|
|
|
}, |
202
|
|
|
|
|
|
|
}, |
203
|
|
|
|
|
|
|
0x10a9 => { |
204
|
|
|
|
|
|
|
Name => 'ColorBalance', |
205
|
|
|
|
|
|
|
Writable => 0, |
206
|
|
|
|
|
|
|
SubDirectory => { TagTable => 'Image::ExifTool::Canon::ColorBalance' }, |
207
|
|
|
|
|
|
|
}, |
208
|
|
|
|
|
|
|
0x10b5 => { #PH |
209
|
|
|
|
|
|
|
Name => 'RawJpgInfo', |
210
|
|
|
|
|
|
|
SubDirectory => { |
211
|
|
|
|
|
|
|
Validate => 'Image::ExifTool::Canon::Validate($dirData,$subdirStart,$size)', |
212
|
|
|
|
|
|
|
TagTable => 'Image::ExifTool::CanonRaw::RawJpgInfo', |
213
|
|
|
|
|
|
|
}, |
214
|
|
|
|
|
|
|
}, |
215
|
|
|
|
|
|
|
0x10ae => { |
216
|
|
|
|
|
|
|
Name => 'ColorTemperature', |
217
|
|
|
|
|
|
|
Writable => 'int16u', |
218
|
|
|
|
|
|
|
}, |
219
|
|
|
|
|
|
|
0x10b4 => { |
220
|
|
|
|
|
|
|
Name => 'ColorSpace', |
221
|
|
|
|
|
|
|
Writable => 'int16u', |
222
|
|
|
|
|
|
|
PrintConv => { |
223
|
|
|
|
|
|
|
1 => 'sRGB', |
224
|
|
|
|
|
|
|
2 => 'Adobe RGB', |
225
|
|
|
|
|
|
|
0xffff => 'Uncalibrated', |
226
|
|
|
|
|
|
|
}, |
227
|
|
|
|
|
|
|
}, |
228
|
|
|
|
|
|
|
0x1803 => { #3 |
229
|
|
|
|
|
|
|
Name => 'ImageFormat', |
230
|
|
|
|
|
|
|
Writable => 0, |
231
|
|
|
|
|
|
|
SubDirectory => { TagTable => 'Image::ExifTool::CanonRaw::ImageFormat' }, |
232
|
|
|
|
|
|
|
}, |
233
|
|
|
|
|
|
|
0x1804 => { Name => 'RecordID', Writable => 'int32u' }, #3 |
234
|
|
|
|
|
|
|
0x1806 => { #3 |
235
|
|
|
|
|
|
|
Name => 'SelfTimerTime', |
236
|
|
|
|
|
|
|
Writable => 'int32u', |
237
|
|
|
|
|
|
|
ValueConv => '$val / 1000', |
238
|
|
|
|
|
|
|
ValueConvInv => '$val * 1000', |
239
|
|
|
|
|
|
|
PrintConv => '"$val s"', |
240
|
|
|
|
|
|
|
PrintConvInv => '$val=~s/\s*s.*//;$val', |
241
|
|
|
|
|
|
|
}, |
242
|
|
|
|
|
|
|
0x1807 => { |
243
|
|
|
|
|
|
|
Name => 'TargetDistanceSetting', |
244
|
|
|
|
|
|
|
Format => 'float', |
245
|
|
|
|
|
|
|
PrintConv => '"$val mm"', |
246
|
|
|
|
|
|
|
PrintConvInv => '$val=~s/\s*mm$//;$val', |
247
|
|
|
|
|
|
|
}, |
248
|
|
|
|
|
|
|
0x180b => [ |
249
|
|
|
|
|
|
|
{ |
250
|
|
|
|
|
|
|
# D30 |
251
|
|
|
|
|
|
|
Name => 'SerialNumber', |
252
|
|
|
|
|
|
|
Condition => '$$self{Model} =~ /EOS D30\b/', |
253
|
|
|
|
|
|
|
Writable => 'int32u', |
254
|
|
|
|
|
|
|
PrintConv => 'sprintf("%x-%.5d",$val>>16,$val&0xffff)', |
255
|
|
|
|
|
|
|
PrintConvInv => '$val=~/(.*)-(\d+)/ ? (hex($1)<<16)+$2 : undef', |
256
|
|
|
|
|
|
|
}, |
257
|
|
|
|
|
|
|
{ |
258
|
|
|
|
|
|
|
# all EOS models (D30, 10D, 300D) |
259
|
|
|
|
|
|
|
Name => 'SerialNumber', |
260
|
|
|
|
|
|
|
Condition => '$$self{Model} =~ /EOS/', |
261
|
|
|
|
|
|
|
Writable => 'int32u', |
262
|
|
|
|
|
|
|
PrintConv => 'sprintf("%.10d",$val)', |
263
|
|
|
|
|
|
|
PrintConvInv => '$val', |
264
|
|
|
|
|
|
|
}, |
265
|
|
|
|
|
|
|
{ |
266
|
|
|
|
|
|
|
# this is not SerialNumber for PowerShot models (but what is it?) - PH |
267
|
|
|
|
|
|
|
Name => 'UnknownNumber', |
268
|
|
|
|
|
|
|
Unknown => 1, |
269
|
|
|
|
|
|
|
}, |
270
|
|
|
|
|
|
|
], |
271
|
|
|
|
|
|
|
0x180e => { |
272
|
|
|
|
|
|
|
Name => 'TimeStamp', |
273
|
|
|
|
|
|
|
Writable => 0, |
274
|
|
|
|
|
|
|
SubDirectory => { |
275
|
|
|
|
|
|
|
TagTable => 'Image::ExifTool::CanonRaw::TimeStamp', |
276
|
|
|
|
|
|
|
}, |
277
|
|
|
|
|
|
|
}, |
278
|
|
|
|
|
|
|
0x1810 => { |
279
|
|
|
|
|
|
|
Name => 'ImageInfo', |
280
|
|
|
|
|
|
|
Writable => 0, |
281
|
|
|
|
|
|
|
SubDirectory => { |
282
|
|
|
|
|
|
|
TagTable => 'Image::ExifTool::CanonRaw::ImageInfo', |
283
|
|
|
|
|
|
|
}, |
284
|
|
|
|
|
|
|
}, |
285
|
|
|
|
|
|
|
0x1813 => { #3 |
286
|
|
|
|
|
|
|
Name => 'FlashInfo', |
287
|
|
|
|
|
|
|
Writable => 0, |
288
|
|
|
|
|
|
|
SubDirectory => { |
289
|
|
|
|
|
|
|
TagTable => 'Image::ExifTool::CanonRaw::FlashInfo', |
290
|
|
|
|
|
|
|
}, |
291
|
|
|
|
|
|
|
}, |
292
|
|
|
|
|
|
|
0x1814 => { #3 |
293
|
|
|
|
|
|
|
Name => 'MeasuredEV', |
294
|
|
|
|
|
|
|
Notes => q{ |
295
|
|
|
|
|
|
|
this is the Canon name for what could better be called MeasuredLV, and |
296
|
|
|
|
|
|
|
should be close to the calculated LightValue for a proper exposure with most |
297
|
|
|
|
|
|
|
models |
298
|
|
|
|
|
|
|
}, |
299
|
|
|
|
|
|
|
Format => 'float', |
300
|
|
|
|
|
|
|
ValueConv => '$val + 5', |
301
|
|
|
|
|
|
|
ValueConvInv => '$val - 5', |
302
|
|
|
|
|
|
|
}, |
303
|
|
|
|
|
|
|
0x1817 => { |
304
|
|
|
|
|
|
|
Name => 'FileNumber', |
305
|
|
|
|
|
|
|
Writable => 'int32u', |
306
|
|
|
|
|
|
|
Groups => { 2 => 'Image' }, |
307
|
|
|
|
|
|
|
PrintConv => '$_=$val;s/(\d+)(\d{4})/$1-$2/;$_', |
308
|
|
|
|
|
|
|
PrintConvInv => '$_=$val;s/-//;$_', |
309
|
|
|
|
|
|
|
}, |
310
|
|
|
|
|
|
|
0x1818 => { #3 |
311
|
|
|
|
|
|
|
Name => 'ExposureInfo', |
312
|
|
|
|
|
|
|
Groups => { 1 => 'CIFF' }, # (only so CIFF shows up in group lists) |
313
|
|
|
|
|
|
|
Writable => 0, |
314
|
|
|
|
|
|
|
SubDirectory => { TagTable => 'Image::ExifTool::CanonRaw::ExposureInfo' }, |
315
|
|
|
|
|
|
|
}, |
316
|
|
|
|
|
|
|
0x1834 => { #PH |
317
|
|
|
|
|
|
|
Name => 'CanonModelID', |
318
|
|
|
|
|
|
|
Writable => 'int32u', |
319
|
|
|
|
|
|
|
PrintHex => 1, |
320
|
|
|
|
|
|
|
Notes => q{ |
321
|
|
|
|
|
|
|
this is the complete list of model ID numbers, but note that many of these |
322
|
|
|
|
|
|
|
models do not produce CRW images |
323
|
|
|
|
|
|
|
}, |
324
|
|
|
|
|
|
|
SeparateTable => 'Canon CanonModelID', |
325
|
|
|
|
|
|
|
PrintConv => \%Image::ExifTool::Canon::canonModelID, |
326
|
|
|
|
|
|
|
}, |
327
|
|
|
|
|
|
|
0x1835 => { |
328
|
|
|
|
|
|
|
Name => 'DecoderTable', |
329
|
|
|
|
|
|
|
Writable => 0, |
330
|
|
|
|
|
|
|
SubDirectory => { TagTable => 'Image::ExifTool::CanonRaw::DecoderTable' }, |
331
|
|
|
|
|
|
|
}, |
332
|
|
|
|
|
|
|
0x183b => { #PH |
333
|
|
|
|
|
|
|
# display format for serial number |
334
|
|
|
|
|
|
|
Name => 'SerialNumberFormat', |
335
|
|
|
|
|
|
|
Writable => 'int32u', |
336
|
|
|
|
|
|
|
PrintHex => 1, |
337
|
|
|
|
|
|
|
PrintConv => { |
338
|
|
|
|
|
|
|
0x90000000 => 'Format 1', |
339
|
|
|
|
|
|
|
0xa0000000 => 'Format 2', |
340
|
|
|
|
|
|
|
}, |
341
|
|
|
|
|
|
|
}, |
342
|
|
|
|
|
|
|
0x2005 => { |
343
|
|
|
|
|
|
|
Name => 'RawData', |
344
|
|
|
|
|
|
|
Writable => 0, |
345
|
|
|
|
|
|
|
Binary => 1, |
346
|
|
|
|
|
|
|
}, |
347
|
|
|
|
|
|
|
0x2007 => { |
348
|
|
|
|
|
|
|
Name => 'JpgFromRaw', |
349
|
|
|
|
|
|
|
Groups => { 2 => 'Preview' }, |
350
|
|
|
|
|
|
|
Writable => 'resize', # 'resize' allows this value to change size |
351
|
|
|
|
|
|
|
Permanent => 0, |
352
|
|
|
|
|
|
|
RawConv => '$self->ValidateImage(\$val,$tag)', |
353
|
|
|
|
|
|
|
}, |
354
|
|
|
|
|
|
|
0x2008 => { |
355
|
|
|
|
|
|
|
Name => 'ThumbnailImage', |
356
|
|
|
|
|
|
|
Groups => { 2 => 'Preview' }, |
357
|
|
|
|
|
|
|
Writable => 'resize', # 'resize' allows this value to change size |
358
|
|
|
|
|
|
|
WriteCheck => '$self->CheckImage(\$val)', |
359
|
|
|
|
|
|
|
Permanent => 0, |
360
|
|
|
|
|
|
|
RawConv => '$self->ValidateImage(\$val,$tag)', |
361
|
|
|
|
|
|
|
}, |
362
|
|
|
|
|
|
|
# the following entries are subdirectories |
363
|
|
|
|
|
|
|
# (any 0x28 and 0x30 tag types are handled automatically by the decoding logic) |
364
|
|
|
|
|
|
|
0x2804 => { |
365
|
|
|
|
|
|
|
Name => 'ImageDescription', |
366
|
|
|
|
|
|
|
SubDirectory => { }, |
367
|
|
|
|
|
|
|
Writable => 0, |
368
|
|
|
|
|
|
|
}, |
369
|
|
|
|
|
|
|
0x2807 => { #3 |
370
|
|
|
|
|
|
|
Name => 'CameraObject', |
371
|
|
|
|
|
|
|
SubDirectory => { }, |
372
|
|
|
|
|
|
|
Writable => 0, |
373
|
|
|
|
|
|
|
}, |
374
|
|
|
|
|
|
|
0x3002 => { #3 |
375
|
|
|
|
|
|
|
Name => 'ShootingRecord', |
376
|
|
|
|
|
|
|
SubDirectory => { }, |
377
|
|
|
|
|
|
|
Writable => 0, |
378
|
|
|
|
|
|
|
}, |
379
|
|
|
|
|
|
|
0x3003 => { #3 |
380
|
|
|
|
|
|
|
Name => 'MeasuredInfo', |
381
|
|
|
|
|
|
|
SubDirectory => { }, |
382
|
|
|
|
|
|
|
Writable => 0, |
383
|
|
|
|
|
|
|
}, |
384
|
|
|
|
|
|
|
0x3004 => { #3 |
385
|
|
|
|
|
|
|
Name => 'CameraSpecification', |
386
|
|
|
|
|
|
|
SubDirectory => { }, |
387
|
|
|
|
|
|
|
Writable => 0, |
388
|
|
|
|
|
|
|
}, |
389
|
|
|
|
|
|
|
0x300a => { #3 |
390
|
|
|
|
|
|
|
Name => 'ImageProps', |
391
|
|
|
|
|
|
|
SubDirectory => { }, |
392
|
|
|
|
|
|
|
Writable => 0, |
393
|
|
|
|
|
|
|
}, |
394
|
|
|
|
|
|
|
0x300b => { |
395
|
|
|
|
|
|
|
Name => 'ExifInformation', |
396
|
|
|
|
|
|
|
SubDirectory => { }, |
397
|
|
|
|
|
|
|
Writable => 0, |
398
|
|
|
|
|
|
|
}, |
399
|
|
|
|
|
|
|
); |
400
|
|
|
|
|
|
|
|
401
|
|
|
|
|
|
|
# Canon binary data blocks |
402
|
|
|
|
|
|
|
%Image::ExifTool::CanonRaw::MakeModel = ( |
403
|
|
|
|
|
|
|
PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData, |
404
|
|
|
|
|
|
|
WRITE_PROC => \&Image::ExifTool::WriteBinaryData, |
405
|
|
|
|
|
|
|
CHECK_PROC => \&Image::ExifTool::CheckBinaryData, |
406
|
|
|
|
|
|
|
DATAMEMBER => [ 0, 6 ], # indices of data members to extract when writing |
407
|
|
|
|
|
|
|
WRITABLE => 1, |
408
|
|
|
|
|
|
|
FORMAT => 'string', |
409
|
|
|
|
|
|
|
GROUPS => { 0 => 'MakerNotes', 2 => 'Camera' }, |
410
|
|
|
|
|
|
|
# (can't specify a first entry because this isn't |
411
|
|
|
|
|
|
|
# a simple binary table with fixed offsets) |
412
|
|
|
|
|
|
|
0 => { |
413
|
|
|
|
|
|
|
Name => 'Make', |
414
|
|
|
|
|
|
|
Format => 'string[6]', # "Canon\0" |
415
|
|
|
|
|
|
|
DataMember => 'Make', |
416
|
|
|
|
|
|
|
RawConv => '$self->{Make} = $val', |
417
|
|
|
|
|
|
|
}, |
418
|
|
|
|
|
|
|
6 => { |
419
|
|
|
|
|
|
|
Name => 'Model', |
420
|
|
|
|
|
|
|
Format => 'string', # no size = to the end of the data |
421
|
|
|
|
|
|
|
Description => 'Camera Model Name', |
422
|
|
|
|
|
|
|
DataMember => 'Model', |
423
|
|
|
|
|
|
|
RawConv => '$self->{Model} = $val', |
424
|
|
|
|
|
|
|
}, |
425
|
|
|
|
|
|
|
); |
426
|
|
|
|
|
|
|
|
427
|
|
|
|
|
|
|
%Image::ExifTool::CanonRaw::TimeStamp = ( |
428
|
|
|
|
|
|
|
PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData, |
429
|
|
|
|
|
|
|
WRITE_PROC => \&Image::ExifTool::WriteBinaryData, |
430
|
|
|
|
|
|
|
CHECK_PROC => \&Image::ExifTool::CheckBinaryData, |
431
|
|
|
|
|
|
|
WRITABLE => 1, |
432
|
|
|
|
|
|
|
FORMAT => 'int32u', |
433
|
|
|
|
|
|
|
FIRST_ENTRY => 0, |
434
|
|
|
|
|
|
|
GROUPS => { 0 => 'MakerNotes', 2 => 'Time' }, |
435
|
|
|
|
|
|
|
0 => { |
436
|
|
|
|
|
|
|
Name => 'DateTimeOriginal', |
437
|
|
|
|
|
|
|
Description => 'Date/Time Original', |
438
|
|
|
|
|
|
|
Shift => 'Time', |
439
|
|
|
|
|
|
|
ValueConv => 'ConvertUnixTime($val)', |
440
|
|
|
|
|
|
|
ValueConvInv => 'GetUnixTime($val)', |
441
|
|
|
|
|
|
|
PrintConv => '$self->ConvertDateTime($val)', |
442
|
|
|
|
|
|
|
PrintConvInv => '$self->InverseDateTime($val)', |
443
|
|
|
|
|
|
|
}, |
444
|
|
|
|
|
|
|
1 => { #3 |
445
|
|
|
|
|
|
|
Name => 'TimeZoneCode', |
446
|
|
|
|
|
|
|
Format => 'int32s', |
447
|
|
|
|
|
|
|
ValueConv => '$val / 3600', |
448
|
|
|
|
|
|
|
ValueConvInv => '$val * 3600', |
449
|
|
|
|
|
|
|
}, |
450
|
|
|
|
|
|
|
2 => { #3 |
451
|
|
|
|
|
|
|
Name => 'TimeZoneInfo', |
452
|
|
|
|
|
|
|
Notes => 'set to 0x80000000 if TimeZoneCode is valid', |
453
|
|
|
|
|
|
|
}, |
454
|
|
|
|
|
|
|
); |
455
|
|
|
|
|
|
|
|
456
|
|
|
|
|
|
|
%Image::ExifTool::CanonRaw::ImageFormat = ( |
457
|
|
|
|
|
|
|
PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData, |
458
|
|
|
|
|
|
|
WRITE_PROC => \&Image::ExifTool::WriteBinaryData, |
459
|
|
|
|
|
|
|
CHECK_PROC => \&Image::ExifTool::CheckBinaryData, |
460
|
|
|
|
|
|
|
WRITABLE => 1, |
461
|
|
|
|
|
|
|
FORMAT => 'int32u', |
462
|
|
|
|
|
|
|
FIRST_ENTRY => 0, |
463
|
|
|
|
|
|
|
GROUPS => { 0 => 'MakerNotes', 2 => 'Image' }, |
464
|
|
|
|
|
|
|
0 => { |
465
|
|
|
|
|
|
|
Name => 'FileFormat', |
466
|
|
|
|
|
|
|
Flags => 'PrintHex', |
467
|
|
|
|
|
|
|
PrintConv => { |
468
|
|
|
|
|
|
|
0x00010000 => 'JPEG (lossy)', |
469
|
|
|
|
|
|
|
0x00010002 => 'JPEG (non-quantization)', |
470
|
|
|
|
|
|
|
0x00010003 => 'JPEG (lossy/non-quantization toggled)', |
471
|
|
|
|
|
|
|
0x00020001 => 'CRW', |
472
|
|
|
|
|
|
|
}, |
473
|
|
|
|
|
|
|
}, |
474
|
|
|
|
|
|
|
1 => { |
475
|
|
|
|
|
|
|
Name => 'TargetCompressionRatio', |
476
|
|
|
|
|
|
|
Format => 'float', |
477
|
|
|
|
|
|
|
}, |
478
|
|
|
|
|
|
|
); |
479
|
|
|
|
|
|
|
|
480
|
|
|
|
|
|
|
%Image::ExifTool::CanonRaw::RawJpgInfo = ( |
481
|
|
|
|
|
|
|
PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData, |
482
|
|
|
|
|
|
|
WRITE_PROC => \&Image::ExifTool::WriteBinaryData, |
483
|
|
|
|
|
|
|
CHECK_PROC => \&Image::ExifTool::CheckBinaryData, |
484
|
|
|
|
|
|
|
WRITABLE => 1, |
485
|
|
|
|
|
|
|
FORMAT => 'int16u', |
486
|
|
|
|
|
|
|
FIRST_ENTRY => 1, |
487
|
|
|
|
|
|
|
GROUPS => { 0 => 'MakerNotes', 2 => 'Image' }, |
488
|
|
|
|
|
|
|
# 0 => 'RawJpgInfoSize', |
489
|
|
|
|
|
|
|
1 => { #PH |
490
|
|
|
|
|
|
|
Name => 'RawJpgQuality', |
491
|
|
|
|
|
|
|
PrintConv => { |
492
|
|
|
|
|
|
|
1 => 'Economy', |
493
|
|
|
|
|
|
|
2 => 'Normal', |
494
|
|
|
|
|
|
|
3 => 'Fine', |
495
|
|
|
|
|
|
|
5 => 'Superfine', |
496
|
|
|
|
|
|
|
}, |
497
|
|
|
|
|
|
|
}, |
498
|
|
|
|
|
|
|
2 => { #PH |
499
|
|
|
|
|
|
|
Name => 'RawJpgSize', |
500
|
|
|
|
|
|
|
PrintConv => { |
501
|
|
|
|
|
|
|
0 => 'Large', |
502
|
|
|
|
|
|
|
1 => 'Medium', |
503
|
|
|
|
|
|
|
2 => 'Small', |
504
|
|
|
|
|
|
|
}, |
505
|
|
|
|
|
|
|
}, |
506
|
|
|
|
|
|
|
3 => 'RawJpgWidth', #PH |
507
|
|
|
|
|
|
|
4 => 'RawJpgHeight', #PH |
508
|
|
|
|
|
|
|
); |
509
|
|
|
|
|
|
|
|
510
|
|
|
|
|
|
|
%Image::ExifTool::CanonRaw::FlashInfo = ( |
511
|
|
|
|
|
|
|
PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData, |
512
|
|
|
|
|
|
|
WRITE_PROC => \&Image::ExifTool::WriteBinaryData, |
513
|
|
|
|
|
|
|
CHECK_PROC => \&Image::ExifTool::CheckBinaryData, |
514
|
|
|
|
|
|
|
WRITABLE => 1, |
515
|
|
|
|
|
|
|
FORMAT => 'float', |
516
|
|
|
|
|
|
|
FIRST_ENTRY => 0, |
517
|
|
|
|
|
|
|
GROUPS => { 0 => 'MakerNotes', 2 => 'Image' }, |
518
|
|
|
|
|
|
|
0 => 'FlashGuideNumber', |
519
|
|
|
|
|
|
|
1 => 'FlashThreshold', |
520
|
|
|
|
|
|
|
); |
521
|
|
|
|
|
|
|
|
522
|
|
|
|
|
|
|
%Image::ExifTool::CanonRaw::ExposureInfo = ( |
523
|
|
|
|
|
|
|
PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData, |
524
|
|
|
|
|
|
|
WRITE_PROC => \&Image::ExifTool::WriteBinaryData, |
525
|
|
|
|
|
|
|
CHECK_PROC => \&Image::ExifTool::CheckBinaryData, |
526
|
|
|
|
|
|
|
WRITABLE => 1, |
527
|
|
|
|
|
|
|
FORMAT => 'float', |
528
|
|
|
|
|
|
|
FIRST_ENTRY => 0, |
529
|
|
|
|
|
|
|
GROUPS => { 0 => 'MakerNotes', 2 => 'Image' }, |
530
|
|
|
|
|
|
|
0 => 'ExposureCompensation', |
531
|
|
|
|
|
|
|
1 => { |
532
|
|
|
|
|
|
|
Name => 'ShutterSpeedValue', |
533
|
|
|
|
|
|
|
ValueConv => 'abs($val)<100 ? 1/(2**$val) : 0', |
534
|
|
|
|
|
|
|
ValueConvInv => '$val>0 ? -log($val)/log(2) : -100', |
535
|
|
|
|
|
|
|
PrintConv => 'Image::ExifTool::Exif::PrintExposureTime($val)', |
536
|
|
|
|
|
|
|
PrintConvInv => 'Image::ExifTool::Exif::ConvertFraction($val)', |
537
|
|
|
|
|
|
|
}, |
538
|
|
|
|
|
|
|
2 => { |
539
|
|
|
|
|
|
|
Name => 'ApertureValue', |
540
|
|
|
|
|
|
|
ValueConv => '2 ** ($val / 2)', |
541
|
|
|
|
|
|
|
ValueConvInv => '$val>0 ? 2*log($val)/log(2) : 0', |
542
|
|
|
|
|
|
|
PrintConv => 'sprintf("%.1f",$val)', |
543
|
|
|
|
|
|
|
PrintConvInv => '$val', |
544
|
|
|
|
|
|
|
}, |
545
|
|
|
|
|
|
|
); |
546
|
|
|
|
|
|
|
|
547
|
|
|
|
|
|
|
%Image::ExifTool::CanonRaw::ImageInfo = ( |
548
|
|
|
|
|
|
|
PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData, |
549
|
|
|
|
|
|
|
WRITE_PROC => \&Image::ExifTool::WriteBinaryData, |
550
|
|
|
|
|
|
|
CHECK_PROC => \&Image::ExifTool::CheckBinaryData, |
551
|
|
|
|
|
|
|
FORMAT => 'int32u', |
552
|
|
|
|
|
|
|
FIRST_ENTRY => 0, |
553
|
|
|
|
|
|
|
GROUPS => { 0 => 'MakerNotes', 2 => 'Image' }, |
554
|
|
|
|
|
|
|
# Note: Don't make these writable (except rotation) because it confuses |
555
|
|
|
|
|
|
|
# Canon decoding software if the are changed |
556
|
|
|
|
|
|
|
0 => 'ImageWidth', #3 |
557
|
|
|
|
|
|
|
1 => 'ImageHeight', #3 |
558
|
|
|
|
|
|
|
2 => { #3 |
559
|
|
|
|
|
|
|
Name => 'PixelAspectRatio', |
560
|
|
|
|
|
|
|
Format => 'float', |
561
|
|
|
|
|
|
|
}, |
562
|
|
|
|
|
|
|
3 => { |
563
|
|
|
|
|
|
|
Name => 'Rotation', |
564
|
|
|
|
|
|
|
Format => 'int32s', |
565
|
|
|
|
|
|
|
Writable => 'int32s', |
566
|
|
|
|
|
|
|
}, |
567
|
|
|
|
|
|
|
4 => 'ComponentBitDepth', #3 |
568
|
|
|
|
|
|
|
5 => 'ColorBitDepth', #3 |
569
|
|
|
|
|
|
|
6 => 'ColorBW', #3 |
570
|
|
|
|
|
|
|
); |
571
|
|
|
|
|
|
|
|
572
|
|
|
|
|
|
|
# ref 4 |
573
|
|
|
|
|
|
|
%Image::ExifTool::CanonRaw::DecoderTable = ( |
574
|
|
|
|
|
|
|
PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData, |
575
|
|
|
|
|
|
|
WRITE_PROC => \&Image::ExifTool::WriteBinaryData, |
576
|
|
|
|
|
|
|
CHECK_PROC => \&Image::ExifTool::CheckBinaryData, |
577
|
|
|
|
|
|
|
GROUPS => { 0 => 'MakerNotes', 2 => 'Camera' }, |
578
|
|
|
|
|
|
|
FORMAT => 'int32u', |
579
|
|
|
|
|
|
|
FIRST_ENTRY => 0, |
580
|
|
|
|
|
|
|
0 => 'DecoderTableNumber', |
581
|
|
|
|
|
|
|
2 => 'CompressedDataOffset', |
582
|
|
|
|
|
|
|
3 => 'CompressedDataLength', |
583
|
|
|
|
|
|
|
); |
584
|
|
|
|
|
|
|
|
585
|
|
|
|
|
|
|
# ref 1/4 |
586
|
|
|
|
|
|
|
%Image::ExifTool::CanonRaw::WhiteSample = ( |
587
|
|
|
|
|
|
|
PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData, |
588
|
|
|
|
|
|
|
WRITE_PROC => \&Image::ExifTool::WriteBinaryData, |
589
|
|
|
|
|
|
|
CHECK_PROC => \&Image::ExifTool::CheckBinaryData, |
590
|
|
|
|
|
|
|
GROUPS => { 0 => 'MakerNotes', 2 => 'Camera' }, |
591
|
|
|
|
|
|
|
FORMAT => 'int16u', |
592
|
|
|
|
|
|
|
FIRST_ENTRY => 1, |
593
|
|
|
|
|
|
|
1 => 'WhiteSampleWidth', |
594
|
|
|
|
|
|
|
2 => 'WhiteSampleHeight', |
595
|
|
|
|
|
|
|
3 => 'WhiteSampleLeftBorder', |
596
|
|
|
|
|
|
|
4 => 'WhiteSampleTopBorder', |
597
|
|
|
|
|
|
|
5 => 'WhiteSampleBits', |
598
|
|
|
|
|
|
|
# this is followed by the encrypted white sample values (ref 1) |
599
|
|
|
|
|
|
|
); |
600
|
|
|
|
|
|
|
|
601
|
|
|
|
|
|
|
#------------------------------------------------------------------------------ |
602
|
|
|
|
|
|
|
# AutoLoad our writer routines when necessary |
603
|
|
|
|
|
|
|
# |
604
|
|
|
|
|
|
|
sub AUTOLOAD |
605
|
|
|
|
|
|
|
{ |
606
|
11
|
|
|
11
|
|
87
|
return Image::ExifTool::DoAutoLoad($AUTOLOAD, @_); |
607
|
|
|
|
|
|
|
} |
608
|
|
|
|
|
|
|
|
609
|
|
|
|
|
|
|
#------------------------------------------------------------------------------ |
610
|
|
|
|
|
|
|
# Process Raw file directory |
611
|
|
|
|
|
|
|
# Inputs: 0) ExifTool object reference |
612
|
|
|
|
|
|
|
# 1) directory information reference, 2) tag table reference |
613
|
|
|
|
|
|
|
# Returns: 1 on success |
614
|
|
|
|
|
|
|
sub ProcessCanonRaw($$$) |
615
|
|
|
|
|
|
|
{ |
616
|
182
|
|
|
182
|
0
|
410
|
my ($et, $dirInfo, $rawTagTable) = @_; |
617
|
182
|
|
|
|
|
376
|
my $blockStart = $$dirInfo{DirStart}; |
618
|
182
|
|
|
|
|
407
|
my $blockSize = $$dirInfo{DirLen}; |
619
|
182
|
50
|
|
|
|
577
|
my $raf = $$dirInfo{RAF} or return 0; |
620
|
182
|
|
|
|
|
283
|
my $buff; |
621
|
182
|
|
|
|
|
627
|
my $verbose = $et->Options('Verbose'); |
622
|
182
|
|
|
|
|
490
|
my $buildMakerNotes = $et->Options('MakerNotes'); |
623
|
|
|
|
|
|
|
|
624
|
|
|
|
|
|
|
# 4 bytes at end of block give directory position within block |
625
|
182
|
50
|
|
|
|
722
|
$raf->Seek($blockStart+$blockSize-4, 0) or return 0; |
626
|
182
|
50
|
|
|
|
600
|
$raf->Read($buff, 4) == 4 or return 0; |
627
|
182
|
|
|
|
|
581
|
my $dirOffset = Get32u(\$buff,0) + $blockStart; |
628
|
|
|
|
|
|
|
# avoid infinite recursion |
629
|
182
|
100
|
|
|
|
691
|
$$et{ProcessedCanonRaw} or $$et{ProcessedCanonRaw} = { }; |
630
|
182
|
50
|
|
|
|
591
|
if ($$et{ProcessedCanonRaw}{$dirOffset}) { |
631
|
0
|
|
|
|
|
0
|
$et->Warn("Not processing double-referenced $$dirInfo{DirName} directory"); |
632
|
0
|
|
|
|
|
0
|
return 0; |
633
|
|
|
|
|
|
|
} |
634
|
182
|
|
|
|
|
678
|
$$et{ProcessedCanonRaw}{$dirOffset} = 1; |
635
|
182
|
50
|
|
|
|
567
|
$raf->Seek($dirOffset, 0) or return 0; |
636
|
182
|
50
|
|
|
|
545
|
$raf->Read($buff, 2) == 2 or return 0; |
637
|
182
|
|
|
|
|
604
|
my $entries = Get16u(\$buff,0); # get number of entries in directory |
638
|
|
|
|
|
|
|
# read the directory (10 bytes per entry) |
639
|
182
|
50
|
|
|
|
571
|
$raf->Read($buff, 10 * $entries) == 10 * $entries or return 0; |
640
|
|
|
|
|
|
|
|
641
|
182
|
100
|
|
|
|
531
|
$verbose and $et->VerboseDir('CIFF', $entries); |
642
|
182
|
|
|
|
|
317
|
my $index; |
643
|
182
|
|
|
|
|
501
|
for ($index=0; $index<$entries; ++$index) { |
644
|
1008
|
|
|
|
|
1871
|
my $pt = 10 * $index; |
645
|
1008
|
|
|
|
|
2532
|
my $tag = Get16u(\$buff, $pt); |
646
|
1008
|
|
|
|
|
2598
|
my $size = Get32u(\$buff, $pt+2); |
647
|
1008
|
|
|
|
|
2599
|
my $valuePtr = Get32u(\$buff, $pt+6); |
648
|
1008
|
|
|
|
|
1824
|
my $ptr = $valuePtr + $blockStart; # all pointers relative to block start |
649
|
1008
|
50
|
|
|
|
2257
|
if ($tag & 0x8000) { |
650
|
0
|
|
|
|
|
0
|
$et->Warn('Bad CRW directory entry'); |
651
|
0
|
|
|
|
|
0
|
return 1; |
652
|
|
|
|
|
|
|
} |
653
|
1008
|
|
|
|
|
1497
|
my $tagID = $tag & 0x3fff; # get tag ID |
654
|
1008
|
|
|
|
|
1750
|
my $tagType = ($tag >> 8) & 0x38; # get tag type |
655
|
1008
|
|
|
|
|
1626
|
my $valueInDir = ($tag & 0x4000); # flag for value in directory |
656
|
1008
|
|
|
|
|
2795
|
my $tagInfo = $et->GetTagInfo($rawTagTable, $tagID); |
657
|
1008
|
100
|
100
|
|
|
4422
|
if (($tagType==0x28 or $tagType==0x30) and not $valueInDir) { |
|
|
|
66
|
|
|
|
|
658
|
|
|
|
|
|
|
# this type of tag specifies a raw subdirectory |
659
|
156
|
|
|
|
|
286
|
my $name; |
660
|
156
|
50
|
|
|
|
580
|
$tagInfo and $name = $$tagInfo{Name}; |
661
|
156
|
50
|
|
|
|
384
|
$name or $name = sprintf("CanonRaw_0x%.4x", $tag); |
662
|
|
|
|
|
|
|
my %subdirInfo = ( |
663
|
|
|
|
|
|
|
DirName => $name, |
664
|
|
|
|
|
|
|
DataLen => 0, |
665
|
|
|
|
|
|
|
DirStart => $ptr, |
666
|
|
|
|
|
|
|
DirLen => $size, |
667
|
|
|
|
|
|
|
Nesting => $$dirInfo{Nesting} + 1, |
668
|
|
|
|
|
|
|
RAF => $raf, |
669
|
|
|
|
|
|
|
Parent => $$dirInfo{DirName}, |
670
|
156
|
|
|
|
|
978
|
); |
671
|
156
|
100
|
|
|
|
440
|
if ($verbose) { |
672
|
6
|
|
|
|
|
33
|
my $fakeInfo = { Name => $name, SubDirectory => { } }; |
673
|
6
|
|
|
|
|
25
|
$et->VerboseInfo($tagID, $fakeInfo, |
674
|
|
|
|
|
|
|
'Index' => $index, |
675
|
|
|
|
|
|
|
'Size' => $size, |
676
|
|
|
|
|
|
|
'Start' => $ptr, |
677
|
|
|
|
|
|
|
); |
678
|
|
|
|
|
|
|
} |
679
|
156
|
|
|
|
|
593
|
$et->ProcessDirectory(\%subdirInfo, $rawTagTable); |
680
|
156
|
|
|
|
|
713
|
next; |
681
|
|
|
|
|
|
|
} |
682
|
852
|
|
|
|
|
1473
|
my ($valueDataPos, $count, $subdir); |
683
|
852
|
|
|
|
|
1875
|
my $format = $crwTagFormat{$tagType}; |
684
|
852
|
100
|
|
|
|
1777
|
if ($tagInfo) { |
685
|
684
|
|
|
|
|
1385
|
$subdir = $$tagInfo{SubDirectory}; |
686
|
684
|
100
|
|
|
|
2217
|
$format = $$tagInfo{Format} if $$tagInfo{Format}; |
687
|
684
|
|
|
|
|
1212
|
$count = $$tagInfo{Count}; |
688
|
|
|
|
|
|
|
} |
689
|
|
|
|
|
|
|
# get value data |
690
|
852
|
|
|
|
|
1319
|
my ($value, $delRawConv); |
691
|
852
|
100
|
|
|
|
1675
|
if ($valueInDir) { # is the value data in the directory? |
692
|
|
|
|
|
|
|
# this type of tag stores the value in the 'size' and 'ptr' fields |
693
|
381
|
|
|
|
|
626
|
$valueDataPos = $dirOffset + $pt + 4; # (remember, +2 for the entry count) |
694
|
381
|
|
|
|
|
583
|
$size = 8; |
695
|
381
|
|
|
|
|
899
|
$value = substr($buff, $pt+2, $size); |
696
|
|
|
|
|
|
|
# set count to 1 by default for normal values in directory |
697
|
381
|
100
|
66
|
|
|
2483
|
$count = 1 if not defined $count and $format and |
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
698
|
|
|
|
|
|
|
$format ne 'string' and not $subdir; |
699
|
|
|
|
|
|
|
} else { |
700
|
471
|
|
|
|
|
744
|
$valueDataPos = $ptr; |
701
|
|
|
|
|
|
|
# do MD5 of image data if requested |
702
|
471
|
50
|
33
|
|
|
1282
|
if ($$et{ImageDataMD5} and $tagID == 0x2005) { |
703
|
0
|
0
|
|
|
|
0
|
$raf->Seek($ptr, 0) and $et->ImageDataMD5($raf, $size, 'raw'); |
704
|
|
|
|
|
|
|
} |
705
|
471
|
100
|
33
|
|
|
1445
|
if ($size <= 512 or ($verbose > 2 and $size <= 65536) |
|
|
|
66
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
|
33
|
|
|
|
|
706
|
|
|
|
|
|
|
or ($tagInfo and ($$tagInfo{SubDirectory} |
707
|
|
|
|
|
|
|
or grep(/^$$tagInfo{Name}$/i, $et->GetRequestedTags()) ))) |
708
|
|
|
|
|
|
|
{ |
709
|
|
|
|
|
|
|
# read value if size is small or specifically requested |
710
|
|
|
|
|
|
|
# or if this is a SubDirectory |
711
|
457
|
50
|
33
|
|
|
1482
|
unless ($raf->Seek($ptr, 0) and $raf->Read($value, $size) == $size) { |
712
|
0
|
|
|
|
|
0
|
$et->Warn(sprintf("Error reading %d bytes from 0x%x",$size,$ptr)); |
713
|
0
|
|
|
|
|
0
|
next; |
714
|
|
|
|
|
|
|
} |
715
|
|
|
|
|
|
|
} else { |
716
|
14
|
|
|
|
|
51
|
$value = "Binary data $size bytes"; |
717
|
14
|
100
|
|
|
|
42
|
if ($tagInfo) { |
718
|
2
|
50
|
33
|
|
|
8
|
if ($et->Options('Binary') or $verbose) { |
719
|
|
|
|
|
|
|
# read the value anyway |
720
|
2
|
50
|
33
|
|
|
11
|
unless ($raf->Seek($ptr, 0) and $raf->Read($value, $size) == $size) { |
721
|
0
|
|
|
|
|
0
|
$et->Warn(sprintf("Error reading %d bytes from 0x%x",$size,$ptr)); |
722
|
0
|
|
|
|
|
0
|
next; |
723
|
|
|
|
|
|
|
} |
724
|
|
|
|
|
|
|
} |
725
|
|
|
|
|
|
|
# force this to be a binary (scalar reference) |
726
|
2
|
|
|
|
|
10
|
$$tagInfo{RawConv} = '\$val'; |
727
|
2
|
|
|
|
|
7
|
$delRawConv = 1; |
728
|
|
|
|
|
|
|
} |
729
|
14
|
|
|
|
|
32
|
$size = length $value; |
730
|
14
|
|
|
|
|
29
|
undef $format; |
731
|
|
|
|
|
|
|
} |
732
|
|
|
|
|
|
|
} |
733
|
|
|
|
|
|
|
# set count from tagInfo count if necessary |
734
|
852
|
100
|
100
|
|
|
3208
|
if ($format and not $count) { |
735
|
|
|
|
|
|
|
# set count according to format and size |
736
|
540
|
|
|
|
|
1305
|
my $fnum = $Image::ExifTool::Exif::formatNumber{$format}; |
737
|
540
|
|
|
|
|
1095
|
my $fsiz = $Image::ExifTool::Exif::formatSize[$fnum]; |
738
|
540
|
|
|
|
|
1380
|
$count = int($size / $fsiz); |
739
|
|
|
|
|
|
|
} |
740
|
852
|
100
|
|
|
|
1742
|
if ($verbose) { |
741
|
43
|
|
|
|
|
77
|
my $val = $value; |
742
|
43
|
100
|
|
|
|
173
|
$format and $val = ReadValue(\$val, 0, $format, $count, $size); |
743
|
43
|
|
|
|
|
278
|
$et->VerboseInfo($tagID, $tagInfo, |
744
|
|
|
|
|
|
|
Table => $rawTagTable, |
745
|
|
|
|
|
|
|
Index => $index, |
746
|
|
|
|
|
|
|
Value => $val, |
747
|
|
|
|
|
|
|
DataPt => \$value, |
748
|
|
|
|
|
|
|
DataPos => $valueDataPos, |
749
|
|
|
|
|
|
|
Size => $size, |
750
|
|
|
|
|
|
|
Format => $format, |
751
|
|
|
|
|
|
|
Count => $count, |
752
|
|
|
|
|
|
|
); |
753
|
|
|
|
|
|
|
} |
754
|
852
|
100
|
|
|
|
1703
|
if ($buildMakerNotes) { |
755
|
|
|
|
|
|
|
# build maker notes information if requested |
756
|
188
|
|
|
|
|
651
|
BuildMakerNotes($et, $tagID, $tagInfo, \$value, $format, $count); |
757
|
|
|
|
|
|
|
} |
758
|
852
|
100
|
|
|
|
2042
|
next unless defined $tagInfo; |
759
|
|
|
|
|
|
|
|
760
|
684
|
100
|
|
|
|
1418
|
if ($subdir) { |
761
|
224
|
|
|
|
|
550
|
my $name = $$tagInfo{Name}; |
762
|
224
|
|
|
|
|
338
|
my $newTagTable; |
763
|
224
|
50
|
|
|
|
641
|
if ($$subdir{TagTable}) { |
764
|
224
|
|
|
|
|
714
|
$newTagTable = GetTagTable($$subdir{TagTable}); |
765
|
224
|
50
|
|
|
|
687
|
unless ($newTagTable) { |
766
|
0
|
|
|
|
|
0
|
warn "Unknown tag table $$subdir{TagTable}\n"; |
767
|
0
|
|
|
|
|
0
|
next; |
768
|
|
|
|
|
|
|
} |
769
|
|
|
|
|
|
|
} else { |
770
|
0
|
|
|
|
|
0
|
warn "Must specify TagTable for SubDirectory $name\n"; |
771
|
0
|
|
|
|
|
0
|
next; |
772
|
|
|
|
|
|
|
} |
773
|
224
|
|
|
|
|
405
|
my $subdirStart = 0; |
774
|
|
|
|
|
|
|
#### eval Start () |
775
|
224
|
50
|
|
|
|
549
|
$subdirStart = eval $$subdir{Start} if $$subdir{Start}; |
776
|
224
|
|
|
|
|
405
|
my $dirData = \$value; |
777
|
|
|
|
|
|
|
my %subdirInfo = ( |
778
|
|
|
|
|
|
|
Name => $name, |
779
|
|
|
|
|
|
|
DataPt => $dirData, |
780
|
|
|
|
|
|
|
DataLen => $size, |
781
|
|
|
|
|
|
|
DataPos => $valueDataPos, |
782
|
|
|
|
|
|
|
DirStart => $subdirStart, |
783
|
|
|
|
|
|
|
DirLen => $size - $subdirStart, |
784
|
|
|
|
|
|
|
Nesting => $$dirInfo{Nesting} + 1, |
785
|
|
|
|
|
|
|
RAF => $raf, |
786
|
|
|
|
|
|
|
DirName => $name, |
787
|
|
|
|
|
|
|
Parent => $$dirInfo{DirName}, |
788
|
224
|
|
|
|
|
2093
|
); |
789
|
|
|
|
|
|
|
#### eval Validate ($dirData, $subdirStart, $size) |
790
|
224
|
50
|
66
|
|
|
1750
|
if (defined $$subdir{Validate} and not eval $$subdir{Validate}) { |
791
|
0
|
|
|
|
|
0
|
$et->Warn("Invalid $name data"); |
792
|
|
|
|
|
|
|
} else { |
793
|
224
|
|
|
|
|
1089
|
$et->ProcessDirectory(\%subdirInfo, $newTagTable, $$subdir{ProcessProc}); |
794
|
|
|
|
|
|
|
} |
795
|
|
|
|
|
|
|
} else { |
796
|
|
|
|
|
|
|
# convert to specified format if necessary |
797
|
460
|
100
|
|
|
|
1789
|
$format and $value = ReadValue(\$value, 0, $format, $count, $size); |
798
|
|
|
|
|
|
|
# save the information |
799
|
460
|
|
|
|
|
1751
|
$et->FoundTag($tagInfo, $value); |
800
|
460
|
100
|
|
|
|
1781
|
delete $$tagInfo{RawConv} if $delRawConv; |
801
|
|
|
|
|
|
|
} |
802
|
|
|
|
|
|
|
} |
803
|
182
|
|
|
|
|
698
|
return 1; |
804
|
|
|
|
|
|
|
} |
805
|
|
|
|
|
|
|
|
806
|
|
|
|
|
|
|
#------------------------------------------------------------------------------ |
807
|
|
|
|
|
|
|
# get information from raw file |
808
|
|
|
|
|
|
|
# Inputs: 0) ExifTool object reference, 1) dirInfo reference |
809
|
|
|
|
|
|
|
# Returns: 1 if this was a valid Canon RAW file |
810
|
|
|
|
|
|
|
sub ProcessCRW($$) |
811
|
|
|
|
|
|
|
{ |
812
|
26
|
|
|
26
|
0
|
99
|
my ($et, $dirInfo) = @_; |
813
|
26
|
|
|
|
|
73
|
my ($buff, $sig); |
814
|
26
|
|
|
|
|
99
|
my $raf = $$dirInfo{RAF}; |
815
|
26
|
|
|
|
|
119
|
my $buildMakerNotes = $et->Options('MakerNotes'); |
816
|
|
|
|
|
|
|
|
817
|
26
|
50
|
|
|
|
209
|
$raf->Read($buff,2) == 2 or return 0; |
818
|
26
|
50
|
|
|
|
155
|
SetByteOrder($buff) or return 0; |
819
|
26
|
50
|
|
|
|
124
|
$raf->Read($buff,4) == 4 or return 0; |
820
|
26
|
50
|
|
|
|
106
|
$raf->Read($sig,8) == 8 or return 0; # get file signature |
821
|
26
|
50
|
|
|
|
280
|
$sig =~ /^HEAP(CCDR|JPGM)/ or return 0; # validate signature |
822
|
26
|
|
|
|
|
135
|
my $hlen = Get32u(\$buff, 0); |
823
|
|
|
|
|
|
|
|
824
|
26
|
50
|
|
|
|
127
|
$raf->Seek(0, 2) or return 0; # seek to end of file |
825
|
26
|
50
|
|
|
|
188
|
my $filesize = $raf->Tell() or return 0; |
826
|
|
|
|
|
|
|
|
827
|
|
|
|
|
|
|
# initialize maker note data if building maker notes |
828
|
26
|
100
|
|
|
|
158
|
$buildMakerNotes and InitMakerNotes($et); |
829
|
|
|
|
|
|
|
|
830
|
|
|
|
|
|
|
# set the FileType tag unless already done (eg. APP0 CIFF record in JPEG image) |
831
|
26
|
|
|
|
|
136
|
$et->SetFileType(); |
832
|
|
|
|
|
|
|
|
833
|
|
|
|
|
|
|
# build directory information for main raw directory |
834
|
26
|
|
|
|
|
306
|
my %dirInfo = ( |
835
|
|
|
|
|
|
|
DataLen => 0, |
836
|
|
|
|
|
|
|
DirStart => $hlen, |
837
|
|
|
|
|
|
|
DirLen => $filesize - $hlen, |
838
|
|
|
|
|
|
|
Nesting => 0, |
839
|
|
|
|
|
|
|
RAF => $raf, |
840
|
|
|
|
|
|
|
Parent => 'CRW', |
841
|
|
|
|
|
|
|
); |
842
|
|
|
|
|
|
|
|
843
|
|
|
|
|
|
|
# process the raw directory |
844
|
26
|
|
|
|
|
103
|
my $rawTagTable = GetTagTable('Image::ExifTool::CanonRaw::Main'); |
845
|
26
|
|
|
|
|
114
|
my $oldIndent = $$et{INDENT}; |
846
|
26
|
|
|
|
|
83
|
$$et{INDENT} .= '| '; |
847
|
26
|
50
|
|
|
|
174
|
unless (ProcessCanonRaw($et, \%dirInfo, $rawTagTable)) { |
848
|
0
|
|
|
|
|
0
|
$et->Warn('CRW file format error'); |
849
|
|
|
|
|
|
|
} |
850
|
26
|
|
|
|
|
120
|
$$et{INDENT} = $oldIndent; |
851
|
|
|
|
|
|
|
|
852
|
|
|
|
|
|
|
# finish building maker notes if necessary |
853
|
26
|
100
|
|
|
|
131
|
$buildMakerNotes and SaveMakerNotes($et); |
854
|
|
|
|
|
|
|
|
855
|
|
|
|
|
|
|
# process trailers if they exist in CRW file (not in CIFF information!) |
856
|
26
|
100
|
|
|
|
234
|
if ($$et{FILE_TYPE} eq 'CRW') { |
857
|
7
|
|
|
|
|
72
|
my $trailInfo = Image::ExifTool::IdentifyTrailer($raf); |
858
|
7
|
50
|
|
|
|
59
|
$et->ProcessTrailers($trailInfo) if $trailInfo; |
859
|
|
|
|
|
|
|
} |
860
|
|
|
|
|
|
|
|
861
|
26
|
|
|
|
|
143
|
return 1; |
862
|
|
|
|
|
|
|
} |
863
|
|
|
|
|
|
|
|
864
|
|
|
|
|
|
|
1; # end |
865
|
|
|
|
|
|
|
|
866
|
|
|
|
|
|
|
__END__ |