Direct2D (39) : 使用 IDWriteTextLayout.Draw() 方法绘制文本


使用 IDWriteTextLayout.Draw() 方法绘制文本主要是实现 IDWriteTextRenderer 接口。
IDWriteTextRenderer 接口只能是手动实现,很灵活。


unit Unit1;



interface



uses

  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,

  Dialogs, Direct2D, D2D1;



type

  TForm1 = class(TForm)

    procedure FormPaint(Sender: TObject);

    procedure FormResize(Sender: TObject);

  end;



  TMyWriteTextRenderer = class(TInterfacedObject, IDWriteTextRenderer)

  private

    FRenderTarge: ID2D1RenderTarget;

    FOutLineBrush,FFillBrush: ID2D1Brush;

  public

    constructor Create(ARenderTarge: ID2D1RenderTarget; AOutLineBrush,AFillBrush: ID2D1Brush);

    function IsPixelSnappingDisabled(clientDrawingContext: Pointer; var isDisabled: LongBool): HRESULT;

      stdcall;

    function GetCurrentTransform(clientDrawingContext: Pointer; var transform: DWRITE_MATRIX): HRESULT;

      stdcall;

    function GetPixelsPerDip(clientDrawingContext: Pointer; var pixelsPerDip: Single): HRESULT; stdcall;

    function DrawGlyphRun(clientDrawingContext: Pointer; baselineOriginX: Single; baselineOriginY: Single;

      measuringMode: DWRITE_MEASURING_MODE; var glyphRun: DWRITE_GLYPH_RUN;

      var glyphRunDescription: DWRITE_GLYPH_RUN_DESCRIPTION; const clientDrawingEffect: IInterface): HRESULT;

      stdcall;

    function DrawUnderline(clientDrawingContext: Pointer; baselineOriginX: Single; baselineOriginY: Single;

      var underline: DWRITE_UNDERLINE; const clientDrawingEffect: IInterface): HRESULT; stdcall;

    function DrawStrikethrough(clientDrawingContext: Pointer; baselineOriginX: Single;

      baselineOriginY: Single; var strikethrough: DWRITE_STRIKETHROUGH;

      const clientDrawingEffect: IInterface): HRESULT; stdcall;

    function DrawInlineObject(clientDrawingContext: Pointer; originX: Single; originY: Single;

      var inlineObject: IDWriteInlineObject; isSideways: LongBool; isRightToLeft: LongBool;

      const clientDrawingEffect: IInterface): HRESULT; stdcall;

  end;



var

  Form1: TForm1;



implementation



{$R *.dfm}





{构建 DWRITE_TEXT_RANGE 结构的函数}

function DWriteTextRange(pos,len: Cardinal): TDwriteTextRange;

begin

  Result.startPosition := pos;

  Result.length := len;

end;



{构建 DWRITE_FONT_FEATURE 结构的函数}

function DWriteFontFeature(nameTag: Integer; parameter: Cardinal): TDwriteFontFeature;

begin

  Result.nameTag := nameTag;

  Result.parameter := parameter;

end;



{建立位图画刷的函数}

function GetBitmapBrush(Canvas: TDirect2DCanvas; filePath: string): ID2D1BitmapBrush;

var

  rBBP: TD2D1BitmapBrushProperties;

  bit: TBitmap;

begin

  bit := TBitmap.Create;

  bit.LoadFromFile(filePath);

  rBBP.extendModeX := D2D1_EXTEND_MODE_WRAP;

  rBBP.extendModeY := D2D1_EXTEND_MODE_WRAP;

  rBBP.interpolationMode := D2D1_BITMAP_INTERPOLATION_MODE_NEAREST_NEIGHBOR;

  Canvas.RenderTarget.CreateBitmapBrush(Canvas.CreateBitmap(bit), @rBBP, nil, Result);

  bit.Free;

end;



procedure TForm1.FormPaint(Sender: TObject);

var

  cvs: TDirect2DCanvas;

  str: string;

  iTextFormat: IDWriteTextFormat;

  iSolidColorBrush: ID2D1SolidColorBrush;

  iBitmapBrush: ID2D1BitmapBrush;

  iTextLayout: IDWriteTextLayout;

  iTypography: IDWriteTypography;

  iTextRenderer: IDWriteTextRenderer;

begin

  str := 'Hello World using DirectWrite!';

  DWriteFactory.CreateTextFormat(

    'Gabriola',

    nil,

    DWRITE_FONT_WEIGHT_REGULAR,

    DWRITE_FONT_STYLE_NORMAL,

    DWRITE_FONT_STRETCH_NORMAL,

    72.0,

    'en-us',

    iTextFormat

  );

  iTextFormat.SetTextAlignment(DWRITE_TEXT_ALIGNMENT_CENTER);

  iTextFormat.SetParagraphAlignment(DWRITE_PARAGRAPH_ALIGNMENT_CENTER);



  DWriteFactory.CreateTextLayout(

    PWideChar(str),

    Length(str),

    iTextFormat,

    ClientWidth,

    ClientHeight,

    iTextLayout

  );



  iTextLayout.SetFontSize(100.0, DWriteTextRange(18, 6));

  iTextLayout.SetUnderline(True, DWriteTextRange(18, 11));

  iTextLayout.SetFontWeight(DWRITE_FONT_WEIGHT_BOLD, DWriteTextRange(18, 11));



  DWriteFactory.CreateTypography(iTypography);

  iTypography.AddFontFeature(DWriteFontFeature(DWRITE_FONT_FEATURE_TAG_STYLISTIC_SET_6, 1));

  iTextLayout.SetTypography(iTypography, DWriteTextRange(0, Length(str)));



  cvs := TDirect2DCanvas.Create(Canvas, ClientRect);

  cvs.RenderTarget.CreateSolidColorBrush(D2D1ColorF(clBlack), nil, iSolidColorBrush);

  iBitmapBrush := GetBitmapBrush(cvs, 'C:\Temp\Test.bmp');

  iTextRenderer := TMyWriteTextRenderer.Create(cvs.RenderTarget, iSolidColorBrush, iBitmapBrush);

  cvs.RenderTarget.BeginDraw;

  cvs.RenderTarget.Clear(D2D1ColorF(clWhite));

  iTextLayout.Draw(nil, iTextRenderer, 0, 0);

  cvs.RenderTarget.EndDraw();

  cvs.Free;

end;



procedure TForm1.FormResize(Sender: TObject);

begin

  Repaint;

end;



{ TMyWriteTextRenderer }



constructor TMyWriteTextRenderer.Create(ARenderTarge: ID2D1RenderTarget; AOutLineBrush,

  AFillBrush: ID2D1Brush);

begin

  FRenderTarge := ARenderTarge;

  FOutLineBrush := AOutLineBrush;

  FFillBrush := AFillBrush;

end;



function TMyWriteTextRenderer.DrawGlyphRun(clientDrawingContext: Pointer; baselineOriginX,

  baselineOriginY: Single; measuringMode: DWRITE_MEASURING_MODE; var glyphRun: DWRITE_GLYPH_RUN;

  var glyphRunDescription: DWRITE_GLYPH_RUN_DESCRIPTION; const clientDrawingEffect: IInterface): HRESULT;

var

  iPathGeometry: ID2D1PathGeometry;

  iGeometrySink: ID2D1GeometrySink;

  iTransformedGeometry: ID2D1TransformedGeometry;

begin

  D2DFactory.CreatePathGeometry(iPathGeometry);

  iPathGeometry.Open(iGeometrySink);

  glyphRun.fontFace.GetGlyphRunOutline(

    glyphRun.fontEmSize,

    glyphRun.glyphIndices,

    glyphRun.glyphAdvances,

    glyphRun.glyphOffsets,

    glyphRun.glyphCount,

    glyphRun.isSideways,

    longBool(glyphRun.bidiLevel div 2),

    iGeometrySink

  );

  iGeometrySink.Close;



  D2DFactory.CreateTransformedGeometry(

    iPathGeometry,

    TD2DMatrix3x2F.Translation(baselineOriginX, baselineOriginY),

    iTransformedGeometry

  );



  FRenderTarge.DrawGeometry(iTransformedGeometry, FOutLineBrush);

  FRenderTarge.FillGeometry(iTransformedGeometry, FFillBrush);

  Result := S_OK;

end;



function TMyWriteTextRenderer.DrawInlineObject(clientDrawingContext: Pointer; originX, originY: Single;

  var inlineObject: IDWriteInlineObject; isSideways, isRightToLeft: LongBool;

  const clientDrawingEffect: IInterface): HRESULT;

begin

  Result := E_NOTIMPL; //未实现

end;



function TMyWriteTextRenderer.DrawStrikethrough(clientDrawingContext: Pointer; baselineOriginX,

  baselineOriginY: Single; var strikethrough: DWRITE_STRIKETHROUGH;

  const clientDrawingEffect: IInterface): HRESULT;

var

  rRectF: TD2DRectF;

  iRectangleGeometry: ID2D1RectangleGeometry;

  iTransformedGeometry: ID2D1TransformedGeometry;

begin

  rRectF := D2D1RectF(

    0,

    strikethrough.offset,

    strikethrough.width,

    strikethrough.offset + strikethrough.thickness

  );



  D2DFactory.CreateRectangleGeometry(rRectF, iRectangleGeometry);

  D2DFactory.CreateTransformedGeometry(

    iRectangleGeometry,

    TD2DMatrix3x2F.Translation(baselineOriginX, baselineOriginY),

    iTransformedGeometry

  );



  FRenderTarge.DrawGeometry(iTransformedGeometry, FOutLineBrush);

  FRenderTarge.FillGeometry(iTransformedGeometry, FFillBrush);

  Result := S_OK;

end;



function TMyWriteTextRenderer.DrawUnderline(clientDrawingContext: Pointer; baselineOriginX,

  baselineOriginY: Single; var underline: DWRITE_UNDERLINE; const clientDrawingEffect: IInterface): HRESULT;

var

  rRectF: TD2DRectF;

  iRectangleGeometry: ID2D1RectangleGeometry;

  iTransformedGeometry: ID2D1TransformedGeometry;

begin

  rRectF := D2D1RectF(

    0,

    underline.offset,

    underline.width,

    underline.offset + underline.thickness

  );



  D2DFactory.CreateRectangleGeometry(rRectF, iRectangleGeometry);

  D2DFactory.CreateTransformedGeometry(

    iRectangleGeometry,

    TD2DMatrix3x2F.Translation(baselineOriginX, baselineOriginY),

    iTransformedGeometry

  );



  FRenderTarge.DrawGeometry(iTransformedGeometry, FOutLineBrush);

  FRenderTarge.FillGeometry(iTransformedGeometry, FFillBrush);

  Result := S_OK;

end;



function TMyWriteTextRenderer.GetCurrentTransform(clientDrawingContext: Pointer;

  var transform: DWRITE_MATRIX): HRESULT;

begin

  FRenderTarge.GetTransform(TD2D1Matrix3x2F(transform));

  Result := S_OK;

end;



function TMyWriteTextRenderer.GetPixelsPerDip(clientDrawingContext: Pointer;

  var pixelsPerDip: Single): HRESULT;

var

  x,y: Single;

begin

  FRenderTarge.GetDpi(x, y);

  pixelsPerDip := x / 96;

  Result := S_OK;

end;



function TMyWriteTextRenderer.IsPixelSnappingDisabled(clientDrawingContext: Pointer;

  var isDisabled: LongBool): HRESULT;

begin

  isDisabled := False;

  Result := S_OK;

end;



end.



效果图:

Direct2D (39) : 使用 IDWriteTextLayout.Draw() 方法绘制文本

简化一下,只描绘文本的轮廓:


unit Unit1;



interface



uses

  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,

  Dialogs, Direct2D, D2D1;



type

  TForm1 = class(TForm)

    procedure FormPaint(Sender: TObject);

    procedure FormResize(Sender: TObject);

  end;



  TMyWriteTextRenderer = class(TInterfacedObject, IDWriteTextRenderer)

  private

    FRenderTarge: ID2D1RenderTarget;

    FOutLineBrush: ID2D1Brush;

  public

    constructor Create(ARenderTarge: ID2D1RenderTarget; AOutLineBrush: ID2D1Brush);

    function IsPixelSnappingDisabled(clientDrawingContext: Pointer; var isDisabled: LongBool): HRESULT;

      stdcall;

    function GetCurrentTransform(clientDrawingContext: Pointer; var transform: DWRITE_MATRIX): HRESULT;

      stdcall;

    function GetPixelsPerDip(clientDrawingContext: Pointer; var pixelsPerDip: Single): HRESULT; stdcall;

    function DrawGlyphRun(clientDrawingContext: Pointer; baselineOriginX: Single; baselineOriginY: Single;

      measuringMode: DWRITE_MEASURING_MODE; var glyphRun: DWRITE_GLYPH_RUN;

      var glyphRunDescription: DWRITE_GLYPH_RUN_DESCRIPTION; const clientDrawingEffect: IInterface): HRESULT;

      stdcall;

    function DrawUnderline(clientDrawingContext: Pointer; baselineOriginX: Single; baselineOriginY: Single;

      var underline: DWRITE_UNDERLINE; const clientDrawingEffect: IInterface): HRESULT; stdcall;

    function DrawStrikethrough(clientDrawingContext: Pointer; baselineOriginX: Single;

      baselineOriginY: Single; var strikethrough: DWRITE_STRIKETHROUGH;

      const clientDrawingEffect: IInterface): HRESULT; stdcall;

    function DrawInlineObject(clientDrawingContext: Pointer; originX: Single; originY: Single;

      var inlineObject: IDWriteInlineObject; isSideways: LongBool; isRightToLeft: LongBool;

      const clientDrawingEffect: IInterface): HRESULT; stdcall;

  end;



var

  Form1: TForm1;



implementation



{$R *.dfm}





{构建 DWRITE_TEXT_RANGE 结构的函数}

function DWriteTextRange(pos,len: Cardinal): TDwriteTextRange;

begin

  Result.startPosition := pos;

  Result.length := len;

end;



{构建 DWRITE_FONT_FEATURE 结构的函数}

function DWriteFontFeature(nameTag: Integer; parameter: Cardinal): TDwriteFontFeature;

begin

  Result.nameTag := nameTag;

  Result.parameter := parameter;

end;



procedure TForm1.FormPaint(Sender: TObject);

var

  cvs: TDirect2DCanvas;

  str: string;

  iTextFormat: IDWriteTextFormat;

  iSolidColorBrush: ID2D1SolidColorBrush;

  iTextLayout: IDWriteTextLayout;

  iTypography: IDWriteTypography;

  iTextRenderer: IDWriteTextRenderer;

begin

  str := 'Hello World using DirectWrite!';

  DWriteFactory.CreateTextFormat(

    'Gabriola',

    nil,

    DWRITE_FONT_WEIGHT_ULTRA_BLACK,

    DWRITE_FONT_STYLE_NORMAL,

    DWRITE_FONT_STRETCH_NORMAL,

    72.0,

    'en-us',

    iTextFormat

  );

  iTextFormat.SetTextAlignment(DWRITE_TEXT_ALIGNMENT_CENTER);

  iTextFormat.SetParagraphAlignment(DWRITE_PARAGRAPH_ALIGNMENT_CENTER);



  DWriteFactory.CreateTextLayout(

    PWideChar(str),

    Length(str),

    iTextFormat,

    ClientWidth,

    ClientHeight,

    iTextLayout

  );



  iTextLayout.SetFontSize(100.0, DWriteTextRange(18, 6));

  iTextLayout.SetUnderline(True, DWriteTextRange(18, 11));

  iTextLayout.SetFontWeight(DWRITE_FONT_WEIGHT_BOLD, DWriteTextRange(18, 11));



  DWriteFactory.CreateTypography(iTypography);

  iTypography.AddFontFeature(DWriteFontFeature(DWRITE_FONT_FEATURE_TAG_STYLISTIC_SET_6, 1));

  iTextLayout.SetTypography(iTypography, DWriteTextRange(0, Length(str)));



  cvs := TDirect2DCanvas.Create(Canvas, ClientRect);

  cvs.RenderTarget.CreateSolidColorBrush(D2D1ColorF(clRed), nil, iSolidColorBrush);

  iTextRenderer := TMyWriteTextRenderer.Create(cvs.RenderTarget, iSolidColorBrush);

  cvs.RenderTarget.BeginDraw;

  cvs.RenderTarget.Clear(D2D1ColorF(clWhite));

  iTextLayout.Draw(nil, iTextRenderer, 0, 0);

  cvs.RenderTarget.EndDraw();

  cvs.Free;

end;



procedure TForm1.FormResize(Sender: TObject);

begin

  Repaint;

end;



{ TMyWriteTextRenderer }



constructor TMyWriteTextRenderer.Create(ARenderTarge: ID2D1RenderTarget; AOutLineBrush: ID2D1Brush);

begin

  FRenderTarge := ARenderTarge;

  FOutLineBrush := AOutLineBrush;

end;



function TMyWriteTextRenderer.DrawGlyphRun(clientDrawingContext: Pointer; baselineOriginX,

  baselineOriginY: Single; measuringMode: DWRITE_MEASURING_MODE; var glyphRun: DWRITE_GLYPH_RUN;

  var glyphRunDescription: DWRITE_GLYPH_RUN_DESCRIPTION; const clientDrawingEffect: IInterface): HRESULT;

var

  iPathGeometry: ID2D1PathGeometry;

  iGeometrySink: ID2D1GeometrySink;

  iTransformedGeometry: ID2D1TransformedGeometry;

begin

  D2DFactory.CreatePathGeometry(iPathGeometry);

  iPathGeometry.Open(iGeometrySink);

  glyphRun.fontFace.GetGlyphRunOutline(

    glyphRun.fontEmSize,

    glyphRun.glyphIndices,

    glyphRun.glyphAdvances,

    glyphRun.glyphOffsets,

    glyphRun.glyphCount,

    glyphRun.isSideways,

    longBool(glyphRun.bidiLevel div 2),

    iGeometrySink

  );

  iGeometrySink.Close;



  D2DFactory.CreateTransformedGeometry(

    iPathGeometry,

    TD2DMatrix3x2F.Translation(baselineOriginX, baselineOriginY),

    iTransformedGeometry

  );



  FRenderTarge.DrawGeometry(iTransformedGeometry, FOutLineBrush);

  Result := S_OK;

end;



function TMyWriteTextRenderer.DrawInlineObject(clientDrawingContext: Pointer; originX, originY: Single;

  var inlineObject: IDWriteInlineObject; isSideways, isRightToLeft: LongBool;

  const clientDrawingEffect: IInterface): HRESULT;

begin

  Result := E_NOTIMPL;

end;



function TMyWriteTextRenderer.DrawStrikethrough(clientDrawingContext: Pointer; baselineOriginX,

  baselineOriginY: Single; var strikethrough: DWRITE_STRIKETHROUGH;

  const clientDrawingEffect: IInterface): HRESULT;

begin

  Result := E_NOTIMPL;

end;



function TMyWriteTextRenderer.DrawUnderline(clientDrawingContext: Pointer; baselineOriginX,

  baselineOriginY: Single; var underline: DWRITE_UNDERLINE; const clientDrawingEffect: IInterface): HRESULT;

var

  rRectF: TD2DRectF;

  iRectangleGeometry: ID2D1RectangleGeometry;

  iTransformedGeometry: ID2D1TransformedGeometry;

begin

  rRectF := D2D1RectF(

    0,

    underline.offset,

    underline.width,

    underline.offset + underline.thickness

  );



  D2DFactory.CreateRectangleGeometry(rRectF, iRectangleGeometry);

  D2DFactory.CreateTransformedGeometry(

    iRectangleGeometry,

    TD2DMatrix3x2F.Translation(baselineOriginX, baselineOriginY),

    iTransformedGeometry

  );



  FRenderTarge.DrawGeometry(iTransformedGeometry, FOutLineBrush);

  Result := S_OK;

end;



function TMyWriteTextRenderer.GetCurrentTransform(clientDrawingContext: Pointer;

  var transform: DWRITE_MATRIX): HRESULT;

begin

  FRenderTarge.GetTransform(TD2D1Matrix3x2F(transform));

  Result := S_OK;

end;



function TMyWriteTextRenderer.GetPixelsPerDip(clientDrawingContext: Pointer;

  var pixelsPerDip: Single): HRESULT;

var

  x,y: Single;

begin

  FRenderTarge.GetDpi(x, y);

  pixelsPerDip := x / 96;

  Result := S_OK;

end;



function TMyWriteTextRenderer.IsPixelSnappingDisabled(clientDrawingContext: Pointer;

  var isDisabled: LongBool): HRESULT;

begin

  isDisabled := False;

  Result := S_OK;

end;



end.



效果图:

Direct2D (39) : 使用 IDWriteTextLayout.Draw() 方法绘制文本

你可能感兴趣的:(layout)