问题
Background
Previously I was rendering text, and giving it a glowing outline by drawing the outline 1px to each side and then placing the text on top:
// Draw outline 1px to each side
context2D.DrawTextLayout(new Vector2(-1, 0), _textLayout, _highlightBrush, DrawTextOptions.NoSnap);
context2D.DrawTextLayout(new Vector2(0, -1), _textLayout, _highlightBrush, DrawTextOptions.NoSnap);
context2D.DrawTextLayout(new Vector2(1, 0), _textLayout, _highlightBrush, DrawTextOptions.NoSnap);
context2D.DrawTextLayout(new Vector2(0, 1), _textLayout, _highlightBrush, DrawTextOptions.NoSnap);
// Draw text on top of outline
context2D.DrawTextLayout(new Vector2(0, 0), _textLayout, _foregroundBrush, DrawTextOptions.NoSnap);
That works great. But I've realized that I need to have different parts of my string have different foreground colors and highlights.
I could have two separate TextLayout's side by side, but I'm already having to scale my font to fit the container size, doing it for two sections side by side just seemed really complex, here's my current scaling code that tries to find the best font size to fit the container:
private void CreateTextFormatAndLayout( string text )
{
float maxFontSize = _settings.BoardLayout.ActualGradeMaxFontSize;
float minFontSize = _settings.BoardLayout.ActualGradeMinFontSize;
var factory = DeviceManager.DirectWriteFactory;
SharpDX.DirectWrite.TextFormat textFormat = null;
SharpDX.DirectWrite.TextLayout textLayout = null;
// step backward through font sizes till we find one that fits
for ( float fontSize = maxFontSize; fontSize > minFontSize; fontSize -= .5f ) {
// if have leftover values from previous loop, dispose
if ( textFormat != null )
textFormat.Dispose();
if ( textLayout != null )
textLayout.Dispose();
// generate sharpdx format and layout based on current font size
textFormat = new SharpDX.DirectWrite.TextFormat(factory, "Arial", SharpDX.DirectWrite.FontWeight.Normal, SharpDX.DirectWrite.FontStyle.Normal, fontSize);
textFormat.WordWrapping = SharpDX.DirectWrite.WordWrapping.NoWrap;
textFormat.TextAlignment = SharpDX.DirectWrite.TextAlignment.Center;
textLayout = new SharpDX.DirectWrite.TextLayout(factory, text, textFormat, _regionWidthPx, _regionWidthPx);
// if text will fit in the container break
if ( textLayout.Metrics.Width < _regionWidthPx )
break;
}
// Set format and layout
_textFormat = ToDispose(textFormat);
_textLayout = ToDispose(textLayout);
}
That's when I discovered you can create custom handlers for different sections of the TextLayout. (Glyphs) I don't know very much about glyphs but this example seemed to indicate it wasn't too difficult:
Example of using custom renderer
What I'm trying to do
I want to do something similar, except I want to pass two colors my custom text renderer, and have it render the outline as well. I'm not looking for a code review, I mostly want to know if I'm on the right track. Is my MultiBrush idea totally wrong or can I do this this way? I am sure others have had to do advanced text formatting. Here's my basic idea, I can flesh it out more if needed but I think anyone familiar with SharpDX will be able to see what I'm trying to do:
public class MultiBrush : ComObject
{
public MultiBrush( Brush foreground, Brush highlight )
{
ForegroundBrush = foreground;
HighlightBrush = highlight;
}
public Brush ForegroundBrush;
public Brush HighlightBrush;
}
public class CustomColorRenderer : SharpDX.DirectWrite.TextRendererBase
{
private RenderTarget renderTarget;
private MultiBrush defaultBrush;
public void AssignResources( RenderTarget renderTarget, MultiBrush defaultBrush )
{
this.renderTarget = renderTarget;
this.defaultBrush = defaultBrush;
}
public override Result DrawGlyphRun( object clientDrawingContext, float baselineOriginX, float baselineOriginY, MeasuringMode measuringMode, GlyphRun glyphRun, GlyphRunDescription glyphRunDescription, ComObject clientDrawingEffect )
{
MultiBrush sb = defaultBrush;
if ( clientDrawingEffect != null && clientDrawingEffect is MultiBrush ) {
sb = (MultiBrush)clientDrawingEffect;
}
try {
// render shadow 1 px away
this.renderTarget.DrawGlyphRun(new Vector2(baselineOriginX + 1, baselineOriginY + 1), glyphRun, sb.HighlightBrush, measuringMode);
// render main text
this.renderTarget.DrawGlyphRun(new Vector2(baselineOriginX, baselineOriginY), glyphRun, sb.ForegroundBrush, measuringMode);
return Result.Ok;
}
catch {
return Result.Fail;
}
}
}
...
CustomColorRenderer customRenderer = new CustomColorRenderer();
textLayout = new TextLayout(dwFactory, introText, textFormat, 300.0f, 200.0f);
SolidColorBrush brush1 = new SolidColorBrush(DeviceManager.Direct2DContext, _foregroundColor);
SolidColorBrush brush2 = new SolidColorBrush(DeviceManager.Direct2DContext, _highlightColor);
multiBrush = new MultiBrush(brush1, brush2);
// Apply custom modification to text
textLayout.SetDrawingEffect(multiBrush, new TextRange(10, 20));
// Render custom text
textLayout.Draw(customRenderer, 0, 0);
来源:https://stackoverflow.com/questions/37311969/can-i-create-a-text-outline-in-sharpdx-using-a-custom-text-renderer