Textblock不实现stroke属性,而是一个密封的类。最常见的解决方法是create your own textblock class from FrameworkElement。但是,我最近偶然发现了DropShadowEffect,想知道是否可以使用自定义效果来获得相同的轮廓文本结果,而无需执行整个轮廓文本块。 (我想要DropShadow给我的清晰轮廓。)
为此,我尝试创建一个从Effect继承的类,但立即遇到问题:
string password = "\"myNewStrongPassword\"";
var encodedBytes = SupportClass.ToSByteArray(Encoding.Unicode.GetBytes(password));
var attributePassword = new LdapAttribute("unicodePwd", encodedBytes);
ldapConnection.Modify(YOUR_DISTINGUISHED_NAME, new LdapModification(LdapModification.REPLACE, attributePassword));
它确实在documentation中说过:
从Effect类派生以实现自定义位图效果。在 大多数情况下,您将从ShaderEffect衍生
所以我认为这是可能的。因此,您如何从效果中得出?
答案 0 :(得分:0)
您必须继承ShaderEffect而不是Effect。这是使用边缘检测滤镜效果概述文本的示例:
结合使用此Shader tutorial和Prewitt Edge Detection Filter,我设法在文本周围获得了不错的轮廓效果。还有其他获得类似效果的方法,例如creating your own outline text block,但是使用效果具有使用GPU进行渲染并通常应用于 any UIElement的优势。但是,我必须在EdgeResponse属性中进行很多工作才能获得漂亮的轮廓。
XAML的最终结果:
<Grid>
<Grid.Resources>
<local:EdgeDetectionEffect x:Key="OutlineEffect"
x:Shared="false"
EdgeResponse="4.0"
ActualHeight="{Binding RelativeSource={RelativeSource AncestorType=TextBlock}, Path=ActualHeight}"
ActualWidth="{Binding RelativeSource={RelativeSource AncestorType=TextBlock}, Path=ActualWidth}"/>
</Grid.Resources>
<TextBlock Text="The Crazy Brown Fox Jumped Over the Lazy Dog."
FontWeight="Bold"
Foreground="Yellow"
Effect="{StaticResource OutlineEffect}"/>
</Grid>
要创建效果,我首先创建了EdgeDetectionColorEffect.fx(hdld)文件-这是GPU用于过滤图像的代码。我在Visual Studio命令提示符中使用以下命令对其进行了编译:
fxc / T ps_2_0 / E main /Focc.ps EdgeDetectionColorEffect.fx
sampler2D Input : register(s0);
float ActualWidth : register(c0);
float ActualHeight : register(c1);
float4 OutlineColor : register(c2);
float EdgeDetectionResponse : register(c3);
float4 GetNeighborPixel(float2 pixelPoint, float xOffset, float yOffset)
{
float2 NeighborPoint = {pixelPoint.x + xOffset, pixelPoint.y + yOffset};
return tex2D(Input, NeighborPoint);
}
// pixel locations:
// 00 01 02
// 10 11 12
// 20 21 22
float main(float2 pixelPoint : TEXCOORD) : COLOR
{
float wo = 1 / ActualWidth; //WidthOffset
float ho = 1 / ActualHeight; //HeightOffset
float4 c00 = GetNeighborPixel(pixelPoint, -wo, -ho); // color of the pixel up and to the left of me.
float4 c01 = GetNeighborPixel(pixelPoint, 00, -ho);
float4 c02 = GetNeighborPixel(pixelPoint, wo, -ho);
float4 c10 = GetNeighborPixel(pixelPoint, -wo, 0);
float4 c11 = tex2D(Input, pixelPoint); // this is the current pixel
float4 c12 = GetNeighborPixel(pixelPoint, wo, 0);
float4 c20 = GetNeighborPixel(pixelPoint, -wo, ho);
float4 c21 = GetNeighborPixel(pixelPoint, 0, ho);
float4 c22 = GetNeighborPixel(pixelPoint, wo, ho);
float t00 = c00.r + c00.g + c00.b; //total of color channels
float t01 = c01.r + c01.g + c01.b;
float t02 = c02.r + c02.g + c02.b;
float t10 = c10.r + c10.g + c10.b;
float t11 = c11.r + c11.g + c11.b;
float t12 = c12.r + c12.g + c12.b;
float t20 = c20.r + c20.g + c20.b;
float t21 = c21.r + c21.g + c21.b;
float t22 = c22.r + c22.g + c22.b;
//Prewitt - convolve the 9 pixels with:
// 01 01 01 01 00 -1
// Gy = 00 00 00 Gx = 01 00 -1
// -1 -1 -1 01 00 -1
float gy = 0.0; float gx = 0.0;
gy += t00; gx += t00;
gy += t01; gx += t10;
gy += t02; gx += t20;
gy -= t20; gx -= t02;
gy -= t21; gx -= t12;
gy -= t22; gx -= t22;
if((gy*gy + gx*gx) > EdgeDetectionResponse)
{
return OutlineColor;
}
return c11;
}
这是wpf效果类:
public class EdgeDetectionEffect : ShaderEffect
{
private static PixelShader _shader = new PixelShader { UriSource = new Uri("path to your compiled shader probably called cc.ps", UriKind.Absolute) };
public EdgeDetectionEffect()
{
PixelShader = _shader;
UpdateShaderValue(InputProperty);
UpdateShaderValue(ActualHeightProperty);
UpdateShaderValue(ActualWidthProperty);
UpdateShaderValue(OutlineColorProperty);
UpdateShaderValue(EdgeResponseProperty);
}
public Brush Input
{
get => (Brush)GetValue(InputProperty);
set => SetValue(InputProperty, value);
}
public static readonly DependencyProperty InputProperty =
ShaderEffect.RegisterPixelShaderSamplerProperty(nameof(Input),
typeof(EdgeDetectionEffect), 0);
public double ActualWidth
{
get => (double)GetValue(ActualWidthProperty);
set => SetValue(ActualWidthProperty, value);
}
public static readonly DependencyProperty ActualWidthProperty =
DependencyProperty.Register(nameof(ActualWidth), typeof(double), typeof(EdgeDetectionEffect),
new UIPropertyMetadata(1.0, PixelShaderConstantCallback(0)));
//notice the PixelShaderConstantCallback(#) - this tells it which GPU register to use (compare the number here to the first few lines of the EdgeDetectionColorEffect.fx file above.
public double ActualHeight
{
get => (double)GetValue(ActualHeightProperty);
set => SetValue(ActualHeightProperty, value);
}
public static readonly DependencyProperty ActualHeightProperty =
DependencyProperty.Register(nameof(ActualHeight), typeof(double), typeof(EdgeDetectionEffect),
new UIPropertyMetadata(1.0, PixelShaderConstantCallback(1)));
public Color OutlineColor
{
get => (Color)GetValue(OutlineColorProperty);
set => SetValue(OutlineColorProperty, value);
}
public static readonly DependencyProperty OutlineColorProperty=
DependencyProperty.Register(nameof(OutlineColor), typeof(Color), typeof(EdgeDetectionEffect),
new UIPropertyMetadata(Colors.Black, PixelShaderConstantCallback(2)));
public double EdgeResponse
{
get => (double)GetValue(EdgeResponseProperty);
set => SetValue(EdgeResponseProperty, value);
}
public static readonly DependencyProperty EdgeResponseProperty =
DependencyProperty.Register(nameof(EdgeResponse), typeof(double), typeof(EdgeDetectionEffect),
new UIPropertyMetadata(4.0, PixelShaderConstantCallback(3)));