delphi - Can I generate an anti-aliased font size larger than 149? -
i have noticed, in delphi xe6 (and in other tools/languages produce applications run on windows, , use native gdi font rendering) win32 textout api not seem smooth font larger 149, is, font.size>149. here screenshot showing 2 speedbuttons, both font.quality set fqcleartype, 1 on left font.size set 149, 1 on right set font.size 150. that's 1 point difference. height values -199 , -200 respectively. demonstrate delphi component , form, demonstrated in tpaintbox, use of canvas.font , call win32 api drawtext
, or pure win32 api application creates window, , draws device context using drawtext
.
the limitation of gdi shown here; note cleartype looks mediocre (horizontal anti-aliasing no vertical) @ size=149 , , cleartype turns off @ 150:
my question is, there way circumvent limitation in win32 api gdi, using raw win32 function available on windows 7 , up, draw text , anti-alias? assume here logical font handling being done properly, inside vcl, because same limit occurs in c# application (using winforms, runs atop gdi) see when try in delphi.
i draw anti-aliased character font size greater 149, gdi canvas, either clear type or classic anti-aliasing. how that?
note have set font.quality explicitly both antialiased , cleartype modes, , win32 gdi api calls ignore these logical font properties size, apparently design. applications microsoft word, have font-rendering capability draw 155 point font or larger, , still anti-alias in case.
update: answered own question showing how easy directwrite+gdi interop is. on windows 7 , windows 8, , later, directwrite provides both horizontal , vertical anti-aliasing, , believe high quality on-screen font rendering mode apps ms word 2013 using. believe answer question showing gdi+ sample, , fit requirements above (as gdi+ included in windows 7 , 8).
a working approach have found interoperates gdi better gdi+ use directwrite
, works in windows 7 , 8, , sample code present here has simple gdi fallback mode (plain gdi, no anti-aliasing) covers xp , vista, provide @ least graceful degradation; still paints text on pre-win7 operating systems, using gdi.
the original demo app here, using tform changed twincontrol, , had no gdi fallback, exception.
http://cc.embarcadero.com/item/27491
the discussion/blog post pawel glowacki wrote above demo here:
http://blogs.embarcadero.com/pawelglowacki/2009/12/14/38872
a code snippet including modified d2dutils.pas pawel's demo addition of gdi fall-back feature (instead of blowing exception) shown here.
uses windows, messages, sysutils, variants, classes, graphics, controls, forms, dialogs, winapi.d2d1, vcl.direct2d; type tcanvasd2d = class(twincontrol) // base class, using twincontrol instead of tform. private finitflag: boolean; fgdimode: boolean; { fallback } fd2dcanvas: tdirect2dcanvas; { used when d2d available , 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 true force gdi fallback, automatically set true if d2d not available, } end; tcanvasd2dsample = class(tcanvasd2d) // subclass of tcanvasd2d primitive "tlabel" private ffontbrush: id2d1solidcolorbrush;// brush generated 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 '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 begin finitflag := true; if (not fgdimode) , (tdirect2dcanvas.supported) begin if assigned(fd2dcanvas) fd2dcanvas.free; fd2dcanvas := tdirect2dcanvas.create(handle); created2dresources; end else begin fgdimode := true; if assigned(fgdicanvas) 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) if supports(rendertarget, id2d1hwndrendertarget, hwndtarget) begin asize := d2d1sizeu(clientwidth, clientheight); hwndtarget.resize(asize); end; invalidate; end; procedure tcanvasd2d.wmerasebkgnd(var message: twmerasebkgnd); begin if (not fgdimode) // avoid flicker 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 begin fgdicanvas.handle := ahdc; paintgdi; end else begin d2dcanvas.begindraw; try paintd2d; 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 hard coded? } end; procedure tcanvasd2dsample.paintd2d; var arect: td2d1rectf; // asize:d2d_size_f; begin // fill white color 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 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;
Comments
Post a Comment