在蘋果手機上,我們只要開啟定位服務,拍照後便能在相簿中找到地圖,地圖上顯示著在各地拍攝的相片。網站上這種顯示方式也並不少見,例如 Flickr、即將關閉的 Panoramio 等。
作為地圖愛好者,每每看到地圖就激動不已,就想若能在自己部落格上也這麼顯示,那該多好!
相片的地理位置資訊,是通過手機等裝置的 GPS 模組記錄的,並在其圖片檔案的 EXIF 資料,保留了這些位置資訊。
使用七牛做部落格圖床以來,其圖片處理 API 為各種顯示需求提供了便利,這其中有個可以獲取圖片 EXIF 資訊的 API,可以很方便的獲取到圖片的 EXIF 資訊,而 EXIF 包含的 GPS 位置資訊,則可以實現以上所提到的效果。
###實現流程
EXIF 為位置資訊保留了經緯座標、海拔等,將它轉成實際地址資訊,或者顯示到地圖上,還需要配合一個地圖 API,在此就以高德地圖為例。
實現流程大致如下:
- 請求資料:利用七牛 API 請求獲取圖片的 GPS 資訊
- 轉換座標:因相片的座標資料是以 WGS84 座標系統為準的,得轉換座標
- 顯示地址:通過高德地圖 API 實現
###獲取座標
我們還是以一張圖片為例,來分析下如何實現。
上圖是在汕頭市澄海區蓮下鎮渡亭村蓮陽河畔拍的花,其圖片地址如下:
source.fooleap.org/show-photo-…
那麼,七牛圖片 EXIF 資訊的介面如下:
source.fooleap.org/show-photo-…
直接用瀏覽器開啟,可以很方便地找到所有 GPS 開頭的屬性。其中,海拔等資料可以忽略掉,位置資訊最為重要的是經緯座標,即以下四個值:
"GPSLatitude": {
"val": "23, 29, 10.91",
"type": 5
},
"GPSLatitudeRef": {
"val": "N",
"type": 2
},
"GPSLongitude": {
"val": "116, 46, 36.49",
"type": 5
},
"GPSLongitudeRef": {
"val": "E",
"type": 2
}
}複製程式碼
那麼這個座標為 23°29’10.91”N, 116°46’36.49”E,也就是北緯 24 度 29 分 10.91 秒,東經 116 度 46 分 36.49 秒。
在各種網際網路地圖上,座標是以度為單位的,東經北緯為正值,西經南緯為負值。這裡需要將度分秒的經緯度轉換以度為單位的,因度分秒之間為 60 進位制,故轉換公式為:度分秒 = 度 + 分 / 60 + 秒 / (60 * 60)
計算後得出上面的座標約為 116.776803, 23.486364,這是一個 WGS84 座標。
座標轉換此前已經說過不少了,因在網頁上使用,直接採用 coordtransform 模組即可,以上座標轉換為 GCJ02 是 116.781381, 23.483788。
可以使用高德的座標拾取系統,按座標搜尋一下,驗證結果是否正確。
以上過程使用 JS 實現程式碼如下,需引入 coordtransform 模組。
var xhr = new XMLHttpRequest();
xhr.open('GET', 'http://source.fooleap.org/show-photo-location-on-map-with-qiniu-and-amap-api.jpg?exif', true);
xhr.onreadystatechange = function() {
if (xhr.readyState == 4 && xhr.status == 200)
{
var data = JSON.parse(xhr.responseText);
if ( !!data.GPSLongitude ) {
var olat = data.GPSLatitude.val.split(', ');
var olng = data.GPSLongitude.val.split(', ');
var lat=0, lng=0, coord;
for( var i = 0; i < olat.length; i++ ){
lat += olat[i] / Math.pow(60, i);
lng += olng[i] / Math.pow(60, i);
}
lat = data.GPSLatitudeRef.val == 'S' ? -lat: lat;
lng = data.GPSLongitudeRef.val == 'W' ? -lng: lng;
coord = coordtransform.wgs84togcj02(lng, lat).join(',');
}
}
}
xhr.send();複製程式碼
獲取圖片地址資訊
有了座標就有了地理位置,有了地理位置就知道是什麼地方。高德地圖逆地理編碼 API 正在招手:「給我一個座標,我將還你一個詳細地址。」
根據文件,最基本的只需 location 引數傳個座標即可返回地址資訊。此 API 還可批量獲取,可以根據自己需求傳入可選的引數。
以上面獲取的座標為例:
http://restapi.amap.com/v3/geocode/regeo?location=116.781381,23.48378&key=使用者的key>複製程式碼
請求後返回的 JSON 如下,具體返回的引數的詳細說明參考文件。
{
"status": "1",
"info": "OK",
"infocode": "10000",
"regeocode": {
"formatted_address": "廣東省汕頭市澄海區蓮下鎮渡亭村",
"addressComponent": {
"country": "中國",
"province": "廣東省",
"city": "汕頭市",
"citycode": "0754",
"district": "澄海區",
"adcode": "440515",
"township": "蓮下鎮",
"towncode": "440515102000",
"neighborhood": {
"name": [],
"type": []
},
"building": {
"name": [],
"type": []
},
"streetNumber": {
"street": "文明路",
"number": "159號",
"location": "116.78592,23.48872",
"direction": "東北",
"distance": "718.365"
},
"businessAreas": [
[]
]
}
}
}複製程式碼
準確度一般般,到鄉(鎮、街道)這一級基本沒問題。我們也不需要太準確的資訊,畢竟定位資訊有時候還是挺隱私的。
顯示相片地圖
將相片顯示在地圖上,這似乎才是初衷,在這裡,我將它分成兩部分,一部分是靜態地圖,一部分是動態地圖。
靜態地圖
將圖片顯示到靜態地圖上面,需要用到的高德地圖 API 是靜態地圖 API。
根據高德的文件,自定義標註(marker)圖片只能支援 PNG 格式,需要多來一張圖片嗎?不需要,這裡可以直接用七牛圖片處理 API,將原圖調下大小並指定輸出格式。
http://source.fooleap.org/show-photo-location-on-map-with-qiniu-and-amap-api.jpg?imageView2/1/w/100/h/100/format/png複製程式碼
上面的連結是輸出等比縮放並居中裁剪的 100x100 PNG 格式圖片,然而應用到高德介面還是出錯了。我嘗試在最後再加上 .png,結果成功,這意味著高德是以字尾名判斷檔案格式的,也是醉了。
http://restapi.amap.com/v3/staticmap?zoom=12&size=640*427&scale=2&markers=-1,http://source.fooleap.org/show-photo-location-on-map-with-qiniu-and-amap-api.jpg?imageView2/1/w/100/h/100/format/png.png,0:116.781381,23.48378&key=使用者的key>複製程式碼
以上拼湊出的連結顯示如下。
高德靜態地圖 API 一樣支援批量,具體可檢視文件。
動態地圖
想要在網頁中實現跟蘋果相簿地圖差不多樣式且可控的地圖,這就得用到高德地圖 JS API,主要是用到點標記,這裡就不多廢話了,直接上圖。
推薦閱讀: