File Coverage

blib/lib/Image/ExifTool/DJI.pm
Criterion Covered Total %
statement 18 37 48.6
branch 0 6 0.0
condition 0 8 0.0
subroutine 6 7 85.7
pod 0 1 0.0
total 24 59 40.6


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   61 use strict;
  10         22  
  10         313  
13 10     10   47 use vars qw($VERSION);
  10         1103  
  10         410  
14 10     10   55 use Image::ExifTool qw(:DataAccess :Utils);
  10         19  
  10         1918  
15 10     10   65 use Image::ExifTool::Exif;
  10         18  
  10         220  
16 10     10   1872 use Image::ExifTool::XMP;
  10         116  
  10         393  
17 10     10   68 use Image::ExifTool::GPS;
  10         21  
  10         6840  
18              
19             $VERSION = '1.05';
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             %Image::ExifTool::DJI::XMP = (
100             %Image::ExifTool::XMP::xmpTableDefaults,
101             GROUPS => { 0 => 'XMP', 1 => 'XMP-drone-dji', 2 => 'Location' },
102             NAMESPACE => 'drone-dji',
103             TABLE_DESC => 'XMP DJI',
104             VARS => { NO_ID => 1 },
105             NOTES => 'XMP tags used by DJI for images from drones.',
106             AbsoluteAltitude => { Writable => 'real' },
107             RelativeAltitude => { Writable => 'real' },
108             GimbalRollDegree => { Writable => 'real' },
109             GimbalYawDegree => { Writable => 'real' },
110             GimbalPitchDegree => { Writable => 'real' },
111             FlightRollDegree => { Writable => 'real' },
112             FlightYawDegree => { Writable => 'real' },
113             FlightPitchDegree => { Writable => 'real' },
114             GpsLatitude => {
115             Name => 'GPSLatitude',
116             Writable => 'real',
117             Avoid => 1,
118             PrintConv => 'Image::ExifTool::GPS::ToDMS($self, $val, 1, "N")',
119             PrintConvInv => 'Image::ExifTool::GPS::ToDegrees($val, 1, "lat")',
120             },
121             GpsLongtitude => { # (sic)
122             Name => 'GPSLongtitude',
123             Writable => 'real',
124             PrintConv => 'Image::ExifTool::GPS::ToDMS($self, $val, 1, "E")',
125             PrintConvInv => 'Image::ExifTool::GPS::ToDegrees($val, 1, "lon")',
126             },
127             GpsLongitude => { #PH (NC)
128             Name => 'GPSLongitude',
129             Writable => 'real',
130             Avoid => 1,
131             PrintConv => 'Image::ExifTool::GPS::ToDMS($self, $val, 1, "E")',
132             PrintConvInv => 'Image::ExifTool::GPS::ToDegrees($val, 1, "lon")',
133             },
134             FlightXSpeed => { Writable => 'real' },
135             FlightYSpeed => { Writable => 'real' },
136             FlightZSpeed => { Writable => 'real' },
137             CamReverse => { }, # integer?
138             GimbalReverse => { }, # integer?
139             SelfData => { Groups => { 2 => 'Image' } },
140             CalibratedFocalLength => { Writable => 'real', Groups => { 2 => 'Image' } },
141             CalibratedOpticalCenterX => { Writable => 'real', Groups => { 2 => 'Image' } },
142             CalibratedOpticalCenterY => { Writable => 'real', Groups => { 2 => 'Image' } },
143             RtkFlag => { }, # integer?
144             RtkStdLon => { Writable => 'real' },
145             RtkStdLat => { Writable => 'real' },
146             RtkStdHgt => { Writable => 'real' },
147             DewarpData => { Groups => { 2 => 'Image' } },
148             DewarpFlag => { Groups => { 2 => 'Image' } }, # integer?
149             Latitude => {
150             Name => 'Latitude',
151             Writable => 'real',
152             PrintConv => 'Image::ExifTool::GPS::ToDMS($self, $val, 1, "N")',
153             PrintConvInv => 'Image::ExifTool::GPS::ToDegrees($val, 1, "lat")',
154             },
155             Longitude => {
156             Name => 'Longitude',
157             Writable => 'real',
158             PrintConv => 'Image::ExifTool::GPS::ToDMS($self, $val, 1, "E")',
159             PrintConvInv => 'Image::ExifTool::GPS::ToDegrees($val, 1, "lon")',
160             },
161             );
162              
163             #------------------------------------------------------------------------------
164             # Process DJI infor (ref PH)
165             # Inputs: 0) ExifTool ref, 1) dirInfo ref, 2) tag table ref
166             # Returns: 1 on success
167             sub ProcessDJIInfo($$$)
168             {
169 0     0 0   my ($et, $dirInfo, $tagTbl) = @_;
170 0           my $dataPt = $$dirInfo{DataPt};
171 0   0       my $dirStart = $$dirInfo{DirStart} || 0;
172 0   0       my $dirLen = $$dirInfo{DirLen} || (length($$dataPt) - $dirStart);
173 0 0         if ($dirStart) {
174 0           my $buff = substr($$dataPt, $dirStart, $dirLen);
175 0           $dataPt = \$buff;
176             }
177 0           while ($$dataPt =~ /\G\[(.*?)\](?=(\[|$))/sg) {
178 0           my ($tag, $val) = split /:/, $1, 2;
179 0 0         if ($val =~ /^([\x20-\x7f]+)\0*$/) {
180 0           $val = $1;
181             } else {
182 0           my $buff = $val;
183 0           $val = \$buff;
184             }
185 0 0 0       if (not $$tagTbl{$tag} and $tag=~ /^[-_a-zA-Z0-9]+$/) {
186 0           my $name = $tag;
187 0           $name =~ s/_([a-z])/_\U$1/g;
188 0           AddTagToTable($tagTbl, $tag, { Name => Image::ExifTool::MakeTagName($name) });
189             }
190 0           $et->HandleTag($tagTbl, $tag, $val);
191             }
192 0           return 1;
193             }
194              
195             __END__