Extracting GPS information from a JPG file

Started by TheStingPilot, July 11, 2020, 10:27:24 AM

Previous topic - Next topic

TheStingPilot

Hello,

I am writing a PowerShell function that reads the EXIF information from a JPG file.
Function Get-EXIFDataFromJPGFile
   {

    <#
    .NOTES
    =============================================================================================================================================
    Created with:     Windows PowerShell ISE
    Created on:       06-July-2020
    Created by:       Willem-Jan Vroom
    Organization:     
    Functionname:     Get-EXIFDataFromJPGFile
    =============================================================================================================================================
    .SYNOPSIS

    This function reads the latitude and longitude data from a JPG file.
    If no valid data is found, the return codes will be 1024 and 1024.
    This code is based on
    http://www.forensicexpedition.com/2017/08/03/imagemapper-a-powershell-metadata-and-geo-maping-tool-for-images/

    #>

    Param
     (
      [String] $FileName
     )
   
   
    $img    = New-Object -TypeName system.drawing.bitmap -ArgumentList $FileName
    $Encode = New-Object System.Text.ASCIIEncoding
    $GPSInfo = $true
    $GPSLat  = ""
    $GPSLon  = ""
     
    # =============================================================================================================================================
    # Try to get the latitude (N or S) from the image.
    # If not successfull then this information is not in the image
    # and quit with the numbers 1024 and 1024.
    # =============================================================================================================================================

    Try
     {
     
      $LatNS = $Encode.GetString($img.GetPropertyItem(1).Value)
     }
      Catch
     {
      $GPSInfo = $False
     }
               
    If ($GPSInfo -eq $true)
     {
      [double]$LatDeg = (([Decimal][System.BitConverter]::ToInt32($img.GetPropertyItem(2).Value, 0))  / ([Decimal][System.BitConverter]::ToInt32($img.GetPropertyItem(2).Value, 4)))
      [double]$LatMin = (([Decimal][System.BitConverter]::ToInt32($img.GetPropertyItem(2).Value, 8))  / ([Decimal][System.BitConverter]::ToInt32($img.GetPropertyItem(2).Value, 12)))
      [double]$LatSec = (([Decimal][System.BitConverter]::ToInt32($img.GetPropertyItem(2).Value, 16)) / ([Decimal][System.BitConverter]::ToInt32($img.GetPropertyItem(2).Value, 20)))
   
      $LonEW = $Encode.GetString($img.GetPropertyItem(3).Value)
      [double]$LonDeg = (([Decimal][System.BitConverter]::ToInt32($img.GetPropertyItem(4).Value, 0))  / ([Decimal][System.BitConverter]::ToInt32($img.GetPropertyItem(4).Value, 4)))
      [double]$LonMin = (([Decimal][System.BitConverter]::ToInt32($img.GetPropertyItem(4).Value, 8))  / ([Decimal][System.BitConverter]::ToInt32($img.GetPropertyItem(4).Value, 12)))
      [double]$LonSec = (([Decimal][System.BitConverter]::ToInt32($img.GetPropertyItem(4).Value, 16)) / ([Decimal][System.BitConverter]::ToInt32($img.GetPropertyItem(4).Value, 20)))



      #$GPSLat = $($LatDeg.ToString("###")) + "º "+$($LatMin.ToString("##"))+"' "+$($LatSec.ToString("##"))+ $([char]34) + " "+$LatNS
      #$GPSLon = $($LonDeg.ToString("###")) + "º "+$($LonMin.ToString("##"))+"' "+$($LonSec.ToString("##"))+ $([char]34) + " "+$LonEW

      $GPSLat = "$([int]$LatDeg)º $([int]$LatMin)' $([int]$LatSec)$([char]34) $LatNS"
      $GPSLon = "$([int]$LonDeg)º $([int]$LonMin)' $([int]$LonSec)$([char]34) $LonEW"

      Write-Verbose "    The picture $FileName has the following GPS coordinates:"
      Write-Verbose "       $GPSLat"       
      Write-Verbose "       $GPSLon"

    # =============================================================================================================================================
    # Convert the latitude and longitude to numbers that Google Maps recognizes.
    # =============================================================================================================================================

      $LatOrt = 0
      $LonOrt = 0

      If ($LatNS -eq 'S')
       {
        $LatOrt = "-"   
       }
      If ($LonEW -eq 'W')
       {
        $LonOrt = "-"
       }

      $LatDec = ($LatDeg + ($LatMin/60) + ($LatSec/3600))
      $LonDec = ($LonDeg + ($LonMin/60) + ($LonSec/3600))

      $LatOrt = $LatOrt + $LatDec
      $LonOrt = $LonOrt + $LonDec

    # =============================================================================================================================================
    # The numbers that where returned contained a decimal comma instead of a decimal point.
    # So the en-US culture is forced to get the correct number notation.
    # =============================================================================================================================================
   
      $LatOrt = $LatOrt.ToString([cultureinfo]::GetCultureInfo('en-US'))
      $LonOrt = $LonOrt.ToString([cultureinfo]::GetCultureInfo('en-US'))

      Write-Verbose "    The picture $FileName has the following decimal coordinates:"
      Write-Verbose "      $LatOrt"
      Write-Verbose "      $LonOrt"
    }
     else
    {
     
   # =============================================================================================================================================
   # Ohoh... No GPS information in this picture.
   # =============================================================================================================================================
     
     Write-Verbose "    The picture $FileName does not contain GPS information."
     $LatOrt = "1024"
     $LonOrt = "1024"
    }

    Return $LatOrt,$LonOrt,$GPSLat,$GPSLon
  }

  Add-Type -AssemblyName System.Drawing
  Get-EXIFDataFromJPGFile "C:\TMP\WP_20170426_15_30_51_Pro.jpg"


There are two things I do not understand.

  • In some cases the minutes and seconds are negative. That happens with Nolia Lumia 930 camera's
  • My script does not find any GPS information and your tool does.

So my simple question is: what should I do to get the correct information from the JPG files. :-)

Your feedback is appreciated and with kind regards,
TheStingPilot

StarGeek

Quote from: TheStingPilot on July 11, 2020, 10:27:24 AM
My script does not find any GPS information and your tool does.

What is the location of the GPS data?  Group name, not actual location.  Use the command in FAQ #3 to see the actual group the tags belong to.

GPS coordinates can also be in the XMP data, though it usually isn't exclusively there.
* Did you read FAQ #3 and use the command listed there?
* Please use the Code button for exiftool code/output.
 
* Please include your OS, Exiftool version, and type of file you're processing (MP4, JPG, etc).

Phil Harvey

I don't know what GetPropertyItem() does, so I can't help much.

But I do know that PowerShell easily mangles binary data, converting newlines to CR/LF sequences.  So watch out for that.

- Phil
...where DIR is the name of a directory/folder containing the images.  On Mac/Linux/PowerShell, use single quotes (') instead of double quotes (") around arguments containing a dollar sign ($).

TheStingPilot

Quote from: StarGeek on July 11, 2020, 10:51:29 AM
Quote from: TheStingPilot on July 11, 2020, 10:27:24 AM
My script does not find any GPS information and your tool does.

What is the location of the GPS data?  Group name, not actual location.  Use the command in FAQ #3 to see the actual group the tags belong to.

GPS coordinates can also be in the XMP data, though it usually isn't exclusively there.

Helllo StarGeek,

Thanks for your response.

The (requested) output:
[ExifTool]      ExifToolVersion                 : 12.01
[ExifTool]      Warning                         : [minor] Unrecognized MakerNotes
[ExifTool]      Warning                         : [minor] Fixed incorrect URI for xmlns:MicrosoftPhoto
[System]        FileName                        : WP_20170426_15_30_51_Pro.jpg
[System]        Directory                       : C:/tmp
[System]        FileSize                        : 4.9 MB
[System]        FileModifyDate                  : 2017:04:26 15:30:54+02:00
[System]        FileAccessDate                  : 2020:07:12 09:59:36+02:00
[System]        FileCreateDate                  : 2020:07:12 09:55:08+02:00
[System]        FilePermissions                 : rw-rw-rw-
[File]          FileType                        : JPEG
[File]          FileTypeExtension               : jpg
[File]          MIMEType                        : image/jpeg
[File]          ExifByteOrder                   : Big-endian (Motorola, MM)
[File]          ImageWidth                      : 5376
[File]          ImageHeight                     : 3024
[File]          EncodingProcess                 : Baseline DCT, Huffman coding
[File]          BitsPerSample                   : 8
[File]          ColorComponents                 : 3
[File]          YCbCrSubSampling                : YCbCr4:2:0 (2 2)
[IFD0]          Make                            : Microsoft
[IFD0]          Model                           : Lumia 930
[IFD0]          Orientation                     : Horizontal (normal)
[IFD0]          XResolution                     : 72
[IFD0]          YResolution                     : 72
[IFD0]          ResolutionUnit                  : inches
[IFD0]          Software                        : Windows Phone
[IFD0]          YCbCrPositioning                : Centered
[IFD0]          Padding                         : (Binary data 2060 bytes, use -b option to extract)
[ExifIFD]       ExposureTime                    : 1/1330
[ExifIFD]       FNumber                         : 2.4
[ExifIFD]       ISO                             : 64
[ExifIFD]       ExifVersion                     : 0220
[ExifIFD]       DateTimeOriginal                : 2017:04:26 15:30:52
[ExifIFD]       CreateDate                      : 2017:04:26 15:30:52
[ExifIFD]       ComponentsConfiguration         : Y, Cb, Cr, -
[ExifIFD]       ShutterSpeedValue               : 1/1330
[ExifIFD]       ApertureValue                   : 2.4
[ExifIFD]       ExposureCompensation            : 0
[ExifIFD]       MeteringMode                    : Average
[ExifIFD]       LightSource                     : Unknown
[ExifIFD]       Flash                           : Auto, Fired
[ExifIFD]       FocalLength                     : 4.5 mm
[ExifIFD]       SubSecTimeOriginal              : 797
[ExifIFD]       SubSecTimeDigitized             : 797
[ExifIFD]       FlashpixVersion                 : 0100
[ExifIFD]       ColorSpace                      : sRGB
[ExifIFD]       ExifImageWidth                  : 5376
[ExifIFD]       ExifImageHeight                 : 3024
[ExifIFD]       ExposureMode                    : Auto
[ExifIFD]       WhiteBalance                    : Auto
[ExifIFD]       DigitalZoomRatio                : 0
[ExifIFD]       FocalLengthIn35mmFormat         : 28 mm
[ExifIFD]       SceneCaptureType                : Standard
[ExifIFD]       Padding                         : (Binary data 2048 bytes, use -b option to extract)
[ExifIFD]       OffsetSchema                    : 0
[GPS]           GPSLatitudeRef                  : North
[GPS]           GPSLatitude                     : 47 deg 33' 21.95"
[GPS]           GPSLongitudeRef                 : East
[GPS]           GPSLongitude                    : 7 deg 35' 30.37"
[XMP-microsoft] CreatorAppID                    : {2d7e7fd6-2942-4d77-9842-389c3f62b14d}
[XMP-microsoft] CreatorOpenWithUIOptions        : 1
[XMP-mwg-rs]    RegionAppliedToDimensionsH      : 3024
[XMP-mwg-rs]    RegionAppliedToDimensionsUnit   : pixel
[XMP-mwg-rs]    RegionAppliedToDimensionsW      : 5376
[XMP-mwg-rs]    RegionTitle                     : LumiaOriginalROI
[XMP-mwg-rs]    RegionAreaX                     : 0.500000
[XMP-mwg-rs]    RegionAreaY                     : 0.500000
[XMP-mwg-rs]    RegionAreaW                     : 1.000000
[XMP-mwg-rs]    RegionAreaH                     : 1.000000
[XMP-mwg-rs]    RegionAreaUnit                  : normalized
[XMP-Nokia]     SharpeningStrength              : 33554710
[Composite]     Aperture                        : 2.4
[Composite]     ImageSize                       : 5376x3024
[Composite]     Megapixels                      : 16.3
[Composite]     ScaleFactor35efl                : 6.3
[Composite]     ShutterSpeed                    : 1/1330
[Composite]     SubSecCreateDate                : 2017:04:26 15:30:52.797
[Composite]     SubSecDateTimeOriginal          : 2017:04:26 15:30:52.797
[Composite]     GPSLatitude                     : 47 deg 33' 21.95" N
[Composite]     GPSLongitude                    : 7 deg 35' 30.37" E
[Composite]     CircleOfConfusion               : 0.005 mm
[Composite]     FOV                             : 65.5 deg
[Composite]     FocalLength35efl                : 4.5 mm (35 mm equivalent: 28.0 mm)
[Composite]     GPSPosition                     : 47 deg 33' 21.95" N, 7 deg 35' 30.37" E
[Composite]     HyperfocalDistance              : 1.73 m
[Composite]     LightValue                      : 13.5


If I check that with my scripts output (same picture):

47º 33' -21" N
7º 35' -13" E


So there is a mismatch.  :(

The (correct) information is there (it is in the EXIFtool's output). The question is: how do I extract it from the image with PowerShell?  :)

With kind regards,
TheStingPilot

TheStingPilot

Quote from: Phil Harvey on July 11, 2020, 10:55:42 AM
I don't know what GetPropertyItem() does, so I can't help much. (...)
- Phil

Hello Phil,

Thanks for your response. GetPropertyItem() reads the Exif information from a JPG file and processes it. It reads the EXIF information as per https://exiftool.org/TagNames/GPS.html.


$LatNS = $Encode.GetString($img.GetPropertyItem(1).Value)
[double]$LatDeg = (([Decimal][System.BitConverter]::ToInt32($img.GetPropertyItem(2).Value, 0))  / ([Decimal][System.BitConverter]::ToInt32($img.GetPropertyItem(2).Value, 4)))
[double]$LatMin = (([Decimal][System.BitConverter]::ToInt32($img.GetPropertyItem(2).Value, 8))  / ([Decimal][System.BitConverter]::ToInt32($img.GetPropertyItem(2).Value, 12)))
[double]$LatSec = (([Decimal][System.BitConverter]::ToInt32($img.GetPropertyItem(2).Value, 16)) / ([Decimal][System.BitConverter]::ToInt32($img.GetPropertyItem(2).Value, 20)))
   
$LonEW = $Encode.GetString($img.GetPropertyItem(3).Value)
[double]$LonDeg = (([Decimal][System.BitConverter]::ToInt32($img.GetPropertyItem(4).Value, 0))  / ([Decimal][System.BitConverter]::ToInt32($img.GetPropertyItem(4).Value, 4)))
[double]$LonMin = (([Decimal][System.BitConverter]::ToInt32($img.GetPropertyItem(4).Value, 8))  / ([Decimal][System.BitConverter]::ToInt32($img.GetPropertyItem(4).Value, 12)))
[double]$LonSec = (([Decimal][System.BitConverter]::ToInt32($img.GetPropertyItem(4).Value, 16)) / ([Decimal][System.BitConverter]::ToInt32($img.GetPropertyItem(4).Value, 20)))



I am not afraid of mangled binary data as the output from many other picture files seems to be right.

With kind regards,
TheStingPilot

Phil Harvey

Is ToInt32() a signed or unsigned integer?  The values should be stored as unsigned, so there should be no way to get a negative number if they are decoded as such.

- Phil
...where DIR is the name of a directory/folder containing the images.  On Mac/Linux/PowerShell, use single quotes (') instead of double quotes (") around arguments containing a dollar sign ($).

TheStingPilot

Hellp Phil,

Thanks for getting back to me. I assume it is signed... See https://docs.microsoft.com/en-us/dotnet/api/system.convert.toint32?view=netcore-3.1. Although I am not using .net.

Does the EXIF tool also use this information https://exiftool.org/TagNames/GPS.html to read jpg files? If so, why does the information not match even the same information source is used?

With kind regards,
TheStingPilot

StarGeek

Quote from: TheStingPilot on July 12, 2020, 07:34:32 AM
Thanks for getting back to me. I assume it is signed... See https://docs.microsoft.com/en-us/dotnet/api/system.convert.toint32?view=netcore-3.1. Although I am not using .net.

Try Convert.ToUInt32 Method.  As Phil mentioned, the data is unsigned.  The ToInt32 specifically says signed on the page you linked.

QuoteDoes the EXIF tool also use this information https://exiftool.org/TagNames/GPS.html to read jpg files?

That's the list of GPS tags that exiftool reads.  You can find exiftool's GPS source code here.
* Did you read FAQ #3 and use the command listed there?
* Please use the Code button for exiftool code/output.
 
* Please include your OS, Exiftool version, and type of file you're processing (MP4, JPG, etc).

TheStingPilot

Hello all,

Solved it, and that is thanks to StarGeeks and Phil's input. There is a difference in the Signed and Unsigned result. A 'signed' returns a negative value, an 'unsigned' positive result. The byte value is calculated differently.

I will update this post with evidence later.

With kind regards,
TheStingPilot

TheStingPilot

Hello,

The update. Changing the from Int32 to UInt32 was the big trick.

I like log files. So my script creates an extensive log file. A part of it:

47 / 1 = 47
33 / 1 = 33
2194586366 / 100000000 = 21.94586366

     --- Overview of the EXIF GPS Data ---
     --- ID 2 of WP_20170426_15_30_51_Pro.jpg
       Number:                     0
       Value:                      47
       Type:                       byte
       Decimal value (Signed)    : 47
       Decimal value (Unsigned)  : 47
       Remark:                     Deg1
       ---------------------------------------------------------------------
       Number:                     4
       Value:                      1
       Type:                       byte
       Decimal value (Signed)    : 1
       Decimal value (Unsigned)  : 1
       Remark:                     Deg2
       ---------------------------------------------------------------------
       Number:                     8
       Value:                      33
       Type:                       byte
       Decimal value (Signed)    : 33
       Decimal value (Unsigned)  : 33
       Remark:                     Min1
       ---------------------------------------------------------------------
       Number:                     12
       Value:                      1
       Type:                       byte
       Decimal value (Signed)    : 1
       Decimal value (Unsigned)  : 1
       Remark:                     Min2
       ---------------------------------------------------------------------
       Number:                     16
       Value:                      254
       Type:                       byte
       Decimal value (Signed)    : -2100380930
       Decimal value (Unsigned)  : 2194586366
       Remark:                     Sec1
       ---------------------------------------------------------------------
       Number:                     20
       Value:                      0
       Type:                       byte
       Decimal value (Signed)    : 100000000
       Decimal value (Unsigned)  : 100000000
       Remark:                     Sec2
       ---------------------------------------------------------------------
7 / 1 = 7
35 / 1 = 35
3036714792 / 100000000 = 30.36714792

     --- Overview of the EXIF GPS Data ---
     --- ID 4 of WP_20170426_15_30_51_Pro.jpg
       Number:                     0
       Value:                      7
       Type:                       byte
       Decimal value (Signed)    : 7
       Decimal value (Unsigned)  : 7
       Remark:                     Deg1
       ---------------------------------------------------------------------
       Number:                     4
       Value:                      1
       Type:                       byte
       Decimal value (Signed)    : 1
       Decimal value (Unsigned)  : 1
       Remark:                     Deg2
       ---------------------------------------------------------------------
       Number:                     8
       Value:                      35
       Type:                       byte
       Decimal value (Signed)    : 35
       Decimal value (Unsigned)  : 35
       Remark:                     Min1
       ---------------------------------------------------------------------
       Number:                     12
       Value:                      1
       Type:                       byte
       Decimal value (Signed)    : 1
       Decimal value (Unsigned)  : 1
       Remark:                     Min2
       ---------------------------------------------------------------------
       Number:                     16
       Value:                      40
       Type:                       byte
       Decimal value (Signed)    : -1258252504
       Decimal value (Unsigned)  : 3036714792
       Remark:                     Sec1
       ---------------------------------------------------------------------
       Number:                     20
       Value:                      0
       Type:                       byte
       Decimal value (Signed)    : 100000000
       Decimal value (Unsigned)  : 100000000
       Remark:                     Sec2
       ---------------------------------------------------------------------
47.5560960732389
7.5917686522
47º 33' 22" N
7º 35' 30" E


And the two functions that take care of it:

Function Get-GPSDetails
{

     <#
    .NOTES
    =============================================================================================================================================
    Created with:     Windows PowerShell ISE
    Created on:       13-July-2020
    Created by:       Willem-Jan Vroom
    Organization:     
    Functionname:     Get-GPSDetails
    =============================================================================================================================================
    .SYNOPSIS

    This function reads the latitude and longitude data from a JPG file. More information can be found at:
    http://www.forensicexpedition.com/2017/08/03/imagemapper-a-powershell-metadata-and-geo-maping-tool-for-images/

    More information about the EXIF layout can be found at: https://exiftool.org/TagNames/GPS.html

    #>

    param
     (
      [int]    $ID,
      [String] $FileNameWithGPSDetails
     )

    $img                 = New-Object -TypeName system.drawing.bitmap -ArgumentList $FileNameWithGPSDetails
    $IMGPropertyItems    = $img.PropertyItems | Where {($_.ID -eq $ID)}
    [Double]$Deg         = 0
    [Double]$Min         = 0
    [Double]$Sec         = 0
    $GPSTable            = @()

 
    For($a=0;$a -le 20;$a++)
     {
     
      $GPSRecord  = [ordered] @{"Number"                   = "";
                                "Value"                    = "";
                                "Type"                     = "";
                                "Decimal value (Signed)"   = "";
                                "Decimal value (Unsigned)" = "";
                                "Remark"                   = ""
                                }
     
      Switch ($a)
       {
        "0"  {$Remark = "Deg1"; Break}
        "4"  {$Remark = "Deg2"; Break}
        "8"  {$Remark = "Min1"; Break}
        "12" {$Remark = "Min2"; Break}
        "16" {$Remark = "Sec1"; Break}
        "20" {$Remark = "Sec2"; Break}
        Default {$Remark = ""}
       }
     
      $GPSRecord."Number"                   = $a
      $GPSRecord."Value"                    = $IMGPropertyItems.Value[$a]
      $GPSRecord."Type"                     = $IMGPropertyItems.Value[$a].Gettype()
      $GPSRecord."Decimal value (Signed)"   = ([System.BitConverter]::ToInt32($img.GetPropertyItem($ID).Value, $a))
      $GPSRecord."Decimal value (Unsigned)" = ([System.BitConverter]::ToUInt32($img.GetPropertyItem($ID).Value, $a))
      $GPSRecord."Remark"                   = $Remark
      $objGPSRecord                         = New-Object PSObject -Property $GPSRecord
      $GPSTable                            += $objGPSRecord
    }
                   
    [Double]$Deg1 = ([Decimal][System.BitConverter]::ToUInt32($img.GetPropertyItem($ID).Value, 0))
    [Double]$Deg2 = ([Decimal][System.BitConverter]::ToUInt32($img.GetPropertyItem($ID).Value, 4))
    [Double]$Deg = $Deg1 / $Deg2

    [Double]$Min1 = ([Decimal][System.BitConverter]::ToUInt32($img.GetPropertyItem($ID).Value, 8))
    [Double]$Min2 = ([Decimal][System.BitConverter]::ToUInt32($img.GetPropertyItem($ID).Value, 12))
    [Double]$Min  = $Min1 / $Min2

    [Double]$Sec1 = ([Decimal][System.BitConverter]::ToUInt32($img.GetPropertyItem($ID).Value, 16))
    [Double]$Sec2 = ([Decimal][System.BitConverter]::ToUInt32($img.GetPropertyItem($ID).Value, 20))
    [Double]$Sec = $Sec1 / $Sec2

    Write-Host "$Deg1 / $Deg2 = $Deg"
    Write-Host "$Min1 / $Min2 = $Min"
    Write-Host "$Sec1 / $Sec2 = $Sec"

    Write-Host ""
    Write-Host "     --- Overview of the EXIF GPS Data ---"
    Write-Host "     --- ID $ID of $(Split-Path -Leaf $FileNameWithGPSDetails)"
    ForEach ($object in $GPSTable)
     {
      if($object."Remark")
       {
        Write-Host "       Number:                     $($object."Number")"
        Write-Host "       Value:                      $($object."Value")"
        Write-Host "       Type:                       $($object."Type")"
        Write-Host "       Decimal value (Signed)    : $($object."Decimal value (Signed)")"
        Write-Host "       Decimal value (Unsigned)  : $($object."Decimal value (Unsigned)")"
        Write-Host "       Remark:                     $($object."Remark")"
        Write-Host "       ---------------------------------------------------------------------"
       }
     }
    $GPSTable.Clear()
   
    Return [Double]$Deg, [Double]$Min, [Double]$Sec
}


Function Get-EXIFDataFromJPGFile
   {

    <#
    .NOTES
    =============================================================================================================================================
    Created with:     Windows PowerShell ISE
    Created on:       06-July-2020
    Created by:       Willem-Jan Vroom
    Organization:     
    Functionname:     Get-EXIFDataFromJPGFile
    =============================================================================================================================================
    .SYNOPSIS

    This function reads the latitude and longitude data from a JPG file.
    If no valid data is found, the return codes will be 1024 and 1024.
    This code is based on
    http://www.forensicexpedition.com/2017/08/03/imagemapper-a-powershell-metadata-and-geo-maping-tool-for-images/

    More information about the EXIF layout can be found at: https://exiftool.org/TagNames/GPS.html

    #>

    Param
     (
      [String] $FileName
     )
   
   
    $img     = New-Object -TypeName system.drawing.bitmap -ArgumentList $FileName
    $Encode  = New-Object System.Text.ASCIIEncoding
    $GPSInfo = $true
    $GPSLat  = ""
    $GPSLon  = ""
     
    # =============================================================================================================================================
    # Try to get the latitude (N or S) from the image.
    # If not successfull then this information is not in the image
    # and quit with the numbers 1024 and 1024.
    # =============================================================================================================================================

    Try
     {
     
      $LatNS = $Encode.GetString($img.GetPropertyItem(1).Value)
     }
      Catch
     {
      $GPSInfo = $False
     }
               
    If ($GPSInfo -eq $true)
     {
      $LonEW = $Encode.GetString($img.GetPropertyItem(3).Value)
     
      [Double]$LatDeg, [Double]$LatMin, [Double]$LatSec = Get-GPSDetails -FileNameWithGPSDetails $FileName -ID 2
      [Double]$LonDeg, [Double]$LonMin, [Double]$LonSec = Get-GPSDetails -FileNameWithGPSDetails $FileName -ID 4
   
      if([Double]$LatMin -lt 0 -or [Double]$LatSec -lt 0 -or [Double]$LonMin -lt 0 -or [Double]$LonSec -lt 0)
       {
        $Alert = $true
        Write-Verbose "    * Error: The picture $FileName has incorrect GPS Data. An alert has been created, it will be mentioned on the HTML page."
      }

      $GPSLat = "$([int]$LatDeg)º $([int]$LatMin)' $([int]$LatSec)$([char]34) $LatNS"
      $GPSLon = "$([int]$LonDeg)º $([int]$LonMin)' $([int]$LonSec)$([char]34) $LonEW"

      Write-Verbose "    The picture $FileName has the following GPS coordinates:"
      Write-Verbose "       $GPSLat"       
      Write-Verbose "       $GPSLon"

    # =============================================================================================================================================
    # Convert the latitude and longitude to numbers that Google Maps recognizes.
    # =============================================================================================================================================

      $LatOrt = 0
      $LonOrt = 0

      If ($LatNS -eq 'S')
       {
        $LatOrt = "-"   
       }
      If ($LonEW -eq 'W')
       {
        $LonOrt = "-"
       }

      $LatDec = ($LatDeg + ($LatMin/60) + ($LatSec/3600))
      $LonDec = ($LonDeg + ($LonMin/60) + ($LonSec/3600))

      $LatOrt = $LatOrt + $LatDec
      $LonOrt = $LonOrt + $LonDec

    # =============================================================================================================================================
    # The numbers that where returned contained a decimal comma instead of a decimal point.
    # So the en-US culture is forced to get the correct number notation.
    # =============================================================================================================================================
   
      $LatOrt = $LatOrt.ToString([cultureinfo]::GetCultureInfo('en-US'))
      $LonOrt = $LonOrt.ToString([cultureinfo]::GetCultureInfo('en-US'))

      Write-Verbose "    The picture $FileName has the following decimal coordinates:"
      Write-Verbose "      $LatOrt"
      Write-Verbose "      $LonOrt"
    }
     else
    {
     
   # =============================================================================================================================================
   # Ohoh... No GPS information in this picture.
   # =============================================================================================================================================
     
     Write-Verbose "    The picture $FileName does not contain GPS information."
     $LatOrt = "1024"
     $LonOrt = "1024"
    }

    Return $LatOrt,$LonOrt,$GPSLat,$GPSLon
  }

  # =============================================================================================================================================
  # Add assemblies.
  # =============================================================================================================================================
 
  Clear-Host

   
  Add-Type -AssemblyName System.Web
  Add-Type -AssemblyName System.Drawing
 
  Get-EXIFDataFromJPGFile -FileName "C:\tmp\WP_20170426_15_30_51_Pro.jpg"


So thanks for Stargeek and Phil for your help. It is appreciated.

With kind regards,
TheStingPilot



YYS

Hello everyone !
Need a bit of help down here )
Cant extract GPS data from a jpg file, it shows me everything exept things that i need )
Could you help me with that ?)

StarGeek

Run this command on the file
exiftool -g1 -a -s -GPS* /path/to/file/

If it doesn't show any GPS coordinates, then they simply don't exist in that file.
* Did you read FAQ #3 and use the command listed there?
* Please use the Code button for exiftool code/output.
 
* Please include your OS, Exiftool version, and type of file you're processing (MP4, JPG, etc).

Hyddo

Thank you for this tip "exiftool -g1 -a -s -GPS* /path/to/file/", it worked perfectly in my case. I was stuck with this jpg file on the pc in my greek flat. Now it's finally sorted.

Hyddo

Quote from: Hyddo on September 17, 2020, 09:17:39 AM
Thank you for this tip "exiftool -g1 -a -s -GPS* /path/to/file/", it worked perfectly in my case. I was stuck with this jpg file on the pc in my greek flat. Now it's finally sorted.

Seems like I have another issue, I will describe it in a new thread in a bit