Image和Bitmap类概述
GDI+的Image类封装了对BMP、GIF、JPEG、PNG、TIFF、WMF(Windows元文件)和EMF(增强WMF)图像文件的调入、格式转换以及简单处理的功能。而Bitmap是从Image类继承的一个图像类,它封装了Windows位图操作的常用功能。例如,Bitmap::SetPixel和Bitmap::GetPixel分别用来对位图进行读写像素操作,从而可以为图像的柔化和锐化处理提供一种可能。 3.DrawImage方法 DrawImage是GDI+的Graphics类显示图像的核心方法,它的重载函数有许多个。常用的一般重载函数有: Status DrawImage( Image* image, INT x, INT y); Status DrawImage( Image* image, const Rect& rect); Status DrawImage( Image* image, const Point* destPoints, INT count); Status DrawImage( Image* image, INT x, INT y, INT srcx, INT srcy, INT srcwidth, INT srcheight, Unit srcUnit); 其中,(x,y)用来指定图像image显示的位置,这个位置和image图像的左上角点相对应。rect用来指定被图像填充的矩形区域, destPoints和count分别用来指定一个多边形的顶点和顶点个数。若count为3时,则表示该多边形是一个平行四边形,另一个顶点由系统自动给出。此时,destPoints中的数据依次对应于源图像的左上角、右上角和左下角的顶点坐标。srcx、srcy、srcwidth 和srcheight用来指定要显示的源图像的位置和大小,srcUnit用来指定所使用的单位,默认时使用PageUnitPixel,即用像素作为度量单位。 调用和显示图像文件 在GDI+中调用和显示图像文件是非常容易的,一般先通过Image或Bitmap调入一个图像文件构造一个对象,然后调用Graphics::DrawImage方法在指定位置处显示全部或部分图像。例如下面的代码: void CEx_GDIPlusView::OnDraw(CDC* pDC) { CEx_GDIPlusDoc* pDoc = GetDocument(); ASSERT_VALID(pDoc); using namespace Gdiplus; Graphics graphics( pDC->m_hDC ); Image image(L"sunflower.jpg"); graphics.DrawImage(&image, 10,10); Rect rect(130, 10, image.GetWidth(), image.GetHeight()); graphics.DrawImage(&image, rect); } 结果如图7.17所示,从图中我们可以看出,两次DrawImage的结果是不同的,按理应该相同,这是怎么一回事?原来,DrawImage在不指定显示区域大小时会自动根据设备分辨率进行缩放,从而造成显示结果的不同。 当然,也可以使用Bitmap类来调入图像文件来构造一个Bitmap对象,其结果也是一样的。例如,上述代码可改为: Bitmap bmp(L"sunflower.jpg"); graphics.DrawImage(&bmp, 10,10); Rect rect(130, 10, bmp.GetWidth(), bmp.GetHeight()); graphics.DrawImage(&bmp, rect); 需要说明的是,Image还提供GetThumbnailImage的方法用来获得一个缩略图的指针,调用DrawImage后可将该缩略图显示,这在图像预览时极其有用。例如下面的代码: Graphics graphics( pDC->m_hDC ); Image image(L"sunflower.jpg"); Image* pThumbnail = image.GetThumbnailImage(50, 50, NULL, NULL); // 显示缩略图 graphics.DrawImage(pThumbnail, 20, 20); // 使用后,不要忘记删除该缩略图指针 delete pThumbnail; 图像旋转和拉伸 图像的旋转和拉伸通常是通过在DrawImage中指定destPoints参数来实现,destPoints包含对新的坐标系定义的点的数据。图7.18说明了坐标系定义的方法。 从图中可以看出,destPoints中的第一个点是用来定义坐标原点的,第二点用来定义X轴的方法和图像X方向的大小,第三个是用来定义Y轴的方法和图像Y方向的大小。若destPoints定义的新坐标系中两轴方向不垂直,就能达到图像拉伸的效果。 下面的代码就是图像旋转和拉伸的一个示例,其结果如图7.19所示。 Image image(L"sunflower.jpg"); graphics.DrawImage(&image, 10,10); Point points[] = { Point(0, 0), Point(image.GetWidth(), 0), Point(0, image.GetHeight())}; Matrix matrix(1,0,0,1,230,10); // 定义一个单位矩阵,坐标原点在(230,10) matrix.Rotate(30); // 顺时针旋转30度 matrix.Scale(0.63,0.6); // X 和 Y 方向分别乘以0.63和0.6比例因子 matrix.TransformPoints(points, 3); // 用该矩阵转换points graphics.DrawImage(&image, points, 3); Point newpoints[] = {Point(450, 10), Point(510, 60), Point(350, 80)}; graphics.DrawImage(&image, newpoints, 3); 当然,对于图像旋转还可直接使用Graphics::RotateTransform来进行,例如下面的代码。但这样设置后,以后所有的绘图结果均会旋转,有时可能感觉不方便。 Image image(L"sunflower.jpg"); graphics.TranslateTransform(230,10); // 将原点移动到(230,10) graphics.RotateTransform(30); // 顺时针旋转30度 graphics.DrawImage(&image, 0,0); 调整插补算法的质量 当图像进行缩放时,需要对图像像素进行插补,不同的插补算法其效果是不一样的。Graphics:: SetInterpolationMode可以让我们根据自己的需要使用不同质量效果的插补算法。当然,质量越高,其渲染时间越长。下面的代码就是使用不同质量效果的插补算法模式,其结果如图7.20所示。 Graphics graphics( pDC->m_hDC ); Image image(L"log.gif"); UINT width = image.GetWidth(); UINT height = image.GetHeight(); // 不进行缩放 graphics.DrawImage( &image,10,10); // 使用低质量的插补算法 graphics.SetInterpolationMode(InterpolationModeNearestNeighbor); graphics.DrawImage( &image, Rect(170, 30, (INT)(0.6*width), (INT)(0.6*height))); // 使用中等质量的插补算法 graphics.SetInterpolationMode(InterpolationModeHighQualityBilinear); graphics.DrawImage( &image, Rect(270, 30, (INT)(0.6*width), (INT)(0.6*height))); // 使用高质量的插补算法 graphics.SetInterpolationMode(InterpolationModeHighQualityBicubic); graphics.DrawImage( &image, Rect(370, 30, (INT)(0.6*width), (INT)(0.6*height))); 事实上,Image功能还不止这些,例如还有不同格式文件之间的转换等。但这些功能和MFC的新类CImage功能基本一样,但CImage更符合MFC程序员的编程习惯,因此下一节中我们来重点介绍CImage的使用方法和技巧。 |