C#中基于GDI+(Graphics)图像处理系列之任意⾓度旋转图像
C#中基于GDI+(Graphics)图像处理系列之任意⾓度旋转图像
简介
图像旋转功能在实际使⽤中出现得不多,Image⾃带RotateFlip⽅法可以简单的实现90、180等⾓度的旋转或者翻转,但是如果要实现任意⾓度的旋转该怎么做?对于⼀个有经验的同学估计不到半天时间就可以完成,如果让新⼿遇到,估计就傻了,毕竟⾥⾯涉及了三⾓函数、空间坐标等⽅⾯的知识,⽐较蛋疼的是,Graphics(或者矩形)的旋转变换都是以左上⾓为原点,如果要以其中⼼进⾏旋转该怎么做?想知道的话就继续往后看吧。
本⽂将重点向⼤家介绍怎么使⽤GDI+(Graphics)获取图像按任意⾓度旋转后的图像。
动⼿前先解决两个问题
获取图⽚旋转后所占的矩形区域宽⾼
如动态图所⽰,我们已知源图宽⾼和旋转⾓度,需要计算动态图中黄⾊矩形的宽⾼,⽤数学⽰意图表⽰如下:
adults movies数学公式如下:
是不是有点晕,不⽤着急,直接看代码
/// <summary>
/// 计算矩形绕中⼼任意⾓度旋转后所占区域矩形宽⾼
/// </summary>
/// <param name="width">原矩形的宽</param>
/// <param name="height">原矩形⾼</param>
/// <param name="angle">顺时针旋转⾓度</param>
/// <returns></returns>
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)));
lamp是什么意思int newHeight =(int)(Math.Max(Math.Abs(width * sin - height * cos), Math.Abs(width * sin + height * cos)));
return new Rectangle(0,0, newWidth, newHeight);
}
已知⼀个矩形,如何绘制其绕其中⼼点旋转N度后的矩形区域
由于Graphics进⾏旋转平移等转换时的原点都是左上⾓,我们的要求是绕矩形中⼼旋转,需要三步完
成
(1)将Graphics的原点移⾄矩形的中点,假设坐标为(x,y)
(2)将Graphics绕当前原点旋转N度
(3)将Graphics沿(-x,-y)移回
每步形成效果如下图所⽰。红⾊为原矩形,黄⾊为第⼀步,蓝⾊为第⼆步,绿⾊为第三步。
上⾯⼏步实现的具体代码如下:
int angle =int.Par(txtDestAngle.Text);//txtDestAngle为界⾯中⼀个TextBox控件
var btn = nder as Button;
Graphics graphics =null;
try
{
//假设待处理的矩形长宽为
var w =120;
var h =60;
//创建graphics
graphics = pictureBox1.CreateGraphics();;//pictureBox1为界⾯中⼀个PictureBox控件
graphics.Clear(Color.Gray);
/
/原始位置
//画出矩形中⼼点
graphics.DrawEllip(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);
every one//画出矩形当前位置
graphics.DrawRectangle(new Pen(Color.Green),new Rectangle(0,0, w, h));
//重⾄绘图的所有变换
graphics.RetTransform();
rm16graphics.Save();
//***结束***
}
catch(Exception ex)
{
MessageBox.Show(ex.Message);
词典英语
}
finally
{
if(graphics !=null)
graphics.Dispo();
}
获得图像旋转任意⾓度后的图像
解决上述两个问题后,再想获取图像旋转任意⾓度后的图像就会变得很简单了
(1)已知⼀个原始图像srcImage和要旋转的⾓度
(2)获取这个图像按⾓度旋转后的宽⾼(rotateRect)
(3)根据旋转后的宽⾼定义Bitmap(rotateImage),定义Graphics,将Graphics按rotateImage的矩形区域中⼼进⾏旋转变换
常用(4)将srcImage绘制到rotateImage中⼼(即两个中⼼点重合)
(5)重置Graphics,完成
完整代码如下:
/// <summary>
/// 获取原图像绕中⼼任意⾓度旋转后的图像
/// </summary>
/// <param name="rawImg"></param>
/// <param name="angle"></param>
/// <returns></returns>
all right
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的旋转
purified
//计算:如果要将源图像画到画布上且中⼼与画布中⼼重合,需要的偏移量
Point Offt =new Point((rotateWidth - srcWidth)/2,(rotateHeight - srcHeight)/2);
//将源图⽚画到rect⾥(rotateRec的中⼼)
林书豪简介graphics.DrawImage(srcImage,new Rectangle(Offt.X, Offt.Y, srcWidth, srcHeight));
//重⾄绘图的所有变换
graphics.RetTransform();
graphics.Save();
}
catch(Exception ex)
{
throw ex;
}
finally
{
if(graphics !=null)
graphics.Dispo();
}
return destImage;
}
注意:如果发现有的⽅法没有具体实现,请移步获取完整的图像处理⼯具类源码