File Coverage

blib/lib/Image/ExifTool/NikonCapture.pm
Criterion Covered Total %
statement 88 127 69.2
branch 33 62 53.2
condition 15 39 38.4
subroutine 6 7 85.7
pod 0 3 0.0
total 142 238 59.6


line stmt bran cond sub pod time code
1             #------------------------------------------------------------------------------
2             # File: NikonCapture.pm
3             #
4             # Description: Read/write Nikon Capture information
5             #
6             # Revisions: 11/08/2005 - P. Harvey Created
7             # 10/10/2008 - P. Harvey Updated for Capture NX 2
8             # 16/04/2011 - P. Harvey Decode NikonCaptureEditVersions
9             #
10             # References: 1) http://www.cybercom.net/~dcoffin/dcraw/
11             # IB) Iliah Borg private communication (LibRaw)
12             #------------------------------------------------------------------------------
13              
14             package Image::ExifTool::NikonCapture;
15              
16 8     8   76 use strict;
  8         33  
  8         323  
17 8     8   73 use vars qw($VERSION);
  8         29  
  8         385  
18 8     8   52 use Image::ExifTool qw(:DataAccess :Utils);
  8         31  
  8         1849  
19 8     8   63 use Image::ExifTool::Exif;
  8         32  
  8         21030  
20              
21             $VERSION = '1.14';
22              
23             sub ProcessNikonCapture($$$);
24              
25             # common print conversions
26             my %offOn = ( 0 => 'Off', 1 => 'On' );
27             my %noYes = ( 0 => 'No', 1 => 'Yes' );
28             my %unsharpColor = (
29             0 => 'RGB',
30             1 => 'Red',
31             2 => 'Green',
32             3 => 'Blue',
33             4 => 'Yellow',
34             5 => 'Magenta',
35             6 => 'Cyan',
36             );
37              
38             # Nikon Capture data (ref PH)
39             %Image::ExifTool::NikonCapture::Main = (
40             PROCESS_PROC => \&ProcessNikonCapture,
41             WRITE_PROC => \&WriteNikonCapture,
42             CHECK_PROC => \&Image::ExifTool::Exif::CheckExif,
43             GROUPS => { 0 => 'MakerNotes', 2 => 'Image' },
44             NOTES => q{
45             This information is written by the Nikon Capture software in tag 0x0e01 of
46             the maker notes of NEF images.
47             },
48             # 0x007ddc9d contains contrast information
49             0x008ae85e => {
50             Name => 'LCHEditor',
51             Writable => 'int8u',
52             PrintConv => \%offOn,
53             },
54             0x0c89224b => {
55             Name => 'ColorAberrationControl',
56             Writable => 'int8u',
57             PrintConv => \%offOn,
58             },
59             0x116fea21 => {
60             Name => 'HighlightData',
61             SubDirectory => {
62             TagTable => 'Image::ExifTool::NikonCapture::HighlightData',
63             },
64             },
65             0x2175eb78 => {
66             Name => 'D-LightingHQ',
67             Writable => 'int8u',
68             PrintConv => \%offOn,
69             },
70             0x2fc08431 => {
71             Name => 'StraightenAngle',
72             Writable => 'double',
73             },
74             0x374233e0 => {
75             Name => 'CropData',
76             SubDirectory => {
77             TagTable => 'Image::ExifTool::NikonCapture::CropData',
78             },
79             },
80             0x39c456ac => {
81             Name => 'PictureCtrl',
82             SubDirectory => {
83             TagTable => 'Image::ExifTool::NikonCapture::PictureCtrl',
84             },
85             },
86             0x3cfc73c6 => {
87             Name => 'RedEyeData',
88             SubDirectory => {
89             TagTable => 'Image::ExifTool::NikonCapture::RedEyeData',
90             },
91             },
92             0x3d136244 => {
93             Name => 'EditVersionName',
94             Writable => 'string', # (null terminated)
95             },
96             # 0x3e726567 added when I rotated by 90 degrees
97             0x416391c6 => {
98             Name => 'QuickFix',
99             Writable => 'int8u',
100             PrintConv => \%offOn,
101             },
102             0x56a54260 => {
103             Name => 'Exposure',
104             SubDirectory => {
105             TagTable => 'Image::ExifTool::NikonCapture::Exposure',
106             },
107             },
108             0x5f0e7d23 => {
109             Name => 'ColorBooster',
110             Writable => 'int8u',
111             PrintConv => \%offOn,
112             },
113             0x6a6e36b6 => {
114             Name => 'D-LightingHQSelected',
115             Writable => 'int8u',
116             PrintConv => \%noYes,
117             },
118             0x753dcbc0 => {
119             Name => 'NoiseReduction',
120             Writable => 'int8u',
121             PrintConv => \%offOn,
122             },
123             0x76a43200 => {
124             Name => 'UnsharpMask',
125             Writable => 'int8u',
126             PrintConv => \%offOn,
127             },
128             0x76a43201 => {
129             Name => 'Curves',
130             Writable => 'int8u',
131             PrintConv => \%offOn,
132             },
133             0x76a43202 => {
134             Name => 'ColorBalanceAdj',
135             Writable => 'int8u',
136             PrintConv => \%offOn,
137             },
138             0x76a43203 => {
139             Name => 'AdvancedRaw',
140             Writable => 'int8u',
141             PrintConv => \%offOn,
142             },
143             0x76a43204 => {
144             Name => 'WhiteBalanceAdj',
145             Writable => 'int8u',
146             PrintConv => \%offOn,
147             },
148             0x76a43205 => {
149             Name => 'VignetteControl',
150             Writable => 'int8u',
151             PrintConv => \%offOn,
152             },
153             0x76a43206 => {
154             Name => 'FlipHorizontal',
155             Writable => 'int8u',
156             PrintConv => \%noYes,
157             },
158             0x76a43207 => { # rotation angle in degrees
159             Name => 'Rotation',
160             Writable => 'int16u',
161             },
162             0x083a1a25 => {
163             Name => 'HistogramXML',
164             Writable => 'undef',
165             Binary => 1,
166             AdjustSize => 4, # patch Nikon bug
167             },
168             0x84589434 => {
169             Name => 'BrightnessData',
170             SubDirectory => {
171             TagTable => 'Image::ExifTool::NikonCapture::Brightness',
172             },
173             },
174             # 0x88f55e48 - related to QuickFix
175             0x890ff591 => {
176             Name => 'D-LightingHQData',
177             SubDirectory => {
178             TagTable => 'Image::ExifTool::NikonCapture::DLightingHQ',
179             },
180             },
181             0x926f13e0 => {
182             Name => 'NoiseReductionData',
183             SubDirectory => {
184             TagTable => 'Image::ExifTool::NikonCapture::NoiseReduction',
185             },
186             },
187             0x9ef5f6e0 => {
188             Name => 'IPTCData',
189             SubDirectory => {
190             TagTable => 'Image::ExifTool::IPTC::Main',
191             },
192             },
193             # 0xa7264a72 - related to QuickFix
194             0xab5eca5e => {
195             Name => 'PhotoEffects',
196             Writable => 'int8u',
197             PrintConv => \%offOn,
198             },
199             0xac6bd5c0 => {
200             Name => 'VignetteControlIntensity',
201             Writable => 'int16s',
202             },
203             0xb0384e1e => {
204             Name => 'PhotoEffectsData',
205             SubDirectory => {
206             TagTable => 'Image::ExifTool::NikonCapture::PhotoEffects',
207             },
208             },
209             0xb999a36f => {
210             Name => 'ColorBoostData',
211             SubDirectory => {
212             TagTable => 'Image::ExifTool::NikonCapture::ColorBoost',
213             },
214             },
215             0xbf3c6c20 => {
216             Name => 'WBAdjData',
217             SubDirectory => {
218             TagTable => 'Image::ExifTool::NikonCapture::WBAdjData',
219             },
220             },
221             0xce5554aa => {
222             Name => 'D-LightingHS',
223             Writable => 'int8u',
224             PrintConv => \%offOn,
225             },
226             0xe2173c47 => {
227             Name => 'PictureControl',
228             Writable => 'int8u',
229             PrintConv => \%offOn,
230             },
231             0xe37b4337 => {
232             Name => 'D-LightingHSData',
233             SubDirectory => {
234             TagTable => 'Image::ExifTool::NikonCapture::DLightingHS',
235             },
236             },
237             0xe42b5161 => {
238             Name => 'UnsharpData',
239             SubDirectory => {
240             TagTable => 'Image::ExifTool::NikonCapture::UnsharpData',
241             },
242             },
243             0xe9651831 => {
244             Name => 'PhotoEffectHistoryXML',
245             Binary => 1,
246             Writable => 'undef',
247             },
248             0xfe28a44f => {
249             Name => 'AutoRedEye',
250             Writable => 'int8u',
251             PrintConv => \%offOn, # (have seen a value of 28 here for older software?)
252             },
253             0xfe443a45 => {
254             Name => 'ImageDustOff',
255             Writable => 'int8u',
256             PrintConv => \%offOn,
257             },
258             );
259              
260             %Image::ExifTool::NikonCapture::UnsharpData = (
261             PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
262             WRITE_PROC => \&Image::ExifTool::WriteBinaryData,
263             CHECK_PROC => \&Image::ExifTool::CheckBinaryData,
264             WRITABLE => 1,
265             FORMAT => 'int8u',
266             FIRST_ENTRY => 0,
267             GROUPS => { 0 => 'MakerNotes', 2 => 'Image' },
268             0 => 'UnsharpCount',
269             19 => { Name => 'Unsharp1Color', Format => 'int16u', PrintConv => \%unsharpColor },
270             23 => { Name => 'Unsharp1Intensity', Format => 'int16u' },
271             25 => { Name => 'Unsharp1HaloWidth', Format => 'int16u' },
272             27 => 'Unsharp1Threshold',
273             46 => { Name => 'Unsharp2Color', Format => 'int16u', PrintConv => \%unsharpColor },
274             50 => { Name => 'Unsharp2Intensity', Format => 'int16u' },
275             52 => { Name => 'Unsharp2HaloWidth', Format => 'int16u' },
276             54 => 'Unsharp2Threshold',
277             73 => { Name => 'Unsharp3Color', Format => 'int16u', PrintConv => \%unsharpColor },
278             77 => { Name => 'Unsharp3Intensity', Format => 'int16u' },
279             79 => { Name => 'Unsharp3HaloWidth', Format => 'int16u' },
280             81 => 'Unsharp3Threshold',
281             100 => { Name => 'Unsharp4Color', Format => 'int16u', PrintConv => \%unsharpColor },
282             104 => { Name => 'Unsharp4Intensity', Format => 'int16u' },
283             106 => { Name => 'Unsharp4HaloWidth', Format => 'int16u' },
284             108 => 'Unsharp4Threshold',
285             # there could be more, but I grow bored of this... :P
286             );
287              
288             %Image::ExifTool::NikonCapture::DLightingHS = (
289             PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
290             WRITE_PROC => \&Image::ExifTool::WriteBinaryData,
291             CHECK_PROC => \&Image::ExifTool::CheckBinaryData,
292             WRITABLE => 1,
293             FORMAT => 'int32u',
294             FIRST_ENTRY => 0,
295             GROUPS => { 0 => 'MakerNotes', 2 => 'Image' },
296             0 => 'D-LightingHSAdjustment',
297             1 => 'D-LightingHSColorBoost',
298             );
299              
300             %Image::ExifTool::NikonCapture::DLightingHQ = (
301             PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
302             WRITE_PROC => \&Image::ExifTool::WriteBinaryData,
303             CHECK_PROC => \&Image::ExifTool::CheckBinaryData,
304             WRITABLE => 1,
305             FORMAT => 'int32u',
306             FIRST_ENTRY => 0,
307             GROUPS => { 0 => 'MakerNotes', 2 => 'Image' },
308             0 => 'D-LightingHQShadow',
309             1 => 'D-LightingHQHighlight',
310             2 => 'D-LightingHQColorBoost',
311             );
312              
313             %Image::ExifTool::NikonCapture::ColorBoost = (
314             PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
315             WRITE_PROC => \&Image::ExifTool::WriteBinaryData,
316             CHECK_PROC => \&Image::ExifTool::CheckBinaryData,
317             WRITABLE => 1,
318             FORMAT => 'int8u',
319             FIRST_ENTRY => 0,
320             GROUPS => { 0 => 'MakerNotes', 2 => 'Image' },
321             0 => {
322             Name => 'ColorBoostType',
323             PrintConv => {
324             0 => 'Nature',
325             1 => 'People',
326             },
327             },
328             1 => {
329             Name => 'ColorBoostLevel',
330             Format => 'int32u',
331             },
332             );
333              
334             %Image::ExifTool::NikonCapture::WBAdjData = (
335             PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
336             WRITE_PROC => \&Image::ExifTool::WriteBinaryData,
337             CHECK_PROC => \&Image::ExifTool::CheckBinaryData,
338             WRITABLE => 1,
339             FORMAT => 'int8u',
340             FIRST_ENTRY => 0,
341             GROUPS => { 0 => 'MakerNotes', 2 => 'Image' },
342             0x00 => {
343             Name => 'WBAdjRedBalance',
344             Format => 'double',
345             },
346             0x08 => {
347             Name => 'WBAdjBlueBalance',
348             Format => 'double',
349             },
350             0x10 => {
351             Name => 'WBAdjMode',
352             PrintConv => {
353             1 => 'Use Gray Point',
354             2 => 'Recorded Value',
355             3 => 'Use Temperature',
356             4 => 'Calculate Automatically',
357             5 => 'Auto2', #IB
358             6 => 'Underwater', #IB
359             7 => 'Auto1',
360             },
361             },
362             0x14 => { #IB
363             Name => 'WBAdjLighting',
364             Format => 'int16u',
365             PrintHex => 1,
366             PrintConv => {
367             0x000 => 'None',
368             0x100 => 'Incandescent',
369             0x200 => 'Daylight (direct sunlight)',
370             0x201 => 'Daylight (shade)',
371             0x202 => 'Daylight (cloudy)',
372             0x300 => 'Standard Fluorescent (warm white)',
373             0x301 => 'Standard Fluorescent (3700K)',
374             0x302 => 'Standard Fluorescent (cool white)',
375             0x303 => 'Standard Fluorescent (5000K)',
376             0x304 => 'Standard Fluorescent (daylight)',
377             0x305 => 'Standard Fluorescent (high temperature mercury vapor)',
378             0x400 => 'High Color Rendering Fluorescent (warm white)',
379             0x401 => 'High Color Rendering Fluorescent (3700K)',
380             0x402 => 'High Color Rendering Fluorescent (cool white)',
381             0x403 => 'High Color Rendering Fluorescent (5000K)',
382             0x404 => 'High Color Rendering Fluorescent (daylight)',
383             0x500 => 'Flash',
384             0x501 => 'Flash (FL-G1 filter)',
385             0x502 => 'Flash (FL-G2 filter)',
386             0x503 => 'Flash (TN-A1 filter)',
387             0x504 => 'Flash (TN-A2 filter)',
388             0x600 => 'Sodium Vapor Lamps',
389             # 0x1002 => seen for WBAdjMode modes of Underwater and Calculate Automatically
390             },
391             },
392             0x18 => {
393             Name => 'WBAdjTemperature',
394             Format => 'int16u',
395             },
396             0x25 => {
397             Name => 'WBAdjTint',
398             Format => 'int32s',
399             },
400             );
401              
402             %Image::ExifTool::NikonCapture::PhotoEffects = (
403             PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
404             WRITE_PROC => \&Image::ExifTool::WriteBinaryData,
405             CHECK_PROC => \&Image::ExifTool::CheckBinaryData,
406             WRITABLE => 1,
407             FORMAT => 'int8u',
408             FIRST_ENTRY => 0,
409             GROUPS => { 0 => 'MakerNotes', 2 => 'Image' },
410             0 => {
411             Name => 'PhotoEffectsType',
412             PrintConv => {
413             0 => 'None',
414             1 => 'B&W',
415             2 => 'Sepia',
416             3 => 'Tinted',
417             },
418             },
419             4 => {
420             Name => 'PhotoEffectsRed',
421             Format => 'int16s',
422             },
423             6 => {
424             Name => 'PhotoEffectsGreen',
425             Format => 'int16s',
426             },
427             8 => {
428             Name => 'PhotoEffectsBlue',
429             Format => 'int16s',
430             },
431             );
432              
433             %Image::ExifTool::NikonCapture::Brightness = (
434             PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
435             WRITE_PROC => \&Image::ExifTool::WriteBinaryData,
436             CHECK_PROC => \&Image::ExifTool::CheckBinaryData,
437             WRITABLE => 1,
438             FORMAT => 'int8u',
439             FIRST_ENTRY => 0,
440             GROUPS => { 0 => 'MakerNotes', 2 => 'Image' },
441             0 => {
442             Name => 'BrightnessAdj',
443             Format => 'double',
444             ValueConv => '$val * 50',
445             ValueConvInv => '$val / 50',
446             },
447             8 => {
448             Name => 'EnhanceDarkTones',
449             PrintConv => \%offOn,
450             },
451             );
452              
453             %Image::ExifTool::NikonCapture::NoiseReduction = (
454             PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
455             WRITE_PROC => \&Image::ExifTool::WriteBinaryData,
456             CHECK_PROC => \&Image::ExifTool::CheckBinaryData,
457             WRITABLE => 1,
458             FORMAT => 'int8u',
459             FIRST_ENTRY => 0,
460             GROUPS => { 0 => 'MakerNotes', 2 => 'Image' },
461             0x04 => {
462             Name => 'EdgeNoiseReduction',
463             PrintConv => \%offOn,
464             },
465             0x05 => {
466             Name => 'ColorMoireReductionMode',
467             PrintConv => {
468             0 => 'Off',
469             1 => 'Low',
470             2 => 'Medium',
471             3 => 'High',
472             },
473             },
474             0x09 => {
475             Name => 'NoiseReductionIntensity',
476             Format => 'int32u',
477             },
478             0x0d => {
479             Name => 'NoiseReductionSharpness',
480             Format => 'int32u',
481             },
482             0x11 => {
483             Name => 'NoiseReductionMethod',
484             Format => 'int16u',
485             PrintConv => {
486             0 => 'Faster',
487             1 => 'Better Quality',
488             2 => 'Better Quality 2013',
489             },
490             },
491             0x15 => {
492             Name => 'ColorMoireReduction',
493             PrintConv => \%offOn,
494             },
495             0x17 => {
496             Name => 'NoiseReduction',
497             PrintConv => \%offOn,
498             },
499             0x18 => {
500             Name => 'ColorNoiseReductionIntensity',
501             Format => 'int32u',
502             },
503             0x1c => {
504             Name => 'ColorNoiseReductionSharpness',
505             Format => 'int32u',
506             },
507             );
508              
509             %Image::ExifTool::NikonCapture::CropData = (
510             PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
511             WRITE_PROC => \&Image::ExifTool::WriteBinaryData,
512             CHECK_PROC => \&Image::ExifTool::CheckBinaryData,
513             WRITABLE => 1,
514             FORMAT => 'int8u',
515             FIRST_ENTRY => 0,
516             GROUPS => { 0 => 'MakerNotes', 2 => 'Image' },
517             0x1e => {
518             Name => 'CropLeft',
519             Format => 'double',
520             ValueConv => '$val / 2',
521             ValueConvInv => '$val * 2',
522             },
523             0x26 => {
524             Name => 'CropTop',
525             Format => 'double',
526             ValueConv => '$val / 2',
527             ValueConvInv => '$val * 2',
528             },
529             0x2e => {
530             Name => 'CropRight',
531             Format => 'double',
532             ValueConv => '$val / 2',
533             ValueConvInv => '$val * 2',
534             },
535             0x36 => {
536             Name => 'CropBottom',
537             Format => 'double',
538             ValueConv => '$val / 2',
539             ValueConvInv => '$val * 2',
540             },
541             0x8e => {
542             Name => 'CropOutputWidthInches',
543             Format => 'double',
544             },
545             0x96 => {
546             Name => 'CropOutputHeightInches',
547             Format => 'double',
548             },
549             0x9e => {
550             Name => 'CropScaledResolution',
551             Format => 'double',
552             },
553             0xae => {
554             Name => 'CropSourceResolution',
555             Format => 'double',
556             ValueConv => '$val / 2',
557             ValueConvInv => '$val * 2',
558             },
559             0xb6 => {
560             Name => 'CropOutputResolution',
561             Format => 'double',
562             },
563             0xbe => {
564             Name => 'CropOutputScale',
565             Format => 'double',
566             },
567             0xc6 => {
568             Name => 'CropOutputWidth',
569             Format => 'double',
570             },
571             0xce => {
572             Name => 'CropOutputHeight',
573             Format => 'double',
574             },
575             0xd6 => {
576             Name => 'CropOutputPixels',
577             Format => 'double',
578             },
579             );
580              
581             %Image::ExifTool::NikonCapture::PictureCtrl = (
582             PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
583             WRITE_PROC => \&Image::ExifTool::WriteBinaryData,
584             CHECK_PROC => \&Image::ExifTool::CheckBinaryData,
585             WRITABLE => 1,
586             FORMAT => 'int8u',
587             FIRST_ENTRY => 0,
588             GROUPS => { 0 => 'MakerNotes', 2 => 'Image' },
589             0x00 => {
590             Name => 'PictureControlActive',
591             PrintConv => \%offOn,
592             },
593             0x13 => {
594             Name => 'PictureControlMode',
595             Format => 'string[16]',
596             },
597             # 0x29 changes with Hue and Sharpening
598             0x2a => {
599             Name => 'QuickAdjust',
600             ValueConv => '$val - 128',
601             ValueConvInv => '$val + 128',
602             },
603             0x2b => {
604             Name => 'SharpeningAdj',
605             ValueConv => '$val ? $val - 128 : "Auto"',
606             ValueConvInv => '$val=~/\d/ ? $val + 128 : 0',
607             },
608             0x2c => {
609             Name => 'ContrastAdj',
610             ValueConv => '$val ? $val - 128 : "Auto"',
611             ValueConvInv => '$val=~/\d/ ? $val + 128 : 0',
612             },
613             0x2d => {
614             Name => 'BrightnessAdj',
615             ValueConv => '$val ? $val - 128 : "Auto"', # no "Auto" mode (yet) for this setting
616             ValueConvInv => '$val=~/\d/ ? $val + 128 : 0',
617             },
618             0x2e => {
619             Name => 'SaturationAdj',
620             ValueConv => '$val ? $val - 128 : "Auto"',
621             ValueConvInv => '$val=~/\d/ ? $val + 128 : 0',
622             },
623             0x2f => {
624             Name => 'HueAdj',
625             ValueConv => '$val - 128',
626             ValueConvInv => '$val + 128',
627             },
628             # 0x37 changed from 0 to 2 when Picture Control is enabled (and no active DLighting)
629             );
630              
631             %Image::ExifTool::NikonCapture::RedEyeData = (
632             PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
633             WRITE_PROC => \&Image::ExifTool::WriteBinaryData,
634             CHECK_PROC => \&Image::ExifTool::CheckBinaryData,
635             WRITABLE => 1,
636             FORMAT => 'int8u',
637             FIRST_ENTRY => 0,
638             GROUPS => { 0 => 'MakerNotes', 2 => 'Image' },
639             0 => {
640             Name => 'RedEyeCorrection',
641             PrintConv => {
642             0 => 'Off',
643             1 => 'Automatic',
644             2 => 'Click on Eyes',
645             },
646             },
647             );
648              
649             %Image::ExifTool::NikonCapture::Exposure = (
650             PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
651             WRITE_PROC => \&Image::ExifTool::WriteBinaryData,
652             CHECK_PROC => \&Image::ExifTool::CheckBinaryData,
653             WRITABLE => 1,
654             FORMAT => 'int8u',
655             FIRST_ENTRY => 0,
656             GROUPS => { 0 => 'MakerNotes', 2 => 'Image' },
657             0x00 => {
658             Name => 'ExposureAdj',
659             Format => 'int16s',
660             ValueConv => '$val / 100',
661             ValueConvInv => '$val * 100',
662             },
663             0x12 => {
664             Name => 'ExposureAdj2',
665             Format => 'double',
666             PrintConv => 'sprintf("%.4f", $val)',
667             PrintConvInv => '$val',
668             },
669             0x24 => {
670             Name => 'ActiveD-Lighting',
671             PrintConv => \%offOn,
672             },
673             0x25 => {
674             Name => 'ActiveD-LightingMode',
675             PrintConv => {
676             0 => 'Unchanged',
677             1 => 'Off',
678             2 => 'Low',
679             3 => 'Normal',
680             4 => 'High',
681             6 => 'Extra High',
682             7 => 'Extra High 1',
683             8 => 'Extra High 2',
684             },
685             },
686             );
687              
688             %Image::ExifTool::NikonCapture::HighlightData = (
689             PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
690             WRITE_PROC => \&Image::ExifTool::WriteBinaryData,
691             CHECK_PROC => \&Image::ExifTool::CheckBinaryData,
692             WRITABLE => 1,
693             FORMAT => 'int8s',
694             FIRST_ENTRY => 0,
695             GROUPS => { 0 => 'MakerNotes', 2 => 'Image' },
696             0 => 'ShadowProtection',
697             1 => 'SaturationAdj',
698             6 => 'HighlightProtection',
699             );
700              
701             #------------------------------------------------------------------------------
702             # write Nikon Capture data (ref 1)
703             # Inputs: 0) ExifTool object reference, 1) reference to directory information
704             # 2) pointer to tag table
705             # Returns: 1 on success
706             sub WriteNikonCapture($$$)
707             {
708 43     43 0 178 my ($et, $dirInfo, $tagTablePtr) = @_;
709 43 100       236 $et or return 1; # allow dummy access to autoload this package
710              
711             # no need to edit this information unless necessary
712 1 0 33     22 unless ($$et{EDIT_DIRS}{MakerNotes} or $$et{EDIT_DIRS}{IPTC}) {
713 0         0 return undef;
714             }
715 1         6 my $dataPt = $$dirInfo{DataPt};
716 1         3 my $dirStart = $$dirInfo{DirStart};
717 1         2 my $dirLen = $$dirInfo{DirLen};
718 1 50       7 if ($dirLen < 22) {
719 0         0 $et->Warn('Short Nikon Capture Data',1);
720 0         0 return undef;
721             }
722             # make sure the capture data is properly contained
723 1         6 SetByteOrder('II');
724 1         19 my $tagID = Get32u($dataPt, $dirStart);
725             # sometimes size includes 18 header bytes, and other times it doesn't (eg. ViewNX 2.1.1)
726 1         8 my $size = Get32u($dataPt, $dirStart + 18);
727 1         4 my $pad = $dirLen - $size - 18;
728 1 50 33     10 unless ($tagID == 0x7a86a940 and ($pad >= 0 or $pad == -18)) {
      33        
729 0         0 $et->Warn('Unrecognized Nikon Capture Data header');
730 0         0 return undef;
731             }
732             # determine if there is any data after this block
733 1 50       6 if ($pad > 0) {
734 0         0 $pad = substr($$dataPt, $dirStart + 18 + $size, $pad);
735 0         0 $dirLen = $size + 18;
736             } else {
737 1         3 $pad = '';
738             }
739 1         3 my $outBuff = '';
740 1         3 my $pos;
741 1         7 my $newTags = $et->GetNewTagInfoHash($tagTablePtr);
742 1         4 my $dirEnd = $dirStart + $dirLen;
743              
744             # loop through all entries in the Nikon Capture data
745 1         7 for ($pos=$dirStart+22; $pos+22<$dirEnd; $pos+=22+$size) {
746 50         115 $tagID = Get32u($dataPt, $pos);
747 50         119 $size = Get32u($dataPt, $pos + 18) - 4;
748 50 50 33     210 last if $size < 0 or $pos + 22 + $size > $dirEnd;
749 50         132 my $tagInfo = $et->GetTagInfo($tagTablePtr, $tagID);
750 50 100       109 if ($tagInfo) {
751 32         46 my $newVal;
752 32 100       101 if ($$tagInfo{SubDirectory}) {
    100          
753             # rewrite the subdirectory
754 12         42 my %subdirInfo = (
755             DataPt => $dataPt,
756             DirStart => $pos + 22,
757             DirLen => $size,
758             );
759 12         42 my $subTable = GetTagTable($tagInfo->{SubDirectory}->{TagTable});
760             # ignore minor errors in IPTC since there is typically trailing garbage
761 12         37 my $oldSetting = $et->Options('IgnoreMinorErrors');
762 12 100       91 $$tagInfo{Name} =~ /IPTC/ and $et->Options(IgnoreMinorErrors => 1);
763             # rewrite the directory
764 12         46 $newVal = $et->WriteDirectory(\%subdirInfo, $subTable);
765             # restore our original options
766 12         45 $et->Options(IgnoreMinorErrors => $oldSetting);
767             } elsif ($$newTags{$tagID}) {
768             # get new value for this tag if we are writing it
769 2   33     16 my $format = $$tagInfo{Format} || $$tagInfo{Writable};
770 2         10 my $oldVal = ReadValue($dataPt,$pos+22,$format,1,$size);
771 2         9 my $nvHash = $et->GetNewValueHash($tagInfo);
772 2 50       13 if ($et->IsOverwriting($nvHash, $oldVal)) {
773 2         8 my $val = $et->GetNewValue($tagInfo);
774 2 50       14 $newVal = WriteValue($val, $$tagInfo{Writable}) if defined $val;
775 2 50 33     12 if (defined $newVal and length $newVal) {
776 2         17 ++$$et{CHANGED};
777             } else {
778 0         0 undef $newVal;
779 0         0 $et->Warn("Can't delete $$tagInfo{Name}");
780             }
781             }
782             }
783 32 100       73 if (defined $newVal) {
784 14 50       34 next unless length $newVal; # don't write zero length information
785             # write the new value
786 14         35 $outBuff .= substr($$dataPt, $pos, 18);
787 14         40 $outBuff .= Set32u(length($newVal) + 4);
788 14         26 $outBuff .= $newVal;
789 14         47 next;
790             }
791             }
792             # rewrite the existing information
793 36         146 $outBuff .= substr($$dataPt, $pos, 22 + $size);
794             }
795 1 50       4 unless ($pos == $dirEnd) {
796 0 0       0 if ($pos == $dirEnd - 4) {
797             # it seems that sometimes (NX2) the main block size is wrong by 4 bytes
798             # (did they forget to include the size word?)
799 0         0 $outBuff .= substr($$dataPt, $pos, 4);
800             } else {
801 0         0 $et->Warn('Nikon Capture Data improperly terminated',1);
802 0         0 return undef;
803             }
804             }
805             # add the header and return the new directory
806 1         6 return substr($$dataPt, $dirStart, 18) .
807             Set32u(length($outBuff) + 4) .
808             $outBuff . $pad;
809             }
810              
811             #------------------------------------------------------------------------------
812             # process Nikon Capture data (ref 1)
813             # Inputs: 0) ExifTool object ref, 1) dirInfo ref, 2) tag table ref
814             # Returns: 1 on success
815             sub ProcessNikonCaptureEditVersions($$$)
816             {
817 0     0 0 0 my ($et, $dirInfo, $tagTablePtr) = @_;
818 0         0 my $dataPt = $$dirInfo{DataPt};
819 0         0 my $dirStart = $$dirInfo{DirStart};
820 0         0 my $dirLen = $$dirInfo{DirLen};
821 0         0 my $dirEnd = $dirStart + $dirLen;
822 0         0 my $verbose = $et->Options('Verbose');
823 0         0 SetByteOrder('II');
824 0 0       0 return 0 unless $dirLen > 4;
825 0         0 my $num = Get32u($dataPt, $dirStart);
826 0         0 my $pos = $dirStart + 4;
827 0 0       0 $verbose and $et->VerboseDir('NikonCaptureEditVersions', $num);
828 0         0 while ($num) {
829 0 0       0 last if $pos + 4 > $dirEnd;
830 0         0 my $len = Get32u($dataPt, $pos);
831 0 0       0 last if $pos + $len + 4 > $dirEnd;
832 0         0 my %dirInfo = (
833             DirName => 'NikonCapture',
834             Parent => 'NikonCaptureEditVersions',
835             DataPt => $dataPt,
836             DirStart => $pos + 4,
837             DirLen => $len,
838             );
839 0         0 $$et{DOC_NUM} = ++$$et{DOC_COUNT};
840 0         0 $et->ProcessDirectory(\%dirInfo, $tagTablePtr);
841 0         0 --$num;
842 0         0 $pos += $len + 4;
843             }
844 0         0 delete $$et{DOC_NUM};
845 0         0 return 1;
846             }
847              
848             #------------------------------------------------------------------------------
849             # process Nikon Capture data (ref 1)
850             # Inputs: 0) ExifTool object ref, 1) dirInfo ref, 2) tag table ref
851             # Returns: 1 on success
852             sub ProcessNikonCapture($$$)
853             {
854 2     2 0 10 my ($et, $dirInfo, $tagTablePtr) = @_;
855 2         8 my $dataPt = $$dirInfo{DataPt};
856 2         6 my $dirStart = $$dirInfo{DirStart};
857 2         5 my $dirLen = $$dirInfo{DirLen};
858 2         5 my $dirEnd = $dirStart + $dirLen;
859 2         13 my $verbose = $et->Options('Verbose');
860 2         5 my $success = 0;
861 2         12 SetByteOrder('II');
862 2 50       14 $verbose and $et->VerboseDir('NikonCapture', 0, $dirLen);
863 2         5 my $pos;
864 2         16 for ($pos=$dirStart+22; $pos+22<$dirEnd; ) {
865 100         249 my $tagID = Get32u($dataPt, $pos);
866 100         233 my $size = Get32u($dataPt, $pos + 18) - 4;
867 100         178 $pos += 22;
868 100 50 33     369 last if $size < 0 or $pos + $size > $dirEnd;
869 100         264 my $tagInfo = $et->GetTagInfo($tagTablePtr, $tagID);
870 100 100 66     301 if ($tagInfo or $verbose) {
871 64         101 my ($format, $value);
872             # (note that Writable will be 0 for Unknown tags)
873 64 50 66     315 $tagInfo and $format = ($$tagInfo{Format} || $$tagInfo{Writable});
874             # generate a reasonable default format type for short values
875 64 50 33     271 if (not $format and ($size == 1 or $size == 2 or $size == 4)) {
      66        
876 0         0 $format = 'int' . ($size * 8) . 'u';
877             }
878 64 100       182 if ($format) {
    50          
879 40         56 my $count = 1;
880 40 50 33     152 if ($format eq 'string' or $format eq 'undef') {
881             # patch Nikon bug in size of some values (HistogramXML)
882 0 0 0     0 $size += $$tagInfo{AdjustSize} if $tagInfo and $$tagInfo{AdjustSize};
883 0         0 $count = $size;
884             }
885 40         115 $value = ReadValue($dataPt,$pos,$format,$count,$size);
886             } elsif ($size == 1) {
887 0         0 $value = substr($$dataPt, $pos, $size);
888             }
889             $et->HandleTag($tagTablePtr, $tagID, $value,
890             DataPt => $dataPt,
891             DataPos => $$dirInfo{DataPos},
892             Base => $$dirInfo{Base},
893 64 100       252 Start => $pos,
894             Size => $size,
895             ) and $success = 1;
896             }
897 100         271 $pos += $size;
898             }
899 2         16 return $success;
900             }
901              
902             1; # end
903              
904             __END__