zl程序教程

您现在的位置是:首页 >  后端

当前栏目

Java获取照片的Exif信息,并解析GPS

JAVA 获取 解析 信息 照片 GPS
2023-09-27 14:26:27 时间

Java获取照片的Exif信息,并解析GPS

❤️ 这篇博客将介绍什么EXIF,以及如何用Java语言读取Exif信息,并转换经纬度为位置信息;❤️

1. 效果图

Exif包含的信息很多,示例如下:

[JPEG] - Compression Type = Baseline
[JPEG] - Data Precision = 8 bits
[JPEG] - Image Height = 3840 pixels
[JPEG] - Image Width = 1744 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
[JFIF] - Version = 1.1
[JFIF] - Resolution Units = inch
[JFIF] - X Resolution = 96 dots
[JFIF] - Y Resolution = 96 dots
[JFIF] - Thumbnail Width Pixels = 0
[JFIF] - Thumbnail Height Pixels = 0
[Exif IFD0] - Image Width = 1744 pixels
[Exif IFD0] - Image Height = 3840 pixels
[Exif IFD0] - Bits Per Sample = 8 8 8 bits/component/pixel
[Exif IFD0] - Make = HUAWEI
[Exif IFD0] - Model = ELS-AN00
[Exif IFD0] - Orientation = Unknown (0)
[Exif IFD0] - X Resolution = 72 dots per inch
[Exif IFD0] - Y Resolution = 72 dots per inch
[Exif IFD0] - Resolution Unit = Inch
[Exif IFD0] - Software = ELS-AN00 11.0.0.176(C00E170R3P6)
[Exif IFD0] - Date/Time = 2021:05:21 07:18:02
[Exif IFD0] - YCbCr Positioning = Center of pixel array
[Exif IFD0] - Device Setting Description = 105 112 112 0
[Exif SubIFD] - Document Name =
[Exif SubIFD] - Exposure Time = 2049/500000 sec
[Exif SubIFD] - F-Number = f/1.8
[Exif SubIFD] - Exposure Program = Program normal
[Exif SubIFD] - ISO Speed Ratings = 50
[Exif SubIFD] - Exif Version = 2.10
[Exif SubIFD] - Date/Time Original = 2021:05:21 07:18:02
[Exif SubIFD] - Date/Time Digitized = 2021:05:21 07:18:02
[Exif SubIFD] - Components Configuration = YCbCr
[Exif SubIFD] - Compressed Bits Per Pixel = 0.95 bits/pixel
[Exif SubIFD] - Shutter Speed Value = 1/999963864 sec
[Exif SubIFD] - Aperture Value = f/1.8
[Exif SubIFD] - Brightness Value = 0.0
[Exif SubIFD] - Exposure Bias Value = 0 EV
[Exif SubIFD] - Max Aperture Value = f/1.8
[Exif SubIFD] - Metering Mode = Multi-segment
[Exif SubIFD] - White Balance = Daylight
[Exif SubIFD] - Flash = Flash did not fire
[Exif SubIFD] - Focal Length = 4.4 mm
[Exif SubIFD] - Makernote = 65 117 116 111 0
[Exif SubIFD] - Sub-Sec Time = 242921
[Exif SubIFD] - Sub-Sec Time Original = 242921
[Exif SubIFD] - Sub-Sec Time Digitized = 242921
[Exif SubIFD] - FlashPix Version = 1.00
[Exif SubIFD] - Color Space = sRGB
[Exif SubIFD] - Exif Image Width = 1744 pixels
[Exif SubIFD] - Exif Image Height = 3840 pixels
[Exif SubIFD] - Sensing Method = One-chip color area sensor
[Exif SubIFD] - File Source = Digital Still Camera (DSC)
[Exif SubIFD] - Scene Type = Directly photographed image
[Exif SubIFD] - Custom Rendered = Custom process
[Exif SubIFD] - Exposure Mode = Auto exposure
[Exif SubIFD] - White Balance Mode = Auto white balance
[Exif SubIFD] - Digital Zoom Ratio = 1
[Exif SubIFD] - Focal Length 35 = 18 mm
[Exif SubIFD] - Scene Capture Type = Standard
[Exif SubIFD] - Gain Control = None
[Exif SubIFD] - Contrast = None
[Exif SubIFD] - Saturation = None
[Exif SubIFD] - Sharpness = None
[Exif SubIFD] - Subject Distance Range = Unknown
[Interoperability] - Interoperability Index = Recommended Exif Interoperability Rules (ExifR98)
[Interoperability] - Interoperability Version = 1.00
[GPS] - GPS Version ID = 2.200
[GPS] - GPS Latitude Ref = N
[GPS] - GPS Latitude = 40° 4’ 22.74"
[GPS] - GPS Longitude Ref = E
[GPS] - GPS Longitude = 116° 20’ 37.01"
[GPS] - GPS Altitude Ref = Below sea level
[GPS] - GPS Altitude = 0 metres
[GPS] - GPS Time-Stamp = 23:18:01.000 UTC
[GPS] - GPS Processing Method = CELLID
[GPS] - GPS Date Stamp = 2021:05:20
[Exif Thumbnail] - Image Width = 256 pixels
[Exif Thumbnail] - Image Height = 528 pixels
[Exif Thumbnail] - Compression = JPEG (old-style)
[Exif Thumbnail] - Orientation = Unknown (0)
[Exif Thumbnail] - X Resolution = 72 dots per inch
[Exif Thumbnail] - Y Resolution = 72 dots per inch
[Exif Thumbnail] - Resolution Unit = Inch
[Exif Thumbnail] - Thumbnail Offset = 1622 bytes
[Exif Thumbnail] - Thumbnail Length = 26099 bytes
[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 = mg.jpg
[File] - File Size = 1771566 bytes
[File] - File Modified Date = 星期五 七月 09 14:30:00 +08:00 2021

获取了常见的属性: 压缩格式、图像宽度、图像高度、拍摄手机、型号、手机系统版本号、gps版本、经度、纬度、高度、UTC时间戳、gps日期、iso速率、曝光时间、曝光模式、光圈值、焦距、图像色彩空间、文件源、场景类型等 效果图如下:
在这里插入图片描述
在这里插入图片描述

2. 什么是Exif?

EXIF是 Exchangeable Image File的缩写,这是一种专门为数码相机照片设定的格式。这种格式可以用来记录数字照片的属性信息,例如相机的品牌及型号、相片的拍摄时间、拍摄时所设置的光圈大小、快门速度、ISO、照片的宽度、高度等信息。

最简单易用的EXIF信息处理的Java包是Drew Noakes写的metadata-extractor,该项目最新的版本是2.16.0,支持EXIF 2.2版本。

并不是每个JPG图像文件都包含有EXIF信息,可以在Windows资源管理器单击选中图片后,如果该图片包含EXIF信息,则在窗口状态栏会显示出相机的型号,否则exif信息丢失。
在这里插入图片描述

3. 源代码

获取图片的压缩格式、图像宽度、图像高度、拍摄手机、型号、手机系统版本号、gps版本、经度、纬度、高度、UTC时间戳、gps日期、iso速率、曝光时间、曝光模式、光圈值、焦距、图像色彩空间、文件源、场景类型等

pom依赖:

<!--获取相机exif信息-->
<dependency>
    <groupId>com.drewnoakes</groupId>
    <artifactId>metadata-extractor</artifactId>
    <version>2.16.0</version>
</dependency>
package com.getGps;

import com.drew.imaging.ImageMetadataReader;
import com.drew.imaging.ImageProcessingException;
import com.drew.imaging.jpeg.JpegMetadataReader;
import com.drew.imaging.jpeg.JpegProcessingException;
import com.drew.metadata.Directory;
import com.drew.metadata.Metadata;
import com.drew.metadata.Tag;

import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

/*************************************
 *Class Name: gpsExifInfo
 *Description: <获取相机经纬度并且转换实际位置>
 *@author: seminar
 *************************************/
public class GpsExifInfo {

    public static void main(String[] args) throws ImageProcessingException, IOException {
        String imgDir = "E:\\imgs";
        File[] files = new File(imgDir).listFiles();
        for (File file : files) {
            if (!file.getName().endsWith(".jpg")) {
                continue;
            }
            System.out.println("----------------------------------------\n" + file.getName());
            // 获取照片信息
            Map exifMap = readPicExifInfo(file);

            // 打印照片信息
            printPicExifInfo(exifMap);
        }
    }

    /**
     * 获取图片文件的Exif信息
     *
     * @param file
     * @return
     * @throws ImageProcessingException
     * @throws IOException
     */
    private static Map<String, String> readPicExifInfo(File file) throws ImageProcessingException, IOException {
        Map<String, String> map = new HashMap<>();
        Metadata metadata = ImageMetadataReader.readMetadata(file);
        for (Directory directory : metadata.getDirectories()) {
            for (Tag tag : directory.getTags()) {
                // 输出所有属性
                System.out.format(
                        "[%s] - %s = %s\n", directory.getName(), tag.getTagName(), tag.getDescription());
                map.put(tag.getTagName(), tag.getDescription());
            }
            if (directory.hasErrors()) {
                for (String error : directory.getErrors()) {
                    System.err.format("ERROR: %s", error);
                }
            }
        }
        return map;
    }

    /**
     * 打印照片Exif信息
     *
     * @param map
     */
    private static void printPicExifInfo(Map<String, String> map) {
        String[] strings = new String[]{"Compression", "Image Width", "Image Height", "Make", "Model", "Software",
                "GPS Version ID", "GPS Latitude", "GPS Longitude", "GPS Altitude", "GPS Time-Stamp", "GPS Date Stamp",
                "ISO Speed Ratings", "Exposure Time", "Exposure Mode", "F-Number", "Focal Length 35", "Color Space", "File Source", "Scene Type"};
        String[] names = new String[]{"压缩格式", "图像宽度", "图像高度", "拍摄手机", "型号", "手机系统版本号",
                "gps版本", "经度", "纬度", "高度", "UTC时间戳", "gps日期",
                "iso速率", "曝光时间", "曝光模式", "光圈值", "焦距", "图像色彩空间", "文件源", "场景类型"};
        for (int i = 0; i < strings.length; i++) {
            if (map.containsKey(strings[i])) {
                if ("GPS Latitude".equals(strings[i]) || "GPS Longitude".endsWith(strings[i])) {
                    System.out.println(names[i] + "  " + strings[i] + " : " + map.get(strings[i]) + ", °转dec: " + latLng2Decimal(map.get(strings[i])));
                } else {
                    System.out.println(names[i] + "  " + strings[i] + " : " + map.get(strings[i]));
                }
            }
        }

        // 经纬度转location地址信息
        if (map.containsKey("GPS Latitude") && map.containsKey("GPS Longitude")) {
            convertLatLng2Loaction(latLng2Decimal(map.get("GPS Latitude")), latLng2Decimal(map.get("GPS Longitude")));
        }
    }

    /**
     * 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 convertLatLng2Loaction(double gps_latitude, double gps_longitude) throws IOException {
        String apiKey = "FxzbLsuDDL4CS2U0M4KezOZZbGUY9iWtRn";

        String res = "";
        String url = "http://api.map.baidu.com/reverse_geocoding/v3/?ak=" + apiKey + "&output=json&coordtype=wgs84ll&location=" + (gps_latitude + "," + gps_longitude);
        System.out.println("【url】" + url);
        CloseableHttpClient client = HttpClients.custom().build();
        HttpGet httpPost = new HttpGet(url);
        httpPost.setHeader("Content-Type", MediaType.APPLICATION_JSON_VALUE);
        CloseableHttpResponse resp = client.execute(httpPost);
        if (resp != null) {
            if (resp.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
                HttpEntity entity = resp.getEntity();
                res = IOUtils.readStreamAsString(entity.getContent());
                System.out.println("resJson: " + res);
                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.out.println("拍摄地点:" + address.get("country") + " " + address.get("province") + " " + address.get("city") + " " + address.get("district") + " "
                                + address.get("street") + " " + result.get("formatted_address") + " " + result.get("business"));
                    }
                }
            }
        }
    }

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

参考