Java读取图片中的地理坐标(四)

2023-12-08 04:10

本文主要是介绍Java读取图片中的地理坐标(四),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

从图片获取信息必须要有Exif字段信息,而Exif只存在于jpeg和tiff格式中
jpeg:开头  FF D8   FF E1
        (jpeg)  (exif)
tif:   开头  49 49    2A 00

JPEG图片的EXIF数据
EXIF JPEG文件将EXIF信息存储在JFIF的APP1标记中。
EXIF主要保存拍摄照片时的相机参数、图像缩略图、GPS信息等。


EXIF在JPEG图片中的存储位置
EXIF 存储在JPEG图片的 APP1标记中,符合JFIF标准。APP1标记的格式包含三部分:标记 (0xFFE1)、数据长度、数据内容。

存储了EXIF的APP1标记通常包含:标记 (0xFFE1)、数据长度、EXIF标示符、EXIF数据。
也就是说,EXIF APP1 在数据内容起始(即紧跟数据长度之后),设置Exif标示符 (“Exif\0\0”),标示该APP1 中的数据是EXIF数据。

EXIF标示符是为了与其它也使用 APP1标记的数据(如XMP)区分。

JPEG图片中存储的EXIF如图:


Fig.1. Basic Structure of JPEG Files.


一个典型的EXIF JPEG文件
一个典型的EXIF JPEG文件结构类似下面这样:
JPEG SOI : FF D8  //  图片起始
JPEG APP1: FF E1
  APP1 Size : 1C 45  //  注意:前面这三个WORD都是big endian的
  EXIF Flag : 'Exif', 0, 0
  ---------
  TIFF :
    TIFF Header:
      Byte Order: 'II'
      Flag      : 2A 00
      IFD0 offset : 08 00 00 00
    ----------------------------
    IFD0:
      Entries Count : 0B 00 // 11
      DE 1:
          Tag    : 0E 01  //  Image Description 图像说明
          Type   : 02 00  //  ASCII
          Size  : 0B 00 00 00
          Value : 92 00 00 00  //  from TIFF Header
      DE 2:
          Tag    : 0F 01  //  Make 制造
          Type   : 02 00
          Size  : 06 00 00 00
          Value: B2 00 00 00
      DE 3:
          Tag    : 10 01  //  Model 型号
          Type   : 02 00
          Size  : 05 00 00 00
          Value: CA 00 00 00
        …
      DE 11:
          Tag    : 69 87  //  EXIF IFD
          Type   : 04 00  //  LONG
          Size  : 01 00 00 00
          Value: 1C 01 00 00  //  Offset of EXIF IFD   
      IFD1 Offset : 18 03 00 00  // END of IFD0
    IFD0 DATA:
      ...  //  存放IFD0中DE 的Value数据
      EXIF sub IFD :
        Entries Count : 18 00
        DE :
          Tag    : 9A 82  //  Exposure time
          ...     
        Next IFD : 00 00 00 00  // END of EXIF IFD. 按标准IFD规定,表示没有后继IFD
      EXIF sub IFD Data :
        ...  //  存放EXIF sub IFD的Value数据
    -----------------------------------------------
    IFD1 :  //  EXIF中用于存放缩略图
      Entries Count : 06 00
      DE :
          Tag    : 03 01
          ...   
      Next IFD : 00 00 00 00  // END OF IFD1. EXIF只用到两个TIFF IFD
    IFD1 Data :
      ... //  Thumbnail etc.
    -----------------------------------
  //  end of TIFF
  -----------------------------
  //  其它JPEG Marker segments
JPEG EOI : FF D9  //  图片结束

我们可以简化一下,看一个只包含主要IFD和JPEG 格式的缩略图的APP1结构("Intel"字节序)。

就像上面描述的那样, Exif 数据开始于ASCII字符 "Exif" 和2个字节的0x00, 后面才是 Exif的数据. 
缩略图数据存储在IFD1的数据域. 
FFE1
APP1 标记
SSSS
APP1 数据
APP1 数据大小
45786966 0000
Exif 头
49492A00 08000000
TIFF 头
XXXX. . . .
IFD0 (主图像)
目录
LLLLLLLL
连接到 IFD1
XXXX. . . .
IFD0的数据域
XXXX. . . .
  
Exif 子IFD
目录
00000000
连接结束
XXXX. . . .
Exif 子IFD的数据域
XXXX. . . .
  
Interoperability IFD
Directory
00000000
连接结束
XXXX. . . .
Interoperability IFD的数据域
XXXX. . . .
Makernote IFD
Directory
00000000
连接结束
XXXX. . . .
Makernote IFD的数据域
XXXX. . . .
IFD1(缩略图像)
目录
00000000
连接结束
XXXX. . . .
IFD1的数据域
FFD8XXXX. . . XXXXFFD9
缩略图像


需要说明的是,尽管 JPEG 数据仅仅是使用 Motorola 字节序, 但 Exif 却是允许Intel字节序 和 Motorola 字节序这两种字节序存在的。 


EXIF中的IFD结构
EXIF遵循TIFF文件格式,并对TIFF格式做了一些扩展。
因此EXIF也是一种非常灵活的格式,具有非常好的可扩充性,要想较好地处理其中的相关数据也是比较麻烦的。

标准的TIFF格式在  上篇中讲到。简单回顾一下TIFF格式中的IFD。
IFD是一个链表结构,如图所示。在每个IFD的末尾包含一个指向下一个IFD的偏移量(同样是从TIFF Header算起),如果这个偏移量为0,则表示已经到了链表的末尾。


                 图 TIFF格式中的IFH和IFD链表结构

在Exif格式中,只有两个标准IFD。第一个IFD 是IFD0(主图像IFD), 然后它连接到IFD1(缩略图IFD) ,并且IFD 连接在此结束。IFD0/IFD1 不包含任何的数字相机的信息,例如快门速度, 焦距等. 

在IFD0中除了自己的DE外,还包括了EXIF自定义的EXIF Sub IFD、GPS IFD,而EXIF sub IFD中又进一步包括了Interoperability IFD(简称IOP)和MakerNote IFD。

EXIF自定义IFD的结构与标准TIFF IFD相同,但不是记录于TIFF的IFD链表中,而是  作为TIFF IFD的子链表形式存在(因为扩展IFD里定义了不同于TIFF标准的Tag,这样为了与标准的TIFF格式区分),使得原来的TIFF IFD链表结构变成了树形结构  


                           图  EXIF IFD的树形结构

EXIF自定义IFD在IFD0中以DE Tag的方式出现,都是LONG类型,它记录了相应扩展IFD的起始位置(从TIFF Header开始的偏移)。

EXIF自定义标签编号的含义
TagID
属性名称
type
说明
8769
EXIF IFD
LONG
数字相机的信息 
8825
GPS IFD
LONG
地理位置信息
A005
Interoperability IFD
LONG
互操作扩展信息
927C
MakerNote IFD
LONG
厂商自己独有的注释信息

扩展IFD中用到的Tag全部是EXIF重新定义的。  Tag的种类和数量非常之大,在EXIF规范里定义了各个Tag的支持级别,光是JPEG格式下必须支持的Tag就有十几个,再加上可选支持的Tag,有几十上百个,并且还存在未来继续扩充的可能。
只存在于结果由于程序一直出现catch不了的异常,

java.lang.ClassNotFoundException : com.adobe.xmp.XMPException

 
Well you are returning a null, are you making provision for that? –  Ruan  May 14 '15 at 6:19
 
Yes i handling situation when null is being returned ! –  Neeraj Jain  May 14 '15 at 6:24
 
This happened because xmpcore.jar is not in the classpath, a dependency of metadata-extractor. –  saurabheights  Mar 10 at 13:09
metadata-extractor依赖于xmpcore.jar 找了2天吧(我逝去的青春)

com.drewnoakes/metadata-extractor/2.8.1 依赖的jar包

GroupIdArtifactIdVersionScope描述
com.adobe.xmpxmpcore5.1.2compileThe XMP Library for Java is based on the C++ XMPCore library and the API is similar.
junitjunit4.11testJUnit is a regression testing framework written by Erich Gamma and Kent Beck. It is used by the developer who implements unit tests in Java.



这篇关于Java读取图片中的地理坐标(四)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/468487

相关文章

Java图片压缩三种高效压缩方案详细解析

《Java图片压缩三种高效压缩方案详细解析》图片压缩通常涉及减少图片的尺寸缩放、调整图片的质量(针对JPEG、PNG等)、使用特定的算法来减少图片的数据量等,:本文主要介绍Java图片压缩三种高效... 目录一、基于OpenCV的智能尺寸压缩技术亮点:适用场景:二、JPEG质量参数压缩关键技术:压缩效果对比

Java调用C++动态库超详细步骤讲解(附源码)

《Java调用C++动态库超详细步骤讲解(附源码)》C语言因其高效和接近硬件的特性,时常会被用在性能要求较高或者需要直接操作硬件的场合,:本文主要介绍Java调用C++动态库的相关资料,文中通过代... 目录一、直接调用C++库第一步:动态库生成(vs2017+qt5.12.10)第二步:Java调用C++

springboot+dubbo实现时间轮算法

《springboot+dubbo实现时间轮算法》时间轮是一种高效利用线程资源进行批量化调度的算法,本文主要介绍了springboot+dubbo实现时间轮算法,文中通过示例代码介绍的非常详细,对大家... 目录前言一、参数说明二、具体实现1、HashedwheelTimer2、createWheel3、n

使用Python开发一个简单的本地图片服务器

《使用Python开发一个简单的本地图片服务器》本文介绍了如何结合wxPython构建的图形用户界面GUI和Python内建的Web服务器功能,在本地网络中搭建一个私人的,即开即用的网页相册,文中的示... 目录项目目标核心技术栈代码深度解析完整代码工作流程主要功能与优势潜在改进与思考运行结果总结你是否曾经

Java利用docx4j+Freemarker生成word文档

《Java利用docx4j+Freemarker生成word文档》这篇文章主要为大家详细介绍了Java如何利用docx4j+Freemarker生成word文档,文中的示例代码讲解详细,感兴趣的小伙伴... 目录技术方案maven依赖创建模板文件实现代码技术方案Java 1.8 + docx4j + Fr

SpringBoot首笔交易慢问题排查与优化方案

《SpringBoot首笔交易慢问题排查与优化方案》在我们的微服务项目中,遇到这样的问题:应用启动后,第一笔交易响应耗时高达4、5秒,而后续请求均能在毫秒级完成,这不仅触发监控告警,也极大影响了用户体... 目录问题背景排查步骤1. 日志分析2. 性能工具定位优化方案:提前预热各种资源1. Flowable

基于SpringBoot+Mybatis实现Mysql分表

《基于SpringBoot+Mybatis实现Mysql分表》这篇文章主要为大家详细介绍了基于SpringBoot+Mybatis实现Mysql分表的相关知识,文中的示例代码讲解详细,感兴趣的小伙伴可... 目录基本思路定义注解创建ThreadLocal创建拦截器业务处理基本思路1.根据创建时间字段按年进

Java编译生成多个.class文件的原理和作用

《Java编译生成多个.class文件的原理和作用》作为一名经验丰富的开发者,在Java项目中执行编译后,可能会发现一个.java源文件有时会产生多个.class文件,从技术实现层面详细剖析这一现象... 目录一、内部类机制与.class文件生成成员内部类(常规内部类)局部内部类(方法内部类)匿名内部类二、

SpringBoot实现数据库读写分离的3种方法小结

《SpringBoot实现数据库读写分离的3种方法小结》为了提高系统的读写性能和可用性,读写分离是一种经典的数据库架构模式,在SpringBoot应用中,有多种方式可以实现数据库读写分离,本文将介绍三... 目录一、数据库读写分离概述二、方案一:基于AbstractRoutingDataSource实现动态

Python FastAPI+Celery+RabbitMQ实现分布式图片水印处理系统

《PythonFastAPI+Celery+RabbitMQ实现分布式图片水印处理系统》这篇文章主要为大家详细介绍了PythonFastAPI如何结合Celery以及RabbitMQ实现简单的分布式... 实现思路FastAPI 服务器Celery 任务队列RabbitMQ 作为消息代理定时任务处理完整