source: main/trunk/greenstone2/perllib/cpan/Image/ExifTool/CanonRaw.pm

Last change on this file was 34921, checked in by anupama, 3 years ago

Committing the improvements to EmbeddedMetaPlugin's processing of Keywords vs other metadata fields. Keywords were literally stored as arrays of words rather than phrases in PDFs (at least in Diego's sample PDF), whereas other meta fields like Subjects and Creators stored them as arrays of phrases. To get both to work, Kathy updated EXIF to a newer version, to retrieve the actual EXIF values stored in the PDF. And Kathy and Dr Bainbridge came up with a new option that I added called apply_join_before_split_to_metafields that's a regex which can list the metadata fields to apply the join_before_split to and whcih previously always got applied to all metadata fields. Now it's applied to any *Keywords metafields by default, as that's the metafield we have experience of that behaves differently to the others, as it stores by word instead of phrases. Tested on Diego's sample PDF. Diego has double-checked it to works on his sample PDF too, setting the split char to ; and turning on the join_before_split and leaving apply_join_before_split_to_metafields at its default of .*Keywords. File changes are strings.properties for the tooltip, the plugin introducing the option and working with it and Kathy's EXIF updates affecting cpan/File and cpan/Image.

File size: 29.7 KB
Line 
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
16package Image::ExifTool::CanonRaw;
17
18use strict;
19use vars qw($VERSION $AUTOLOAD %crwTagFormat);
20use Image::ExifTool qw(:DataAccess :Utils);
21use Image::ExifTool::Exif;
22use Image::ExifTool::Canon;
23
24$VERSION = '1.58';
25
26sub WriteCRW($$);
27sub ProcessCanonRaw($$$);
28sub WriteCanonRaw($$$);
29sub CheckCanonRaw($$$);
30sub InitMakerNotes($);
31sub SaveMakerNotes($);
32sub 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#
604sub AUTOLOAD
605{
606 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
614sub ProcessCanonRaw($$$)
615{
616 my ($et, $dirInfo, $rawTagTable) = @_;
617 my $blockStart = $$dirInfo{DirStart};
618 my $blockSize = $$dirInfo{DirLen};
619 my $raf = $$dirInfo{RAF} or return 0;
620 my $buff;
621 my $verbose = $et->Options('Verbose');
622 my $buildMakerNotes = $et->Options('MakerNotes');
623
624 # 4 bytes at end of block give directory position within block
625 $raf->Seek($blockStart+$blockSize-4, 0) or return 0;
626 $raf->Read($buff, 4) == 4 or return 0;
627 my $dirOffset = Get32u(\$buff,0) + $blockStart;
628 $raf->Seek($dirOffset, 0) or return 0;
629 $raf->Read($buff, 2) == 2 or return 0;
630 my $entries = Get16u(\$buff,0); # get number of entries in directory
631 # read the directory (10 bytes per entry)
632 $raf->Read($buff, 10 * $entries) == 10 * $entries or return 0;
633
634 $verbose and $et->VerboseDir('CIFF', $entries);
635 my $index;
636 for ($index=0; $index<$entries; ++$index) {
637 my $pt = 10 * $index;
638 my $tag = Get16u(\$buff, $pt);
639 my $size = Get32u(\$buff, $pt+2);
640 my $valuePtr = Get32u(\$buff, $pt+6);
641 my $ptr = $valuePtr + $blockStart; # all pointers relative to block start
642 if ($tag & 0x8000) {
643 $et->Warn('Bad CRW directory entry');
644 return 1;
645 }
646 my $tagID = $tag & 0x3fff; # get tag ID
647 my $tagType = ($tag >> 8) & 0x38; # get tag type
648 my $valueInDir = ($tag & 0x4000); # flag for value in directory
649 my $tagInfo = $et->GetTagInfo($rawTagTable, $tagID);
650 if (($tagType==0x28 or $tagType==0x30) and not $valueInDir) {
651 # this type of tag specifies a raw subdirectory
652 my $name;
653 $tagInfo and $name = $$tagInfo{Name};
654 $name or $name = sprintf("CanonRaw_0x%.4x", $tag);
655 my %subdirInfo = (
656 DirName => $name,
657 DataLen => 0,
658 DirStart => $ptr,
659 DirLen => $size,
660 Nesting => $$dirInfo{Nesting} + 1,
661 RAF => $raf,
662 Parent => $$dirInfo{DirName},
663 );
664 if ($verbose) {
665 my $fakeInfo = { Name => $name, SubDirectory => { } };
666 $et->VerboseInfo($tagID, $fakeInfo,
667 'Index' => $index,
668 'Size' => $size,
669 'Start' => $ptr,
670 );
671 }
672 $et->ProcessDirectory(\%subdirInfo, $rawTagTable);
673 next;
674 }
675 my ($valueDataPos, $count, $subdir);
676 my $format = $crwTagFormat{$tagType};
677 if ($tagInfo) {
678 $subdir = $$tagInfo{SubDirectory};
679 $format = $$tagInfo{Format} if $$tagInfo{Format};
680 $count = $$tagInfo{Count};
681 }
682 # get value data
683 my ($value, $delRawConv);
684 if ($valueInDir) { # is the value data in the directory?
685 # this type of tag stores the value in the 'size' and 'ptr' fields
686 $valueDataPos = $dirOffset + $pt + 4; # (remember, +2 for the entry count)
687 $size = 8;
688 $value = substr($buff, $pt+2, $size);
689 # set count to 1 by default for normal values in directory
690 $count = 1 if not defined $count and $format and
691 $format ne 'string' and not $subdir;
692 } else {
693 $valueDataPos = $ptr;
694 if ($size <= 512 or ($verbose > 2 and $size <= 65536)
695 or ($tagInfo and ($$tagInfo{SubDirectory}
696 or grep(/^$$tagInfo{Name}$/i, $et->GetRequestedTags()) )))
697 {
698 # read value if size is small or specifically requested
699 # or if this is a SubDirectory
700 unless ($raf->Seek($ptr, 0) and $raf->Read($value, $size) == $size) {
701 $et->Warn(sprintf("Error reading %d bytes from 0x%x",$size,$ptr));
702 next;
703 }
704 } else {
705 $value = "Binary data $size bytes";
706 if ($tagInfo) {
707 if ($et->Options('Binary') or $verbose) {
708 # read the value anyway
709 unless ($raf->Seek($ptr, 0) and $raf->Read($value, $size) == $size) {
710 $et->Warn(sprintf("Error reading %d bytes from 0x%x",$size,$ptr));
711 next;
712 }
713 }
714 # force this to be a binary (scalar reference)
715 $$tagInfo{RawConv} = '\$val';
716 $delRawConv = 1;
717 }
718 $size = length $value;
719 undef $format;
720 }
721 }
722 # set count from tagInfo count if necessary
723 if ($format and not $count) {
724 # set count according to format and size
725 my $fnum = $Image::ExifTool::Exif::formatNumber{$format};
726 my $fsiz = $Image::ExifTool::Exif::formatSize[$fnum];
727 $count = int($size / $fsiz);
728 }
729 if ($verbose) {
730 my $val = $value;
731 $format and $val = ReadValue(\$val, 0, $format, $count, $size);
732 $et->VerboseInfo($tagID, $tagInfo,
733 Table => $rawTagTable,
734 Index => $index,
735 Value => $val,
736 DataPt => \$value,
737 DataPos => $valueDataPos,
738 Size => $size,
739 Format => $format,
740 Count => $count,
741 );
742 }
743 if ($buildMakerNotes) {
744 # build maker notes information if requested
745 BuildMakerNotes($et, $tagID, $tagInfo, \$value, $format, $count);
746 }
747 next unless defined $tagInfo;
748
749 if ($subdir) {
750 my $name = $$tagInfo{Name};
751 my $newTagTable;
752 if ($$subdir{TagTable}) {
753 $newTagTable = GetTagTable($$subdir{TagTable});
754 unless ($newTagTable) {
755 warn "Unknown tag table $$subdir{TagTable}\n";
756 next;
757 }
758 } else {
759 warn "Must specify TagTable for SubDirectory $name\n";
760 next;
761 }
762 my $subdirStart = 0;
763 #### eval Start ()
764 $subdirStart = eval $$subdir{Start} if $$subdir{Start};
765 my $dirData = \$value;
766 my %subdirInfo = (
767 Name => $name,
768 DataPt => $dirData,
769 DataLen => $size,
770 DataPos => $valueDataPos,
771 DirStart => $subdirStart,
772 DirLen => $size - $subdirStart,
773 Nesting => $$dirInfo{Nesting} + 1,
774 RAF => $raf,
775 DirName => $name,
776 Parent => $$dirInfo{DirName},
777 );
778 #### eval Validate ($dirData, $subdirStart, $size)
779 if (defined $$subdir{Validate} and not eval $$subdir{Validate}) {
780 $et->Warn("Invalid $name data");
781 } else {
782 $et->ProcessDirectory(\%subdirInfo, $newTagTable, $$subdir{ProcessProc});
783 }
784 } else {
785 # convert to specified format if necessary
786 $format and $value = ReadValue(\$value, 0, $format, $count, $size);
787 # save the information
788 $et->FoundTag($tagInfo, $value);
789 delete $$tagInfo{RawConv} if $delRawConv;
790 }
791 }
792 return 1;
793}
794
795#------------------------------------------------------------------------------
796# get information from raw file
797# Inputs: 0) ExifTool object reference, 1) dirInfo reference
798# Returns: 1 if this was a valid Canon RAW file
799sub ProcessCRW($$)
800{
801 my ($et, $dirInfo) = @_;
802 my ($buff, $sig);
803 my $raf = $$dirInfo{RAF};
804 my $buildMakerNotes = $et->Options('MakerNotes');
805
806 $raf->Read($buff,2) == 2 or return 0;
807 SetByteOrder($buff) or return 0;
808 $raf->Read($buff,4) == 4 or return 0;
809 $raf->Read($sig,8) == 8 or return 0; # get file signature
810 $sig =~ /^HEAP(CCDR|JPGM)/ or return 0; # validate signature
811 my $hlen = Get32u(\$buff, 0);
812
813 $raf->Seek(0, 2) or return 0; # seek to end of file
814 my $filesize = $raf->Tell() or return 0;
815
816 # initialize maker note data if building maker notes
817 $buildMakerNotes and InitMakerNotes($et);
818
819 # set the FileType tag unless already done (eg. APP0 CIFF record in JPEG image)
820 $et->SetFileType();
821
822 # build directory information for main raw directory
823 my %dirInfo = (
824 DataLen => 0,
825 DirStart => $hlen,
826 DirLen => $filesize - $hlen,
827 Nesting => 0,
828 RAF => $raf,
829 Parent => 'CRW',
830 );
831
832 # process the raw directory
833 my $rawTagTable = GetTagTable('Image::ExifTool::CanonRaw::Main');
834 my $oldIndent = $$et{INDENT};
835 $$et{INDENT} .= '| ';
836 unless (ProcessCanonRaw($et, \%dirInfo, $rawTagTable)) {
837 $et->Warn('CRW file format error');
838 }
839 $$et{INDENT} = $oldIndent;
840
841 # finish building maker notes if necessary
842 $buildMakerNotes and SaveMakerNotes($et);
843
844 # process trailers if they exist in CRW file (not in CIFF information!)
845 if ($$et{FILE_TYPE} eq 'CRW') {
846 my $trailInfo = Image::ExifTool::IdentifyTrailer($raf);
847 $et->ProcessTrailers($trailInfo) if $trailInfo;
848 }
849
850 return 1;
851}
852
8531; # end
854
855__END__
856
857=head1 NAME
858
859Image::ExifTool::CanonRaw - Read Canon RAW (CRW) meta information
860
861=head1 SYNOPSIS
862
863This module is loaded automatically by Image::ExifTool when required.
864
865=head1 DESCRIPTION
866
867This module contains definitions required by Image::ExifTool to interpret
868meta information from Canon CRW raw files. These files are written directly
869by some Canon cameras, and contain meta information similar to that found in
870the EXIF Canon maker notes.
871
872=head1 NOTES
873
874The CR2 format written by some Canon cameras is very different the CRW
875format processed by this module. (CR2 is TIFF-based and uses standard EXIF
876tags.)
877
878=head1 AUTHOR
879
880Copyright 2003-2021, Phil Harvey (philharvey66 at gmail.com)
881
882This library is free software; you can redistribute it and/or modify it
883under the same terms as Perl itself.
884
885=head1 REFERENCES
886
887=over 4
888
889=item L<http://www.cybercom.net/~dcoffin/dcraw/>
890
891=item L<http://www.wonderland.org/crw/>
892
893=item L<http://xyrion.org/ciff/>
894
895=item L<https://exiftool.org/canon_raw.html>
896
897=back
898
899=head1 ACKNOWLEDGEMENTS
900
901Thanks to Dave Nicholson for decoding a number of new tags.
902
903=head1 SEE ALSO
904
905L<Image::ExifTool::TagNames/CanonRaw Tags>,
906L<Image::ExifTool::Canon(3pm)|Image::ExifTool::Canon>,
907L<Image::ExifTool(3pm)|Image::ExifTool>
908
909=cut
910
Note: See TracBrowser for help on using the repository browser.