Java 纠正上传图片自动旋转与镜像的问题
遇到一个图片看着是方向是正的,但是用特定的工具打开后自动旋转与镜像。
查看这篇文章后:https://www.cnblogs.com/csonezp/p/5564809.html。
原文中的一句话:原来是因为相机给图片的exif信息加上了一个Orientation,然后图片浏览器会对这个属性做出兼容,让图片以竖图的形式显示出来。下面我来对Orientation这个属性做一些解释。
为什么我们在一些软件上,或者浏览器中看到是正的,是因为这些软件,浏览器自动的纠正了这个图片。
然而我们的Java并没有自动的为我们去纠正这个图片当我们使用BufferImage
去绘制图片的时候发现高与居然是相反的。
如何解决?
引入
<dependency>
<groupId>com.drewnoakes</groupId>
<artifactId>metadata-extractor</artifactId>
<version>2.7.0</version>
</dependency>
这个包可以帮我去获取图片的exif信息。
// 1.获取图片的元数据
Metadata metadata = ImageMetadataReader.readMetadata(file);
// 2.图片元数据处理那种方向
int orientation = 0;
for (Directory directory : metadata.getDirectories()) {
// 3.只需要TAG_ORIENTATION的数据即可。
if(directory.containsTag(ExifIFD0Directory.TAG_ORIENTATION)){
for (Tag tag : directory.getTags()) {
System.out.println(tag);
}
orientation = directory.getInt(ExifIFD0Directory.TAG_ORIENTATION);
}
}
// 输出[Exif IFD0] Orientation - Right side, top (Rotate 90 CW)
理解
EXIF Orientation Value | Row #0 is: | Column #0 is: | 对应的方向应该如何纠正 |
---|---|---|---|
1 | Top | Left side | 无需纠正 |
2 | Top | Right side | 水平翻转(镜像) |
3 | Bottom | Right side | 垂直翻转(旋转180°) |
4 | Bottom | Left side | 水平翻转+垂直翻转 |
5 | Left side | Top | 水平翻转+旋转90° |
6 | Right side | Top | 旋转90° |
7 | Right side | Bottom | 水平翻转+旋转270° |
8 | Left side | Bottom | +旋转270° |
可以参考下图一起理解
实现
public class ImageRotate {
/**
* 纠正图片方法
*
* @param srcImgPath
*/
/**
* 纠正图片旋转
*
* @param srcImgPath
*/
public static void correctImg(String srcImgPath) {
FileOutputStream fos = null;
try {
// 原始图片
File srcFile = new File(srcImgPath);
// 1.获取纠正
RectifyDirection rotateAngle = getRectifyDirection(srcFile);
// 2.无需纠正直接返回
if(rotateAngle == null){
return;
}
System.out.println(rotateAngle.angel+":"+rotateAngle.isMirror);
// 原始图片缓存
BufferedImage srcImg = ImageIO.read(srcFile);
// 原始宽度
int imgWidth = srcImg.getWidth();
// 原始高度
int imgHeight = srcImg.getHeight();
// 3.如果不是垂直的就代表他们的宽高需要互换
if (rotateAngle.angel != 180) {
int temp = imgWidth;
imgWidth = imgHeight;
imgHeight = temp;
}
// 中心点位置
double centerWidth = ((double) imgWidth) / 2;
double centerHeight = ((double) imgHeight) / 2;
// 图片缓存
BufferedImage targetImg = new BufferedImage(imgWidth, imgHeight, BufferedImage.TYPE_INT_RGB);
// 旋转对应角度
Graphics2D g = targetImg.createGraphics();
// 4.以中心点位置 向左旋转
g.rotate(Math.toRadians(rotateAngle.angel), centerWidth, centerHeight);
// 5.旋转后图片的宽高就又替换了。
System.out.println(srcImg.getWidth());
System.out.println(srcImg.getHeight());
// 6.这里就需要找到替换后原有的宽高与现有的宽高,从这个坐标开始绘制图片
int x = (imgWidth - srcImg.getWidth()) / 2;
int y = (imgHeight - srcImg.getHeight()) / 2;
g.drawImage(srcImg, x, y, null);
g.dispose();
// 7.是否需要水平翻转
if (rotateAngle.isMirror){
BufferedImage tempImage = new BufferedImage(targetImg.getWidth(), targetImg.getHeight(), BufferedImage.TYPE_INT_RGB);
g = tempImage.createGraphics();
// 使用 AffineTransform 进行水平翻转
AffineTransform transform = new AffineTransform();
// 8.平移现在图片的宽度后
transform.translate(targetImg.getWidth() , 0);
// 9. 缩放
// 因为横坐标缩放是-1,所以是水平翻转
// 翻转过程见水平翻转图片
transform.scale(-1, 1);
g.setTransform(transform);
g.drawImage(targetImg,0, 0, null);
g.dispose();
targetImg = tempImage;
}
// 输出图片
fos = new FileOutputStream(new File(srcFile.getAbsolutePath() + "." + srcImgPath.substring(srcImgPath.lastIndexOf(".") + 1)));
ImageIO.write(targetImg, srcImgPath.substring(srcImgPath.lastIndexOf(".") + 1), fos);
} catch (Exception e) {
e.printStackTrace();
} finally {
if (fos != null) {
try {
fos.flush();
fos.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
/**
* 获取纠正方向
* @param file
* @return
* @throws Exception
*/
public static RectifyDirection getRectifyDirection(File file) throws Exception {
// 1.获取图片的元数据
Metadata metadata = ImageMetadataReader.readMetadata(file);
// 2.图片元数据处理那种方向
int orientation = 0;
for (Directory directory : metadata.getDirectories()) {
// 3.只需要TAG_ORIENTATION的数据即可。
if(directory.containsTag(ExifIFD0Directory.TAG_ORIENTATION)){
for (Tag tag : directory.getTags()) {
System.out.println(tag);
}
orientation = directory.getInt(ExifIFD0Directory.TAG_ORIENTATION);
}
}
// 4.根据不同的orientation创建不同的处理方式
switch (orientation){
case 2:
return new RectifyDirection(0,true);
case 3:
return new RectifyDirection(180,false);
case 4:
return new RectifyDirection(180, true);
case 5:
return new RectifyDirection(90,true);
case 6:
return new RectifyDirection(90,false);
case 7:
return new RectifyDirection(270,true);
case 8:
return new RectifyDirection(270,false);
default:
return null;
}
}
static class RectifyDirection{
/**
* 角度
*/
public int angel;
/**
* 是否镜像
*/
public boolean isMirror;
public RectifyDirection(int angel, boolean isMirror) {
this.angel = angel;
this.isMirror = isMirror;
}
}
}