欢迎使用CSDN-markdown编辑器
来源:互联网 发布:小明看看白白永久域名 编辑:程序博客网 时间:2024/05/22 02:08
使用Windows API SetWorldTransForm()对图片进行旋转
版权声明:本文为博主原创文章,未经博主允许不得转载。
目录(?)[+]
1.问题描述
很多朋友可能都会遇到图片旋转的相关编程,一般的图像处理的书里面都会用一个自己写的函数对一个大的数组进行操作来解决旋转问题,这些函数往往还需要很多输入参数,如图片的大小,位的深度之类的,为了处理多种格式的图片我们往往需要重复编写代码,这样非常麻烦。
2.SetWorldTransForm函数
其实Windows 本身就提供了一个API函数SetWorldTransForm来解决图片旋转、位移及其他变形,这个函数是对一个设备上下文DC进行操作,通过坐标转换来实现各种功能的。
SetWorldTransForm内部的算法其实相当于用线性代数里矩阵与一个向量相乘的办法来解决图形的变换,只要我们知道要乘上的变换方程是哪一个,就能进行各种变换(不止是旋转)。
参考这篇文章的内容:Using SetWorldTransform() to rotate basic shapes by any angle - CodeProject
msdn对于SetWorldTransForm的参考说明
3.编程原理
对于选定DC的任何坐标(x, y)将被SetWindowsForm设定的变换转换为坐标(x’, y’),两个坐标的对应关系是
- x’ = x * eM11 + y * eM12 + eDx;
- y’ = x * eM12 + y * eM22 + eDy;
- x2 = cos(q)*(x1-x0) – sin(q)*(y1-y0) + x0;
- y2 = sin(q)*(x1-x0) + cos(q)*(y1-y0) + y0;
- xform.eM11 = cos(q);
- xform.eM12 = sin(q);
- xform.eM21 = -sin(q);
- xform.eM22 = cos(q);
- xform.eDx = x0 – cos(q)*x0 + sin(q)*y0;
- xform.eDy = y0 – cos(q)*y0 - sin(q)*x0;
4.源码
利用以上这一组参数,我封装了一个旋转函数RotateDC,并为之写了对应的恢复函数,以使DC被旋转后能转回原样:- #include <math.h>
- // 将DC旋转一定的角度
- inline int RotateDC(HDC hDc, int iAngle, POINT centerPt)
- {
- int nGraphicsMode = SetGraphicsMode(hDc, GM_ADVANCED);
- XFORM xform;
- if ( iAngle != 0 )
- {
- double fangle = (double)iAngle / 180. * 3.1415926;
- xform.eM11 = (float)cos(fangle);
- xform.eM12 = (float)sin(fangle);
- xform.eM21 = (float)-sin(fangle);
- xform.eM22 = (float)cos(fangle);
- xform.eDx = (float)(centerPt.x - cos(fangle)*centerPt.x + sin(fangle)*centerPt.y);
- xform.eDy = (float)(centerPt.y - cos(fangle)*centerPt.y - sin(fangle)*centerPt.x);
- SetWorldTransform(hDc, &xform);
- }
- return nGraphicsMode;
- }
- // 恢复旋转过的DC
- inline void RestoreRotatedDC(HDC hDc, int nGraphicsMode)
- {
- XFORM xform;
- xform.eM11 = (float)1.0;
- xform.eM12 = (float)0;
- xform.eM21 = (float)0;
- xform.eM22 = (float)1.0;
- xform.eDx = (float)0;
- xform.eDy = (float)0;
- SetWorldTransform(hDc, &xform);
- SetGraphicsMode(hDc, nGraphicsMode);
- }
5.使用方法及注意事项
@1.如何将一个图片转换后显示出来,或者得到旋转过的Bitmat对象?
此部分代码取自我自己的部分程序代码,是用GDI+绘制图片的,前面一半代码是绘制旋转的图片,后面是按正常坐标(不旋转)画一个扇形。
- // 获取控件尺寸
- CRect rc;
- GetClientRect(rc);
- CDC MemDC;
- MemDC.CreateCompatibleDC(pDC);
- // 创建内存DC
- CBitmap MemBmp;
- MemBmp.CreateCompatibleBitmap(pDC, rc.Width(), rc.Height());
- CBitmap *pOldBmp = MemDC.SelectObject(&MemBmp);
- Graphics graphics(MemDC.m_hDC);
- // 绘制背景图片
- CPoint centerPt((INT)((rc.left + rc.right) * 0.5), (INT)((rc.top + rc.bottom) * 0.5));
- // 获取一个旋转过的Graphics对象
- int nGraphicsMode = RotateDC(MemDC.m_hDC, 35, centerPt);
- Graphics rotatedGraphics(MemDC.m_hDC);
- RestoreRotatedDC(MemDC.m_hDC, nGraphicsMode);
- // 绘制图片
- Image image(m_pStream);
- rotatedGraphics.DrawImage(&image, (INT)rc.left, (INT)rc.top, (INT)(rc.right-rc.left), (INT)(rc.bottom-rc.top));
- // 扇形的外接长方开左上角坐标计算
- INT ellipseWidth = (INT)((rc.right-rc.left) * TYRE_SCALE);
- INT ellipseHeight = (INT)((rc.right-rc.left) * TYRE_SCALE);
- INT ellipseX = (INT)((rc.left + rc.right - ellipseWidth) * 0.5);
- INT ellipseY = (INT)((rc.top + rc.bottom - ellipseHeight) * 0.5);
- // 绘制当前位置
- SolidBrush redBrush(Color(128, 255, 0, 0));
- SolidBrush greenBrush(Color(128, 0, 255, 0));
- Rect ellipseRect(ellipseX, ellipseY, ellipseWidth, ellipseHeight);
- REAL startAngle = -90.0f;
- REAL sweepAngle = 90.0f;
- graphics.FillPie(&greenBrush, ellipseRect, startAngle, m_fCurrentDegree);
- pDC->BitBlt(0, 0, rc.Width(), rc.Height(), &MemDC, 0, 0, SRCCOPY);
- MemDC.SelectObject(pOldBmp);
- MemBmp.DeleteObject();
- MemDC.DeleteDC();
在经过这个处理之后,MemBmp里的内容就是旋转后的图片。如果直接调用BitBlt将MemDC的内容拷贝到显示DC中,可以直接显示旋转后的图片。
@2.在GDI+中的特别注意事项
注意Graphics对象如果是在RotateDC前创建的,那使用那个对象绘制的任何图形都不没有旋转的(如上面代码中第11行的graphics,尽管下面使用了RotateDC,但它绘制的效果并不旋转,只有像下面这段代码中的graphics对象绘制的效果才翻转,尽管后面的RestoreRotatedDC已经将MemDC恢复成不旋转,但这不影响rotatedGraphics的绘制)
- // 获取一个旋转过的Graphics对象
- int nGraphicsMode = RotateDC(MemDC.m_hDC, 35, centerPt);
- Graphics rotatedGraphics(MemDC.m_hDC);
- RestoreRotatedDC(MemDC.m_hDC, nGraphicsMode);
@3.可执行的演示程序
请参考Using SetWorldTransform() to rotate basic shapes by any angle - CodeProject
- 欢迎使用CSDN-markdown编辑器
- 欢迎使用CSDN-markdown编辑器
- 欢迎使用CSDN-markdown编辑器
- 欢迎使用CSDN-markdown编辑器
- 欢迎使用CSDN-markdown编辑器
- 欢迎使用CSDN-markdown编辑器
- 欢迎使用CSDN-markdown编辑器
- 欢迎使用CSDN-markdown编辑器
- 欢迎使用CSDN-markdown编辑器
- 欢迎使用CSDN-markdown编辑器
- 欢迎使用CSDN-markdown编辑器
- 欢迎使用CSDN-markdown编辑器
- 欢迎使用CSDN-markdown编辑器
- 欢迎使用CSDN-markdown编辑器
- 欢迎使用CSDN-markdown编辑器
- 欢迎使用CSDN-markdown编辑器
- 欢迎使用CSDN-markdown编辑器
- 欢迎使用CSDN-markdown编辑器
- textview点击弹出键盘的回车键,添加相应事件
- C3P0与数据库的连接与配置
- 幸运的袋子
- Java学习-反射机制的学习
- WebView跳转H5页面后无法交互问题
- 欢迎使用CSDN-markdown编辑器
- 学校私有云盘(私有云存储)解决方案!
- 【MySQL】Windows系统下安装MySQL 5.6.37(压缩包方式)
- Xcode Tips
- 测试之黑盒用例设计方法(状态迁移图法)
- 评职称自费出书需要多长时间
- 2.mybatis核心API以及创建dao的方式
- Golang简单总结
- Eclipse创建Maven项目时报错记录