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