File Coverage

blib/lib/Image/ExifTool/DJI.pm
Criterion Covered Total %
statement 18 39 46.1
branch 0 8 0.0
condition 0 11 0.0
subroutine 6 7 85.7
pod 0 1 0.0
total 24 66 36.3


line stmt bran cond sub pod time code
1             #------------------------------------------------------------------------------
2             # File: DJI.pm
3             #
4             # Description: DJI Phantom maker notes tags
5             #
6             # Revisions: 2016-07-25 - P. Harvey Created
7             # 2017-06-23 - PH Added XMP tags
8             #------------------------------------------------------------------------------
9              
10             package Image::ExifTool::DJI;
11              
12 10     10   120 use strict;
  10         32  
  10         408  
13 10     10   89 use vars qw($VERSION);
  10         53  
  10         546  
14 10     10   84 use Image::ExifTool qw(:DataAccess :Utils);
  10         29  
  10         2433  
15 10     10   83 use Image::ExifTool::Exif;
  10         23  
  10         283  
16 10     10   2357 use Image::ExifTool::XMP;
  10         151  
  10         511  
17 10     10   71 use Image::ExifTool::GPS;
  10         48  
  10         10270  
18              
19             $VERSION = '1.08';
20              
21             sub ProcessDJIInfo($$$);
22              
23             my %convFloat2 = (
24             PrintConv => 'sprintf("%+.2f", $val)',
25             PrintConvInv => '$val',
26             );
27              
28             # DJI maker notes (ref PH, mostly educated guesses based on DJI QuickTime::UserData tags)
29             %Image::ExifTool::DJI::Main = (
30             WRITE_PROC => \&Image::ExifTool::Exif::WriteExif,
31             CHECK_PROC => \&Image::ExifTool::Exif::CheckExif,
32             GROUPS => { 0 => 'MakerNotes', 2 => 'Camera' },
33             NOTES => q{
34             This table lists tags found in the maker notes of images from some DJI
35             Phantom drones.
36             },
37             0x01 => { Name => 'Make', Writable => 'string' },
38             # 0x02 - int8u[4]: "1 0 0 0", "1 1 0 0"
39             0x03 => { Name => 'SpeedX', Writable => 'float', %convFloat2 }, # (guess)
40             0x04 => { Name => 'SpeedY', Writable => 'float', %convFloat2 }, # (guess)
41             0x05 => { Name => 'SpeedZ', Writable => 'float', %convFloat2 }, # (guess)
42             0x06 => { Name => 'Pitch', Writable => 'float', %convFloat2 },
43             0x07 => { Name => 'Yaw', Writable => 'float', %convFloat2 },
44             0x08 => { Name => 'Roll', Writable => 'float', %convFloat2 },
45             0x09 => { Name => 'CameraPitch',Writable => 'float', %convFloat2 },
46             0x0a => { Name => 'CameraYaw', Writable => 'float', %convFloat2 },
47             0x0b => { Name => 'CameraRoll', Writable => 'float', %convFloat2 },
48             );
49              
50             # DJI debug maker notes
51             %Image::ExifTool::DJI::Info = (
52             PROCESS_PROC => \&ProcessDJIInfo,
53             GROUPS => { 0 => 'MakerNotes', 2 => 'Camera' },
54             NOTES => 'Tags written by some DJI drones.',
55             VARS => { LONG_TAGS => 2 },
56             ae_dbg_info => { Name => 'AEDebugInfo' },
57             ae_histogram_info => { Name => 'AEHistogramInfo' },
58             ae_local_histogram => { Name => 'AELocalHistogram' },
59             ae_liveview_histogram_info => { Name => 'AELiveViewHistogramInfo' },
60             ae_liveview_local_histogram => { Name => 'AELiveViewLocalHistogram' },
61             awb_dbg_info => { Name => 'AWBDebugInfo' },
62             af_dbg_info => { Name => 'AFDebugInfo' },
63             hiso => { Name => 'Histogram' },
64             xidiri => { Name => 'Xidiri' },
65             'GimbalDegree(Y,P,R)'=> { Name => 'GimbalDegree' },
66             'FlightDegree(Y,P,R)'=> { Name => 'FlightDegree' },
67             adj_dbg_info => { Name => 'ADJDebugInfo' },
68             sensor_id => { Name => 'SensorID' },
69             'FlightSpeed(X,Y,Z)' => { Name => 'FlightSpeed' },
70             hyperlapse_dbg_info => { Name => 'HyperlapsDebugInfo' },
71             );
72              
73             # thermal parameters in APP4 of DJI ZH20T images (ref forum11401)
74             %Image::ExifTool::DJI::ThermalParams = (
75             PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
76             GROUPS => { 0 => 'APP4', 2 => 'Image' },
77             NOTES => 'Thermal parameters extracted from APP4 of DJI RJPEG files from the ZH20T.',
78             # 0x00 - 0xaa551206 - temperature header magic number
79             0x24 => { Name => 'K1', Format => 'float' },
80             0x28 => { Name => 'K2', Format => 'float' },
81             0x2c => { Name => 'K3', Format => 'float' },
82             0x30 => { Name => 'K4', Format => 'float' },
83             0x34 => { Name => 'KF', Format => 'float' },
84             0x38 => { Name => 'B1', Format => 'float' },
85             0x3c => { Name => 'B2', Format => 'float' },
86             0x44 => { Name => 'ObjectDistance', Format => 'int16u' },
87             0x46 => { Name => 'RelativeHumidity', Format => 'int16u' },
88             0x48 => { Name => 'Emissivity', Format => 'int16u' },
89             0x4a => { Name => 'Reflection', Format => 'int16u', },
90             0x4c => { Name => 'AmbientTemperature', Format => 'int16u' }, # (aka D1)
91             0x50 => { Name => 'D2', Format => 'int32s' },
92             0x54 => { Name => 'KJ', Format => 'int16u' },
93             0x56 => { Name => 'DB', Format => 'int16u' },
94             0x58 => { Name => 'KK', Format => 'int16u' },
95             # 0x500 - 0x55aa1206 - device header magic number
96             # (nothing yet decoded from device header)
97             );
98              
99             # thermal parameters in APP4 of DJI M3T, H20N, M2EA and some M30T images (ref PH/forum11401)
100             %Image::ExifTool::DJI::ThermalParams2 = (
101             PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
102             GROUPS => { 0 => 'APP4', 2 => 'Image' },
103             NOTES => 'Thermal parameters extracted from APP4 of DJI M3T RJPEG files.',
104             0x00 => { Name => 'AmbientTemperature', Format => 'float', PrintConv => 'sprintf("%.1f C",$val)' }, # (NC)
105             0x04 => { Name => 'ObjectDistance', Format => 'float', PrintConv => 'sprintf("%.1f m",$val)' },
106             0x08 => { Name => 'Emissivity', Format => 'float', PrintConv => 'sprintf("%.2f",$val)' },
107             0x0c => { Name => 'RelativeHumidity', Format => 'float', PrintConv => 'sprintf("%g %%",$val*100)' },
108             0x10 => { Name => 'ReflectedTemperature',Format => 'float', PrintConv => 'sprintf("%.1f C",$val)' },
109             0x65 => { Name => 'IDString', Format => 'string[16]' }, # (NC)
110             );
111              
112             # thermal parameters in APP4 of some DJI M30T images (ref PH)
113             %Image::ExifTool::DJI::ThermalParams3 = (
114             PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
115             GROUPS => { 0 => 'APP4', 2 => 'Image' },
116             NOTES => 'Thermal parameters extracted from APP4 of some DJI RJPEG files.',
117             # 0x00 - 0xaa553800 - params3 magic number
118             0x04 => { Name => 'RelativeHumidity', Format => 'int16u' },
119             0x06 => { Name => 'ObjectDistance', Format => 'int16u', ValueConv => '$val / 10' },
120             0x08 => { Name => 'Emissivity', Format => 'int16u', ValueConv => '$val / 100' },
121             0x0a => { Name => 'ReflectedTemperature',Format => 'int16u', ValueConv => '$val / 10' },
122             );
123              
124             %Image::ExifTool::DJI::XMP = (
125             %Image::ExifTool::XMP::xmpTableDefaults,
126             GROUPS => { 0 => 'XMP', 1 => 'XMP-drone-dji', 2 => 'Location' },
127             NAMESPACE => 'drone-dji',
128             TABLE_DESC => 'XMP DJI',
129             VARS => { NO_ID => 1 },
130             NOTES => 'XMP tags used by DJI for images from drones.',
131             AbsoluteAltitude => { Writable => 'real' },
132             RelativeAltitude => { Writable => 'real' },
133             GimbalRollDegree => { Writable => 'real' },
134             GimbalYawDegree => { Writable => 'real' },
135             GimbalPitchDegree => { Writable => 'real' },
136             FlightRollDegree => { Writable => 'real' },
137             FlightYawDegree => { Writable => 'real' },
138             FlightPitchDegree => { Writable => 'real' },
139             GpsLatitude => {
140             Name => 'GPSLatitude',
141             Writable => 'real',
142             Avoid => 1,
143             PrintConv => 'Image::ExifTool::GPS::ToDMS($self, $val, 1, "N")',
144             PrintConvInv => 'Image::ExifTool::GPS::ToDegrees($val, 1, "lat")',
145             },
146             GpsLongtitude => { # (sic)
147             Name => 'GPSLongtitude',
148             Writable => 'real',
149             PrintConv => 'Image::ExifTool::GPS::ToDMS($self, $val, 1, "E")',
150             PrintConvInv => 'Image::ExifTool::GPS::ToDegrees($val, 1, "lon")',
151             },
152             GpsLongitude => { #PH (NC)
153             Name => 'GPSLongitude',
154             Writable => 'real',
155             Avoid => 1,
156             PrintConv => 'Image::ExifTool::GPS::ToDMS($self, $val, 1, "E")',
157             PrintConvInv => 'Image::ExifTool::GPS::ToDegrees($val, 1, "lon")',
158             },
159             FlightXSpeed => { Writable => 'real' },
160             FlightYSpeed => { Writable => 'real' },
161             FlightZSpeed => { Writable => 'real' },
162             CamReverse => { }, # integer?
163             GimbalReverse => { }, # integer?
164             SelfData => { Groups => { 2 => 'Image' } },
165             CalibratedFocalLength => { Writable => 'real', Groups => { 2 => 'Image' } },
166             CalibratedOpticalCenterX => { Writable => 'real', Groups => { 2 => 'Image' } },
167             CalibratedOpticalCenterY => { Writable => 'real', Groups => { 2 => 'Image' } },
168             RtkFlag => { }, # integer?
169             RtkStdLon => { Writable => 'real' },
170             RtkStdLat => { Writable => 'real' },
171             RtkStdHgt => { Writable => 'real' },
172             DewarpData => { Groups => { 2 => 'Image' } },
173             DewarpFlag => { Groups => { 2 => 'Image' } }, # integer?
174             Latitude => {
175             Name => 'Latitude',
176             Writable => 'real',
177             PrintConv => 'Image::ExifTool::GPS::ToDMS($self, $val, 1, "N")',
178             PrintConvInv => 'Image::ExifTool::GPS::ToDegrees($val, 1, "lat")',
179             },
180             Longitude => {
181             Name => 'Longitude',
182             Writable => 'real',
183             PrintConv => 'Image::ExifTool::GPS::ToDMS($self, $val, 1, "E")',
184             PrintConvInv => 'Image::ExifTool::GPS::ToDegrees($val, 1, "lon")',
185             },
186             );
187              
188             #------------------------------------------------------------------------------
189             # Process DJI info (ref PH)
190             # Inputs: 0) ExifTool ref, 1) dirInfo ref, 2) tag table ref
191             # Returns: 1 on success
192             sub ProcessDJIInfo($$$)
193             {
194 0     0 0   my ($et, $dirInfo, $tagTbl) = @_;
195 0           my $dataPt = $$dirInfo{DataPt};
196 0   0       my $dirStart = $$dirInfo{DirStart} || 0;
197 0   0       my $dirLen = $$dirInfo{DirLen} || (length($$dataPt) - $dirStart);
198 0 0         if ($dirStart) {
199 0           my $buff = substr($$dataPt, $dirStart, $dirLen);
200 0           $dataPt = \$buff;
201             }
202 0           $et->VerboseDir('DJIInfo', undef, length $$dataPt);
203 0           while ($$dataPt =~ /\G\[(.*?)\](?=(\[|$))/sg) {
204 0           my ($tag, $val) = split /:/, $1, 2;
205 0 0 0       next unless defined $tag and defined $val;
206 0 0         if ($val =~ /^([\x20-\x7f]+)\0*$/) {
207 0           $val = $1;
208             } else {
209 0           my $buff = $val;
210 0           $val = \$buff;
211             }
212 0 0 0       if (not $$tagTbl{$tag} and $tag=~ /^[-_a-zA-Z0-9]+$/) {
213 0           my $name = $tag;
214 0           $name =~ s/_([a-z])/_\U$1/g;
215 0           AddTagToTable($tagTbl, $tag, { Name => Image::ExifTool::MakeTagName($name) });
216             }
217 0           $et->HandleTag($tagTbl, $tag, $val);
218             }
219 0           return 1;
220             }
221              
222             __END__