Java 纠正上传图片自动旋转与镜像的问题

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信息。

import com.drew.imaging.ImageMetadataReader;
import com.drew.metadata.Directory;
import com.drew.metadata.Metadata;
import com.drew.metadata.Tag;
import com.drew.metadata.exif.ExifIFD0Directory;

// 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 ValueRow #0 is:Column #0 is:对应的方向应该如何纠正
1TopLeft side无需纠正
2TopRight side水平翻转(镜像)
3BottomRight side垂直翻转(旋转180°)
4BottomLeft side水平翻转+垂直翻转
5Left sideTop水平翻转+旋转90°
6Right sideTop旋转90°
7Right sideBottom水平翻转+旋转270°
8Left sideBottom+旋转270°

可以参考下图一起理解

实现

import com.drew.imaging.ImageMetadataReader;
import com.drew.metadata.Directory;
import com.drew.metadata.Metadata;
import com.drew.metadata.Tag;
import com.drew.metadata.exif.ExifIFD0Directory;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileOutputStream;

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;
        }
    }
}
旋转后移动坐标

水平翻转

  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论
Java中实现图片镜像翻转可以通过使用Graphics2D类的方法来实现。首先,我们需要创建一个BufferedImage对象来装载原始图片,并且获取其宽度和高度,然后创建一个新的BufferedImage对象作为目标图片。接着,我们可以通过Graphics2D对象的drawImage()方法将原始图片绘制到目标图片上,并通过设置AffineTransform对象的scale()方法来进行水平或垂直方向的镜像翻转。最后,将目标图片保存到磁盘上或者显示在界面上。 具体地,我们可以通过如下的代码来实现图片的水平镜像翻转: ```java public BufferedImage flipImageHorizontally(BufferedImage originalImage) { int width = originalImage.getWidth(); int height = originalImage.getHeight(); BufferedImage flippedImage = new BufferedImage(width, height, originalImage.getType()); Graphics2D g = flippedImage.createGraphics(); g.drawImage(originalImage, 0, 0, width, height, width, 0, 0, height, null); g.dispose(); return flippedImage; } ``` 而如果需要实现垂直镜像翻转,可以通过如下的代码来完成: ```java public BufferedImage flipImageVertically(BufferedImage originalImage) { int width = originalImage.getWidth(); int height = originalImage.getHeight(); BufferedImage flippedImage = new BufferedImage(width, height, originalImage.getType()); Graphics2D g = flippedImage.createGraphics(); g.drawImage(originalImage, 0, 0, width, height, 0, height, width, 0, null); g.dispose(); return flippedImage; } ``` 以上就是在Java中实现图片镜像翻转的简单方法,通过Graphics2D类和AffineTransform对象的配合,可以轻松实现图片的水平或垂直镜像翻转。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

假女吖☌

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值