图片Exif信息解析(Java实现)

本文涉及的产品
云解析 DNS,旗舰版 1个月
全局流量管理 GTM,标准版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
简介: 图片Exif信息解析(Java实现)

前言


可交换图像文件(Exchangeable Image File,Exif)信息图像在拍摄时保留的相关参数:比如图像信息(厂商,分辨率等),相机拍摄记录(ISO,白平衡,饱和度,锐度等),缩略图(缩略图宽度,高度等),GPS(拍摄时的经度,纬度,高度)等,按照图像文件标准存储在图像头文件。一般使用支持图像读取的软件即可查看部分参数,但是图像如果修改,Exif信息可能丢失。


问题


然而一些开发任务需要图片Exif信息某项信息进行后续处理,无法使用软件获取信息输入到程序中,对开发任务带来一些困难。


解决


引入drewnoakes库,该库可以分析照片、视频相关信息等强大功能。


有兴趣可关注微信公众号:Java烂笔头,回复:drewnoakes,查看完整源码及说明。


示例代码


Maven依赖

<dependency>
            <groupId>com.drewnoakes</groupId>
            <artifactId>metadata-extractor</artifactId>
            <version>2.7.2</version>
        </dependency>

代码实现

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;
public class ExifTest {
    public static void main(String[] args) throws Exception {
        File file = new File("D:\\Java学习\\二维码生成与解析\\mmexport1632468955620.jpg");
        printImageTags(file);
    }
    /**
     * 读取照片相关信息
     */
    private static void printImageTags(File file) throws ImageProcessingException, Exception {
        Metadata metadata = ImageMetadataReader.readMetadata(file);
        String lat = "";
        String log = "";
        for (Directory directory : metadata.getDirectories()) {
            for (Tag tag : directory.getTags()) {
                String tagName = tag.getTagName();  //标签名
                String desc = tag.getDescription(); //标签信息
                System.out.println(tagName + "   " + desc);//照片信息
            }
        }
    }
}

照片信息输出


(由于不同照片所包含信息不完全一样,部分相关信息没有)

Compression Type   Baseline
Data Precision   8 bits
Image Height   1080 pixels
Image Width   1440 pixels
Number of Components   3
Component 1   Y component: Quantization table 0, Sampling factors 2 horiz/2 vert
Component 2   Cb component: Quantization table 1, Sampling factors 1 horiz/1 vert
Component 3   Cr component: Quantization table 1, Sampling factors 1 horiz/1 vert
Version   1.1
Resolution Units   none
X Resolution   1 dot
Y Resolution   1 dot
Profile Size   536
Version   2.1.0
Class   Display Device
Color space   RGB 
Profile Connection Space   XYZ 
Profile Date/Time   Wed Dec 31 08:00:00 CST 2
Signature   acsp
Rendering Intent   Media-Relative Colorimetric
XYZ values   0.9642029 1.0 0.8249054
Tag Count   9
Profile Description   1 enUS(sRGB                                        )
Red Colorant   (0.43606567, 0.2224884, 0.013916016)
Green Colorant   (0.3851471, 0.71687317, 0.097076416)
Blue Colorant   (0.1430664, 0.06060791, 0.71409607)
Red TRC   para(0x70617261): 40 bytes
Green TRC   para(0x70617261): 40 bytes
Blue TRC   para(0x70617261): 40 bytes
Media White Point   (0.9642029, 1.0, 0.8249054)
Copyright   1 enUS(Google Inc. 2016)


应用场景


需求:根据照片(包含位置信息)查找该照片拍摄定位


思路:首先引入drewnoakes库读取照片所有信息,判断tag信息为经度、纬度,根据经纬度转换为具体坐标位置。


工具代码:


以下代码还引入alibaba.fasejson库对读取的Exif信息进一步分析

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
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.net.URL;
    public class EXIFUtil {
        public static void main(String[] args) throws Exception {
            File file = new File("D:\\Java学习\\二维码生成与解析\\mmexport1632468955620.jpg");
            printImageTags(file);
        }
        /**
         * 读取照片里面的信息
         */
        private static void printImageTags(File file) throws ImageProcessingException, Exception {
            Metadata metadata = ImageMetadataReader.readMetadata(file);
            String lat = "";
            String log = "";
            for (Directory directory : metadata.getDirectories()) {
                for (Tag tag : directory.getTags()) {
                    String tagName = tag.getTagName();  //标签名
                    String desc = tag.getDescription(); //标签信息
                    System.out.println(tagName + "   " + desc);//照片信息
                    switch (tagName) {
                        //                    经度
                        case "GPS Longitude":
                            lat = pointToLatlong(desc);
                            break;
                        //                        纬度
                        case "GPS Latitude":
                            log = pointToLatlong(desc);
                            break;
                        default:
                            break;
                    }
                }
            }
            String add = getAdd(log, lat);
            JSONObject jsonObject = JSON.parseObject(add);
            JSONArray jsonArray = jsonObject.getJSONArray("addrList");
            JSONObject jso = jsonArray.getJSONObject(0);
            String allAdd = jso.getString("admName");
            String arr[] = allAdd.split(",");
            String adds = jso.getString("name");
            System.out.println("省:" + arr[0] + "\n市:" + arr[1] + "\n区:" + arr[2] + "\n" + adds);
        }
        /**
         * 经纬度格式  转换
         *
         * @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 log 经度
         *
         * @param lat 纬度
         *
         * @return
         */
        public static String getAdd(String log, String lat) {
            //参数解释: 纬度,经度 type 001 (100代表道路,010代表POI,001代表门址,111可以同时显示前三项)
            String urlString = "http://gc.ditu.aliyun.com/regeocoding?l=" + lat + "," + log + "&type=010";
            String res = "";
            try {
                URL url = new URL(urlString);
                java.net.HttpURLConnection conn = (java.net.HttpURLConnection) url.openConnection();
                conn.setDoOutput(true);
                conn.setRequestMethod("POST");
                java.io.BufferedReader in = new java.io.BufferedReader(new java.io.InputStreamReader(conn.getInputStream(), "UTF-8"));
                String line;
                while ((line = in.readLine()) != null) {
                    res += line + "\n";
                }
                in.close();
            } catch (Exception e) {
                System.out.println("error in wapaction,and e is " + e.getMessage());
            }
            return res;
        }
    }
相关文章
|
6天前
|
设计模式 Java 关系型数据库
【Java笔记+踩坑汇总】Java基础+JavaWeb+SSM+SpringBoot+SpringCloud+瑞吉外卖/谷粒商城/学成在线+设计模式+面试题汇总+性能调优/架构设计+源码解析
本文是“Java学习路线”专栏的导航文章,目标是为Java初学者和初中高级工程师提供一套完整的Java学习路线。
|
3天前
|
Java 程序员 开发者
Java中的异常处理机制深度解析
本文旨在深入探讨Java中异常处理的核心概念与实际应用,通过剖析异常的本质、分类、捕获及处理方法,揭示其在程序设计中的关键作用。不同于常规摘要,本文将直接切入主题,以简明扼要的方式概述异常处理的重要性及其在Java编程中的应用策略,引导读者快速把握异常处理的精髓。
|
2天前
|
安全 Java 开发者
Java并发编程中的锁机制解析
本文深入探讨了Java中用于管理多线程同步的关键工具——锁机制。通过分析synchronized关键字和ReentrantLock类等核心概念,揭示了它们在构建线程安全应用中的重要性。同时,文章还讨论了锁机制的高级特性,如公平性、类锁和对象锁的区别,以及锁的优化技术如锁粗化和锁消除。此外,指出了在高并发环境下锁竞争可能导致的问题,并提出了减少锁持有时间和使用无锁编程等策略来优化性能的建议。最后,强调了理解和正确使用Java锁机制对于开发高效、可靠并发应用程序的重要性。
12 3
|
5天前
|
存储 监控 算法
Java中的内存管理与垃圾回收机制解析
本文深入探讨了Java编程语言中的内存管理策略和垃圾回收机制。首先介绍了Java内存模型的基本概念,包括堆、栈以及方法区的划分和各自的功能。进一步详细阐述了垃圾回收的基本原理、常见算法(如标记-清除、复制、标记-整理等),以及如何通过JVM参数调优垃圾回收器的性能。此外,还讨论了Java 9引入的接口变化对垃圾回收的影响,以及如何通过Shenandoah等现代垃圾回收器提升应用性能。最后,提供了一些编写高效Java代码的实践建议,帮助开发者更好地理解和管理Java应用的内存使用。
|
6天前
|
Java 开发者
深入解析Java中的异常处理机制
本文将深入探讨Java中异常处理的核心概念和实际应用,包括异常的分类、捕获、处理以及最佳实践。我们将通过具体示例展示如何有效使用try-catch块、throws关键字和自定义异常类,以帮助读者更好地理解和应用Java异常处理机制。
11 1
|
6天前
|
Java 程序员 开发者
Java中的异常处理机制深度解析
本文旨在深入探讨Java中异常处理的机制,包括异常的分类、如何捕获和处理异常,以及自定义异常的最佳实践。通过实例讲解,帮助读者更好地理解如何在Java编程中有效管理和利用异常处理来提高代码的健壮性和可维护性。
|
7天前
|
存储 负载均衡 Java
Jetty技术深度解析及其在Java中的实战应用
【9月更文挑战第3天】Jetty,作为一款开源的、轻量级、高性能的Java Web服务器和Servlet容器,自1995年问世以来,凭借其卓越的性能、灵活的配置和丰富的扩展功能,在Java Web应用开发中占据了举足轻重的地位。本文将详细介绍Jetty的背景、核心功能点以及在Java中的实战应用,帮助开发者更好地理解和利用Jetty构建高效、可靠的Web服务。
21 2
|
10天前
|
Java 编译器 测试技术
|
18天前
|
数据采集 存储 前端开发
Java爬虫开发:Jsoup库在图片URL提取中的实战应用
Java爬虫开发:Jsoup库在图片URL提取中的实战应用
|
20天前
|
C# 开发者 Windows
震撼发布:全面解析WPF中的打印功能——从基础设置到高级定制,带你一步步实现直接打印文档的完整流程,让你的WPF应用程序瞬间升级,掌握这一技能,轻松应对各种打印需求,彻底告别打印难题!
【8月更文挑战第31天】打印功能在许多WPF应用中不可或缺,尤其在需要生成纸质文档时。WPF提供了强大的打印支持,通过`PrintDialog`等类简化了打印集成。本文将详细介绍如何在WPF应用中实现直接打印文档的功能,并通过具体示例代码展示其实现过程。
79 0

推荐镜像

更多