您的位置:首页 > 编程语言 > C#

在C#中使用GDI的简单总结

2011-07-09 16:56 274 查看
在C#中使用GDI的简单总结在C#默认支持的是GDI+库,使用GDI+库,有很丰富的函数和排版手段,可以满足大部分的要求.除非,你需要使用bitmap字体,GDI+对于字体的支持有很大限制,支持truetype字体,而对于点阵字体(栅格字体)则不再支持,但是很多字体都是这种点阵字体,这样就带来一个问题,使用不了了.而很多公司则会自己制作某些用途的字体,比如说在LED显示屏上使用,这个时候使用GDI+则不再是一个明智的选择了.此外GDI+虽然强大,但是经过测试发现效率却是低下,速度比GDI慢了不少.但是CS的界面开发环境和编码习惯又很适合,所以比较折衷的解决方法是使用C#调用系统的gdiapi函数实现编程.首先C#环境中的color结构是AARRGGBB,而在win32的颜色结构却是AABBGGRR,所以如果不注意则会使到颜色出现偏差或者逆转.在.net环境的类库当中,在system.drawing的命名空间中有ColorTranslator.ToWin32()这个函数,来对color结构转换成win32的api使用的颜色结构.GDI中比较重要的函数,gdi函数基本都是来之一个dll.Gdi32.dll[DllImport("gdi32.dll")] publicstaticexternIntPtrSelectObject(IntPtrhdc,IntPtrhgdiobj); [DllImport("GDI32.dll")] publicstaticexternboolDeleteObject(IntPtrobjectHandle); [DllImport("gdi32.dll")] publicstaticexternboolFillRgn(IntPtrhdc,IntPtrhrgn,IntPtrhbr); [DllImport("gdi32.dll")] publicstaticexternIntPtrCreateRectRgn(intnLeftRect,intnTopRect,intnRightRect, intnBottomRect); [DllImport("gdi32.dll")] publicstaticexternIntPtrCreateSolidBrush(Int32crColor); [DllImport("gdi32.dll")] publicstaticexternintSetBkMode(IntPtrhdc,intiBkMode); publicconstintTRANSPARENT=1; publicconstintOPAQUE=2; [DllImport("gdi32.dll")] staticexternuintSetBkColor(IntPtrhdc,intcrColor); [DllImport("gdi32.dll")] staticexternuintSetTextColor(IntPtrhdc,intcrColor); [DllImport("gdi32",EntryPoint="CreateFontW",CharSet=CharSet.Auto)] staticexternIntPtrCreateFontW( [In]Int32nHeight, [In]Int32nWidth, [In]Int32nEscapement, [In]Int32nOrientation, [In]FontWeightfnWeight, [In]BooleanfdwItalic, [In]BooleanfdwUnderline, [In]BooleanfdwStrikeOut, [In]FontCharSetfdwCharSet, [In]FontPrecisionfdwOutputPrecision, [In]FontClipPrecisionfdwClipPrecision, [In]FontQualityfdwQuality, [In]FontPitchAndFamilyfdwPitchAndFamily, [In]StringlpszFace); [DllImport("gdi32.dll")] publicstaticexternintGetTextFace(IntPtrhdc,intnCount, [Out]StringBuilderlpFaceName); publicconstInt32LF_FACESIZE=32; [DllImport("gdi32.dll",ExactSpelling=true)] publicstaticexternboolBitBlt( IntPtrhdcDest,//目标设备的句柄 intnXDest,//目标对象的左上角的X坐标 intnYDest,//目标对象的左上角的Y坐标 intnWidth,//目标对象的矩形的宽度 intnHeight,//目标对象的矩形的长度 IntPtrhdcSrc,//源设备的句柄 intnXSrc,//源对象的左上角的X坐标 intnYSrc,//源对象的左上角的X坐标 TernaryRasterOperationsdwRop//光栅的操作值 ); [DllImport("gdi32.dll")] publicstaticexternboolStretchBlt(IntPtrhdcDest,intnXOriginDest,intnYOriginDest, intnWidthDest,intnHeightDest, IntPtrhdcSrc,intnXOriginSrc,intnYOriginSrc,intnWidthSrc,intnHeightSrc, TernaryRasterOperationsdwRop); [DllImport("gdi32.dll",CharSet=CharSet.Auto)] publicstaticexternboolGetTextExtentPoint(IntPtrhdc,stringlpString, intcbString,refSizelpSize); [DllImport("Gdi32.dll",CharSet=CharSet.Auto)] publicstaticexternboolGetTextMetrics(IntPtrhdc,outTEXTMETRIClptm); [DllImport("gdi32.dll")] publicstaticexternboolGetCharABCWidthsFloatW(IntPtrhdc,uintiFirstChar,uintiLastChar,[Out]ABCFloat[]lpABCF); [DllImport("gdi32.dll",CharSet=CharSet.Auto)] publicstaticexternboolTextOutW(IntPtrhdc,intnXStart,intnYStart, stringlpString,intcbString); [DllImport("gdi32.dll",CharSet=CharSet.Auto)] publicstaticexternboolGetCharWidth32(IntPtrhdc,uintiFirstChar,uintiLastChar, [Out]int[]lpBuffer); [DllImport("user32.dll",CharSet=CharSet.Unicode)] publicstaticexternintDrawText(IntPtrhdc,stringlpStr,intnCount,refRectlpRect,dwDTFormatwFormat); [DllImport("gdi32.dll",ExactSpelling=true,SetLastError=true)] staticexternIntPtrCreateCompatibleDC(IntPtrhdc); [DllImport("gdi32.dll",ExactSpelling=true,SetLastError=true)] staticexternboolDeleteDC(IntPtrhdc);
这些都是在GDI中比较常用的函数,其中SelectObject,和DeleteObject更是关键,在GDI的使用中最容易出现的问题就是内存泄漏,很多时候是因为没有正确释放资源引起的.所以需要特别小心,在GDI中释放资源使用DeleteObject这个函数来释放.
下面来实现一些具体的函数
/// ///填充特定DC的一个区域的特定颜色 /// ///给定DC ///给定区域 ///给定颜色 publicstaticvoidFillRect(IntPtrhdc,RectangleRect,ColorFillColor) { IntPtrfillBrush=CreateSolidBrush(ColorTranslator.ToWin32(FillColor)); IntPtrrectR=CreateRectRgn(Rect.Left,Rect.Top,Rect.Right,Rect.Bottom); FillRgn(hdc,rectR,fillBrush); DeleteObject(rectR); DeleteObject(fillBrush); }
这个函数实现对一个区域填充一个颜色,当中创建了画笔,创建了区域,然后最后,当然还要记得释放两者占用的资源.
创建字体函数
publicstaticIntPtrCreatFont(StringFontName,Int32Height,FontStyleStyle) { IntPtrResult;//=IntPtr.Zero; FontWeightboldWeight=FontWeight.FW_NORMAL; BooleanItalic=false; BooleanUnderline=false; BooleanBold=false; if((Style&FontStyle.Bold)!=0) { Bold=true; } if((Style&FontStyle.Italic)!=0) { Italic=true; } if((Style&FontStyle.Underline)!=0) { Underline=true; } if(Bold) { boldWeight=FontWeight.FW_BOLD; } Result=CreateFontW(Height,0,0,0,boldWeight,Italic,Underline,false, FontCharSet.DEFAULT_CHARSET,FontPrecision.OUT_DEFAULT_PRECIS, FontClipPrecision.CLIP_DEFAULT_PRECIS,FontQuality.DRAFT_QUALITY, FontPitchAndFamily.DEFAULT_PITCH,FontName); returnResult; }
在.net中,默认的字体类,不支持点阵字体,所以要使用CreateFontW这个函数来创建自己的字体资源,其中大部分的选项都试用默认值即可.
然后就是设置画板字体,在GDI环境中,DC是带着字体的,而不像GDI+那样子是分离的,所以经常需要设置不同的字体
publicstaticIntPtrSetCanvasFont(IntPtrhdc,ApiFontNewFont) { IntPtrFontPtr=CreatFont(NewFont.Name,NewFont.Size,NewFont.Style); IntPtrOldPtr=SelectObject(hdc,FontPtr); DeleteObject(OldPtr); returnOldPtr; }
这个函数,将DC原来的字体资源释放掉,这样的实现会带来一个新的问题,因为一般来说都需要将DC原来的字体资源再通过selectobject函数放回去,然后将新的字体资源释放掉.所以这个函数是要小心使用的.
所以就有了第二个版本
publicstaticIntPtrSetCanvasFontNotDelete(IntPtrhdc,ApiFontNewFont)
{

IntPtrFontPtr=CreatFont(NewFont.Name,NewFont.Size,NewFont.Style);

IntPtrOldPtr=SelectObject(hdc,FontPtr);

returnOldPtr;

}


这样子就可以手动的释放资源,但是需要特别注意,的是一定要记得释放掉字体资源.
一般的使用画图的步骤
IntPtrpTarget=e.Graphics.GetHdc();

IntPtrpSource=CreateCompatibleDC(pTarget);

IntPtrpOrig=SelectObject(pSource,drawBmp.GetHbitmap());

GDIApi.StretchBlt(pTarget,0,0,this.Width,this.Height,pSource,0,0,drawWidth,drawHeight,TernaryRasterOperations.SRCCOPY);

IntPtrpNew=SelectObject(pSource,pOrig);

DeleteObject(pNew);

DeleteDC(pSource);

e.Graphics.ReleaseHdc(pTarget);

这样子就可以将drawBmp画到e.graphics上面了.最重要的是后面释放掉资源,否则内存的泄漏速度是很厉害的.我的软件每次重画就有7M左右的泄漏.一下子从十几M的内存上升到几百M的内存占用
[DllImport("gdi32.dll")]

publicstaticexternintSetBkMode(IntPtrhdc,intiBkMode);

publicconstintTRANSPARENT=1;

publicconstintOPAQUE=2;

这个函数是设置透明度的,参数2如果为1则是透明,2则是不透明.
不透明的话,将字符串画上去的时候,会有白色的背景.一般来说设为透明.
获取字符或者字体的信息函数
[DllImport("gdi32.dll",CharSet=CharSet.Auto)]

publicstaticexternboolGetTextExtentPoint(IntPtrhdc,stringlpString,

intcbString,refSizelpSize);

[DllImport("Gdi32.dll",CharSet=CharSet.Auto)]

publicstaticexternboolGetTextMetrics(IntPtrhdc,outTEXTMETRIClptm);

[DllImport("gdi32.dll")]

publicstaticexternboolGetCharABCWidthsFloatW(IntPtrhdc,uintiFirstChar,uintiLastChar,[Out]ABCFloat[]lpABCF);

[DllImport("gdi32.dll",CharSet=CharSet.Auto)]

publicstaticexternboolGetCharWidth32(IntPtrhdc,uintiFirstChar,uintiLastChar,

[Out]int[]lpBuffer);

这几个函数都可以获取字体或者字符串占用的空间大小,而又各有区别.
GetTextExtentPoint可以方便的获取一个字符串,或者字符串的部分的长度,因为可以通过cbString这个长度来控制获取的范围.
GetTextMetrics则是获取一个字体的各种高度信息,包括height,ascent,descent,还包括字体能够表现的字符范围等等信息.
GetCharABCWidthsFloatW则是获取某段连续字符串的abcwidth信息,abcwidth信息在某些情况下,需要特别注意,否则斜体会排版得很难看.
GetCharWidth32获取一个连续的字符段的宽度信息,但是根据实践,居然和GetTextExtentPoint获取的信息不大一致,暂时是少于实际占用的空间.使到计算出来的占用宽度实际上不足以容纳字符串的排版.
字符串的描绘
这是在gdi操作中非常重要的一部分,使用Gdi是因为需要使用特殊字体,而字体当然是针对字符串来使用的的.所以,这根本就是使用gdi的目的.
常用的字符串输出有来个函数
[DllImport("gdi32.dll",CharSet=CharSet.Auto)]

publicstaticexternboolTextOutW(IntPtrhdc,intnXStart,intnYStart,

stringlpString,intcbString);

[DllImport("user32.dll",CharSet=CharSet.Unicode)]

publicstaticexternintDrawText(IntPtrhdc,stringlpStr,intnCount,refRectlpRect,dwDTFormatwFormat);


TextOutW是一个比较简单的函数,适合一般的场合,只需要设置X和Y的坐标即可
DrawText,则会控制输出的空间大小,排版规则.比较适合需要精确控制的场所,又或者比如说输出阿拉伯文字的时候,要设置为右对齐.
获取系统所有的字体
由于C#不支持点阵字体,所以自然地,使用.net提供的函数,获取的安装字体列表自然是不包含点阵字体的.所以并不符合我的要求.所以还得使用系统的api函数,来获取安装字体列表.
privateInt32EnumFontCallBack(refENUMLOGFONTEXlpelfe,IntPtrlpntme,intFontType,intlParam)

{

//Debug.WriteLine(lpelfe.elfFullName);

if(lpelfe.elfFullName.Substring(0,1)!="@")

{

if(!sysFontList.Contains(lpelfe.elfFullName))

{

sysFontList.Add(lpelfe.elfFullName);

}

}

return1;

}

LOGFONTlogfont=newLOGFONT();

logfont.lfCharSet=FontCharSet.DEFAULT_CHARSET;

Bitmapbmp=newBitmap(10,10);

Graphicsg=Graphics.FromImage(bmp);

IntPtrhDC=g.GetHdc();

EnumFontFamilies.EnumFontFamiliesEx(hDC,logfont,EnumFontCallBack,IntPtr.Zero,0);

g.ReleaseHdc(hDC);

g.Dispose();

bmp.Dispose();

publicclassEnumFontFamilies

{

publicconstintLF_FACESIZE=32;

publicdelegateintEnumFontExDelegate(refENUMLOGFONTEXlpelfe,IntPtrlpntme,intFontType,intlParam);

[DllImport("gdi32.dll",EntryPoint="EnumFontFamiliesEx",CharSet=CharSet.Unicode)]

publicstaticexternintEnumFontFamiliesEx(IntPtrhDC,[In]LOGFONTlogFont,EnumFontExDelegateenumFontExCallback,

IntPtrlParam,uintdwFlags);

}


其中EnumFontCallBack为回调函数,通过这个回调函数,可以获取到系统所有的字体,包括点阵的字体.
附录A:
GDI使用的结构和常量
[StructLayout(LayoutKind.Sequential,CharSet=CharSet.Auto)]

publicstructENUMLOGFONTEX
{

publicLOGFONTelfLogFont;

[MarshalAs(UnmanagedType.ByValTStr,SizeConst=32)]

publicstringelfFullName;

[MarshalAs(UnmanagedType.ByValTStr,SizeConst=32)]

publicstringelfStyle;

[MarshalAs(UnmanagedType.ByValTStr,SizeConst=32)]

publicstringelfScript;

}

[StructLayout(LayoutKind.Sequential,CharSet=CharSet.Auto)]

publicclassLOGFONT
{

publicintlfHeight;

publicintlfWidth;

publicintlfEscapement;

publicintlfOrientation;

publicFontWeightlfWeight;

[MarshalAs(UnmanagedType.U1)]

publicboollfItalic;

[MarshalAs(UnmanagedType.U1)]

publicboollfUnderline;

[MarshalAs(UnmanagedType.U1)]

publicboollfStrikeOut;

publicFontCharSetlfCharSet;

publicFontPrecisionlfOutPrecision;

publicFontClipPrecisionlfClipPrecision;

publicFontQualitylfQuality;

publicFontPitchAndFamilylfPitchAndFamily;

[MarshalAs(UnmanagedType.ByValTStr,SizeConst=32)]

publicstringlfFaceName;

publicoverridestringToString()
{

StringBuildersb=newStringBuilder();

sb.Append("LOGFONT\n");

sb.AppendFormat("lfHeight:{0}\n",lfHeight);

sb.AppendFormat("lfWidth:{0}\n",lfWidth);

sb.AppendFormat("lfEscapement:{0}\n",lfEscapement);

sb.AppendFormat("lfOrientation:{0}\n",lfOrientation);

sb.AppendFormat("lfWeight:{0}\n",lfWeight);

sb.AppendFormat("lfItalic:{0}\n",lfItalic);

sb.AppendFormat("lfUnderline:{0}\n",lfUnderline);

sb.AppendFormat("lfStrikeOut:{0}\n",lfStrikeOut);

sb.AppendFormat("lfCharSet:{0}\n",lfCharSet);

sb.AppendFormat("lfOutPrecision:{0}\n",lfOutPrecision);

sb.AppendFormat("lfClipPrecision:{0}\n",lfClipPrecision);

sb.AppendFormat("lfQuality:{0}\n",lfQuality);

sb.AppendFormat("lfPitchAndFamily:{0}\n",lfPitchAndFamily);

sb.AppendFormat("lfFaceName:{0}\n",lfFaceName);

returnsb.ToString();

}

}

publicenumFontWeight:int
{

FW_DONTCARE=0,

FW_THIN=100,

FW_EXTRALIGHT=200,

FW_LIGHT=300,

FW_NORMAL=400,

FW_MEDIUM=500,

FW_SEMIBOLD=600,

FW_BOLD=700,

FW_EXTRABOLD=800,

FW_HEAVY=900,

}

publicenumFontCharSet:byte
{

ANSI_CHARSET=0,

DEFAULT_CHARSET=1,

SYMBOL_CHARSET=2,

SHIFTJIS_CHARSET=128,

HANGEUL_CHARSET=129,

HANGUL_CHARSET=129,

GB2312_CHARSET=134,

CHINESEBIG5_CHARSET=136,

OEM_CHARSET=255,

JOHAB_CHARSET=130,

HEBREW_CHARSET=177,

ARABIC_CHARSET=178,

GREEK_CHARSET=161,

TURKISH_CHARSET=162,

VIETNAMESE_CHARSET=163,

THAI_CHARSET=222,

EASTEUROPE_CHARSET=238,

RUSSIAN_CHARSET=204,

MAC_CHARSET=77,

BALTIC_CHARSET=186,

}

publicenumFontPrecision:byte
{

OUT_DEFAULT_PRECIS=0,

OUT_STRING_PRECIS=1,

OUT_CHARACTER_PRECIS=2,

OUT_STROKE_PRECIS=3,

OUT_TT_PRECIS=4,

OUT_DEVICE_PRECIS=5,

OUT_RASTER_PRECIS=6,

OUT_TT_ONLY_PRECIS=7,

OUT_OUTLINE_PRECIS=8,

OUT_SCREEN_OUTLINE_PRECIS=9,

OUT_PS_ONLY_PRECIS=10,

}

publicenumFontClipPrecision:byte
{

CLIP_DEFAULT_PRECIS=0,

CLIP_CHARACTER_PRECIS=1,

CLIP_STROKE_PRECIS=2,

CLIP_MASK=0xf,

CLIP_LH_ANGLES=(1<<4),

CLIP_TT_ALWAYS=(2<<4),

CLIP_DFA_DISABLE=(4<<4),

CLIP_EMBEDDED=(8<<4),

}

publicenumFontQuality:byte
{

DEFAULT_QUALITY=0,

DRAFT_QUALITY=1,

PROOF_QUALITY=2,

NONANTIALIASED_QUALITY=3,

ANTIALIASED_QUALITY=4,

CLEARTYPE_QUALITY=5,

CLEARTYPE_NATURAL_QUALITY=6,

}

[Flags]

publicenumFontPitchAndFamily:byte
{

DEFAULT_PITCH=0,

FIXED_PITCH=1,

VARIABLE_PITCH=2,

FF_DONTCARE=(0<<4),

FF_ROMAN=(1<<4),

FF_SWISS=(2<<4),

FF_MODERN=(3<<4),

FF_SCRIPT=(4<<4),

FF_DECORATIVE=(5<<4),

}

///<summary>

///EnumerationfortherasteroperationsusedinBitBlt.

///InC++theseareactually#define.Buttousethese

///constantswithC#,anewenumerationtypeisdefined.

///</summary>

publicenumTernaryRasterOperations
{

SRCCOPY=0x00CC0020,/*dest=source*/

SRCPAINT=0x00EE0086,/*dest=sourceORdest*/

SRCAND=0x008800C6,/*dest=sourceANDdest*/

SRCINVERT=0x00660046,/*dest=sourceXORdest*/

SRCERASE=0x00440328,/*dest=sourceAND(NOTdest)*/

NOTSRCCOPY=0x00330008,/*dest=(NOTsource)*/

NOTSRCERASE=0x001100A6,/*dest=(NOTsrc)AND(NOTdest)*/

MERGECOPY=0x00C000CA,/*dest=(sourceANDpattern)*/

MERGEPAINT=0x00BB0226,/*dest=(NOTsource)ORdest*/

PATCOPY=0x00F00021,/*dest=pattern*/

PATPAINT=0x00FB0A09,/*dest=DPSnoo*/

PATINVERT=0x005A0049,/*dest=patternXORdest*/

DSTINVERT=0x00550009,/*dest=(NOTdest)*/

BLACKNESS=0x00000042,/*dest=BLACK*/

WHITENESS=0x00FF0062,/*dest=WHITE*/

};

[Flags]

publicenumdwDTFormat:int
{

DT_TOP=0,DT_LEFT=0x00000000,DT_CENTER=0x00000001,DT_RIGHT=0x00000002,

DT_VCENTER=0x00000004,DT_BOTTOM=0x00000008,DT_WORDBREAK=0x00000010,DT_SINGLELINE=0x00000020,

DT_EXPANDTABS=0x00000040,DT_TABSTOP=0x00000080,DT_NOCLIP=0x00000100,DT_EXTERNALLEADING=0x00000200,

DT_CALCRECT=0x00000400,DT_NOPREFIX=0x00000800,DT_INTERNAL=0x00001000

};

publicstructRect
{

publicintLeft,Top,Right,Bottom;

publicRect(Rectangler)
{

this.Left=r.Left;

this.Top=r.Top;

this.Bottom=r.Bottom;

this.Right=r.Right;

}

}

[StructLayout(LayoutKind.Sequential,CharSet=CharSet.Auto)]

publicstructTEXTMETRIC
{

publicInt32tmHeight;

publicInt32tmAscent;

publicInt32tmDescent;

publicInt32tmInternalLeading;

publicInt32tmExternalLeading;

publicInt32tmAveCharWidth;

publicInt32tmMaxCharWidth;

publicInt32tmWeight;

publicInt32tmOverhang;

publicInt32tmDigitizedAspectX;

publicInt32tmDigitizedAspectY;

publicchartmFirstChar;

publicchartmLastChar;

publicchartmDefaultChar;

publicchartmBreakChar;

publicbytetmItalic;

publicbytetmUnderlined;

publicbytetmStruckOut;

publicbytetmPitchAndFamily;

publicbytetmCharSet;

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: