小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

GDI+學習及代碼總結(jié)之

 雨是雨花是花 2017-11-27

像的基本操作

在GDI+中,對圖像的處理主要靠兩個類,Image類和Bitmap類,Bitmap類是在Image類的基礎(chǔ)上派生出來的。這里主要講Image類的使用,Image類支持對BMP, GIF, JPEG, PNG, TIFF, 和 EMF,尤其注意,在PNG圖像中,包含ALPHA通道,所以能實現(xiàn)不規(guī)則圖像;

一、圖像的打開與顯示

圖像打開
我們在前言部分已經(jīng)講到,在GDI+中,對圖像的處理主要靠兩個類,Image類和Bitmap類,在Image類的構(gòu)造函數(shù)中,可以直接加載圖片供開發(fā)者使用,其加載方式為:

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ì)量

首先考慮兩個問題:
1、在拉伸圖像時,假設(shè)圖像會被拉大好幾倍,如何用原來的那些像素點來填充拉大后的圖像,就出現(xiàn)了問題,比如,原來一個像素點,在拉大圖像后,這個像素點周圍會變得空白,如何運用算法填充這些空白呢?
2、在縮小圖像時,同樣假設(shè)圖像縮小為原來的1/5,那么就說明在原圖像中,每5個像素,會被整合成一個像素,那這些像素怎么整合呢?哪種整合方法更好一點呢?

以上這兩上放、大縮小時,如何填充被放大的空間,如何整合縮小的像素,這些問題,這就是插補模式要考慮的問題,插補模式又稱為“插值模式”,是指如何計算兩個終點之間的中間值。也就是定義了很多種算法,這些算法的效果決定了縮放后圖像的質(zhì)量。
GDI+中使用Graphics類的SetInterpolationMode(設(shè)置插值模式)函數(shù)來指定插補算法??聪潞瘮?shù)定義:

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類只能整體克隆;
我們看下Bitmap類的Clone函數(shù):

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)下圖的效果;


但是,我們得一個個計算這些矩形的四個點坐標,很難,還好,DrawImage為我們提供了一個重載函數(shù),函數(shù)如下:

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)。











    本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導購買等信息,謹防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊一鍵舉報。
    轉(zhuǎn)藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多