【问题标题】:Extracting GPS numerical values from byte array using PowerShell使用 PowerShell 从字节数组中提取 GPS 数值
【发布时间】:2017-07-17 05:59:24
【问题描述】:

我希望从图像文件的 EXIF 属性中提取 GPS 位置数据。我正在使用 System.Drawing.Bitmap 类来获取原始值。我能够提取我正在寻找的值,但它们以字节或可能的字节数组的形式返回,我需要帮助将字节转换为合理的数字。这是我目前所拥有的:

$imagePath = 'C:\temp\picTest\WP_20150918_003.jpg'
$imageProperties = New-Object -TypeName System.Drawing.Bitmap -ArgumentList $imagePath

EXIF GPS Tag Reference我知道我要找的属性标签是:

  • 0x0001 - GPSLatitudeRef - 指示纬度是北纬还是南纬。
  • 0x0002 - GPSLatitude - 表示纬度。
  • 0x0003 - GPSLongitudeRef - 指示经度是东经还是西经。
  • 0x0004 - GPSLongitude - 表示经度。
  • 0x0005 - GPSAltitudeRef - 指示用作参考高度的高度。
  • 0x0006 - GPSAltitude - 指示基于 GPSAltitudeRef 中的参考的高度。

首先我得到 GPSLatitudeRef

$imageProperies.PropertyItems | ? ID -eq 0x0001

我得到:

 Id Len Type Value
-- --- ---- -----
 1   2    2 {78, 0}

根据System.Drawing library 的 MSDN 文档,“2”的 PropertyItem.Type 是 ASCII。

我将值加载到变量中:

$GPSLatRef = $imageProperties.PropertyItems| Where ID -eq 0x0001
$GPSLatRef = $GPSLatRef.Value
$GPSLatRef
78
0

Get-Member 变量返回类型 System.Byte。我知道如何将字节转换回 ASCII:

$GPSLatRef = [System.Text.Encoding]::ASCII.GetString($GPSLatRef.Value)
$GPSLatRef

返回:

N

但是 GPSLatitude 值 (0x0002) 对我来说很棘手:

$imageProperies.PropertyItems | ? ID -eq 0x0002

返回:

Id Len Type Value
-- --- ---- -----
 2  24    5 {37, 0, 0, 0...}

将值加载到变量中:

$GPSLatitiude = $imageProperties.PropertyItems| Where ID -eq 0x0002
$GPSLatitiude.Value

返回值为:

37
0
0
0
1
0
0
0
40
0
0
0
1
0
0
0
220
182
0
0
232
3
0
0

根据上面引用的 MSDN 文档,PropertyItem.Type 为“5” "指定 Value 数据成员是 无符号长整数的数组每对代表一个分数;第一个整数是分子和第二个整数是分母。

在 Windows 资源管理器中查看文件本身的属性,我看到十进制形式的 GPS 位置值。

"37;40;46.812000000005156"

根据上面的值数据,以及文档中对数据类型的描述,并与 Windows 资源管理器中的十进制值进行比较,我可以推测 $GPSLatitude.Value 实际上向我显示了三个不同的两个整数集合。例如,

37
0
0
0

= 37

1
0
0
0

= 1

和 37/1 = 37,它与 Windows 资源管理器中的十进制值匹配,所以我知道我在正确的轨道上。

如何从 GPSLatitude 属性中找到的(数组?)字节中拆分三组值?尽管字节中的数据被描述为长整数,但 Windows 资源管理器中显示的十进制值显示结果可能是小数点右侧有 15 位数字的数字,这让我认为除法的乘积来自属性值的字节中的两个长整数可能需要存储在 [double] 或 [decimal] 中?

【问题讨论】:

    标签: arrays powershell gps byte type-conversion


    【解决方案1】:

    这个 sn-p 将为您提供纬度和经度详细信息,我正在使用 BitConverter 从字节数组中提取数据:

    [double]$LatDegrees = (([System.BitConverter]::ToInt32( $imageProperties.GetPropertyItem(2).Value, 0)) / ([System.BitConverter]::ToInt32( $imageProperties.GetPropertyItem(2).Value, 4)));
    [double]$LatMinutes = ([System.BitConverter]::ToInt32( $imageProperties.GetPropertyItem(2).Value, 8)) / ([System.BitConverter]::ToInt32( $imageProperties.GetPropertyItem(2).Value, 12));
    [double]$LatSeconds = ([System.BitConverter]::ToInt32( $imageProperties.GetPropertyItem(2).Value, 16)) / ([System.BitConverter]::ToInt32( $imageProperties.GetPropertyItem(2).Value, 20));
    [double]$LonDegrees = (([System.BitConverter]::ToInt32( $imageProperties.GetPropertyItem(4).Value, 0)) / ([System.BitConverter]::ToInt32( $imageProperties.GetPropertyItem(4).Value, 4)));
    [double]$LonMinutes = ([System.BitConverter]::ToInt32( $imageProperties.GetPropertyItem(4).Value, 8)) / ([System.BitConverter]::ToInt32( $imageProperties.GetPropertyItem(4).Value, 12));
    [double]$LonSeconds = ([System.BitConverter]::ToInt32( $imageProperties.GetPropertyItem(4).Value, 16)) / ([System.BitConverter]::ToInt32( $imageProperties.GetPropertyItem(4).Value, 20));
     "Latitude: $LatDegrees;$LatMinutes;$LatSeconds"
     "Longitude: $LonDegrees;$LonMinutes;$LonSeconds"
    

    【讨论】:

    • 谢谢 - 我相信这是有道理的,让我确保我理解:这些值是长整数,因此长 32 位,因此长 4 字节。所以括号中的参考号是我们正在转换的 int32 数组中的起始字节。我得到了它。我唯一的问题是,为什么在我的示例中,Windows 资源管理器中显示的 GPS 纬度秒的十进制值是“46.812000000005156”,但上面 [double]$LatSeconds 的乘积是“46.812”。出于我的目的,不太精确的值实际上是有效的,但我希望了解其中的区别。
    猜你喜欢
    • 2015-04-08
    • 2017-03-02
    • 2013-03-15
    • 1970-01-01
    • 2016-01-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-05-30
    相关资源
    最近更新 更多