Direct2D (40) : 分别设置 IDWriteTextLayout 中文本的颜色


function SetDrawingEffect(
  const drawingEffect: IUnknown; //颜色接口; 该接口需自己定义和实现, 只要能存取颜色即可
  textRange: TDwriteTextRange    //要设置的范围
): HResult; stdcall;


测试代码:

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, Direct2D, D2D1;

const
  SID_IColorDrawingEffect = '{22FBE54E-5058-47C4-9A7C-6482827713A6}'; //这是使用 Ctri+Shift+G 随意产生的
  IID_IColorDrawingEffect: TGUID = SID_IColorDrawingEffect;

type
  TForm1 = class(TForm)
    procedure FormPaint(Sender: TObject);
    procedure FormResize(Sender: TObject);
  end;

  {自定义的颜色接口}
  IColorDrawingEffect = interface
  [SID_IColorDrawingEffect]
    function GetColor: TD2D1ColorF;
  end;

  {实现 IColorDrawingEffect 的类}
  TColorDrawingEffect = class(TInterfacedObject, IColorDrawingEffect)
  private
    FColor: TD2D1ColorF;
  public
    constructor Create(const AColor: TD2D1ColorF);
    function GetColor: TD2D1ColorF;
  end;

  {实现 IWriteTextRenderer 接口}
  TMyWriteTextRenderer = class(TInterfacedObject, IDWriteTextRenderer)
  private
    FRenderTarge: ID2D1RenderTarget;
  public
    constructor Create(ARenderTarge: ID2D1RenderTarget);
    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;
  iTextLayout: IDWriteTextLayout;
  iTypography: IDWriteTypography;
  iTextRenderer: IDWriteTextRenderer;
  iColor1,iColor2,iColor3: IColorDrawingEffect;
begin
  str := 'Client Drawing Effect Example!';

  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
  );

  DWriteFactory.CreateTypography(iTypography);
  iTypography.AddFontFeature(DWriteFontFeature(DWRITE_FONT_FEATURE_TAG_STYLISTIC_SET_7, 1));
  iTextLayout.SetTypography(iTypography, DWriteTextRange(0, Length(str)));

  {分段设置颜色; 算上没有设置的范围, 下面的设置将会有四种颜色}
  iColor1 := TColorDrawingEffect.Create(D2D1ColorF(clRed));
  iColor2 := TColorDrawingEffect.Create(D2D1ColorF(clBlue));
  iColor3 := TColorDrawingEffect.Create(D2D1ColorF(clGreen));
  iTextLayout.SetDrawingEffect(iColor1, DWriteTextRange(0, 14));
  iTextLayout.SetDrawingEffect(iColor2, DWriteTextRange(14, 7));
  iTextLayout.SetDrawingEffect(iColor3, DWriteTextRange(21, 8));

  cvs := TDirect2DCanvas.Create(Canvas, ClientRect);
  iTextRenderer := TMyWriteTextRenderer.Create(cvs.RenderTarget);
  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;

{ TColorDrawingEffect }
constructor TColorDrawingEffect.Create(const AColor: TD2D1ColorF);
begin
  inherited Create;
  FColor := AColor;
end;

function TColorDrawingEffect.GetColor: TD2D1ColorF;
begin
  Result := FColor;
end;

{ TMyWriteTextRenderer }

constructor TMyWriteTextRenderer.Create(ARenderTarge: ID2D1RenderTarget);
begin
  FRenderTarge := ARenderTarge;
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;
  iBrush: ID2D1SolidColorBrush;
  iColorEffect: IColorDrawingEffect; //供注释掉的代码使用
  rColor: TD2D1ColorF;
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
  );

  {获取颜色}
  rColor := D2D1ColorF(clBlack);
  if Assigned(clientDrawingEffect) then rColor := IColorDrawingEffect(clientDrawingEffect).GetColor;
  {下面是官方获取颜色的写法}
//  if clientDrawingEffect <> nil then
//  begin
//    clientDrawingEffect.QueryInterface(IID_IColorDrawingEffect, iColorEffect);
//    rColor := iColorEffect.GetColor;
//  end else
//    rColor := D2D1ColorF(clBlack);

  FRenderTarge.CreateSolidColorBrush(rColor, nil, iBrush);
  FRenderTarge.DrawGeometry(iTransformedGeometry, iBrush);
  FRenderTarge.FillGeometry(iTransformedGeometry, iBrush);
  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;
  iBrush: ID2D1SolidColorBrush;
  rColor: TD2D1ColorF;
begin
  rRectF := D2D1RectF(
    0,
    strikethrough.offset,
    strikethrough.width,
    strikethrough.offset + strikethrough.thickness
  );
  D2DFactory.CreateRectangleGeometry(rRectF, iRectangleGeometry);

  D2DFactory.CreateTransformedGeometry(
    iRectangleGeometry,
    TD2DMatrix3x2F.Translation(baselineOriginX, baselineOriginY),
    iTransformedGeometry
  );

  rColor := D2D1ColorF(clBlack); //没有设置的部分默认使用黑色
  if Assigned(clientDrawingEffect) then rColor := IColorDrawingEffect(clientDrawingEffect).GetColor;
  FRenderTarge.CreateSolidColorBrush(rColor, nil, iBrush);
  FRenderTarge.DrawGeometry(iTransformedGeometry, iBrush);
  FRenderTarge.FillGeometry(iTransformedGeometry, iBrush);
  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;
  iBrush: ID2D1SolidColorBrush;
  rColor: TD2D1ColorF;
begin
  rRectF := D2D1RectF(
    0,
    underline.offset,
    underline.width,
    underline.offset + underline.thickness
  );
  D2DFactory.CreateRectangleGeometry(rRectF, iRectangleGeometry);

  D2DFactory.CreateTransformedGeometry(
    iRectangleGeometry,
    TD2DMatrix3x2F.Translation(baselineOriginX, baselineOriginY),
    iTransformedGeometry
  );

  rColor := D2D1ColorF(clBlack);
  if Assigned(clientDrawingEffect) then rColor := IColorDrawingEffect(clientDrawingEffect).GetColor;
  FRenderTarge.CreateSolidColorBrush(rColor, nil, iBrush);
  FRenderTarge.DrawGeometry(iTransformedGeometry, iBrush);
  FRenderTarge.FillGeometry(iTransformedGeometry, iBrush);
  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.


效果图:



原文地址:https://www.cnblogs.com/del/p/2015631.html