用數位相機或手機拍的影像都會有個EXIF資訊,裡面會有很多資訊,上面是我寫的一個小程式可以抓出這些資訊,但是對我有用的就是上面幾個而已,所以只抓他們出來。我之前做過很多聲納二進位檔案的資料處理,所以寫這個程式不難!
如PhotoShop等軟體也有類似的讀取這些資訊的功能,但是多數軟體工程師都會希望自己寫這些程式,可以融入到自己的軟體中。大多數的資料項目要讀取都不難,但是顯然GPS的資料讀取讓網路上的工程師們頭痛不已怎麼讀都不對?下面就是某張影像在PhotoShop裡面顯示的經緯度,是我們參考的標準答案。
然後我們去讀取同檔案中相對以上資訊的Byte陣列如下:
我們很快可以看到相對應的度與分的數字,但是秒的部分卻考倒了幾乎所有工程師,我一開始當然也想偷懶,直接找到現成的原始碼,但是這一部份只看到一大堆討論,卻沒有看到結論?也許有吧?但是我不耐煩繼續Google爬文了,把它當作謎題自己來解!
簡單說就是要如何翻譯後段的164 156等等數字成為30.22與45.61啦!我試過把他們當作Single或Double資料型態去讀,結果都是沒意義的天文數字!直接讀Byte值則根本不是數字,不像前面的度與分。怎麼辦?其實可以嘗試的狀況也不多,我就試著將164 156 4 0當作一個四Byte的整數讀取,答案是302244!Bingo!原來他們是將秒也用整數儲存的!
簡單說,如果是30.2244秒就以整數302244儲存!讀出之後除以10000就是正確的秒數了!但是如果文件沒說清楚誰知道呢?真的很搞怪整人了!同理可證,183 245 6 0讀成四Byte整數就是456119,正確秒數是:45.6119。答案與PhotoShop軟體顯示的完全一樣還多兩位數。但是我的程式會自動把它們變成幾點幾度,方便用Google Maps查詢。
我可以破解這個數位資料的特殊寫法,功力來自我以前玩過很多特殊格式的二進位聲納資料,總算在此有用到了!就此分享給有此需要的軟體工程師們!
Structure PicInfo
Dim Camera As String
Dim Time As Date
Dim Lat As String
Dim Lon As String
Dim Orientation As Int16
Dim width As Int16, height As Int16
End Structure
Private Function getPicInfo(ByVal picFullPath As String) As PicInfo
Dim bmp As New Bitmap(picFullPath)
Dim p As New PicInfo
Dim B(47) As Byte
For Each pro As Imaging.PropertyItem In bmp.PropertyItems
Select Case pro.Id
Case 2
Array.Copy(pro.Value, 0, B, 0, 24)
Case 4
Array.Copy(pro.Value, 0, B, 24, 24)
Case 256
Dim q() As Byte = pro.Value
p.width = BitConverter.ToInt16(q, 0)
Case 257
Dim q() As Byte = pro.Value
p.height = BitConverter.ToInt16(q, 0)
Case 271
p.Camera = System.Text.Encoding.ASCII.GetString(pro.Value).Replace(Chr(0), "")
Case 36867
Dim s As String = System.Text.Encoding.ASCII.GetString(pro.Value).Replace(Chr(0), "")
Dim C() As String = s.Split(" ")
Dim D() As String = C(0).Split(":")
Dim K() As String = C(1).Split(":")
p.Time = New Date(Val(D(0)), Val(D(1)), Val(D(2)), Val(K(0)), Val(K(1)), Val(K(2)))
End Select
Next
Dim G(11) As Integer
For i As Integer = 0 To 11
G(i) = BitConverter.ToInt32(q, i * 4)
Next
Dim Lat As Double = G(0) + G(2) / 60.0 + G(4) / 10000 / 3600
Dim Lon As Double = G(6) + G(8) / 60.0 + G(10) / 10000 / 3600
p.Lat = Format(Lat, "00.00000")
p.Lon = Format(Lon, "000.00000")
Return p
End Function
限會員,要發表迴響,請先登入