zoukankan      html  css  js  c++  java
  • 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.
    


    效果图:



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

    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.
    


    效果图:



  • 相关阅读:
    Linux基础命令(二)
    Linux基础命令(一)
    安装Centos 7操作系统
    网络基础之网络协议
    操作系统简介
    计算机硬件知识
    VS快捷键
    VB.NET 编程元素支持更改总结
    VB.Net中确认退出对话框的实现
    VB定义变量
  • 原文地址:https://www.cnblogs.com/del/p/2014946.html
Copyright © 2011-2022 走看看