public static void main(String[] args) throws Exception {
File mFile = new File(“F:/XXX.JPG”);
Metadata metadata = ImageMetadataReader.readMetadata(mFile);
for (Directory directory : metadata.getDirectories()) {
if(“ExifSubIFDDirectory”.equalsIgnoreCase( directory.getClass().getSimpleName() )){
//光圈F值=镜头的焦距/镜头光圈的直径
System.out.println(“光圈值: f/” + directory.getString(ExifSubIFDDirectory.TAG_FNUMBER) );
System.out.println("曝光时间: " + directory.getString(ExifSubIFDDirectory.TAG_EXPOSURE_TIME)+ “秒” );
System.out.println("ISO速度: " + directory.getString(ExifSubIFDDirectory.TAG_ISO_EQUIVALENT) );
System.out.println("焦距: " + directory.getString(ExifSubIFDDirectory.TAG_FOCAL_LENGTH) + “毫米” );
System.out.println("拍照时间: " + directory.getString(ExifSubIFDDirectory.TAG_DATETIME_ORIGINAL) );
System.out.println("宽: " + directory.getString(ExifSubIFDDirectory.TAG_EXIF_IMAGE_WIDTH) );
System.out.println("高: " + directory.getString(ExifSubIFDDirectory.TAG_EXIF_IMAGE_HEIGHT) );
}
if(“ExifIFD0Directory”.equalsIgnoreCase( directory.getClass().getSimpleName() )){
System.out.println("照相机制造商: " + directory.getString(ExifIFD0Directory.TAG_MAKE) );
System.out.println("照相机型号: " + directory.getString(ExifIFD0Directory.TAG_MODEL) );
System.out.println("水平分辨率: " + directory.getString(ExifIFD0Directory.TAG_X_RESOLUTION) );
System.out.println("垂直分辨率: " + directory.getString(ExifIFD0Directory.TAG_Y_RESOLUTION) );
}
}
}
示例3):
File mFilePath=“C://XXX.jpg”;
Metadata metadata = com.drew.imaging.jpeg.JpegMetadataReader.readMetadata(mFilePath);
JpegDirectory jd = (JpegDirectory)metadata.getDirectory(JpegDirectory.class);
System.out.println(“------------” + jd.getImageHeight()); //图片的高
System.out.println(“------------” + jd.getImageWidth()); //图片的宽
//由于只是读取图片的头信息,所以无论多大的图片都能读取,而且速度很快.
从执行的中可以看到照片的详细拍摄时间,拍摄用的相机型号,曝光时间,光圈值,焦距,ISO值 等等。
你也可以直接指定读取其中任意参数的值,ExifDirectory 类中定义了很多以 TAG_ 开头的整数常量,这些常量代表特定的一个参数值,例如要读取相机的型号,可以用下面代码来获取。
Metadata metadata = JpegMetadataReader.readMetadata(jpegFile);
Directory exif = metadata.getDirectory(ExifDirectory.class);
String model = exif.getString(ExifDirectory.TAG_MODEL);
上述提到的是如何获取照片的EXIF信息,其中包含一个很重要的信息就是——拍摄方向。例如所用的图片拍摄方向是:Orientation - Top, left side (Horizontal / normal)。我们在拍照的时候经常会根据场景的不同来选择相机的方向,例如拍摄一颗高树,我们会把相机竖着拍摄,使景物刚好适合整个取景框,但是这样得到的图片如果用普通的图片浏览器看便是倒着的,需要调整角度才能得到一个正常的图像。
通过读取图片的EXIF信息,可以得到关于拍摄方向的这样一个结果:Orientation - Left side, bottom (Rotate 270 CW)。
而直接读取 ExitDirectory.TAG_ORIENTATION 标签的值是8。
来看下这个项目是如何来定义这些返回值的,打开源码包中的ExifDescriptor类的getOrientationDescription(),该方法代码如下:
public String getOrientationDescription() throws MetadataException{
if (!_directory.containsTag(ExifDirectory.TAG_ORIENTATION)) return null;
int orientation = _directory.getInt(ExifDirectory.TAG_ORIENTATION);
switch (orientation) {
case 1: return “Top, left side (Horizontal / normal)”;
case 2: return “Top, right side (Mirror horizontal)”;
case 3: return “Bottom, right side (Rotate 180)”;
case 4: return “Bottom, left side (Mirror vertical)”;
case 5: return “Left side, top (Mirror horizontal and rotate 270 CW)”;
case 6: return “Right side, top (Rotate 90 CW)”;
case 7: return “Right side, bottom (Mirror horizontal and rotate 90 CW)”;
case 8: return “Left side, bottom (Rotate 270 CW)”;
default:
return String.valueOf(orientation);
}
}
从这个方法可以清楚看到各个返回值的意思,如此我们便可以根据实际的返回值来对图像进行旋转或者是镜像处理了。
下面给出代码用以旋转图片,其他的关于图片的镜像等处理读者可以依此类推:
String mPath = “D:\XXX.JPG”;
File img = new File(mPath);
BufferedImage old_img = (BufferedImage)ImageIO.read(img);
int w = old_img.getWidth();
int h = old_img.getHeight();
BufferedImage new_img = new BufferedImage(h,w,BufferedImage.TYPE_INT_BGR);
Graphics2D g2d =new_img.createGraphics();
AffineTransform origXform = g2d.getTransform();
AffineTransform newXform = (AffineTransform)(origXform.clone());
// center of rotation is center of the panel
double xRot = w/2.0;
newXform.rotate(Math.toRadians(270.0), xRot, xRot); //旋转270度
g2d.setTransform(newXform);
// draw image centered in panel
g2d.drawImage(old_img, 0, 0, null);
// Reset to Original
g2d.setTransform(origXform);
//写到新的文件
FileOutputStream out = new FileOutputStream(“D:\XXX2.jpg”);
try{
ImageIO.write(new_img, “JPG”, out);
}finally{
out.close();
}
注:利用上面的代码旋转照片后,原有照片包含的EXIF信息就不存在了。关于该问题需要在照片旋转之前先把EXIF信息读出,然后再在旋转后写入新的照片中,可以使用 MediaUtil 包来写EXIF信息到图片文件中,关于这个包的使用可参考最后的链接。
照片的镜面翻转可以直接利用Graphic2D 的 drawImage 方法来实现:
public abstract boolean drawImage(Image img,
int dx1,int dy1,
int dx2,int dy2,
int sx1,int sy1,
int sx2,int sy2,
ImageObserver observer);
三、补充说明
======
解释部分参数的实际含义:
Make 生产者 指产品生产厂家
Model 型号 指设备型号
Orientation 方向 有的相机支持,有的不支持
X Resolution/Y Resolution X/Y方向分辨率 本栏目已有专门条目解释此问题
ResolutionUnit 分辨率单位 一般为PPI
Software 软件 显示固件Firmware版本
DateTime 日期和时间
YCbCrPositioning 色相定位
ExifOffsetExif 信息位置,定义Exif在信息在文件中的写入,有些软件不显示。
ExposureTime 曝光时间 即快门速度
FNumber 光圈系数
ISO speed ratings 感光度
ExifVersionExif 版本
DateTimeOriginal 创建时间
DateTimeDigitized 数字化时间
ComponentsConfiguration 图像构造(多指色彩组合方案)
CompressedBitsPerPixel(BPP) 压缩时每像素色彩位 指压缩程度
ExposureBiasValue 曝光补偿。
MaxApertureValue 最大光圈
MeteringMode 测光方式, 平均式测光、中央重点测光、点测光等。
Lightsource 光源 指白平衡设置
Flash 是否使用闪光灯。
FocalLength 焦距,一般显示镜头物理焦距,有些软件可以定义一个系数,显示相当于35mm相机的焦距 MakerNote(User Comment)作者标记、说明、记录
FlashPixVersionFlashPix 版本 (个别机型支持)
ColorSpace 色域、色彩空间
尾声
如果你想成为一个优秀的 Android 开发人员,请集中精力,对基础和重要的事情做深度研究。
对于很多初中级Android工程师而言,想要提升技能,往往是自己摸索成长,不成体系的学习效果低效漫长且无助。 整理的这些架构技术希望对Android开发的朋友们有所参考以及少走弯路,本文的重点是你有没有收获与成长,其余的都不重要,希望读者们能谨记这一点。
这里,笔者分享一份从架构哲学的层面来剖析的视频及资料给大家梳理了多年的架构经验,筹备近6个月最新录制的,相信这份视频能给你带来不一样的启发、收获。
Android进阶学习资料库
一共十个专题,包括了Android进阶所有学习资料,Android进阶视频,Flutter,java基础,kotlin,NDK模块,计算机网络,数据结构与算法,微信小程序,面试题解析,framework源码!
大厂面试真题
PS:之前因为秋招收集的二十套一二线互联网公司Android面试真题 (含BAT、小米、华为、美团、滴滴)和我自己整理Android复习笔记(包含Android基础知识点、Android扩展知识点、Android源码解析、设计模式汇总、Gradle知识点、常见算法题汇总。)
《2019-2021字节跳动Android面试历年真题解析》
《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》,点击传送门,即可获取!
计算机网络,数据结构与算法,微信小程序,面试题解析,framework源码!
[外链图片转存中…(img-sI5xkBw7-1714709397312)]
大厂面试真题
PS:之前因为秋招收集的二十套一二线互联网公司Android面试真题 (含BAT、小米、华为、美团、滴滴)和我自己整理Android复习笔记(包含Android基础知识点、Android扩展知识点、Android源码解析、设计模式汇总、Gradle知识点、常见算法题汇总。)
[外链图片转存中…(img-ukak8qQB-1714709397312)]
《2019-2021字节跳动Android面试历年真题解析》
[外链图片转存中…(img-bnaN8fSr-1714709397313)]
《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》,点击传送门,即可获取!