起因

一个对试卷进行OCR识别需求,需要实现一个功能,一个章节下的题目图片需要上下拼接合成一张大图,起初写了一个工具实现图片的合并,程序一直很稳定的运行着,有一反馈合成的图片方向不对,起初怀疑是本身图片方向有问题,但是用windows图片查看器打开图片方向是正常“显示”的

定位

exif信息

查阅相关资料,图片信息中有个exif标准,exif信息如下:

图虫exif信息查看器:https://exif.tuchong.com/

关注IFD0节点方向,Rotate 270 CW,意思图片需要顺时针旋转270°方向正常,windows默认的图片查看器已经帮我们自动旋转展示了,我们在手机横排或者扫描仪、数码相机输出的图片通常包含此类信息,但是我们java读取的是图片的真实方向,所以在生成图片方向自然也就不对了

代码

添加依赖

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

自旋转代码

旋转图片

private static void rotateImage(List<String> stringList) {
stringList.forEach(s -> {
File file = new File(s);
try {
Metadata metadata = ImageMetadataReader.readMetadata(file);
StringBuilder description = new StringBuilder();
metadata.getDirectories().forEach(directory -> {
directory.getTags().forEach(tag -> {
if (tag.getTagType() == ExifDirectoryBase.TAG_ORIENTATION) {
description.append(tag.getDescription().replaceAll(" ", ""));
}
});
});
if (description.length() > 0) {
int rotateIndex = description.indexOf("Rotate");
int cwIndex = description.indexOf("CW");
if (rotateIndex >= 0 && cwIndex > 0 && rotateIndex < cwIndex) {
int angel = Integer.valueOf(description.substring(rotateIndex + 6, cwIndex));
log.info("============图片方向纠正,顺时针旋转{}°,图片路径:{}===========", angel, s);
BufferedImage oldImage = ImageIO.read(file);
BufferedImage newImage = RotateImage.Rotate(oldImage, angel);
ImageIO.write(newImage, "jpg", file);
newImage.getGraphics().dispose();
oldImage.getGraphics().dispose();
}
}
} catch (ImageProcessingException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} });
}

图片旋转工具类

import java.awt.*;
import java.awt.image.BufferedImage; public class RotateImage {
/**
* 对图片进行旋转
*
* @param src 被旋转图片
* @param angel 旋转角度
* @return 旋转后的图片
*/
public static BufferedImage Rotate(Image src, int angel) {
int srcWidth = src.getWidth(null);
int srcHeight = src.getHeight(null);
// 计算旋转后图片的尺寸
Rectangle rect_des = CalcRotatedSize(new Rectangle(new Dimension(
srcWidth, srcHeight)), angel);
BufferedImage res = null;
res = new BufferedImage(rect_des.width, rect_des.height,
BufferedImage.TYPE_INT_RGB);
Graphics2D g2 = res.createGraphics();
// 进行转换
g2.translate((rect_des.width - srcWidth) / 2,
(rect_des.height - srcHeight) / 2);
g2.rotate(Math.toRadians(angel), srcWidth / 2, srcHeight / 2); g2.drawImage(src, null, null);
return res;
} /**
* 计算旋转后的图片
*
* @param src 被旋转的图片
* @param angel 旋转角度
* @return 旋转后的图片
*/
public static Rectangle CalcRotatedSize(Rectangle src, int angel) {
// 如果旋转的角度大于90度做相应的转换
if (angel >= 90) {
if (angel / 90 % 2 == 1) {
int temp = src.height;
src.height = src.width;
src.width = temp;
}
angel = angel % 90;
} double r = Math.sqrt(src.height * src.height + src.width * src.width) / 2;
double len = 2 * Math.sin(Math.toRadians(angel) / 2) * r;
double angelAlpha = (Math.PI - Math.toRadians(angel)) / 2;
double angelDeltaWidth = Math.atan((double) src.height / src.width);
double angelDeltaHeight = Math.atan((double) src.width / src.height); int lenDeltaWidth = (int) (len * Math.cos(Math.PI - angelAlpha
- angelDeltaWidth));
int lenDeltaHeight = (int) (len * Math.cos(Math.PI - angelAlpha
- angelDeltaHeight));
int desWidth = src.width + lenDeltaWidth * 2;
int desHeight = src.height + lenDeltaHeight * 2;
return new Rectangle(new Dimension(desWidth, desHeight));
}
}

测试代码

public static void main(String[] args) throws ImageProcessingException, IOException {
File file = new File("D:\\temp\\error_direction");
List<String> stringList = Arrays.asList(file.listFiles()).stream().map(File::getAbsolutePath).collect(Collectors.toList());
rotateImage(stringList);
}

控制台日志如下:

18:52:40.066 [main] INFO ============图片方向纠正,顺时针旋转270°,图片路径:D:\temp\error_direction\185.jpg===========
18:52:40.879 [main] INFO ============图片方向纠正,顺时针旋转90°,图片路径:D:\temp\error_direction\186.jpg===========

至此,我们原始图片的方向被纠正了,我们再来看下纠正之后的图片的exif信息,发现旋转信息已经没有了

Java读取图片exif信息实现图片方向自动纠正的更多相关文章

  1. Android 图片Exif信息相关的获取与修改

    1 Exif是什么 Exif是一种图像文件格式,它的数据存储于JPEG格式是完全相同的,实际上Exif格式就是JPEG格式头插入了 数码照片的信息,包括拍摄的光圈.快门.平衡白.ISO.焦距.日期时间 ...

  2. Android--操作图片Exif信息

    前言 在Android系统中,图片文件在内存中以像素点的二维数组加载,存放像素信息,还会在开头加上一些额外的照片拍摄参数信息,这些信息就是Exif.Android2.0之后,媒体库加入了操作图片Exi ...

  3. Android -- 加载大图片到内存,从gallery获取图片,获取图片exif信息

    1. 加载大图片到内存,从gallery获取图片 android默认的最大堆栈只有16M, 图片像素太高会导致内存不足的异常, 需要将图片等比例缩小到适合手机屏幕分辨率, 再加载. 从gallery ...

  4. 七牛--关于图片上传方向不统一的问题--主要关于图片EXIF信息中旋转参数Orientation的理解

    [图片引用方向纠正]直接在图片后面添加 ?imageMogr/auto-orient eg:http://data.upfitapp.com/data/2016/10/18/1629114767606 ...

  5. Android 获取图片exif信息

    使用android api读取图片的exif信息 布局代码: <LinearLayout xmlns:android="http://schemas.android.com/apk/r ...

  6. 改动图片exif信息

    我们先了解一下EXIF: EXIF能够附加于JPEG.TIFF.RIFF等文件之中.为其添加有关数码相机拍摄信息的内容和索引图或图像处理软件的版本号信息. 全部的JPEG文件以字符串"0xF ...

  7. 图片Exif 信息中Orientation的理解和对此的处理

    这个问题是在用七牛上传图片后获取宽高时发现的,一张图片,用图片浏览器打开始终是竖图,但是查看属性或者用七牛获取宽高,却发现宽大于高,也就是在属性中这是个横图.这样导致客户端用该宽高来展示图片会出现问题 ...

  8. 七牛:关于图片 EXIF 信息中旋转参数 Orientation 的理解

    EXIF(Exchangeable Image File)是 “可交换图像文件” 的缩写,当中包含了专门为数码相机的照片而定制的元数据,可以记录数码照片的拍摄参数.缩略图及其他属性信息,简单来说,Ex ...

  9. 图片Exif信息

    Exif文件格式简述链接:https://www.zhihu.com/question/23727439/answer/25467748 可交换图像文件常被简称为Exif(Exchangeable i ...

随机推荐

  1. rxjs 常用的subject

    api列表 Subject Subject是可观察的一种特殊类型,它允许将值多播到许多观察者 import {Subject} from 'rxjs'; const l = console.log; ...

  2. 初学c++,vc++6.0必备!

    文章首发 | 公众号:lunvey 作为一个纯粹的萌新,工作需要,刚接触到c++. 按照以往的经验,配置一个开发环境是首要的,其次便是边学边敲. c++入门书籍寻找了一堆,发现了一个共同点,在Wind ...

  3. node初体验(一)

    1.node.js是一个构建在chrome V8引擎上的javascript运行环境 2.node.js特点:单线程.事件驱动.非阻塞IO模型.轻量 3.node.js是单线程的(多个请求都是一个线程 ...

  4. 一文读懂网管协议 - SNMP,NETCONF,RESTCONF

    本文篇幅较长,主要涉及以下内容: 介绍传统 CLI 配置网络设备存在的挑战,网管协议出现的背景 SNMP 原理,交互过程,以及 trade-off NETCONF 架构,交互过程 RESTCONF 架 ...

  5. 翻译:《实用的Python编程》02_04_Sequences

    目录| 上一节 (2.3 格式化) | 下一节 (2.5 Collections模块) 2.4 序列 序列数据类型 Python 有三种序列数据类型. 字符串:如 'Hello'.字符串是字符序列 列 ...

  6. [计算机图形学]Blinn-Phong光照模型

    目录 一.前言 二.原理 三.代码 一.前言 Blinn-Phong光照模型以Phong模型为基础的,提供比Phong更柔和.更平滑的高光,而且由于Blinn-Phong的光照模型省去了计算反射光线的 ...

  7. windows server 2008 r2 AD域服务器设置

    域控制器是指在"域"模式下,至少有一台服务器负责每一台联入网络的电脑和用户的验证工作,相当于一个单位的门卫一样,称为"域控制器(Domain Controller,简写为 ...

  8. 【产品设计】linux产品设计总结笔记

    Linux 预研产品设计   产品的目的: 1.综合集团内部重复性开发的工作,将多种操作系统统一到科东统一负责 2.明确技术在哪些设备上是可行的,再去拓展.一开始不做平台化产品 3.软件规划需要结合硬 ...

  9. Java 开发工具

    开发工具·Eclipse 常见开发工具介绍 * A:操作系统自带的记事本软件 * B:高级记事本软件 * C:集成开发环境 IDE     * (Integrated Development Envi ...

  10. 免费报表工具 积木报表(JiMuReport)的安装

    分享一b/s报表工具(服务),积木报表(JiMuReport),张代浩大佬出品. 官网:http://www.jimureport.com/ 离线版官方下载:https://github.com/zh ...