Java 提取图片 GPS 信息

总结摘要
Java 提取图片 GPS 信息

需求

解析图片元数据,获取 GPS 数据,并根据经纬度在地图上定位到具体的省/市/县

解析图片元数据

引入metadata-extractor 依赖

1
2
3
4
5
<dependency>
    <groupId>com.drewnoakes</groupId>
    <artifactId>metadata-extractor</artifactId>
    <version>2.18.0</version>
</dependency>

解析图片元数据

1
2
File jpegFile = new File("D:\\MyCode\\JavaStudy\\JavaDemo\\Javabase\\IMG_20240620_193001.jpg");
Metadata metadata = ImageMetadataReader.readMetadata(jpegFile);

Metadata 对象中包含了图片的元数据。不同类型的数据在不同的 Directory 中,在 Directory 包含了具体的数据 Tag,Tag 是一个 key-value 类型

获取 GPS 信息

因为图片的元数据有很多,而我只需要用到 GPS,所以将 GPS 封装为对象

1
2
3
4
5
6
7
public class GpsData {

    private String longitude;  // 经度

    private String latitude;   // 纬度

}

调用第三方 api

添加 httputils 依赖

1
2
3
4
5
<dependency>
    <groupId>com.ejlchina</groupId>
    <artifactId>httputils</artifactId>
    <version>2.1.2</version>
</dependency>

使用高德的 api 接口,申请所需服务平台的 key,如果类型不对,调用会报错

alt text

高德开发者文档: https://lbs.amap.com/api/webservice/guide/api/georegeo#t5

alt text

完整代码

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110

public class GpsData {

    private String longitude;  // 经度

    private String latitude;   // 纬度

}

public class Main {

    static String key = "xxxx";

    public static void main(String[] args) throws Exception {

        File jpegFile = new File("D:\\MyCode\\JavaStudy\\JavaDemo\\Javabase\\IMG_20240620_193001.jpg");
        Metadata metadata = ImageMetadataReader.readMetadata(jpegFile);

        // 获取GPS信息
        GpsData gpsData = new GpsData();
        for (Directory directory : metadata.getDirectories()) {
            if (directory.getName().equalsIgnoreCase("GPS")) {
                for (Tag tag : directory.getTags()) {
                    if (tag.getTagName().equalsIgnoreCase("GPS Latitude")) {
                        gpsData.setLatitude(tag.getDescription());
                    }
                    if (tag.getTagName().equalsIgnoreCase("GPS Longitude")) {
                        gpsData.setLongitude(tag.getDescription());
                    }
                }
            }
        }
        System.out.println("gps:" + gpsData);

        // 获取具体的地址
        convertGpsToLocation(gpsData);
    }


    public static void convertGpsToLocation(GpsData gpsData) {
        double longitude = toDecimal(gpsData.getLongitude());
        double latitude = toDecimal(gpsData.getLatitude());
        System.out.println("longitude:" + longitude + " latitude:" + latitude);

        // 逆地理编码接口
        String url = "https://restapi.amap.com/v3/geocode/regeo?";

        HTTP http = HTTP.builder().baseUrl(url).build();

        Map<String, Object> params = new HashMap<>();
        params.put("key", key);
        params.put("location", "" + longitude + "," + latitude);
        HttpResult httpResult = http.sync(url).addUrlParam(params).get();

        if (httpResult.getStatus() == 200) {
            JSONObject jsonObject = httpResult.getBody().toJsonObject();
            System.out.println(jsonObject);

            JSONObject address = jsonObject.getJSONObject("regeocode").getJSONObject("addressComponent");
            System.out.println(address.get("country"));
            System.out.println(address.get("province"));
            System.out.println(address.get("city"));
            System.out.println(address.get("district"));
            System.out.println(address.get("township"));
        }

    }


    /**
     * 经纬度坐标格式转换: 十进制格式 转 度分秒
     * @param point 坐标点
     * @return
     */
    public static String toDMS(String point) {
        Double d = Double.parseDouble(point.substring(0, point.indexOf("°")).trim());
        Double m = Double.parseDouble(point.substring(point.indexOf("°") + 1, point.indexOf("'")).trim());
        Double s = Double.parseDouble(point.substring(point.indexOf("'") + 1, point.indexOf("\"")).trim());
        Double duStr = d + m / 60 + s / 60 / 60;
        return duStr.toString();
    }


    /**
     * 经纬度坐标格式转换: 度分秒 转 十进制格式
     * @param gps
     * @return
     */
    public static double toDecimal(String gps) {
        String a = gps.split("°")[0].replace(" ", "");
        String b = gps.split("°")[1].split("'")[0].replace(" ", "");
        String c = gps.split("°")[1].split("'")[1].replace(" ", "").replace("\"", "");
        double gps_dou = Double.parseDouble(a) + Double.parseDouble(b) / 60 + Double.parseDouble(c) / 60 / 60;
        return gps_dou;
    }
}

/**
运行结果:

gps:GpsData(longitude=113° 53' 7.74", latitude=22° 34' 27.87")
longitude:113.88548333333334 latitude:22.574408333333334
{"infocode":"10000","regeocode":{"formatted_address":"广东省深圳市宝安区西乡街道生力机电大厦","addressComponent":{"businessAreas":[{"name":"西乡","location":"113.880975,22.579020","id":"440306"},{"name":"新安","location":"113.895323,22.568951","id":"440306"}],"country":"中国","province":"广东省","citycode":"0755","city":"深圳市","adcode":"440306","streetNumber":{"number":"107国道19号","distance":"51.2658","street":"广深公路","location":"113.885921,22.574630","direction":"东北"},"towncode":"440306003000","district":"宝安区","neighborhood":{"name":[],"type":[]},"township":"西乡街道","building":{"name":[],"type":[]}}},"status":"1","info":"OK"}
中国
广东省
深圳市
宝安区
西乡街道

 */