「Java 开发工具」Java 解析图片详细(地理位置)信息

359 阅读5分钟

一、前言

通过Java 技术框架获取图片的详细信息。(① 手机-相册-图片详细;② 图片-右键-属性-详细信息;)

image.png

二、实操

  1. 解析图片的常用信息,包括地理位置信息;
  2. 通过第三方API(例如百度/高德/腾讯地图开放API等)根据经纬度获取具体的地址;
(1)引入Maven依赖
<!-- 核心:图片解析工具类-->
<dependency>
    <groupId>com.drewnoakes</groupId>
    <artifactId>metadata-extractor</artifactId>
    <version>2.16.0</version>
</dependency>

<!-- 辅助:工具类 hutool :https://mvnrepository.com/artifact/cn.hutool/hutool-all -->
<dependency>
    <groupId>cn.hutool</groupId>
    <artifactId>hutool-all</artifactId>
    <version>5.6.6</version>
</dependency>
(2)Java 完整实例代码
package edu.study.module.up.util.image;

import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson.JSONObject;
import com.drew.imaging.ImageMetadataReader;
import com.drew.imaging.ImageProcessingException;
import com.drew.metadata.Directory;
import com.drew.metadata.Metadata;
import com.drew.metadata.Tag;

import java.io.File;
import java.io.IOException;

/**
 * 解析图片详细(拍摄时间,拍摄地址,标记等)信息
 */
public class ImageUtils {

    public static void main(String[] args) throws Exception {
        // 准备一张带有地理位置信息的图片(方便测试是否可以读取到图片的地理位置经纬度信息)
        File file = new File("C:\\Users\\drew\\Pictures\\Saved Pictures\\test.jpg");
        readImageInfo(file);
    }

    /**
     * 提取照片里面的信息
     *
     * @param file 照片文件
     * @throws ImageProcessingException
     * @throws Exception
     */
    private static void readImageInfo(File file) throws ImageProcessingException, Exception {
        Metadata metadata = ImageMetadataReader.readMetadata(file);

        System.out.println("---打印全部详情---");
        for (Directory directory : metadata.getDirectories()) {
            for (Tag tag : directory.getTags()) {
                System.out.format("[%s] - %s = %s\n", directory.getName(), tag.getTagName(), tag.getDescription());
            }
            if (directory.hasErrors()) {
                for (String error : directory.getErrors()) {
                    System.err.format("ERROR: %s", error);
                }
            }
        }

        System.out.println("--打印常用信息---");

        Double lat = null;
        Double lng = null;
        for (Directory directory : metadata.getDirectories()) {
            for (Tag tag : directory.getTags()) {
                String tagName = tag.getTagName();  //标签名
                String desc = tag.getDescription(); //标签信息
                if (tagName.equals("Image Height")) {
                    System.err.println("图片高度: " + desc);
                } else if (tagName.equals("Image Width")) {
                    System.err.println("图片宽度: " + desc);
                } else if (tagName.equals("Date/Time Original")) {
                    System.err.println("拍摄时间: " + desc);
                } else if (tagName.equals("GPS Latitude")) {
                    System.err.println("纬度 : " + desc);
                    System.err.println("纬度(度分秒格式) : " + pointToLatlong(desc));
                    lat = latLng2Decimal(desc);
                } else if (tagName.equals("GPS Longitude")) {
                    System.err.println("经度: " + desc);
                    System.err.println("经度(度分秒格式): " + pointToLatlong(desc));
                    lng = latLng2Decimal(desc);
                }
            }
        }
        System.err.println("--经纬度转地址--");
        //经纬度转地主使用百度api
        convertGpsToLoaction(lat, lng);


    }

    /**
     * 经纬度格式  转换为  度分秒格式 ,如果需要的话可以调用该方法进行转换
     *
     * @param point 坐标点
     * @return
     */
    public static String pointToLatlong(String point) {
        Double du = Double.parseDouble(point.substring(0, point.indexOf("°")).trim());
        Double fen = Double.parseDouble(point.substring(point.indexOf("°") + 1, point.indexOf("'")).trim());
        Double miao = Double.parseDouble(point.substring(point.indexOf("'") + 1, point.indexOf("\"")).trim());
        Double duStr = du + fen / 60 + miao / 60 / 60;
        return duStr.toString();
    }

    /***
     * 经纬度坐标格式转换(* °转十进制格式)
     * @param gps
     */
    public static double latLng2Decimal(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;
    }

    /**
     * api_key:注册的百度api的key
     * coords:经纬度坐标
     * http://api.map.baidu.com/reverse_geocoding/v3/?ak="+api_key+"&output=json&coordtype=wgs84ll&location="+coords
     * <p>
     * 经纬度转地址信息
     *
     * @param gps_latitude  纬度
     * @param gps_longitude 经度
     */
    private static void convertGpsToLoaction(double gps_latitude, double gps_longitude) throws IOException {
        String apiKey = "YNxcSCAphFvuPD4LwcgWXwC3SEZZc7Ra";

        String res = "";
        String url = "http://api.map.baidu.com/reverse_geocoding/v3/?ak=" + apiKey
                + "&output=json&coordtype=wgs84ll&location=" + (gps_latitude + "," + gps_longitude);
        System.err.println("【url】" + url);

        res = HttpUtil.get(url);
        JSONObject object = JSONObject.parseObject(res);
        if (object.containsKey("result")) {
            JSONObject result = object.getJSONObject("result");
            if (result.containsKey("addressComponent")) {
                JSONObject address = object.getJSONObject("result").getJSONObject("addressComponent");
                System.err.println("拍摄地点:" + address.get("country") + " "
                        + address.get("province") + " " + address.get("city") + " " + address.get("district") + " "
                        + address.get("street") + " " + result.get("formatted_address") + " " + result.get("business"));
            }
        }
    }

}
(3)测试
① 准备图片

准备一张带有地理位置信息的图片(见附件test.jpg):

  1. 设置【拍照-保存地理信息】;
  2. 微信-发送图片-勾选【原图】到 文件传输助手;
  3. 保存到电脑位置上,修改号 代码里面的 图片在电脑上的地址;
② 测试结果
---打印全部详情---
[JPEG] - Compression Type = Baseline
[JPEG] - Data Precision = 8 bits
[JPEG] - Image Height = 3000 pixels
[JPEG] - Image Width = 4000 pixels
[JPEG] - Number of Components = 3
[JPEG] - Component 1 = Y component: Quantization table 0, Sampling factors 2 horiz/2 vert
[JPEG] - Component 2 = Cb component: Quantization table 1, Sampling factors 1 horiz/1 vert
[JPEG] - Component 3 = Cr component: Quantization table 1, Sampling factors 1 horiz/1 vert
[Exif IFD0] - Image Width = 4000 pixels
[Exif IFD0] - Model = Redmi Note 7 Pro
[Exif IFD0] - Image Height = 3000 pixels
[Exif IFD0] - Orientation = Right side, top (Rotate 90 CW)
[Exif IFD0] - Date/Time = 2022:01:06 09:22:27
[Exif IFD0] - YCbCr Positioning = Center of pixel array
[Exif IFD0] - Resolution Unit = Inch
[Exif IFD0] - X Resolution = 72 dots per inch
[Exif IFD0] - Y Resolution = 72 dots per inch
[Exif IFD0] - Make = Xiaomi
[Exif SubIFD] - Unknown tag (0x9aaa) = [2176 values]
[Exif SubIFD] - ISO Speed Ratings = 192
[Exif SubIFD] - Exposure Program = Program normal
[Exif SubIFD] - F-Number = f/1.8
[Exif SubIFD] - Exposure Time = 1/33 sec
[Exif SubIFD] - Unknown tag (0x9999) = {"mirror":false,"?sensor_type":"rear","Hdr":"off","OpMode":32769,"AIScene":0,"FilterId":66048,"ZoomMultiple":1}
[Exif SubIFD] - Sensing Method = (Not defined)
[Exif SubIFD] - Unknown tag (0x8895) = 0
[Exif SubIFD] - Sub-Sec Time Digitized = 451999
[Exif SubIFD] - Sub-Sec Time Original = 451999
[Exif SubIFD] - Sub-Sec Time = 451999
[Exif SubIFD] - Focal Length = 4.7 mm
[Exif SubIFD] - Flash = Flash did not fire, auto
[Exif SubIFD] - White Balance = D65
[Exif SubIFD] - Metering Mode = Center weighted average
[Exif SubIFD] - Scene Capture Type = Standard
[Exif SubIFD] - Focal Length 35 = 25 mm
[Exif SubIFD] - Max Aperture Value = f/1.8
[Exif SubIFD] - Date/Time Digitized = 2022:01:06 09:22:27
[Exif SubIFD] - Exposure Bias Value = 0 EV
[Exif SubIFD] - Exif Image Height = 3000 pixels
[Exif SubIFD] - White Balance Mode = Auto white balance
[Exif SubIFD] - Date/Time Original = 2022:01:06 09:22:27
[Exif SubIFD] - Brightness Value = 0.86
[Exif SubIFD] - Exif Image Width = 4000 pixels
[Exif SubIFD] - Exposure Mode = Auto exposure
[Exif SubIFD] - Aperture Value = f/1.8
[Exif SubIFD] - Components Configuration = YCbCr
[Exif SubIFD] - Color Space = sRGB
[Exif SubIFD] - Scene Type = Directly photographed image
[Exif SubIFD] - Shutter Speed Value = 1/33 sec
[Exif SubIFD] - Exif Version = 2.20
[Exif SubIFD] - FlashPix Version = 1.00
[Interoperability] - Interoperability Index = Recommended Exif Interoperability Rules (ExifR98)
[Interoperability] - Interoperability Version = 1.00
[GPS] - GPS Latitude Ref = N
[GPS] - GPS Latitude = 22° 51' 55.45"
[GPS] - GPS Longitude Ref = E
[GPS] - GPS Longitude = 113° 4' 50.53"
[GPS] - GPS Altitude Ref = Sea level
[GPS] - GPS Altitude = 0 metres
[GPS] - GPS Time-Stamp = 01:22:23.000 UTC
[GPS] - GPS Processing Method = CELLID
[GPS] - GPS Date Stamp = 2022:01:06
[Exif Thumbnail] - Thumbnail Offset = 3425 bytes
[Exif Thumbnail] - Orientation = Right side, top (Rotate 90 CW)
[Exif Thumbnail] - Thumbnail Length = 12043 bytes
[Exif Thumbnail] - Compression = JPEG (old-style)
[Exif Thumbnail] - Resolution Unit = Inch
[Exif Thumbnail] - X Resolution = 72 dots per inch
[Exif Thumbnail] - Y Resolution = 72 dots per inch
[Exif Thumbnail] - Exif Image Height = 240 pixels
[Exif Thumbnail] - Exif Image Width = 320 pixels
[Huffman] - Number of Tables = 4 Huffman tables
[File Type] - Detected File Type Name = JPEG
[File Type] - Detected File Type Long Name = Joint Photographic Experts Group
[File Type] - Detected MIME Type = image/jpeg
[File Type] - Expected File Name Extension = jpg
[File] - File Name = test.jpg
[File] - File Size = 7212261 bytes
[File] - File Modified Date = 星期四 一月 06 09:23:27 +08:00 2022
--打印常用信息---
图片高度: 3000 pixels
图片宽度: 4000 pixels
图片宽度: 4000 pixels
图片高度: 3000 pixels
拍摄时间: 2022:01:06 09:22:27
纬度 : 22° 51' 55.45"
纬度(度分秒格式) : 22.865402777777778
经度: 113° 4' 50.53"
经度(度分秒格式): 113.08070277777777
--经纬度转地址--
【url】http://api.map.baidu.com/reverse_geocoding/v3/?ak=YNxcSCAphFvuPD4LwcgWXwC3SEZZc7Ra&output=json&coordtype=wgs84ll&location=22.865402777777778,113.08070277777777
拍摄地点:中国 广东省 佛山市 顺德区 龙洲西路 广东省佛山市顺德区龙洲西路75 
③ 温馨提示

为了防止图片泄露个人隐私数据(地理位置信息),建议如下:

  1. 拍照--设置--关闭【保存地理位置信息】;
  2. 涉及到拍照功能,建议限制授权【设置 使用中询问保存地理信息 或  关闭地理信息授权】功能;

至此,感谢阅读🙏

美女背景图2.png