- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我注意到,在 Delphi XE6(以及生成在 Windows 上运行的应用程序并使用 native GDI 字体渲染的其他工具/语言)中,Win32 TextOut API 似乎无法平滑任何大于 149 的字体,即,字体大小>149。下面是两个 SpeedButton 的屏幕截图,两个 SpeedButton 的 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 中尝试此操作时所看到的那样。
我想使用 Clear Type 或经典的抗锯齿功能在 GDI Canvas 上绘制字体大小大于 149 的抗锯齿字符。我该怎么做?
请注意,我已经将 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 回退,只是一个异常(exception)。
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),
nil,
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, 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,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;
关于delphi - 我可以生成大于 149 的抗锯齿字体吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25368821/
尝试使用 tkinter 为一系列 PIL 图像制作动画。我的帧持续时间 (ms) 的图表如下所示: 有人知道是什么导致了这种尖尖的锯齿图案吗? 这是一个重现的脚本: from PIL import
我正在尝试使用 Canvas 创建“星爆”效果,但线段出现令人难以置信的像素化。我做错了什么吗? var rays = 40; var canvas = $("header canvas")[0];
爪牙 我在 JAGS 中有一个仅拦截逻辑模型,定义如下: model{ for(i in 1:Ny){ y[i] ~ dbern(mu[s[i]]) } for(j in 1:Ns){
我是一名优秀的程序员,十分优秀!