圖像的基本操作
在GDI+中,對圖像的處理主要靠兩個類,Image類和Bitmap類,Bitmap類是在Image類的基礎(chǔ)上派生出來的。這里主要講Image類的使用,Image類支持對BMP, GIF, JPEG, PNG, TIFF, 和 EMF,尤其注意,在PNG圖像中,包含ALPHA通道,所以能實現(xiàn)不規(guī)則圖像; 一、圖像的打開與顯示 圖像打開 Image(filename, useEmbeddedColorManagement) Image(stream, useEmbeddedColorManagement) ;//這個不講了,在一般不用,只在剪切保存圖片時有用參數(shù)說明: filename:[in]文件名,(可以是絕對地址,也可以是相對地址) useEmbeddedColorManament:[in]是否使用在保存在圖片中的色彩校正信息(如ICM、Gamma較正),該參數(shù)默認值為FALSE; 顯示圖片
對于圖像文件的顯示,GDI+主要使用DrawImage函數(shù)來完成。DrawImage函數(shù)是GDI+功能最強大、調(diào)用方式最為靈活的函數(shù)中的一種。能夠?qū)崿F(xiàn)在GDI中使用BitBlt函數(shù)不能實現(xiàn)的功能(如圖片的任意角度旋轉(zhuǎn)、倒置及插值運算),看下DrawImage的形式: DrawImage(Image* image, Point* destPoints, INT count) DrawImage(Image* image, PointF* destPoints, INT count) DrawImage(Image* image, Point* destPoints, INT count, INT srcx, INT srcy, INT srcwidth, INT srcheight, Unit srcUnit, ImageAttributes* imageAttributes, DrawImageAbort callback, VOID* callbackData) DrawImage(Image* image, PointF* destPoints, INT count, REAL srcx, REAL srcy, REAL srcwidth, REAL srcheight, Unit srcUnit, ImageAttributes* imageAttributes, DrawImageAbort callback, VOID* callbackData) DrawImage(Image* image, Rect& destRect, INT srcx, INT srcy, INT srcwidth, INT srcheight, Unit srcUnit, ImageAttributes* imageAttributes, DrawImageAbort callback, VOID* callbackData) DrawImage(Image* image, RectF& destRect, REAL srcx, REAL srcy, REAL srcwidth, REAL srcheight, Unit srcUnit, ImageAttributes* imageAttributes, DrawImageAbort callback, VOID* callbackData) DrawImage(Image* image, Point& point) DrawImage(Image* image, PointF& point) DrawImage(Image* image, Rect& rect) DrawImage(Image* image, RectF& rect) DrawImage(Image* image, INT x, INT y) DrawImage(Image* image, REAL x, REAL y) DrawImage(Image* image, INT x, INT y, INT srcx, INT srcy, INT srcwidth, INT srcheight, Unit srcUnit) DrawImage(Image* image, REAL x, REAL y, REAL srcx, REAL srcy, REAL srcwidth, REAL srcheight, Unit srcUnit) DrawImage(Image* image, INT x, INT y, INT width, INT height) DrawImage(Image* image, REAL x, REAL y, REAL width, REAL height)呃,上面的重載形式太多了,看得眼花繚亂,不過都是一種重載形式,由于變量的不同所以會出現(xiàn)兩個重載函數(shù),把相同的給咔嚓掉,最后實際就是下面幾種:
DrawImage(Image* image, PointF* destPoints, INT count) DrawImage(Image* image, PointF* destPoints, INT count, REAL srcx, REAL srcy, REAL srcwidth, REAL srcheight, Unit srcUnit, ImageAttributes* imageAttributes, DrawImageAbort callback, VOID* callbackData) DrawImage(Image* image, Rect& destRect, INT srcx, INT srcy, INT srcwidth, INT srcheight, Unit srcUnit, ImageAttributes* imageAttributes, DrawImageAbort callback, VOID* callbackData) DrawImage(Image* image, PointF& point) DrawImage(Image* image, RectF& rect) DrawImage(Image* image, INT x, INT y) DrawImage(Image* image, INT x, INT y, INT srcx, INT srcy, INT srcwidth, INT srcheight, Unit srcUnit) DrawImage(Image* image, INT x, INT y, INT width, INT height)其它先不看,我們看一種最難的形式: DrawImage(Image* image, Rect& destRect, INT srcx, INT srcy, INT srcwidth, INT srcheight, Unit srcUnit, ImageAttributes* imageAttributes, DrawImageAbort callback, VOID* callbackData)參數(shù)說明: image:[in]圖像文件對象; destRect:[in]目標顯示區(qū)域 srcx:[in]要截取的目標位置,在原圖中的X點坐標 srcy:[in]要截取的目標位置,在原圖中的Y坐標 srcwidth:[in]要截取的目標圖像的寬度 srcheight:[in]要截取的目標圖像的高度 注意:由于是截取一塊圖像作為顯示圖像在目標區(qū)域中顯示,所以這就出現(xiàn)了問題 1、當截取的圖像比目標區(qū)域小呢? 這時,就是將截取的圖像拉伸,以至完全填充到目標區(qū)域 2、當截取的圖像比目標區(qū)域大呢? 這里,就會將截取的圖像縮小并平鋪到目標區(qū)域中,并不會截取一部分顯示
看示例:(放大、縮?。?br> Image image(L"wlh.bmp"); UINT width=image.GetWidth(); UINT height=image.GetHeight(); //原圖顯示 graphics.DrawImage(&image,RectF(0,0,width,height)); //縮小并平鋪 graphics.TranslateTransform(width+10,0); graphics.DrawImage(&image,RectF(0,0,width/2,height/2-40)); //放大并平鋪,將在原圖指定區(qū)域截取的圖像,填充到目標區(qū)域中,填充時采用了縮放模式 graphics.TranslateTransform(width/2+10,0); RectF destinationRect(0,0,1.4*width,1.4*height); graphics.DrawImage(&image,destinationRect,20,20,width/2,height,UnitPixel); 二、使用插補模式控制圖形縮放質(zhì)量
首先考慮兩個問題: Status SetInterpolationMode( InterpolationMode interpolationMode );其中InterpolationMode是個枚舉類,枚舉了幾種插補模式,定義如下: enum InterpolationMode{ InterpolationModeInvalid = QualityModeInvalid,//插值無效 InterpolationModeDefault = QualityModeDefault,//默認模式 InterpolationModeLowQuality = QualityModeLow,//低質(zhì)量插值法 InterpolationModeHighQuality = QualityModeHigh,//高質(zhì)量插值法 InterpolationModeBilinear,//雙線性插值法 InterpolationModeBicubic,//雙三次插值法 InterpolationModeNearestNeighbor,//最臨近插值法 InterpolationModeHighQualityBilinear,//高質(zhì)量雙線性插值法 InterpolationModeHighQualityBicubic//高質(zhì)量雙三次插值法 };看下面這個圖片,顯示了將一個圖像使用不同的插值算法放大兩倍后的結(jié)果: 看一個簡單的應(yīng)用的例子吧:(最臨近插值法) Image image(L"bird.bmp"); UINT width=image.GetWidth(); UINT height=image.GetHeight(); Matrix matrix; graphics.GetTransform(&matrix); graphics.DrawImage(&image,RectF(0,0,width,height)); graphics.TranslateTransform(width+10,0); RectF destinationRect(0,0,2*width,2*height); graphics.SetInterpolationMode(InterpolationModeNearestNeighbor); graphics.DrawImage(&image,destinationRect,20,20,width/2,height/2,UnitPixel); 結(jié)論:由上面的所有擴大結(jié)果來看,只有“最臨近插值法”會產(chǎn)生馬賽克,而PS和其它的圖像處理工具都是用的它??赡苁且驗樗馁Y源消耗比較小,要注意,不同插值模式對系統(tǒng)資源的消耗也不同,其中高質(zhì)量雙三次插值方式對系統(tǒng)資源的消耗最大。 三、圖像操作 圖片的簡單旋轉(zhuǎn) 利用Bitmap或Image對象的RotateFilip函數(shù)就可以實現(xiàn)圖像的旋轉(zhuǎn)和翻轉(zhuǎn)了。該函數(shù)的調(diào)用方法為: Status RotateFlip( RotateFlipType rotateFlipType );其中RotateFlipType是一個枚舉類,枚舉了8種旋轉(zhuǎn)方式,看下定義: enum RotateFlipType{ RotateNoneFlipNone = 0,//不旋轉(zhuǎn)不翻轉(zhuǎn) Rotate90FlipNone = 1,//旋轉(zhuǎn)90度不翻轉(zhuǎn) Rotate180FlipNone = 2,//旋轉(zhuǎn)180度不翻轉(zhuǎn) Rotate270FlipNone = 3,//旋轉(zhuǎn)270度不翻轉(zhuǎn) RotateNoneFlipX = 4,//不旋轉(zhuǎn)水平翻轉(zhuǎn) Rotate90FlipX = 5,//旋轉(zhuǎn)90度水平翻轉(zhuǎn) Rotate180FlipX = 6,//旋轉(zhuǎn)180度水平翻轉(zhuǎn) Rotate270FlipX = 7,//旋轉(zhuǎn)270度水平翻轉(zhuǎn) RotateNoneFlipY = Rotate180FlipX,//往下的這些跟上面的效果都是一樣的,所以一般都不用下面的幾個 Rotate90FlipY = Rotate270FlipX, Rotate180FlipY = RotateNoneFlipX, Rotate270FlipY = Rotate90FlipX, RotateNoneFlipXY = Rotate180FlipNone, Rotate90FlipXY = Rotate270FlipNone, Rotate180FlipXY = RotateNoneFlipNone, Rotate270FlipXY = Rotate90FlipNone };看下效果: 看個簡單示例吧(RotateNoneFlipX--不旋轉(zhuǎn)水平翻轉(zhuǎn)) Image image(L"bird.bmp"); UINT width=image.GetWidth(); UINT height=image.GetHeight(); Matrix matrix; graphics.GetTransform(&matrix); graphics.DrawImage(&image,RectF(0,0,width/2,height/2)); graphics.SetTransform(&matrix); graphics.TranslateTransform(width/2+10,0); Image *img2=image.Clone(); img2->RotateFlip(RotateNoneFlipX); graphics.DrawImage(img2,RectF(0,0,width/2,height/2)); 使用縮略圖 GDI+中可以定制縮略圖,具體辦法是使用Image類的GetThumbnailImage來實現(xiàn),該函數(shù)的調(diào)用方法為: Image* GetThumbnailImage( UINT thumbWidth, UINT thumbHeight, GetThumbnailImageAbort callback, VOID* callbackData );參數(shù)說明: thumbWidh、thumbHeightt:[in]指明需要建立的縮略圖寬度和高度,在IMG中不會自動保持寬高比,會根據(jù)指定的高度和寬度完全填充; callback、callbackData:[in]建立縮略圖時要用到的回調(diào)函數(shù)及回調(diào)函數(shù)中數(shù)據(jù)的存放地址;在GDI+1.0版中不能使用此功能;注意XP中使用也是1.0版 注意:這里雖是指獲取縮略圖,但當所指區(qū)域比原圖大時,就會把原圖放大,與DrawImage指定目標區(qū)域,沒什么區(qū)別;
示例: graphics.SetInterpolationMode(InterpolationModeHighQualityBicubic); Image img(L"wlh.bmp"); float shear=img.GetHeight()/img.GetWidth();//獲取高/寬比,以至縮放時不變形 Image *pThumbnail=img.GetThumbnailImage(80,80*shear,NULL,NULL);//高度乘以高寬比 TextureBrush picBrush(pThumbnail); graphics.FillEllipse(&picBrush,RectF(10,10,400,200)); 克隆圖片 克隆復制是GDI+中的新概念,對圖片克隆的范圍可以是整體,也可以是局部的。實現(xiàn)克隆的辦法是使用Bitmap類/Image類的Clone成員函數(shù);需要注意的是,Bitmap類可以實現(xiàn)局部克隆和整體克隆,而Image類只能整體克隆; Clone() Clone(Rect& rect, PixelFormat format) Clone(RectF& rect, PixelFormat format) Clone(INT x, INT y, INT width, INT height, PixelFormat format) Clone(REAL x, REAL y, REAL width, REAL, height, PixelFormat format)參數(shù)說明: rect:[in]要克隆的區(qū)域,指在原圖中的坐標區(qū)域矩形; x,y:[in]要克隆區(qū)域的X,Y坐標; width,height:[in]要克隆區(qū)域的寬度和高度; 看下示例(將圖片通過克隆,分成四塊): Bitmap bmp(L"wlh.bmp"); INT height=bmp.GetHeight(); INT width=bmp.GetWidth(); RectF dest[4]; dest[0]=RectF(0,0,width/2,height/2); dest[1]=RectF(width/2,0,width/2,height/2); dest[2]=RectF(0,height/2,width/2,height/2); dest[3]=RectF(width/2,height/2,width/2,height/2); //把原圖像分為分四塊克隆 Bitmap *s[4]; s[0]=bmp.Clone(dest[0],PixelFormatDontCare); s[1]=bmp.Clone(dest[1],PixelFormatDontCare); s[2]=bmp.Clone(dest[2],PixelFormatDontCare); s[3]=bmp.Clone(dest[3],PixelFormatDontCare); //繪圖 graphics.DrawImage(s[0],RectF(0,0,width/2,height/2)); graphics.DrawImage(s[1],RectF(width/2+10,0,width/2,height/2)); graphics.DrawImage(s[2],RectF(0,height/2+10,width/2,height/2)); graphics.DrawImage(s[3],RectF(width/2+10,height/2+10,width/2,height/2)); 投射與傾斜 在前面我們講了,在DrawImge可以指定目標區(qū)域矩形,然后圖像就會自適應(yīng)這個矩形,所以按說我們可以用指定目標矩形的方式來實現(xiàn)下圖的效果;
Status DrawImage( Image* image, const Point* destPoints, INT count );參數(shù)說明: image:[in]圖像對象 destPoints:[in]目標區(qū)域的點的組合,這里只包含三個點,左上,右上,左下,對于第四個點的坐標,GDI+會根據(jù)平行四邊形原理自動計算位置; count:[in]destPoints數(shù)組里的點的個數(shù),必須等于3 示例:(實現(xiàn)上面的三面立方體) //清空原背景色,然后將背景色換為綠色 graphics.Clear(Color::Green); //設(shè)置填充模式 graphics.SetInterpolationMode(InterpolationModeHighQualityBicubic); Image img(L"wlh.bmp"); INT left=100; INT top=200; INT width=img.GetWidth(); INT height=img.GetHeight(); //正面 PointF desFace[]={ PointF(left,top), PointF(left+width,top), PointF(left,top+width), }; graphics.DrawImage(&img,desFace,3); //上面投射 PointF destTop[]={ PointF(left+width/2,top-width/2), PointF(left+width/2+width,top-width/2), PointF(left,top), }; graphics.DrawImage(&img,destTop,3); //側(cè)面投射 PointF desRight[]={ PointF(left+width,top), PointF(left+width/2+width,top-width/2), PointF(left+width,top+width) }; graphics.DrawImage(&img,desRight,3); 調(diào)整圖像的色彩信息
色彩調(diào)整,主要靠ImageAttributes類中的函數(shù)來操作的,所以這里也就是對ImageAttributes類中各函數(shù)功能的講解;這里說色彩較正,其實就是通過色彩變換矩陣,對色彩所進行的操作。 使用色彩變換矩陣,程序開發(fā)人員可以使用ImageAttributes對象修改在繪圖平面上的圖片輸出行為:使用修改后的色彩對應(yīng)關(guān)系。在修改過程中,可以臨時禁用或啟用色彩校正行為。ImageAttributes類的成員函數(shù)SetNoOp和ClearNoOp實現(xiàn)了對色彩校正的臨時關(guān)閉與啟用,其函數(shù)調(diào)用格式為: Status SetNoOp( ColorAdjustType type ); Status ClearNoOp( ColorAdjustType type );
其中,ColorAdjustType是個枚舉類,指明了幾種色彩調(diào)整對象; enum ColorAdjustType{ ColorAdjustTypeDefault,//匹配全部對象 ColorAdjustTypeBitmap,//僅匹配圖像,雖然這里用的是Bitmap,但不僅限于BMP圖像,只要是圖像都用這個 ColorAdjustTypeBrush,//僅匹配畫刷 ColorAdjustTypePen,//僅匹配畫筆 ColorAdjustTypeText,//僅匹配對文字的調(diào)整 ColorAdjustTypeCount,//不用 ColorAdjustTypeAny//不用,最后兩個是不用的; };上代碼,看示例: Image img(L"wlh.bmp"); int width=img.GetWidth(); int height=img.GetHeight(); //原圖 graphics.DrawImage(&img,RectF(0,0,width,height)); //應(yīng)用色彩變換 graphics.TranslateTransform(width+10,0); ColorMatrix colorMatrix={ 0.0f,1.0f,0.0f,0.0f,0.0f, 0.0f,1.0f,0.0f,0.0f,0.0f, 0.0f,0.0f,1.0f,0.0f,0.0f, 0.0f,0.0f,0.0f,1.0f,0.0f, 0.0f,0.0f,0.0f,0.0f,1.0f }; ImageAttributes imgattr; imgattr.SetColorMatrix(&colorMatrix,ColorMatrixFlagsDefault,ColorAdjustTypeBitmap); graphics.DrawImage(&img,RectF(0,0,img.GetWidth(),img.GetHeight()),0,0,img.GetWidth(),img.GetHeight(),UnitPixel,&imgattr); //清除對圖像的變換 imgattr.SetNoOp(ColorAdjustTypeBitmap); graphics.TranslateTransform(width+10,0); graphics.DrawImage(&img,RectF(0,0,img.GetWidth(),img.GetHeight()),0,0,img.GetWidth(),img.GetHeight(),UnitPixel,&imgattr); //清除剛才的清除操作 imgattr.ClearNoOp(ColorAdjustTypeBitmap); graphics.TranslateTransform(width+10,0); graphics.DrawImage(&img,RectF(0,0,img.GetWidth(),img.GetHeight()),0,0,img.GetWidth(),img.GetHeight(),UnitPixel,&imgattr); 二、設(shè)置透明色范圍(ImageAttributes::SetColorKey) 在上面的應(yīng)用中,我們可以通過對圖像的圖像逐個像素操作將指定的顏色設(shè)定為透明色,也可以通過ColorMap將指定的幾個顏色替換為其它顏色,在這里,是另一種設(shè)定圖片透明的方法——設(shè)定關(guān)鍵色(ColorKey),關(guān)鍵色就是指要設(shè)為透明的顏色值。通過ImageAttributes類的SetColorKey方法,定義如下: Status SetColorKey( const Color& colorLow, const Color& colorHigh, ColorAdjustType type );參數(shù)說明: colorLow:[in]透明色的最低值; colorHigh:[in]透明色的最高值; type:[in]指定要設(shè)定關(guān)鍵色的對象; 注意:假設(shè)colorLow設(shè)定為Color(100, 95, 30),colorHigh設(shè)定為:Color(250, 245, 60);那么對于顏色值Color(x,y,z);如果100<x<250 and 95<y<245 and 30<z<60,那么它就會被設(shè)為透明色; 示例:(去除王力宏圖片的背景,背景色我用PS加了個漸變,從Color(200,200,200)到Color(255,255,255),所以這個范圍也是要設(shè)定為關(guān)鍵色的范圍) 代碼: Image img(L"wlh2.bmp"); graphics.Clear(Color(255,0,255,0)); //繪制原圖 graphics.DrawImage(&img,RectF(0,0,img.GetWidth(),img.GetHeight())); //設(shè)置透明色范圍 graphics.TranslateTransform(img.GetWidth()+10,0); ImageAttributes imgAttributes; imgAttributes.SetColorKey(Color(255,200,200,200),Color(255,255,255,255),ColorAdjustTypeBitmap); graphics.DrawImage(&img,RectF(0,0,img.GetWidth(),img.GetHeight()),0,0,img.GetWidth(),img.GetHeight(),UnitPixel,&imgAttributes); 注意:在圖片上也可以看得到,王的鼻尖處也變成了透明色,這是因為它的色彩值范圍在設(shè)定的ColorKey的范圍內(nèi)。
|
|
來自: 雨是雨花是花 > 《大數(shù)據(jù)》