当前位置: 首页 > news >正文

java 图片数据管理_Java实现图片内容无损任意角度旋转

主要问题是如何在图片做旋转后计算出新图片的长宽。

在java 2d和基本math库的帮助下,其实利用简单的计算就可以知道。

以下算法只是计算出旋转小于90度时的公式。当旋转大于90时,可以先把问题域换算到锐角的情况,再进行计算即可。

如下图所示,需要计算出来的是len_delta的长度,就是有双竖线的位置,它是新图片要增加的宽。(要增加的高度同理可得。)

其实只要知道len的长度,还有len和len_delta的夹角,就可以算出len_delta的长度了。

1. len的长度。注意到它是等腰三角形的底边,顶角为angel, 容易得到len=2*R*sin(angel/2)

2. len和len_delta的夹角。先可以计算出angel_alpha,也就是等腰三角形的底角 angel_alpha = (PI - angel) / 2

然后是R和原图像的底边的夹角angel_delta,显然其tan值是原图片的高宽比(注意计算增加的高度时是宽高比)。用arctan求出其角度。

len和len_delta的夹角 = PI - angel_alpha - angel_delta

3. len_delta = len * cos(len和len_delta的夹角)

0_1330575546IDxZ.gif

java代码示例如下

[java]

importjava.awt.Dimension;

importjava.awt.Graphics2D;

importjava.awt.Image;

importjava.awt.Rectangle;

importjava.awt.image.BufferedImage;

publicclassRotateImage {

publicstaticBufferedImage Rotate(Image src,intangel) {

intsrc_width = src.getWidth(null);

intsrc_height = src.getHeight(null);

// calculate the new image size

Rectangle rect_des = CalcRotatedSize(newRectangle(newDimension(

src_width, src_height)), angel);

BufferedImage res = null;

res = newBufferedImage(rect_des.width, rect_des.height,

BufferedImage.TYPE_INT_RGB);

Graphics2D g2 = res.createGraphics();

// transform

g2.translate((rect_des.width - src_width) / 2,

(rect_des.height - src_height) / 2);

g2.rotate(Math.toRadians(angel), src_width / 2, src_height /2);

g2.drawImage(src, null,null);

returnres;

}

publicstaticRectangle CalcRotatedSize(Rectangle src,intangel) {

// if angel is greater than 90 degree, we need to do some conversion

if(angel >=90) {

if(angel /90%2==1){

inttemp = src.height;

src.height = src.width;

src.width = temp;

}

angel = angel % 90;

}

doubler = Math.sqrt(src.height * src.height + src.width * src.width) /2;

doublelen =2* Math.sin(Math.toRadians(angel) /2) * r;

doubleangel_alpha = (Math.PI - Math.toRadians(angel)) /2;

doubleangel_dalta_width = Math.atan((double) src.height / src.width);

doubleangel_dalta_height = Math.atan((double) src.width / src.height);

intlen_dalta_width = (int) (len * Math.cos(Math.PI - angel_alpha

- angel_dalta_width));

intlen_dalta_height = (int) (len * Math.cos(Math.PI - angel_alpha

- angel_dalta_height));

intdes_width = src.width + len_dalta_width *2;

intdes_height = src.height + len_dalta_height *2;

returnnewjava.awt.Rectangle(newDimension(des_width, des_height));

}

}


 

JUnit测试代码如下,将图片路径改为你自己准备测试用的图片路径即可。


 
importjava.awt.image.BufferedImage;

importjava.io.File;

importjava.io.IOException;

importjavax.imageio.ImageIO;

importjunit.framework.Assert;

importorg.junit.Test;

importJugnoo.RotateImage;

publicclassRotateImageTest {

@Test

publicvoidtestRotate()throwsIOException {

BufferedImage src = ImageIO.read(newFile("d:/dog.jpg"));

BufferedImage des = RotateImage.Rotate(src, 30);

Assert.assertNotNull(des);

Assert.assertTrue(ImageIO.write(des, "jpg",newFile("d:/dog2.jpg")));

// bigger angel

des = RotateImage.Rotate(src, 150);

Assert.assertNotNull(des);

Assert.assertTrue(ImageIO.write(des, "jpg",newFile("d:/dog3.jpg")));

// bigger angel

des = RotateImage.Rotate(src, 270);

Assert.assertNotNull(des);

Assert.assertTrue(ImageIO.write(des, "jpg",newFile("d:/dog4.jpg")));

}

}


 

 

相关文章:

  • java流量监控系统demo_搭建一个简单的基于web的网络流量监控可视化系统
  • jquery与java_纯javascript和jquery实现增删改查
  • mysql 批量字段前缀_sqlserver数据库,批量更改表名和字段的前缀 | 学步园
  • pdfpcell 怎么设置单元格大小_PdfPCell的方法隐藏单元格的边框
  • java strace_用strace排查故障的5种简单方法(每日一译)
  • java银行账户系统_用java编的银行账户系统代码
  • java扩展包_CodeRunner 的 Java 扩展 Jar 包支持
  • java session 修改_修改 Servlet 的sessionId
  • qt添加qwt帮助文件_win 7下安装qwt 6.1.0,基于qt 4.8.5
  • java亮眼_一些java处理变量的 让我眼前一亮的
  • 36岁自学python_深入 Python 解释器源码,我终于搞明白了字符串驻留的原理!
  • idea 收费标准_2013年IDEA期限与费用
  • java反射机制学习_java学习之 反射机制
  • 怎样看java文件的编码方式_如何查看Java源文件的编码方式及去掉BOM
  • 蓝桥杯泊松分酒java_蓝桥杯编程大题-泊松分酒 | 学步园
  • IE9 : DOM Exception: INVALID_CHARACTER_ERR (5)
  • Android开源项目规范总结
  • Apache Zeppelin在Apache Trafodion上的可视化
  • GDB 调试 Mysql 实战(三)优先队列排序算法中的行记录长度统计是怎么来的(上)...
  • JavaScript的使用你知道几种?(上)
  • JS变量作用域
  • Python 反序列化安全问题(二)
  • Quartz实现数据同步 | 从0开始构建SpringCloud微服务(3)
  • select2 取值 遍历 设置默认值
  • tab.js分享及浏览器兼容性问题汇总
  • Vue 2.3、2.4 知识点小结
  • vuex 学习笔记 01
  • 多线程 start 和 run 方法到底有什么区别?
  • 技术发展面试
  • 每天10道Java面试题,跟我走,offer有!
  • Spark2.4.0源码分析之WorldCount 默认shuffling并行度为200(九) ...
  • ​批处理文件中的errorlevel用法
  • #gStore-weekly | gStore最新版本1.0之三角形计数函数的使用
  • #ubuntu# #git# repository git config --global --add safe.directory
  • #调用传感器数据_Flink使用函数之监控传感器温度上升提醒
  • #我与Java虚拟机的故事#连载01:人在JVM,身不由己
  • (16)Reactor的测试——响应式Spring的道法术器
  • (java版)排序算法----【冒泡,选择,插入,希尔,快速排序,归并排序,基数排序】超详细~~
  • (剑指Offer)面试题41:和为s的连续正数序列
  • (六)c52学习之旅-独立按键
  • (三) prometheus + grafana + alertmanager 配置Redis监控
  • (算法)前K大的和
  • (原創) 如何將struct塞進vector? (C/C++) (STL)
  • (转)EXC_BREAKPOINT僵尸错误
  • .NET 6 Mysql Canal (CDC 增量同步,捕获变更数据) 案例版
  • .net core 实现redis分片_基于 Redis 的分布式任务调度框架 earth-frost
  • .NET Standard 支持的 .NET Framework 和 .NET Core
  • .net 微服务 服务保护 自动重试 Polly
  • .net/c# memcached 获取所有缓存键(keys)
  • .NET开源全面方便的第三方登录组件集合 - MrHuo.OAuth
  • .net企业级架构实战之7——Spring.net整合Asp.net mvc
  • @for /l %i in (1,1,10) do md %i 批处理自动建立目录
  • [100天算法】-每个元音包含偶数次的最长子字符串(day 53)
  • [20150904]exp slow.txt
  • [3D基础]理解计算机3D图形学中的坐标系变换