title: Extracting GPS numerical values from byte array using PowerShell
body: <p>I wish to extract GPS Location data from the EXIF properties of image files.  I am using the System.Drawing.Bitmap class to get raw the values.  I am able to extract the values I am looking for but they are coming back as bytes, or possibly arrays of bytes and I need help converting the bytes into sensible numbers.  Here is what I have so far:</p>
  
  <pre><code>$imagePath = 'C:\temp\picTest\WP_20150918_003.jpg'
  $imageProperties = New-Object -TypeName System.Drawing.Bitmap -ArgumentList $imagePath
  </code></pre>
  
  <p>From the <a href="http://www.awaresystems.be/imaging/tiff/tifftags/privateifd/gps.html" rel="nofollow noreferrer">EXIF GPS Tag Reference</a> I know that the property tags I am looking for are:</p>
  
  <ul>
  <li>0x0001 - <strong>GPSLatitudeRef</strong> - Indicates whether the latitude is north or south latitude.</li>
  <li>0x0002 - <strong>GPSLatitude</strong> - Indicates the latitude.</li>
  <li>0x0003 - <strong>GPSLongitudeRef</strong> - Indicates whether the longitude is east or west longitude.</li>
  <li>0x0004 - <strong>GPSLongitude</strong> - Indicates the longitude.</li>
  <li>0x0005 - <strong>GPSAltitudeRef</strong> - Indicates the altitude used as the reference altitude.</li>
  <li>0x0006 - <strong>GPSAltitude</strong> - Indicates the altitude based on the reference in GPSAltitudeRef.</li>
  </ul>
  
  <p>First I get the <strong>GPSLatitudeRef</strong>:</p>
  
  <pre><code>$imageProperies.PropertyItems | ? ID -eq 0x0001
  </code></pre>
  
  <p>and I get:</p>
  
  <pre><code> Id Len Type Value
  -- --- ---- -----
   1   2    2 {78, 0}
  </code></pre>
  
  <p>According to the MSDN documentation for <a href="https://msdn.microsoft.com/en-us/library/system.drawing.imaging.propertyitem.type(v=vs.110).aspx" rel="nofollow noreferrer">System.Drawing library</a>, PropertyItem.Type of "2" is ASCII. </p>
  
  <p>I load the value into a variable:</p>
  
  <pre><code>$GPSLatRef = $imageProperties.PropertyItems| Where ID -eq 0x0001
  $GPSLatRef = $GPSLatRef.Value
  $GPSLatRef
  78
  0
  </code></pre>
  
  <p>Get-Member on the variable returns type System.Byte.  I know how to convert byte back into ASCII: </p>
  
  <pre><code>$GPSLatRef = [System.Text.Encoding]::ASCII.GetString($GPSLatRef.Value)
  $GPSLatRef
  </code></pre>
  
  <p>returns:</p>
  
  <pre><code>N
  </code></pre>
  
  <p>But things get tricky for me with the <strong>GPSLatitude</strong> value (0x0002):</p>
  
  <pre><code>$imageProperies.PropertyItems | ? ID -eq 0x0002
  </code></pre>
  
  <p>returns:</p>
  
  <pre><code>Id Len Type Value
  -- --- ---- -----
   2  24    5 {37, 0, 0, 0...}
  </code></pre>
  
  <p>Load the value up into a variable:</p>
  
  <pre><code>$GPSLatitiude = $imageProperties.PropertyItems| Where ID -eq 0x0002
  $GPSLatitiude.Value
  </code></pre>
  
  <p>The value returned is:</p>
  
  <pre><code>37
  0
  0
  0
  1
  0
  0
  0
  40
  0
  0
  0
  1
  0
  0
  0
  220
  182
  0
  0
  232
  3
  0
  0
  </code></pre>
  
  <p>According to the MSDN documentation referenced above, PropertyItem.Type of "5" 
   "<em>Specifies that Value data member is an <strong>array</strong> of <strong>pairs</strong> of unsigned long integers. <strong>Each pair represents a fraction</strong>; the first integer is the numerator and the second integer is the denominator.</em>  </p>
  
  <p>Looking at the properties of the file itself in Windows Explorer I see the GPS Location values in decimal form. </p>
  
  <pre><code>"37;40;46.812000000005156"
  </code></pre>
  
  <p>From the value data above, and the description of the data type from the documentation, and comparing to the decimal values from Windows Explorer I can surmise that $GPSLatitude.Value actually shows me three different sets of two integers apiece.  For example,</p>
  
  <pre><code>37
  0
  0
  0
  </code></pre>
  
  <p>= 37</p>
  
  <pre><code>1
  0
  0
  0
  </code></pre>
  
  <p>= 1</p>
  
  <p>and 37/1 = 37, which matches the decimal value from Windows Explorer so I know I am on the right track.   </p>
  
  <p>How can I split the three sets of values from the (array of?) bytes found in the GPSLatitude property?  Even though the data in the bytes is described as long integers, the decimal value displayed in the Windows Explorer shows that the outcome could be a number with fifteen digits to the right of the decimal point makes me think that the product of the division of the two long integers in the bytes from the property value might need to be stored in a [double] or perhaps [decimal]?</p>