之前在网上看见了图片中含义GPS信息的说法,兴起就写写代码尝试一下发现果然可以读到,只有图片中含义GPS信息才可以读到
原理:
将图片转换为二进制数据,然后根据二进制数据获取Drawing.Image对象,再对PropertyItems中ID为前30的数据进行处理
直接上代码:
#Region "读取图片中GPS点"
/*
''' <summary>
''' 传入图片二进制获取图片中的GPS坐标点
''' </summary>
''' <param name="path">图片路径</param>
''' <returns>返回坐标【纬度+经度】用"+"分割 取数组中第0和1个位置的值</returns>
*/
Public Function fnGPS(ByVal sFileContent As Byte()) As Strin
Dim strPro As String = "" /* 返回值 */
Dim chrGPSLatitudeRef As Char = "N" /* 暂定纬度N(北纬) */
Dim chrGPSLongitudeRef As Char = "E" /* 暂定经度为E(东经) */
For Each objItem As Drawing.Imaging.PropertyItem In GetImageFromStream(sFileContent).PropertyItems
/* 只取Id范围为0x0000到0x001e */
If objItem.Id >= Convert.ToInt32("0x0000", 16) And objItem.Id <= Convert.ToInt32("0x001e", 16) Then
Select Case objItem.Id
Case Convert.ToInt32("0x0000", 16)
/* GPSVersion */
Dim sVersion As String() = BitConverter.ToString(objItem.Value).Split("-")
For i As Integer = 0 To sVersion.Length - 1
If IsNumeric(sVersion(i)) Then
sVersion(i) = Integer.Parse(sVersion(i))
End If
Next
Dim sreVersion As String = String.Join(".", sVersion)
strPro += "GPS版本:" + sreVersion
Case Convert.ToInt32("0x0001", 16)
/* 透过BitConverter, 将Value转成Char(N / S) */
/* 经纬度,此值在后续的Longitude计算上会用到 */
chrGPSLatitudeRef = BitConverter.ToChar(objItem.Value, 0)
Case Convert.ToInt32("0x0002", 16)
If objItem.Value.Length = 24 Then
Dim d As Double = BitConverter.ToUInt32(objItem.Value, 0) * 1D / BitConverter.ToUInt32(objItem.Value, 4)
Dim m As Double = BitConverter.ToUInt32(objItem.Value, 8) * 1D / BitConverter.ToUInt32(objItem.Value, 12)
Dim s As Double = BitConverter.ToUInt32(objItem.Value, 16) * 1D / BitConverter.ToUInt32(objItem.Value, 20)
/* 计算纬度数值, 如果是南纬, 要乘上(-1) */
Dim dblGPSLatitude As Double = (((s / 60 + m) / 60) + d) * IIf(chrGPSLatitudeRef.ToString.Equals("N"), 1, -1)
strPro += vbCrLf + "经纬度:" + dblGPSLatitude.ToString + ","
End If
Case Convert.ToInt32("0x0003", 16)
/* 透过BitConverter, 将Value转成Char(E/W) */
/* 经纬度,此值在后续的Longitude计算上会用到 */
chrGPSLongitudeRef = BitConverter.ToChar(objItem.Value, 0)
Case Convert.ToInt32("0x0004", 16)
If objItem.Value.Length = 24 Then
Dim d As Double = BitConverter.ToUInt32(objItem.Value, 0) * 1D / BitConverter.ToUInt32(objItem.Value, 4)
Dim m As Double = BitConverter.ToUInt32(objItem.Value, 8) * 1D / BitConverter.ToUInt32(objItem.Value, 12)
Dim s As Double = BitConverter.ToUInt32(objItem.Value, 16) * 1D / BitConverter.ToUInt32(objItem.Value, 20)
/* 计算经度数值, 如果是西经, 要乘上(-1) */
Dim dblGPSLatitude As Double = (((s / 60 + m) / 60) + d) * IIf(chrGPSLongitudeRef.ToString.Equals("E"), 1, -1)
strPro += dblGPSLatitude.ToString
End If
Case Convert.ToInt32("0x0005", 16)
Dim strAltitude As String = IIf(BitConverter.ToBoolean(objItem.Value, 0), "1", "0")
strPro += vbCrLf + "海拔参考值:" + strAltitude
Case Convert.ToInt32("0x0006", 16)
If objItem.Value.Length = 8 Then
Dim dblAltitude As Double = BitConverter.ToUInt32(objItem.Value, 0) * 1D / BitConverter.ToUInt32(objItem.Value, 4)
strPro += vbCrLf + "海拔:" + dblAltitude.ToString
End If
End Select
End If
Next
Return strPro
End Function
/*
''' <summary>
''' 根据二进制数据获取Drawing.Image对象
''' </summary>
''' <param name="ImageStream"></param>
''' <returns></returns>
*/
Public Function GetImageFromStream(ByVal ImageStream As Byte()) As Drawing.Image
Dim objImage As Drawing.Image = Nothing
If (ImageStream Is Nothing) Then
Return Nothing
End If
Dim index As Integer = 0
If (((ImageStream(0) = &H15) AndAlso (ImageStream(1) = &H1C)) AndAlso (ImageStream.Length >= 80)) Then
index = &H4E
Do While (index < (ImageStream.Length - 1))
If ((ImageStream(index) = &H42) AndAlso (ImageStream((index + 1)) = &H4D)) Then
Exit Do
End If
index += 1
Loop
If ((ImageStream(index) <> &H42) OrElse (ImageStream((index + 1)) <> &H4D)) Then
index = &H87
End If
End If
Try
Dim stream As New MemoryStream(ImageStream, index, (ImageStream.Length - index))
objImage = Drawing.Image.FromStream(stream)
Catch obj1 As Exception
Return Nothing
End Try
Return objImage
End Function
#End Region
在主函数中的使用
Dim sFileContent As Byte() = New Byte(UpPhoto.PostedFile.ContentLength) {}
UpPhoto.PostedFile.InputStream.Read(sFileContent, 0, UpPhoto.PostedFile.ContentLength)
fnGPS(sFileContent)
其中UpPhoto是type="file"的上传控件
'''<summary>
'''UpPhoto 控件。
'''</summary>
'''<remarks>
'''自动生成的字段。
'''若要进行修改,请将字段声明从设计器文件移到代码隐藏文件。
'''</remarks>
Protected WithEvents UpPhoto As Global.System.Web.UI.HtmlControls.HtmlInputFile
<input id="UpPhoto" runat="server" name="File1" size="43" style="width: 374px; height: 22px; padding-left: 10px;" type="file/>
测试的效果图,只要图片中有GPS数据,就可以获取到拍摄的GPS和海拔
这里最后再推荐两个辅助验证网站
1. 图片EXIF信息获取可以验证获取的GPS信息是否正确和查看其它图片包含信息
2. 拾取坐标系统可以验证获取的GPS是哪个位置的