delphi – 我可以生成大于149的抗锯齿字体吗?
我注意到,在Delphi XE6(以及生成在
Windows上运行的应用程序并使用本机GDI字体渲染的其他工具/语言)中,Win32 TextOut API似乎不会平滑任何大于149的字体,即字体.Size> 149.这是一个屏幕截图,显示两个SpeedButtons,其中Font.Quality设置为fqClearType,左边的一个Font.Size设置为149,右边的一个设置Font.Size是150.这是一个点差异.高度值分别为-199和-200.这只是用Delphi组件和表单演示,也可以在TPaintBox中演示,使用Canvas.Font和调用Win32 API DrawText,或者使用创建窗口的纯Win32 API应用程序,并绘制使用DrawText到设备上下文.
GDI的局限性在这里清楚地显示出来;请注意,ClearType在size = 149时看起来平庸(水平抗锯齿但没有垂直),而ClearType在150处完全关闭: 我的问题是,有没有办法绕过Win32 API GDI中的这个限制,使用Windows 7及更高版本上提供的一些原始Win32函数来绘制文本并始终使用反别名?我假设逻辑字体处理正在VCL内部正确完成,因为在C#应用程序中使用相同的限制(使用WinForms,它在GDI上运行),正如我在Delphi中尝试这样做时所见. 我想将一个字体大小超过149的消除锯齿的字符绘制到GDI画布上,使用Clear Type或使用经典的Anti-Aliasing.我该怎么办? 请注意,我已经将Font.Quality显式设置为AntiAliased和ClearType模式,并且Win32 GDI api调用忽略了某些大小的逻辑字体属性,显然是通过设计.某些应用程序(如Microsoft Word)显然具有字体呈现功能,可以绘制155磅或更大的字体,在这种情况下仍然是抗锯齿. 更新:我回答了我自己的问题,显示了DirectWrite GDI互操作是多么容易.在Windows 7和Windows 8以及之后,DirectWrite实际上提供了水平和垂直抗锯齿,我相信这是高质量的屏幕字体渲染模式,就像MS Word 2013这样的应用程序正在使用.我相信有人可以轻松回答我的问题,显示GDI示例,这也符合我的要求(因为GDI包含在Windows 7和8中). 解决方法
我发现一种比GDI更好地与GDI进行互操作的工作方法是使用DirectWrite,但这只适用于Windows 7和8,我在这里提供的示例代码有一个简单的GDI回退模式(普通GDI,没有反…别名),涵盖XP和Vista,至少提供优雅的降级;它仍然使用GDI在Win7之前的操作系统上绘制文本.
原始的演示应用程序在这里,但它使用的是TForm,我改为TWinControl,它没有GDI后备,只是一个例外. http://cc.embarcadero.com/item/27491 撰写上述演示的Pawel Glowacki的讨论/博客文章如下: http://blogs.embarcadero.com/pawelglowacki/2009/12/14/38872 此处显示了一个代码片段,其中包含来自Pawel演示的修改后的D2DUtils.pas,并添加了GDI后备功能(而不是用例说明). uses Windows,Messages,SysUtils,Variants,Classes,Graphics,Controls,Forms,Dialogs,Winapi.D2D1,Vcl.Direct2D; type TCanvasD2D = class(TWinControl) // a base class,using TWinControl instead of TForm. private FInitFlag: Boolean; FGDIMode: Boolean; { Fallback } FD2DCanvas: TDirect2DCanvas; { Used When D2D is available and GDIMode=False } FGDICanvas: TCanvas; { Fallback canvas,used when FGDIMode=True } procedure WMEraseBkgnd(var Message: TWMEraseBkgnd); message WM_ERASEBKGND; protected procedure Resize; override; procedure DoPaint(AHDC: HDC); virtual; procedure CreateD2DResources; virtual; procedure PaintD2D; virtual; procedure PaintGDI; virtual; function RenderTarget: ID2D1RenderTarget; // convenience function used during D2D Paints. procedure PaintWindow(DC: HDC); override; public constructor Create(AOwner: TComponent); override; destructor Destroy; override; procedure Init; property D2DCanvas: TDirect2DCanvas read FD2DCanvas; property GDICanvas: TCanvas read FGDICanvas; property GDIMode: Boolean read FGDIMode write FGDIMode; { Set to true to force GDI fallback,will automatically set true if D2D is not available,also } end; TCanvasD2DSample = class(TCanvasD2D) // subclass of TCanvasD2D that is a primitive "TLabel" private FFontBrush: ID2D1SolidColorBrush;// Brush generated from current value of FFontColor FBackgroundColor:TColor; // clWhite FFontColor:TColor; //clBlack; FTextFormat: IDWriteTextFormat; FFontName: string; FFontSize: Integer; { Units?} FDisplayText: String; FLocale: String; procedure SetFontName(const Value: String); procedure SetFontSize(const Value: Integer); procedure SetDisplayText(const Value: String); protected procedure PaintD2D; override; procedure PaintGDI; override; procedure CreateD2DResources; override; function FontSizeToDip(FontSize:Integer ):Double; public constructor Create(AOwner: TComponent); override; property TextFormat:IDWriteTextFormat read FTextFormat; property FontSize:Integer read FFontSize write SetFontSize; property FontName:String read FFontName write SetFontName; property DisplayText: String read FDisplayText write SetDisplayText; property BackgroundColor:TColor read FBackgroundColor write FBackgroundColor; property FontColor:TColor read FFontColor write FFontColor; //clBlack; property Locale: String read FLocale write FLocale; // string like 'en-us' end; implementation constructor TCanvasD2D.Create(AOwner: TComponent); begin inherited; end; destructor TCanvasD2D.Destroy; begin FD2DCanvas.Free; FD2DCanvas := nil; FGDICanvas.Free; FGDICanvas := nil; inherited; end; procedure TCanvasD2D.Init; begin if not FInitFlag then begin FInitFlag := True; if (not FGDIMode) and (TDirect2DCanvas.Supported) then begin if Assigned(FD2DCanvas) then FD2DCanvas.Free; FD2DCanvas := TDirect2DCanvas.Create(Handle); CreateD2DResources; end else begin FGDIMode := True; if Assigned(FGDICanvas) then FGDICanvas.Free; FGDICanvas := TCanvas.Create; FGDICanvas.Handle := GetDC(Self.Handle); end; end; end; procedure TCanvasD2D.CreateD2DResources; begin // create Direct2D resources in descendant class end; function TCanvasD2D.RenderTarget: ID2D1RenderTarget; begin Result := D2DCanvas.RenderTarget; end; procedure TCanvasD2D.Resize; var HwndTarget: ID2D1HwndRenderTarget; ASize: TD2D1SizeU; begin inherited; if Assigned(D2DCanvas) then if Supports(RenderTarget,ID2D1HwndRenderTarget,HwndTarget) then begin ASize := D2D1SizeU(ClientWidth,ClientHeight); HwndTarget.Resize(ASize); end; Invalidate; end; procedure TCanvasD2D.WMEraseBkgnd(var Message: TWMEraseBkgnd); begin if (not FGDIMode) then // avoid flicker as described here: // http://chrisbensen.blogspot.com/2009/09/touch-demo-part-i.html Message.Result := 1 else inherited; end; procedure TCanvasD2D.DoPaint(AHDC: HDC); begin Init; if FGDIMode then begin FGDICanvas.Handle := AHDC; PaintGDI; end else begin D2DCanvas.BeginDraw; try PaintD2D; finally D2DCanvas.EndDraw; end; end; end; procedure TCanvasD2D.PaintD2D; begin // implement painting code in descendant class end; procedure TCanvasD2D.PaintGDI; begin // implement in descendant. end; procedure TCanvasD2D.PaintWindow(DC: HDC); begin DoPaint(DC); inherited; end; { Custom Control Subclass } procedure TCanvasD2DSample.CreateD2DResources; begin inherited; D2DCanvas.RenderTarget.CreateSolidColorBrush( D2D1ColorF(FFontColor,1),nil,FFontBrush ); DWriteFactory.CreateTextFormat( PWideChar(FontName),DWRITE_FONT_WEIGHT_REGULAR,DWRITE_FONT_STYLE_NORMAL,DWRITE_FONT_STRETCH_NORMAL,FontSizeToDip( FontSize),PWideChar(FLocale),FTextFormat ); FTextFormat.SetTextAlignment(DWRITE_TEXT_ALIGNMENT_CENTER); FTextFormat.SetParagraphAlignment(DWRITE_PARAGRAPH_ALIGNMENT_CENTER); end; function TCanvasD2DSample.FontSizeToDip(FontSize: Integer): Double; begin result := FontSize * (96.0 / 72.0); { TODO: 96.0 should not be hard coded? } end; procedure TCanvasD2DSample.PaintD2D; var aRect: TD2D1RectF; // ASize:D2D_SIZE_F; begin // fill with white color the whole window RenderTarget.Clear(D2D1ColorF(FBackgroundColor)); RenderTarget.DrawText( PWideChar(FDisplayText),Length(FDisplayText),FTextFormat,D2D1RectF(0,ClientWidth,ClientHeight),FFontBrush ); // RenderTarget.GetSize(ASize); end; procedure TCanvasD2DSample.PaintGDI; begin { FALLBACK PAINT MODE} GDICanvas.Lock; GDICanvas.Font.Name := FFontName; GDICanvas.Font.Size := FFontSize; GDICanvas.Font.Color := FFontColor; GDICanvas.Brush.Style := bsSolid; GDICanvas.Brush.Color := FBackgroundColor; GDICanvas.Rectangle(Self.ClientRect); GDICanvas.TextOut(0,FDisplayText); GDICanvas.Unlock; end; procedure TCanvasD2DSample.SetDisplayText(const Value: String); begin if Value<>FDisplayText then begin FDisplayText := Value; Invalidate; end; end; procedure TCanvasD2DSample.SetFontName(const Value: String); begin FFontName := Value; end; procedure TCanvasD2DSample.SetFontSize(const Value: Integer); begin FFontSize := Value; end; (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |