有人问我如何对图像进行旋转处理,也就是让用户歪着脖子看图像,用户的脖子拧断了怎么办?反正不会来找我......
其实这个问题的一种解决方法是利用二维(x,y坐标中)矩阵转换实现图像旋转。使用高中时所学的三角知识或者大学中的线性代数知识就可以解决。其原理是已知一个点的坐标,那么这个点的旋转坐标可以通过(x*cos(A) + y*sin(A),- x*sin(A) + y*cos(A))
求得,这里A是以弧度为单位的角度(2P弧度=360度)。因此,只要将图像加载到内存中,然后将它选入设备上下文,接着调用GetPixel和SetPixel,象上面所说的那样映射所有的像素,便可以实现图像的旋转效果。对于90、180、-90度的旋转,这是一个不错的方法,因为正弦、余弦的值无外乎+/-1或者0......话还没等我说完,一块砖头就朝我头上飞过来了,啊唷,我当然不会叫你用这种方法做事情啦!有更好的方法呢。下面就是本文的正题:使用GDI+实现图像旋转处理。我想了解GDI+的人不是很多,因为它是Windows中的新东西。要想了解它的细节,请参考MSDN的有关文章。
GDI+是GDI图形库的一个增强版本,C++可以使用这个库。它内建于Windows XP 和Microsoft .NET,而对于Windows 98、Windows NT和Windows 2000,则有一个可重新发布的版本。GDI+是一个C++ API。它用C++类和C++方法。GDI+所包含的内容非常多,远远不止我在此所描述的这些。为了使用GDI+,你必须包含(#include)<gdiplus.h>文件,并将工程链接到gdiplus.lib库,这两个文件包含在最新的Windows SDK中。我对“在MFC程序中显示JPG/GIF图像”一文中的例子代码Myimgapp进行了重写,并改名为Myimgapp2,其代码对CPicture类进行了重大改动,因为原来的CPicture主要针对IPicture进行封装,而这一次主要是封装GDI+。下面是Myimgapp2运行画面,如图一所示。这个程序示范了如何用GDI+来旋转图像。
图一 图像旋转90度
前面说过,原来程序中的那个C++类CPicture是基于IPicture接口的,它处理图像的COM接口。在本文的例子程序Myimgapp2中,我重写了CPicture的代码,使用了GDI+里的图像类(Image)。对所有的细节都进行了封装。新的CPicture类不再使用 IPicture 这个COM接口,而是用Image取而代之,所有其它的类如CPictureView 和 CPictureCtrl都能和从前一样工作。但有两个障碍要解决:第一个是你必须对GDI库进行初始化以及最后的终止释放操作,与其说它是个障碍,还不如说它是GDI+本身的需要,在哪里进行这两个操作呢?最佳的地方莫过于在程序的 InitInstance 和 ExitInstance函数中: //初始化 GDI
class CMyApp : public CWinApp {
protected:
GdiplusStartupInput m_gdiplusStartupInput;
ULONG_PTR m_gdiplusToken;
…….
};
//释放GDI
BOOL CMyApp::InitInstance()
{
VERIFY(GdiplusStartup(&m_gdiplusToken,
&m_gdiplusStartupInput, NULL)==Ok);
…….
}
int CMyApp::ExitInstance()
{
GdiplusShutdown(m_gdiplusToken);
return CWinApp::ExitInstance();
}
CMyApp::m_gdiplusToken 是一个很神奇的东东,它来自GdiplusStartup 并被传递到GdiplusShutdown。m_gdiplusStartupInput 是一个结构,它包含某些GDI+的启动参数。缺省构造函数建立一个智能的缺省值,它又一次证明了C++比C更好。一旦你启动GDI+,就可以使用它了。原来的CPicture类有一个指向IPicture的指针,而新版的CPicture类有一个指向Image的指针。同样,它也有可重载的Load函数来从不同的地方加载图象。例如,下面便是新版的CPicture如何从某个路径名中加载图像文件。 BOOL CPicture::Load(LPCTSTR pszPathName)
{
Free();
USES_CONVERSION;
m_pImage = Image::FromFile(A2W(pszPathName),
m_bUseEmbeddedColorManagement);
return m_pImage->GetLastStatus()==Ok;
}