图像旋转功能在实际使用中出现得不多,Image自带RotateFlip方法可以简单的实现90、180等角度的旋转或者翻转,但是如果要实现任意角度的旋转该怎么做?对于一个有经验的同学估计不到半天时间就可以完成,如果让新手遇到,估计就傻了,毕竟里面涉及了三角函数、空间坐标等方面的知识,比较蛋疼的是,Graphics(或者矩形)的旋转变换都是以左上角为原点,如果要以其中心进行旋转该怎么做?想知道的话就继续往后看吧。
本文将重点向大家介绍怎么使用GDI+(Graphics)获取图像按任意角度旋转后的图像。
如动态图所示,我们已知源图宽高和旋转角度,需要计算动态图中黄色矩形的宽高,用数学示意图表示如下:
数学公式如下:
是不是有点晕,不用着急,直接看代码
///
/// 计算矩形绕中心任意角度旋转后所占区域矩形宽高
///
/// 原矩形的宽
/// 原矩形高
/// 顺时针旋转角度
///
public Rectangle GetRotateRectangle(int width, int height, float angle)
{
double radian = angle * Math.PI / 180; ;
double cos = Math.Cos(radian);
double sin = Math.Sin(radian);
//只需要考虑到第四象限和第三象限的情况取大值(中间用绝对值就可以包括第一和第二象限)
int newWidth = (int)(Math.Max(Math.Abs(width * cos - height * sin), Math.Abs(width * cos + height * sin)));
int newHeight = (int)(Math.Max(Math.Abs(width * sin - height * cos), Math.Abs(width * sin + height * cos)));
return new Rectangle(0, 0, newWidth, newHeight);
}
由于Graphics进行旋转平移等转换时的原点都是左上角,我们的要求是绕矩形中心旋转,需要三步完成
(1)将Graphics的原点移至矩形的中点,假设坐标为(x,y)
(2)将Graphics绕当前原点旋转N度
(3)将Graphics沿(-x,-y)移回
每步形成效果如下图所示。红色为原矩形,黄色为第一步,蓝色为第二步,绿色为第三步。
上面几步实现的具体代码如下:
int angle = int.Parse(txtDestAngle.Text);//txtDestAngle为界面中一个TextBox控件
var btn = sender as Button;
Graphics graphics = null;
try
{
//假设待处理的矩形 长宽为
var w = 120;
var h = 60;
//创建graphics
graphics = pictureBox1.CreateGraphics(); ;//pictureBox1为界面中一个PictureBox控件
graphics.Clear(Color.Gray);
//原始位置
//画出矩形中心点
graphics.DrawEllipse(new Pen(Color.Red), new Rectangle(w / 2 - 2, h / 2 - 2, 4, 4));
//画出矩形当前位置
graphics.DrawRectangle(new Pen(Color.Red), new Rectangle(0, 0, w, h));
//***第一步***
//将graphics坐标原点移到矩形中心点
graphics.TranslateTransform(w / 2, h / 2);
//画出矩形当前位置
graphics.DrawRectangle(new Pen(Color.Yellow), new Rectangle(0, 0, w, h));
//***第二步***
//graphics旋转相应的角度(绕当前原点)
graphics.RotateTransform(angle);
//画出矩形当前位置
graphics.DrawRectangle(new Pen(Color.Blue), new Rectangle(0, 0, w, h));
//***每三步***
//恢复graphics在水平和垂直方向的平移(沿当前原点)
graphics.TranslateTransform(-w / 2, -h / 2);
//画出矩形当前位置
graphics.DrawRectangle(new Pen(Color.Green), new Rectangle(0, 0, w, h));
//重至绘图的所有变换
graphics.ResetTransform();
graphics.Save();
//***结束***
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
finally
{
if (graphics != null)
graphics.Dispose();
}
解决上述两个问题后,再想获取图像旋转任意角度后的图像就会变得很简单了
(1)已知一个原始图像srcImage和要旋转的角度
(2)获取这个图像按角度旋转后的宽高(rotateRect)
(3)根据旋转后的宽高定义Bitmap(rotateImage),定义Graphics,将Graphics按rotateImage的矩形区域中心进行旋转变换
(4)将srcImage绘制到rotateImage中心(即两个中心点重合)
(5)重置Graphics,完成
完整代码如下
///
/// 获取原图像绕中心任意角度旋转后的图像
///
///
///
///
public Image GetRotateImage(Image srcImage, int angle)
{
angle = angle % 360;
//原图的宽和高
int srcWidth = srcImage.Width;
int srcHeight = srcImage.Height;
//图像旋转之后所占区域宽和高
Rectangle rotateRec = GetRotateRectangle(srcWidth, srcHeight, angle);
int rotateWidth = rotateRec.Width;
int rotateHeight = rotateRec.Height;
//目标位图
Bitmap destImage = null;
Graphics graphics = null;
try
{
//定义画布,宽高为图像旋转后的宽高
destImage = new Bitmap(rotateWidth, rotateHeight);
//graphics根据destImage创建,因此其原点此时在destImage左上角
graphics = Graphics.FromImage(destImage);
//要让graphics围绕某矩形中心点旋转N度,分三步
//第一步,将graphics坐标原点移到矩形中心点,假设其中点坐标(x,y)
//第二步,graphics旋转相应的角度(沿当前原点)
//第三步,移回(-x,-y)
//获取画布中心点
Point centerPoint = new Point(rotateWidth / 2, rotateHeight / 2);
//将graphics坐标原点移到中心点
graphics.TranslateTransform(centerPoint.X, centerPoint.Y);
//graphics旋转相应的角度(绕当前原点)
graphics.RotateTransform(angle);
//恢复graphics在水平和垂直方向的平移(沿当前原点)
graphics.TranslateTransform(-centerPoint.X, -centerPoint.Y);
//此时已经完成了graphics的旋转
//计算:如果要将源图像画到画布上且中心与画布中心重合,需要的偏移量
Point Offset = new Point((rotateWidth - srcWidth) / 2, (rotateHeight - srcHeight) / 2);
//将源图片画到rect里(rotateRec的中心)
graphics.DrawImage(srcImage, new Rectangle(Offset.X, Offset.Y, srcWidth, srcHeight));
//重至绘图的所有变换
graphics.ResetTransform();
graphics.Save();
}
catch (Exception ex)
{
throw ex;
}
finally
{
if (graphics != null)
graphics.Dispose();
}
return destImage;
}
注意:如果发现有的方法没有具体实现,请移步《C#中基于GDI+(Graphics)图像处理系列之前言》获取完整的图像处理工具类源码
http://download.csdn.net/detail/lhtzbj12/9730116
如果想查阅本系列其他文章,请移步《C#中基于GDI+(Graphics)图像处理系列之前言》