File Coverage

blib/lib/Image/ExifTool/Apple.pm
Criterion Covered Total %
statement 19 21 90.4
branch 1 2 50.0
condition 1 3 33.3
subroutine 5 5 100.0
pod 0 1 0.0
total 26 32 81.2


line stmt bran cond sub pod time code
1             #------------------------------------------------------------------------------
2             # File: Apple.pm
3             #
4             # Description: Apple EXIF maker notes tags
5             #
6             # Revisions: 2013-09-13 - P. Harvey Created
7             #
8             # References: 1) http://www.photoinvestigator.co/blog/the-mystery-of-maker-apple-metadata/
9             # 2) Frank Rupprecht private communication
10             #------------------------------------------------------------------------------
11              
12             package Image::ExifTool::Apple;
13              
14 5     5   4792 use strict;
  5         17  
  5         203  
15 5     5   30 use vars qw($VERSION);
  5         13  
  5         254  
16 5     5   1403 use Image::ExifTool::Exif;
  5         65  
  5         146  
17 5     5   1847 use Image::ExifTool::PLIST;
  5         15  
  5         3077  
18              
19             $VERSION = '1.08';
20              
21             sub ConvertPLIST($$);
22              
23             # Apple iPhone metadata (ref PH)
24             %Image::ExifTool::Apple::Main = (
25             WRITE_PROC => \&Image::ExifTool::Exif::WriteExif,
26             CHECK_PROC => \&Image::ExifTool::Exif::CheckExif,
27             WRITABLE => 1,
28             GROUPS => { 0 => 'MakerNotes', 2 => 'Image' },
29             NOTES => 'Tags extracted from the maker notes of iPhone images.',
30             0x0001 => { # (Version, ref 2)
31             Name => 'MakerNoteVersion',
32             Writable => 'int32s',
33             },
34             0x0002 => { #2
35             Name => 'AEMatrix',
36             Unknown => 1,
37             # (not currently writable)
38             ValueConv => \&ConvertPLIST,
39             },
40             0x0003 => { # (Timestamp, ref 2)
41             Name => 'RunTime', # (includes time plugged in, but not when suspended, ref 1)
42             SubDirectory => { TagTable => 'Image::ExifTool::Apple::RunTime' },
43             },
44             0x0004 => { #2
45             Name => 'AEStable',
46             Writable => 'int32s',
47             PrintConv => { 0 => 'No', 1 => 'Yes' },
48             },
49             0x0005 => { #2
50             Name => 'AETarget',
51             Writable => 'int32s',
52             },
53             0x0006 => { #2
54             Name => 'AEAverage',
55             Writable => 'int32s',
56             },
57             0x0007 => { #2
58             Name => 'AFStable',
59             Writable => 'int32s',
60             PrintConv => { 0 => 'No', 1 => 'Yes' },
61             },
62             0x0008 => { #1 (FocusAccelerometerVector, ref 2)
63             Name => 'AccelerationVector',
64             Groups => { 2 => 'Camera' },
65             Writable => 'rational64s',
66             Count => 3,
67             # Note: the directions are contrary to the Apple documentation (which have the
68             # signs of all axes reversed -- apparently the Apple geeks aren't very good
69             # with basic physics, and don't understand the concept of acceleration. See
70             # http://nscookbook.com/2013/03/ios-programming-recipe-19-using-core-motion-to-access-gyro-and-accelerometer/
71             # for one of the few correct descriptions of this). Note that this leads to
72             # a left-handed coordinate system for acceleration.
73             Notes => q{
74             XYZ coordinates of the acceleration vector in units of g. As viewed from
75             the front of the phone, positive X is toward the left side, positive Y is
76             toward the bottom, and positive Z points into the face of the phone
77             },
78             },
79             # 0x0009 - int32s: seen 19,275,531,4371 (SISMethod, ref 2)
80             0x000a => { # (HDRMethod, ref 2)
81             Name => 'HDRImageType',
82             Writable => 'int32s',
83             PrintConv => {
84             # 2 => ? (iPad mini 2)
85             3 => 'HDR Image',
86             4 => 'Original Image',
87             },
88             },
89             0x000b => { # (BurstUUID, ref 2)
90             Name => 'BurstUUID',
91             Writable => 'string',
92             Notes => 'unique ID for all images in a burst',
93             },
94             0x000c => { # ref forum13710 (Neal Krawetz) (SphereHealthTrackingError, ref 2)
95             Name => 'FocusDistanceRange',
96             Writable => 'rational64s',
97             Count => 2,
98             PrintConv => q{
99             my @a = split ' ', $val;
100             sprintf('%.2f - %.2f m', $a[0] <= $a[1] ? @a : reverse @a);
101             },
102             PrintConvInv => '$val =~ s/ - //; $val =~ s/ ?m$//; $val',
103             },
104             # 0x000d - int32s: 0,1,6,20,24,32,40 (SphereHealthAverageCurrent, ref 2)
105             # 0x000e - int32s: 0,1,4,12 (Orientation? 0=landscape? 4=portrait? ref 1) (SphereMotionDataStatus, ref 2)
106             0x000f => { #2
107             Name => 'OISMode',
108             Writable => 'int32s',
109             # seen: 2,3,5
110             },
111             # 0x0010 - int32s: 1 (SphereStatus, ref 2)
112             0x0011 => { # (if defined, there is a live photo associated with the video, #forum13565) (AssetIdentifier, ref 2)
113             Name => 'MediaGroupUUID', #NealKrawetz private communication
114             # (changed in 12.19 from Name => 'ContentIdentifier', #forum8750)
115             Writable => 'string',
116             },
117             # 0x0012 - (QRMOutputType, ref 2)
118             # 0x0013 - (SphereExternalForceOffset, ref 2)
119             0x0014 => { # (StillImageCaptureType, ref 2)
120             Name => 'ImageCaptureType',
121             Writable => 'int32s',
122             Unknown => 1, # (don't know what the values mean)
123             # seen: 1,2,3,4,5,10,12
124             },
125             0x0015 => { # (ImageGroupIdentifier, ref 2)
126             Name => 'ImageUniqueID',
127             Writable => 'string',
128             },
129             # 0x0016 - string[29]: "AXZ6pMTOh2L+acSh4Kg630XCScoO\0" (PhotosOriginatingSignature, ref 2)
130             0x0017 => { #forum13565 (only valid if MediaGroupUUID exists) (StillImageCaptureFlags, ref 2)
131             Name => 'LivePhotoVideoIndex',
132             Notes => 'divide by RunTimeScale to get time in seconds',
133             },
134             # 0x0018 - (PhotosRenderOriginatingSignature, ref 2)
135             0x0019 => { # (StillImageProcessingFlags, ref 2)
136             Name => 'ImageProcessingFlags',
137             Writable => 'int32s',
138             Unknown => 1,
139             PrintConv => { BITMASK => { } },
140             },
141             0x001a => { # (PhotoTranscodeQualityHint, ref 2)
142             Name => 'QualityHint',
143             Writable => 'string',
144             Unknown => 1,
145             # seen: "q825s\0", "q750n\0", "q900n\0"
146             },
147             # 0x001b - (PhotosRenderEffect, ref 2)
148             # 0x001c - (BracketedCaptureSequenceNumber, ref 2)
149             0x001d => { #2
150             Name => 'LuminanceNoiseAmplitude',
151             Writable => 'rational64s',
152             },
153             # 0x001e - (OriginatingAppID, ref 2)
154             # 0x001f - int32s: 0,1 (PhotosAppFeatureFlags, ref 2)
155             0x0020 => { # (ImageCaptureRequestIdentifier, ref 2)
156             Name => 'ImageCaptureReqestID',
157             Writable => 'string',
158             Unknown => 1,
159             },
160             0x0021 => { # (MeteorHeadroom, ref 2)
161             Name => 'HDRHeadroom',
162             Writable => 'rational64s',
163             },
164             # 0x0022 - (ARKitPhoto, ref 2)
165             # 0x0023 - int32s[2] (AFPerformance, ref 2)
166             # 0x0024 - (AFExternalOffset, ref 2)
167             0x0025 => { # (StillImageSceneFlags, ref 2)
168             Name => 'SceneFlags',
169             Writable => 'int32s',
170             Unknown => 1,
171             PrintConv => { BITMASK => { } },
172             },
173             0x0026 => { # (StillImageSNRType, ref 2)
174             Name => 'SignalToNoiseRatioType',
175             Writable => 'int32s',
176             Unknown => 1,
177             },
178             0x0027 => { # (StillImageSNR, ref 2)
179             Name => 'SignalToNoiseRatio',
180             Writable => 'rational64s',
181             },
182             # 0x0028 - int32s (UBMethod, ref 2)
183             # 0x0029 - string (SpatialOverCaptureGroupIdentifier, ref 2)
184             # 0x002A - (iCloudServerSoftwareVersionForDynamicallyGeneratedMedia, ref 2)
185             # 0x002B - (PhotoIdentifier, ref 2)
186             # 0x002C - (SpatialOverCaptureImageType, ref 2)
187             # 0x002D - (CCT, ref 2)
188             # 0x002E - (ApsMode, ref 2)
189             0x002F => { #2
190             Name => 'FocusPosition',
191             Writable => 'int32s',
192             },
193             0x0030 => { # (MeteorPlusGainMap, ref 2)
194             Name => 'HDRGain',
195             Writable => 'rational64s',
196             },
197             # 0x0031 - (StillImageProcessingHomography, ref 2)
198             # 0x0032 - (IntelligentDistortionCorrection, ref 2)
199             # 0x0033 - (NRFStatus, ref 2)
200             # 0x0034 - (NRFInputBracketCount, ref 2)
201             # 0x0035 - (NRFRegisteredBracketCount, ref 2)
202             # 0x0036 - (LuxLevel, ref 2)
203             # 0x0037 - (LastFocusingMethod, ref 2)
204             0x0038 => { # (TimeOfFlightAssistedAutoFocusEstimatorMeasuredDepth, ref 2)
205             Name => 'AFMeasuredDepth',
206             Notes => 'from the time-of-flight-assisted auto-focus estimator',
207             Writable => 'int32s',
208             },
209             # 0x0039 - (TimeOfFlightAssistedAutoFocusEstimatorROIType, ref 2)
210             # 0x003A - (NRFSRLStatus, ref 2)
211             # 0x003B - (SystemPressureLevel, ref 2)
212             # 0x003C - (CameraControlsStatisticsMaster, ref 2)
213             0x003D => { # (TimeOfFlightAssistedAutoFocusEstimatorSensorConfidence, ref 2)
214             Name => 'AFConfidence',
215             Writable => 'int32s',
216             },
217             0x003E => { # (ColorCorrectionMatrix, ref 2)
218             Name => 'ColorCorrectionMatrix',
219             Unknown => 1,
220             ValueConv => \&ConvertPLIST,
221             },
222             0x003F => { #2
223             Name => 'GreenGhostMitigationStatus',
224             Writable => 'int32s',
225             Unknown => 1,
226             },
227             0x0040 => { #2
228             Name => 'SemanticStyle',
229             ValueConv => \&ConvertPLIST,
230             },
231             0x0041 => { # (SemanticStyleKey_RenderingVersion, ref 2)
232             Name => 'SemanticStyleRenderingVer',
233             ValueConv => \&ConvertPLIST,
234             },
235             0x0042 => { # (SemanticStyleKey_Preset, ref 2)
236             Name => 'SemanticStylePreset',
237             ValueConv => \&ConvertPLIST,
238             },
239             # 0x0043 - (SemanticStyleKey_ToneBias, ref 2)
240             # 0x0044 - (SemanticStyleKey_WarmthBias, ref 2)
241             0x0045 => { # (FrontFacing, ref 2)
242             Name => 'FrontFacingCamera',
243             Writable => 'int32s',
244             PrintConv => { 0 => 'No', 1 => 'Yes' }, #PH (NC)
245             },
246             # 0x0046 - (TimeOfFlightAssistedAutoFocusEstimatorContainsBlindSpot, ref 2)
247             # 0x0047 - (LeaderFollowerAutoFocusLeaderDepth, ref 2)
248             # 0x0048 - (LeaderFollowerAutoFocusLeaderFocusMethod, ref 2)
249             # 0x0049 - (LeaderFollowerAutoFocusLeaderConfidence, ref 2)
250             # 0x004A - (LeaderFollowerAutoFocusLeaderROIType, ref 2)
251             # 0x004B - (ZeroShutterLagFailureReason, ref 2)
252             # 0x004C - (TimeOfFlightAssistedAutoFocusEstimatorMSPMeasuredDepth, ref 2)
253             # 0x004D - (TimeOfFlightAssistedAutoFocusEstimatorMSPSensorConfidence, ref 2)
254             # 0x004E - (Camera, ref 2)
255             );
256              
257             # PLIST-format CMTime structure (ref PH)
258             # (CMTime ref https://developer.apple.com/library/ios/documentation/CoreMedia/Reference/CMTime/Reference/reference.html)
259             %Image::ExifTool::Apple::RunTime = (
260             PROCESS_PROC => \&Image::ExifTool::PLIST::ProcessBinaryPLIST,
261             GROUPS => { 0 => 'MakerNotes', 2 => 'Image' },
262             NOTES => q{
263             This PLIST-format information contains the elements of a CMTime structure
264             representing the amount of time the phone has been running since the last
265             boot, not including standby time.
266             },
267             timescale => { Name => 'RunTimeScale' }, # (seen 1000000000 --> ns)
268             epoch => { Name => 'RunTimeEpoch' }, # (seen 0)
269             value => { Name => 'RunTimeValue' }, # (should divide by RunTimeScale to get seconds)
270             flags => {
271             Name => 'RunTimeFlags',
272             PrintConv => { BITMASK => {
273             0 => 'Valid',
274             1 => 'Has been rounded',
275             2 => 'Positive infinity',
276             3 => 'Negative infinity',
277             4 => 'Indefinite',
278             }},
279             },
280             );
281              
282             # Apple composite tags
283             %Image::ExifTool::Apple::Composite = (
284             GROUPS => { 2 => 'Camera' },
285             RunTimeSincePowerUp => {
286             Require => {
287             0 => 'Apple:RunTimeValue',
288             1 => 'Apple:RunTimeScale',
289             },
290             ValueConv => '$val[1] ? $val[0] / $val[1] : undef',
291             PrintConv => 'ConvertDuration($val)',
292             },
293             );
294              
295             # add our composite tags
296             Image::ExifTool::AddCompositeTags('Image::ExifTool::Apple');
297              
298             #------------------------------------------------------------------------------
299             # Convert from binary PLIST format to a tag value we can use
300             # Inputs: 0) binary plist data, 1) ExifTool ref
301             # Returns: converted value
302             sub ConvertPLIST($$)
303             {
304 1     1 0 4 my ($val, $et) = @_;
305 1         3 my $dirInfo = { DataPt => \$val };
306 1         8 require Image::ExifTool::PLIST;
307 1         7 Image::ExifTool::PLIST::ProcessBinaryPLIST($et, $dirInfo);
308 1         3 $val = $$dirInfo{Value};
309 1 50 33     14 if (ref $val eq 'HASH' and not $et->Options('Struct')) {
310 0         0 require 'Image/ExifTool/XMPStruct.pl';
311 0         0 $val = Image::ExifTool::XMP::SerializeStruct($val);
312             }
313 1         6 return $val;
314             }
315              
316             1; # end
317              
318             __END__