スムヌズなテキストスケヌリング

テキストのスケヌリングは、䞀芋するず思えるほど簡単な䜜業ではありたせん。 フォントサむズを単玔に倉曎するず、テキストの幅をスムヌズか぀比䟋的に倉曎するこずはできたせん。 倉曎は「段階的に」行われるため、スケヌリングが䜿甚されるあらゆる堎所で、あらゆる皮類の゚ディタヌ、グラフ、チャヌトの開発が倧幅に劚げられたす。

画像

䟋ずしお。 シヌルの線集者によっお開発されたした。 サブゞェクト領域の詳现のため、䜜業は「埮芖的」フォントで実行されたす。そのサむズは分数で非垞に小さくなりたす。 スケヌルなしではできたせん。 ただし、最倧スケヌルですべおのテキストが適切に蚭定されおいお、䜍眮合わせが完了し、すべおが矎しい堎合、「通垞の」スケヌルに戻るず、すべおの曞匏蚭定が「飛ぶ」こずができたす。

画像

倧芏暡な堎合、右偎のロゎは芋栄えがしたす。 ズヌムアりトのプロセスでは、状況が定期的に発生したす。これは巊の図に瀺されおいたす-碑文「スプロヌル」です。

画像

碑文は2぀の郚分で構成されおいたす。 巊偎にあるように、単䞀の党䜓のように芋えるマヌゞされたテキストがありたす。 しかし、碑文間をズヌムアりトするず、ギャップが顕著に珟れたす。
このようなプロゞェクトのスケヌル機胜は非垞に重芁です。 たた、圌らが倧芏暡に行ったこずは、どのような芏暡でも芋られるはずです。 蚱容できない「小さな」シフトや゚ラヌはありたせん。

テストアプリケヌション


スケヌルの方法をテストするために、小さなアプリケヌションを䜜成したす。 ゜ヌスコヌドはアヌカむブに蚘茉されおいたす。

画像


TxDrawZoomFunc = function (ACanvas : TCanvas; //    ARect : TRect; //   AZoom, ASize : double;// ,   AText : string //    ) : boolean; //   


 //****************************************************************************** //        //****************************************************************************** function DrawZoomCalcRect (ACanvas : TCanvas; ARect : TRect; AZoom, ASize : double; AText : string) : TRect; var siz : TSize; begin //--    ,   --------------------------------- ACanvas.Font.Height := -trunc(ASize * ACanvas.Font.PixelsPerInch/72); //--         ----------- GetTextExtentPoint32(ACanvas.Handle,PWideChar(AText),Length(AText), siz); //---------------------------------------------------------------------------- //  ,     , //       //---------------------------------------------------------------------------- result := ARect; result.Right := result.Left + round (AZoom * siz.Width); result.Bottom := result.Top + round (AZoom * siz.Height); end; 


いく぀かの補助機胜が䜿甚されたす。
 //****************************************************************************** //     //****************************************************************************** function WidthRect (ARect : TRect) : Integer; begin result := ARect.Right - ARect.Left; end; function HeightRect (ARect : TRect) : Integer; begin result := ARect.Bottom - ARect.Top; end; //****************************************************************************** //      //****************************************************************************** function CheckParamsValid (ACanvas : TCanvas; ARect : TRect; AObject : TObject; AObjChecked : boolean = true) : boolean; begin result := (ACanvas <> nil) and ((not AObjChecked) or (AObject <> nil)) and (WidthRect (ARect) > 0) and (HeightRect (ARect)>0); end; //****************************************************************************** //     ARect //****************************************************************************** function CreateBmpRect (ARect : TRect) : TBitmap; begin result := TBitmap.Create; result.Width := abs (WidthRect (ARect)); result.Height := abs (HeightRect (ARect)); end; 


方法1「額に」 分数フォントサむズ


問題を「真正面から」解決する堎合、これは道を譲りたすスケヌルに応じおフォントの高さを倉曎したす。 これには、Font.Heightなどのパラメヌタヌが適しおいたす。 これはピクセル単䜍のフォントの高さであり、物事の論理によるず、これはスムヌズなズヌムに぀ながるはずです。

Font.Height=−truncAZoom∗ASize∗Font.PixelsPerInch/72;

どこで


匏はどこから来たのですか。 Windowsのフォントの高さはポむントで衚されたすが、これはタむポグラフィに由来したす。

1むンチ= 25.4 mm = 72ポむント

したがっお、最初のズヌム機胜は次のずおりです。

 //****************************************************************************** //  " " // 1  = 25.4  = 72  //****************************************************************************** function DrawZoomTextSimple (ACanvas : TCanvas; ARect : TRect; AZoom, ASize : double; AText : string) : boolean; var rct : TRect; begin result := CheckParamsValid(ACanvas,ARect,nil,false) and (AText<>''); if not result then exit; rct := DrawZoomCalcRect(ACanvas, ARect, AZoom, ASize, AText); with Acanvas do begin Pen.Color := clGreen; Pen.Width := 1; Rectangle(rct); Font.Height := -trunc(AZoom * ASize * Font.PixelsPerInch / 72); TextOut (ARect.Left, ARect.Top, AText); GDiffWidth := WidthRect(rct) / TextWidth(AText); end; end; 

結果は図に衚瀺されたす。

画像

巊偎のデュヌスが゚ッゞのある灰色の線䞊に明確に配眮されおいる堎合、右偎の図のスケヌルがわずかに倉化するず、灰色の線は䞭倮のデュヌスず亀差したす。

結果は䞍十分です。

方法2「䞖界座暙」SetGraphicsMode


ノミをxで抌し蟌めないこずは明らかです。 Windowsが提䟛するツヌルを䜿甚する必芁がありたす。

 function SetGraphicsMode(hdc: HDC; iMode: Integer): Integer; 



操䜜アルゎリズムは次のずおりです。

  1. DCをGM_ADVANCEDに蚭定したす。
  2. TXForm構造䜓実際は行列ですのフィヌルドを初期化したす。 倉換は、次の匏に埓っお実行されたす。
    x ′ = x ∗ e M 11 + y ∗ e M 21 + e D x
    y ′ = x ∗ e M 12 + y ∗ e M 22 + e D y
    ご芧のずおり、スケヌルを実装するために、eM11およびeM22フィヌルドに関心がありたす。
  3. 倉換マトリックスの割り圓おSetWorldTransformDC、xFrm;
  4. スケヌルに関係なく、「通垞の」サむズで「通垞の」座暙にテキストを描画したす。
  5. 倉換を元の状態に戻したす。
  6. 前のモヌドに戻りたす。

2番目のズヌム機胜は次のずおりです。

 //****************************************************************************** //  SetGraphicsMode (GM_ADVANCED) //    //****************************************************************************** function DrawZoomTextWorldMode(ACanvas : TCanvas; ARect : TRect; AZoom, ASize : double; AText : string) : boolean; var rct : TRect; oldM : integer; xFrm : TXForm; begin result := CheckParamsValid(ACanvas,ARect,nil,false) and (AText <> ''); if not result then exit; //--      , =1 ------------- rct := DrawZoomCalcRect(ACanvas,ARect,1,ASize,AText); //--  ""    ---------------------- oldM := SetGraphicsMode(ACanvas.Handle, GM_ADVANCED); try //--   ------------------------------------------------------ FillChar(xFrm,SizeOf(xFrm),0); //--    ------------------------------------- // x' = x * eM11 + y * eM21 + eDx // y' = x * eM12 + y * eM22 + eDy xFrm.eM11 := AZoom; xFrm.eM22 := AZoom; //--    -------------------------------------- SetWorldTransform(ACanvas.Handle, xFrm); //--  ,        --------------------- with Acanvas do begin Pen.Color := clRed; Pen.Width := 1; Rectangle (rct); TextOut (rct.Left, rct.Top, AText); //--    /   -------- GDiffWidth := WidthRect(rct)/TextWidth(AText); end; finally //--      -------------------------------- xFrm.eM11 := 1; xFrm.eM22 := 1; SetWorldTransform(ACanvas.Handle, xFrm); //--     --------------------------------------------- SetGraphicsMode(ACanvas.Handle, oldM); end; end; 

結果は次のずおりです。

画像

状況は前の状況ず䌌おいたす。 巊偎では、デュヌスはセルの灰色の境界線の間に快適に配眮され、右偎ではセルラむンが亀差したす。 ぀たり 圌らは倧芏暡に「匕っ匵る」こずを取り陀きたせんでした。

ただし、肯定的な偎面もありたす。スケヌルを気にせずに描画できたす。 ぀たり、スケヌルに関係なく、非垞に䞍均衡にクヌルな䜕かを描画する非垞に倧きな関数がありたす。 呌び出す前に倉換行列を割り圓おるこずができ、それによっおスケヌリングする胜力が埗られたす。 この堎合、eDxおよびeDyパラメヌタヌを䜿甚しお、倉䜍も取埗したす。

線の倪さも瞮尺によっお倉わるこずに泚意しおください。 远加の利点ず倉換はトピック倖です。

その間、望たしい結果は達成されおいたせん。

スケヌル方法3 SetMapMode / MM_ISOTROPIC


SetGraphicsModeGM_ADVANCEDメ゜ッド2を䜿甚しおWindowsを䜿甚しお座暙を倉換しおも、そこで終了したせん。 以䞋の関数の束を考慮しおください。

 function SetMapMode(DC: HDC; p2: Integer): Integer; function SetWindowExtEx(DC: HDC; XExt, YExt: Integer; Size: PSize): BOOL; function SetViewportExtEx(DC: HDC; XExt, YExt: Integer; Size: PSize): BOOL; 

SetMapMode関数は、遞択されたデバむスコンテキストがピクセルを別のものず芋なすよう匷制したす。 ピクセルが実際に0.001むンチであるず仮定したす。 次の倀を取るこずができるパラメヌタヌp2に䟝存したす。


「巊から右にX、䞋から䞊にY」ずいう語句の意味は䜕ですか。 これは、Xの座暙は非垞に普通ですが、Y座暙は負であるこずを意味したす。 ぀たり、長方圢10,10,1000,1000に楕円を描きたい堎合、远加の倉換なしでそれを芋るには、楕円10、-10,1000、-1000を曞く必芁がありたす。

しかし、スケヌルに興味がありたす。 さらに、最も䞀般的で、すべおの軞で同じです。 したがっお、p2 = MM_ISOTROPICを䜿甚したす。

モヌドを蚭定した埌、スケヌル係数を蚭定する必芁がありたす。 これは、SetWindowExtEx / SetViewportExtEx関数のペアによっお行われたす

  1. 出力論理りィンドりの蚭定
    SetWindowExtExDC、論理幅、論理高さ、nil;
  2. 実際の出力りィンドりを蚭定する
    SetViewportExtExDC、実幅、実高、nil;

これで、画面の実際の幅高さ、圢状、ペむントボックス、任意の長方圢などのスケヌルができたした。 特定の論理的な幅高さに察応したす。たずえば、プリンタヌの甚玙、たたは瞮尺で衚瀺する必芁のある倧きな画像の幅などです。

スケヌルファクタヌは、F =実数倀/論理倀です。
なぜなら スケヌルは䞡方の軞で同じである必芁があり、Windowsは最小の比率を遞択したす。

論理量ずは䜕ですか。 特定の画像を反映したい堎合は、その幅ず高さになりたす。実際のサむズは、反映したいピクセル単䜍の領域です。

倉換関数は次のずおりです。
x '= x * F
y '= y * F

したがっお、幅の実際の倀ズヌム*幅ず高さズヌム*高さ。
3番目のズヌム機胜は次のようになりたす。

 //****************************************************************************** // :    SetMapMode/SetWindowExtEx/SetViewportExtEx //****************************************************************************** function DrawZoomTextMapMode (ACanvas : TCanvas; ARect : TRect; AZoom, ASize : double; AText : string) : boolean; var DC : HDC; rct : TRect; Old : integer; w,h : Integer; begin result := CheckParamsValid(ACanvas,ARect,nil,false); if not result then exit; //--   ,       ---- rct := DrawZoomCalcRect(ACanvas,ARect,1,ASize,AText) and (AText <> ''); //--       ----------------------------- DC := ACanvas.Handle; w := WidthRect(ARect); h := heightRect(ARect); //--     MM_ISOTROPIC    X  Y //--   (..       ) Old := SetMapMode(DC, MM_ISOTROPIC); //--     ---------------------- SetWindowExtEx(DC, w, h, nil); //--     ------------------------ SetViewportExtEx(DC, round(AZoom*W), round(AZoom*H), nil); //--  ------------------------------------------------- try with ACanvas do begin Pen.Color := clPurple; Pen.Width := 1; Rectangle(rct); TextOut (ARect.Left, ARect.Top, AText); GDiffWidth := WidthRect(rct)/TextWidth(AText); end; finally SetMapMode(DC, Old); end; end; 

ただし、結果はただ満足のいくものではありたせん。

画像

この状況は、前の2぀の状況ずたったく同じです。

この方法の利点は方法2ず䌌おいたす。「描画」関数を䜜成する際にスケヌルに぀いお心配する必芁はありたせんが、スケヌルを移動する方法はありたせん。 運動の倉容は玔粋に手䜜業です。

䞀般に、この関数は倉換によっおシャヌプ化されたせん。 この䜕かの単䜍で䜕かを衚瀺するのに適しおいたす。 これは、ナニットの1぀の蚀語から画面衚珟の蚀語ぞの䞀皮の「翻蚳者」です。

方法4 "むンチ" SetMapMode / MM_HIENGLISH


しかし、別のオプションを詊しおください。 方法3では、SetMapMode関数に぀いお詳しく説明したす。 メヌトル法からスクリヌンぞの倉換のフラグを含めるこずが蚀及されたした。 むンチ座暙系で䜜業しおみたしょう。 ミリ単䜍ではない理由-远加の倉換を避けるため。 結局のずころ、ただ最初はただいく぀かのむンチむンゞケヌタヌがありたす。 なぜ25.4で远加するのか方法1を参照。

䜕が促した。 それでも、0.001むンチの倀は非垞に小さな離散です。 もしもし
4番目のスケヌリング関数は次のずおりです。

 //****************************************************************************** //     SetMapMode/SetWindowExtEx/SetViewportExtEx // MM_HIENGLISH -      0.001 . //****************************************************************************** function DrawZoomTextMapModeHIENGLISH(ACanvas : TCanvas; ARect : TRect; AZoom, ASize : double; AText : string) : boolean; var DC : HDC; Old: integer; pnt : TPoint; rct : TRect; siz : TSize; tmp : Integer; begin result := CheckParamsValid(ACanvas,ARect,nil,false) and (AText <> ''); if not result then exit; //--    ,     --------- ACanvas.Font.Height := -trunc(ASize * ACanvas.Font.PixelsPerInch / 72); tmp := ACanvas.Font.Height; DC := ACanvas.Handle; //--       ------------------------ pnt.X := GetDeviceCaps(DC,LogPixelsX); //--       -------------------------- pnt.Y := GetDeviceCaps(DC,LogPixelsY); //--     (0.001 )----------------------------------- GetTextExtentPoint32(DC,PWideChar(AText),Length(AText), siz); rct.Top := -round(1000* AZoom * ARect.Top / pnt.Y); rct.Left := round(1000* AZoom * ARect.Left / pnt.X); rct.Right := rct.Left + round(1000* AZoom * siz.Width / pnt.X); rct.Bottom := rct.Top - round(1000* AZoom * siz.Height / pnt.Y); ACanvas.Font.Height := -round(rct.Bottom-rct.Top) ; Old := SetMapMode(DC, MM_HIENGLISH); try with Acanvas do begin Pen.Color := clTeal; Pen.Width := 1; Rectangle (rct); TextOut (rct.Left, rct.Top, AText); GDiffWidth := WidthRect(rct) / TextWidth(AText); end; finally SetMapMode(DC, Old); ACanvas.Font.Height := tmp; end; end; 

残念ながら、結果は以前のものより良くありたせん

画像

方法5「文字ごずのレンダリング」


以前のすべおのメ゜ッドでは、TLogFontの敎数郚分のように感じられたす。 lfHeightは寿呜を著しく損ない、特定のスケヌルぞの「埮調敎」を蚱可したせん。 ええず...それが分数だった堎合...たあ、さお、問題を別の方法で解決しおみたしょう。

䞻なアむデアは次のずおりです。テキストのすべおの文字を通過させるには、文字が衚瀺されるX軞に沿っお先頭をカりントしたす。 倉換係数は、蚈算された幅ず実数の比率ずしお最初に蚈算されたす。

 //****************************************************************************** //    //****************************************************************************** function DrawZoomTextChar(ACanvas : TCanvas; ARect : TRect; AZoom, ASize : double; AText : string) : boolean; var rct : TRect; fct : double; i : Integer; w : Integer; begin result := CheckParamsValid(ACanvas,ARect,nil,false) and (AText <> ''); if not result then exit; //-- ,        ---------- rct := DrawZoomCalcRect(ACanvas,ARect,AZoom,ASize,AText); try with ACanvas do begin Pen.Color := clMaroon; Pen.Width := 1; Rectangle(rct); GDiffWidth := WidthRect (rct); //--   ---------------------------------------------- Font.Height := -trunc(AZoom * ASize * Font.PixelsPerInch/72); //--  ""    ---------------------------- fct := WidthRect (rct)/TextWidth(AText); //--     ,   ,  w := 0; for i := 1 to Length(AText) do begin TextOut (rct.Left, rct.Top, AText[i]); w := w + TextWidth(AText[i]); //--        ----- rct.Left := round (ARect.Left + w * fct); end; GDiffWidth := GDiffWidth / (rct.Left-ARect.Left); end; except result := false; end; end; 

驚くべきこずに、それは動䜜したす

画像

デュヌスはラむンにしっかりずくっ぀いおおり、どんなスケヌルでもそれを残したせん。

最初の成功したスケヌリング方法。 目暙は達成されたしたが、より良い解決策が欲しいです。

方法6「ビットマップバッファヌ」


以前の方法は、各文字のレンダリングの開始をシフトするこずにより、事前に蚈算された必芁なサむズに文字ごずに「適合する」ずいうものでした。 しかし、ビットマップに基づいおすべお同じこずが行われた堎合はどうなりたすか

これは、テキストが最初に䞭間ビットマップ䞊に所定の瞮尺で描かれるずいうものです。 これを「戊闘」マトリックスず呌びたす。 次に、蚈算された倀に応じお、サむズが蚭定された別のビットマップ行列ぞのストレッチコピヌがありたす。 その埌、「透明な」コピヌが「䜜業䞭の」キャンバスにコピヌされたす。

機胜テキスト

 //****************************************************************************** //    TBitmap  StretchDraw //****************************************************************************** function DrawZoomTextBitmap(ACanvas : TCanvas; ARect : TRect; AZoom, ASize : double; AText : string) : boolean; var rct: TRect; val: TRect; siz: TSize; bmp: TBitmap; // - ""  dst: TBitmap; // -stretch  begin result := CheckParamsValid(ACanvas,ARect,nil,false) and (AText <> ''); if not result then exit; //-- ,        ---------- rct := DrawZoomCalcRect(Acanvas,Arect,AZoom,ASize,AText); //--      ----------------------------- ACanvas.Font.Height := -trunc(AZoom * ASize * ACanvas.Font.PixelsPerInch / 72); GetTextExtentPoint32(ACanvas.Handle,PWideChar(AText),Length(AText), siz); val := ARect; val.Right := val.Left + siz.Width; val.Bottom := val.Top + siz.Height; //-- -,     ----------------------------------- bmp := CreateBMPRect (val);//  ,  ""  try with bmp.Canvas do begin Font.Assign(ACanvas.Font); Brush.Color := clWhite; TextOut(0,0,AText); end; //--      ---------------------------------- dst := CreateBmpRect(rct); //-- / ""   ,    dst.Canvas.StretchDraw(dst.Canvas.ClipRect,bmp); //--      --------------------------------------- dst.TransparentColor := clWhite; dst.Transparent := true; with ACanvas do begin Pen.Color := clBlue; Pen.Width := 1; Rectangle(rct); ACanvas.Draw(rct.Left,rct.Top,dst); end; GDiffWidth := WidthRect(rct) / dst.Width; finally if dst <> nil then dst.Free; bmp.Free; end; end; 

そしお、この方法もうたく機胜したす

画像

テキストはそのセルに付着しおいるように芋えたした。 非垞にスムヌズなスケヌリング。

2番目に成功したスケヌリング方法。 目暙は達成されたしたが、さらに良い゜リュヌションが欲しいです。 最埌の2぀の方法は、リ゜ヌスを集䞭的に䜿甚したす。 これは盎接感じられたす。

方法7「GDI +」フォントサむズの拡倧瞮小


そこで、GDI +を䜿甚したスケヌリングやテキスト出力など、独自の正確で壮倧なツヌルを開発したした。

コメントする特別なものはありたせん。 䞻なこずは、スケヌルに応じおフォントサむズを倉曎するこずです。 アンチ゚むリアスTextRenderingHintAntiAliasを䜿甚しお、GDI +を䜿甚したテキスト出力。 他のすべおは゜ヌスから非垞に明確です

 //****************************************************************************** //  GDI+     //****************************************************************************** function DrawZoomTextGDIPlus(ACanvas : TCanvas; ARect : TRect; AZoom, ASize : double; AText : string) : boolean; var clr : TColor; grp : TGPGraphics; brh : TGPSolidBrush; nam : TGPFontFamily; fsl : FontStyle; src : TGPRectF; fnt : TGPFont; begin result := CheckParamsValid(ACanvas,ARect,nil,false) and (AText<>''); if not result then exit; ACanvas.Font.Height := -trunc(AZoom * ASize * ACanvas.Font.PixelsPerInch / 72); grp := TGPGraphics.Create(ACanvas.Handle); try with ACanvas do begin clr := Font.Color; //--    --------------------------------------------- nam := TGPFontFamily.Create(Font.Name); //--    --------------------------------------------- fsl := FontStyleRegular; if fsBold in Font.Style then fsl := fsl + FontStyleBold; if fsItalic in Font.Style then fsl := fsl + FontStyleItalic; if fsUnderline in Font.Style then fsl := fsl + FontStyleUnderline; if fsStrikeOut in Font.Style then fsl := fsl + FontStyleStrikeout; //--    ""    ---- grp.SetTextRenderingHint(TextRenderingHintAntiAlias); //--    ,   ------------------------------- brh := TGPSolidBrush.Create(MakeColor(GetRValue(clr), GetGValue(clr), GetBValue(clr))); //--    ,  ""  ---------------------- Fnt := TGPFont.Create(nam, ASize * Font.PixelsPerInch / 72, fsl, UnitPixel); //--  ""  ------------------------------- grp.MeasureString(AText,-1,fnt,MakePoint(ARect.Left*1.0, ARect.Top*1.0),src); //--  ""  ------------------------------- Pen.Color := clNavy; pen.Width := 1; Rectangle (round(src.X),round(src.Y), round(src.X + AZoom*src.Width), round(src.Y + AZoom*src.Height)); //--    ,     ------------------- GDiffWidth := AZoom*src.Width; Fnt.Free; //--      ------------------------------------- Fnt := TGPFont.Create(nam, AZoom * ASize * Font.PixelsPerInch / 72, fsl, UnitPixel); grp.SetTextRenderingHint(TextRenderingHintAntiAlias); grp.DrawString(AText, -1, Fnt, MakePoint(ARect.Left*1.0, ARect.Top*1.0), brh); //--        ------------------ grp.MeasureString(AText,-1,fnt,MakePoint(ARect.Left*1.0, ARect.Top*1.0),src); GDiffWidth := GDiffWidth / src.Width; end; except result := false; end; Fnt.free; brh.free; nam.free; grp.free; end; 

結果は圓然すべおの期埅を䞊回りたした。スクリヌンショットは提䟛したせん これらは、最埌の2぀の方法の䞊蚘に䌌おいたす。実行可胜ファむルを実行するこずで、GDI +のパワヌをさらに感じたす。

方法8「GDI +」スケヌル倉換


そしお再び、GDI +。しかし、今回はスケヌル倉換を䜿甚したす。぀たり「通垞の」サむズでテキストを描画するず、GDI +゚ンゞンがそのスケヌリングを凊理したす。倉換は、ScaleTransformAZoom、AZoomを呌び出すこずにより実行されたす。

 //****************************************************************************** //  GDI+     //****************************************************************************** function DrawZoomTextGDIPlusScale(ACanvas : TCanvas; ARect : TRect; AZoom, ASize : double; AText : string) : boolean; var clr : TColor; grp : TGPGraphics; brh : TGPSolidBrush; nam : TGPFontFamily; fsl : FontStyle; src : TGPRectF; fnt : TGPFont; pnt : TGPPointF; begin result := CheckParamsValid(ACanvas,ARect,nil,false) and (AText<>''); if not result then exit; grp := TGPGraphics.Create(ACanvas.Handle); try with ACanvas do begin clr := Font.Color; pnt := MakePoint(ARect.Left*1.0, ARect.Top*1.0); //--    --------------------------------------------- nam := TGPFontFamily.Create(Font.Name); //--    --------------------------------------------- fsl := FontStyleRegular; if fsBold in Font.Style then fsl := fsl + FontStyleBold; if fsItalic in Font.Style then fsl := fsl + FontStyleItalic; if fsUnderline in Font.Style then fsl := fsl + FontStyleUnderline; if fsStrikeOut in Font.Style then fsl := fsl + FontStyleStrikeout; //--    ""    ---- grp.SetTextRenderingHint(TextRenderingHintAntiAlias); //--    ,   ------------------------------- brh := TGPSolidBrush.Create(MakeColor(GetRValue(clr), GetGValue(clr), GetBValue(clr))); //--    ,  ""  ---------------------- Fnt := TGPFont.Create(nam, ASize * Font.PixelsPerInch / 72, fsl, UnitPixel); //--  ""  ------------------------------- grp.MeasureString(AText,-1,fnt,pnt,src); //--  ""  ------------------------------- Pen.Color := $00BC6C01; pen.Width := 1; Rectangle (round(AZoom*src.X),round(AZoom*src.Y), round(AZoom*(src.X + src.Width)), round(AZoom*(src.Y + src.Height))); //--    ---------------------------------- grp.ScaleTransform(AZoom,AZoom); grp.DrawString(AText, -1, Fnt, pnt, brh); GDiffWidth := 1; end; except result := false; end; Fnt.free; brh.free; nam.free; grp.free; end; 

䞊蚘のすべおの最良の結果。

詊隓結果


テストプログラムでは、[開始]ボタンをクリックしお統蚈の収集を開始できたす。提瀺されたすべおの方法の順次怜玢は、プログラムで可胜なすべおのスケヌルで行われたす。䜜業が終了するず、次のグラフが衚瀺されたす

画像

。最初の列はミリ秒単䜍の平均描画時間です。 2番目は、実際の倀からの蚈算倀の盞察偏差です。簡単に蚀えば、最初の列-操䜜にかかる時間の短さ、2番目の列-スケヌリング結果の高さです。

ご芧のずおり、メ゜ッドは2぀のグルヌプに分けられたす-最初の4぀-スケヌルの結果が䞍十分で、2぀目の4-スケヌリングが成功したす。

奇劙ですが、速床の面で最も䞍噚甚な最初の方法は、敗者のグルヌプでその掟手な兄匟よりも良い結果を瀺したした。確かに、圌の蚈算倀からの偏差は最倧です。

傑出した勝者は、スケヌル倉換を䌎う方法8「GDI +」です。
したがっお、個別の関数ずしおGDI +でテキストのレンダリングを䜜成したす。

指定された角床の回転ずアンチ゚むリアシングによるテキストの滑らかなスケヌリングの機胜


 //****************************************************************************** //   GDI+ //****************************************************************************** function DrawGDIPlusText (ACanvas : TCanvas; ARect : TRect; Angle, ASize : double; AText : string; AZoom : double = 1) : boolean; var clr : TColor; grp : TGPGraphics; brh : TGPSolidBrush; nam : TGPFontFamily; fsl : FontStyle; fnt : TGPFont; pnt : TGPPointF; begin result := CheckParamsValid(ACanvas,ARect,nil,false) and (AText<>''); if not result then exit; grp := TGPGraphics.Create(ACanvas.Handle); try with ACanvas do begin clr := Font.Color; //--    --------------------------------------------- nam := TGPFontFamily.Create(Font.Name); //--    --------------------------------------------- fsl := FontStyleRegular; if fsBold in Font.Style then fsl := fsl + FontStyleBold; if fsItalic in Font.Style then fsl := fsl + FontStyleItalic; if fsUnderline in Font.Style then fsl := fsl + FontStyleUnderline; if fsStrikeOut in Font.Style then fsl := fsl + FontStyleStrikeout; //--    ,   ------------------------------- brh := TGPSolidBrush.Create(MakeColor(GetRValue(clr),GetGValue(clr),GetBValue(clr))); //--    ,  ""  ---------------------- Fnt := TGPFont.Create(nam, ASize * Font.PixelsPerInch / 72, fsl, UnitPixel); //--    ""    ---- grp.SetTextRenderingHint(TextRenderingHintAntiAlias); //--     -------------------------------------- pnt := MakePoint(ARect.Left*1.0, ARect.Top*1.0); //--  ,  ,       grp.TranslateTransform(pnt.X,pnt.y); //--   ,    ------------------ if Angle <> 0 then begin //--    ---------------------------------- grp.RotateTransform(Angle); end; //--      ""  ------------------- pnt := MakePoint(0.0,0.0); //--   ,    ------------------ if AZoom <> 1 then begin grp.ScaleTransform(AZoom,AZoom); end; //--      ------------------------------------- grp.DrawString(AText, -1, Fnt, pnt, brh); end; except result := false; end; Fnt.free; brh.free; nam.free; grp.free; end; 

短い結論ずコメント



最新のステヌトメントのデモンストレヌションずしお、統蚈出力関数は、DrawGDIPlusText関数を䜿甚しお、角床ず角床を含むテキストの出力ずスケヌルずオフセットを担圓するSetGraphicsModeを䜿甚しお蚘述されたす。

次の圢匏で
 type TFmMain = class(TForm) 
 private FList : TxZoomStatList; //   (utlZoomStat) FListPoint : TPoint; FMouseDown : boolean; FMousePoint: TPoint; FProcessing : boolean; 
 End; procedure TFmMain.pbMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); begin FMouseDown := (Button = mbLeft) and //--  -    ----------------- (ComboBox1.ItemIndex=ComboBox1.Items.Count-1); if FMouseDown then begin //--  ,    ---------------- FMousePoint := Point(X,Y); //--    --------------------------------- FListPoint := Point(FList.OffX, FList.OffY); end; end; procedure TFmMain.pbMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer); begin if FMouseDown then begin //--    ------------------------------------------ FList.OffX := FListPoint.X + X-FMousePoint.X; FList.OffY := FListPoint.Y + Y-FMousePoint.Y; //--   ----------------------------------------------- pbPaint(Sender); end; end; procedure TFmMain.pbMouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); begin //--   --------------------- FMouseDown := false; end; 


統蚈クラスの説明
 type //****************************************************************************** //    //****************************************************************************** PxZoomStat = ^TxZoomStat; TxZoomStat = packed record FIndex : Integer; FColor : TColor; FName : string; FCount : Integer; FTime : extended; FDiff : extended; FTimeC : extended; FDiffC : extended; FTimeR : TRect; FDiffR : TRect; end; TxZoomStatList = class private FOffX : Integer; FOffY : Integer; FList : TList; FGDIPlus : boolean; function GetCount : Integer; function GetItem (Index : Integer) : PxZoomStat; public Constructor Create; virtual; Destructor Destroy; override; function Add (AIndex : Integer; AName : string; ATime, ADiff : Extended) : Integer; overload; function Add (AIndex : Integer; ATime, ADiff : Extended) : PxZoomStat; overload; procedure Delete (Index : Integer); procedure Clear; property Count : Integer read GetCount; property Items[Index : Integer] : PxZoomStat read GetItem; default; //-------------------------------------------------------------------------- property GDIPlus : boolean read FGDIPlus write FGDIPlus; property OffX : Integer read FOffX write FOffX; property OffY : Integer read FOffY write FOffY; end; 


統蚈を描画したす。DrawZoomStatList
 //****************************************************************************** //   //   .    ,      //  .  ,      . //        // SetGraphicsMode(DC, GM_ADVANCED); //****************************************************************************** function DrawZoomStatList(ACanvas : TCanvas; ARect : TRect; AZoom, ASize : double; AText : string) : boolean; var lst : TxZoomStatList; //     (  utlZoomStat) rct : TRect; val : TRect; str : string; i : Integer; p : PxZoomStat; wBar : Integer; //------------------------------------------------------------------------------ maxTime : Extended; maxDiff : Extended; minTime : Extended; minDiff : Extended; wTime : Extended; wDiff : Extended; //--  ------------------------------------------------------------------- DC : HDC; fnt : hFont; tmp : hFont; //-------------------------------------- oldM : integer; xFrm : TXForm; begin lst := xGZoomList(false); result := CheckParamsValid(ACanvas,ARect,lst,true); if not result then exit; DC := ACanvas.Handle; maxTime :=-1; maxDiff :=-1; minTime := MaxInt; minDiff := MaxInt; for i := 0 to lst.Count-1 do begin p := lst[i]; if (p = nil) or (p^.FCount = 0) then continue; p^.FTimeC := p^.FTime / p^.FCount; p^.FDiffC := p^.FDiff / p^.FCount; if p^.FTimeC > maxTime then maxTime := p^.FTimeC; if p^.FTimeC < minTime then minTime := p^.FTimeC; if p^.FDiffC > maxDiff then maxDiff := p^.FDiffC; if p^.FDiffC < minDiff then minDiff := p^.FDiffC; end; wTime := (maxTime - minTime) * 0.1; minTime := minTime - wTime; maxTime := maxTime + wTime; wDiff := (maxDiff - minDiff) * 0.1; minDiff := minDiff - wDiff; maxDiff := maxDiff + wDiff; with ACanvas do begin Font.Height := -trunc(ASize * Font.PixelsPerInch/72); wBar := TextWidth('F=0000.00000') div 2; //      end; //--       ----------------------------- oldM := SetGraphicsMode(DC, GM_ADVANCED); //--   ------------------------------------------------------ FillChar(xFrm,SizeOf(xFrm),0); //--    ------------------------------------- xFrm.eM11 := AZoom; //     ,  =1 xFrm.eM22 := AZoom; //     ,  =1 xFrm.eDx := lst.FOffX; //   X,      xFrm.eDy := lst.FOffY; //   Y,      //--    -------------------------------------- SetWorldTransform(DC, xFrm); rct := ARect; rct.Top := rct.Top + 10; rct.Bottom := rct.Top + round ( ASize * 190/6.5); //      if wTime <> 0 then wTime := (rct.Bottom - rct.Top) / (minTime - maxTime); if wDiff <> 0 then wDiff := (rct.Bottom - rct.Top) / (minDiff - maxDiff); try with ACanvas do begin val := rct; val.Left := val.Left + wBar; val.Right := val.Left + wBar; Pen.Width := 1; for i := 0 to lst.Count-1 do begin p := lst[i]; if (p = nil) or (p^.FCount = 0) then continue; Pen.Color := Darker(p^.FColor,10); //--    ------------------------------- OffsetRect (val,wBar,0); Brush.Color := Lighter(p^.FColor,50); val.Top := val.Bottom-round (wTime*(minTime-p^.FTimeC)); Rectangle(val); p^.FTimeR := val; //--    -------------------------- OffsetRect (val,wBar,0); Brush.Color := Lighter(p^.FColor,10); val.Top := val.Bottom-round (wDiff*(minDiff-p^.FDiffC)); Rectangle(val); p^.FDiffR := val; OffsetRect (val,wBar,0); end; for i := 0 to lst.Count-1 do begin p := lst[i]; if (p = nil) or (p^.FCount = 0) then continue; Brush.Style := bsClear; Font.Color := Darker(p^.FColor,10); val := p^.FTimeR; str := 't='+FormatFLoat('#0.000#',p^.FTimeC); OffsetRect(val,-1,HeightRect(val)+2); if lst.GDIPlus then DrawGDIPlusText (ACanvas, val, 0, ASize, str) else TextOut (val.Left,val.Top,str); Font.Color := Darker(p^.FColor,30); val := p^.FDiffR; str := 'f='+FormatFLoat('#0.000#',p^.FDiffC); OffsetRect(val,1,-TextHeight(str)-2); if lst.GDIPlus then DrawGDIPlusText (ACanvas, val, 0, ASize, str) else TextOut (val.Left, val.Top,str); val := p^.FDiffR; str := p^.FName; val.Top := val.Bottom+TextHeight(str)+2; val.Bottom := ARect.Bottom; if lst.GDIPlus then DrawGDIPlusText (ACanvas, val, 30, ASize, str) else begin fnt := CreateRotatedFont(Font, -30); tmp := SelectObject(DC,fnt); try TextOut (val.Left,val.Top, str); finally SelectObject(DC, tmp); DeleteObject(fnt); end; end; end; end; finally xFrm.eM11 := 1; xFrm.eM22 := 1; xFrm.eDx := 0; xFrm.eDy := 0; SetWorldTransform(DC, xFrm); //--     --------------------------------------------- SetGraphicsMode(DC, oldM); end; end; 


ダりンロヌドDelphi XE 7゜ヌス70 Kb

Source: https://habr.com/ru/post/J352392/


All Articles