如何在中间没有线条的情况下使刷子光滑

时间:2012-03-21 09:12:00

标签: c# wpf blend

enter image description here

大家好, 正如你在之前的画笔中看到的那样,中间有一些线条,它不是那么平滑 如何让它流畅? (如何删除那些行) 我用混合

创建它
<Grid x:Name="LayoutRoot">
        <Grid.Background>
            <LinearGradientBrush EndPoint="0.452,1.962" StartPoint="1.164,-0.352">
                <GradientStop Color="#FF202020" Offset="0"/>
                <GradientStop Color="#FF545454" Offset="1"/>
            </LinearGradientBrush>
        </Grid.Background>
    </Grid>

3 个答案:

答案 0 :(得分:10)

条带是梯度算法的假象。它必须打破区域,每个区域都填充略有不同的颜色。边缘实际上是一种视错觉,其效果使它们比您想象的更加明显。要减少这种影响,您需要减小每个波段的宽度。

解决方案是:

  1. 填充较小的区域 - 每个区域都较窄。
  2. 增加乐队数量。使两个极端之间的对比更大。
  3. 提高显示器的色彩分辨率。如果您有更多颜色可供选择,那么两种颜色之间的可用范围将更大。
  4. 我确实意识到这些解决方案要么a)不可能,要么b)不实用。这是你不得不忍受的问题。

    一个实用的解决方案可能是用Photoshop或其他图像处理包中创建的图像替换画笔。这可能会给你一个带有较少条带的图像 - 但是你被限制在图像的大小 - 你不能在没有像素化的情况下成长它。

答案 1 :(得分:8)

前段时间我为WPF项目编写了平滑的线性渐变。它删除了条带,但有两个警告:

  • 它不能用于数据绑定颜色或{DynamicResource}
  • 它目前仅支持垂直渐变,因为这就是我需要的所有内容

使用Ordered Dithering将其实施为动态创建的ImageBrush。另外,它也是MarkupExtension,因为我们不能简单地继承任何Brush类(&#39;全部密封)。

/// <summary>
/// Brush that lets you draw vertical linear gradient without banding.
/// </summary>
[MarkupExtensionReturnType(typeof(Brush))]
public class SmoothLinearGradientBrush : MarkupExtension
{
    private static PropertyInfo dpiX_;
    private static PropertyInfo dpiY_;
    private static byte[,] bayerMatrix_ = 
    {
        { 1, 9, 3, 11 },
        { 13, 5, 15, 7 },
        { 1, 9, 3, 11 },
        { 16, 8, 14, 6 }
    };

    static SmoothLinearGradientBrush()
    {
        dpiX_ = typeof(SystemParameters).GetProperty("DpiX", BindingFlags.NonPublic | BindingFlags.Static);
        dpiY_ = typeof(SystemParameters).GetProperty("Dpi", BindingFlags.NonPublic | BindingFlags.Static);
    }

    /// <summary>
    /// Gradient color at the top
    /// </summary>
    public Color From { get; set; }

    /// <summary>
    /// Gradient color at the bottom
    /// </summary>
    public Color To { get; set; }

    public override object ProvideValue(IServiceProvider serviceProvider)
    {
        //If user changes dpi/virtual screen height during applicaiton lifetime,
        //wpf will scale the image up for us.
        int width = 20;
        int height = (int)SystemParameters.VirtualScreenHeight;
        int dpix = (int)dpiX_.GetValue(null);
        int dpiy = (int)dpiY_.GetValue(null);


        int stride = 4 * ((width * PixelFormats.Bgr24.BitsPerPixel + 31) / 32);

        //dithering parameters
        double bayerMatrixCoefficient = 1.0 / (bayerMatrix_.Length + 1);
        int bayerMatrixSize = bayerMatrix_.GetLength(0);

        //Create pixel data of image
        byte[] buffer = new byte[height * stride];

        for (int line = 0; line < height; line++)
        {
            double scale = (double)line / height;

            for (int x = 0; x < width * 3; x += 3)
            {
                //scaling of color
                double blue = ((To.B * scale) + (From.B * (1.0 - scale)));
                double green = ((To.G * scale) + (From.G * (1.0 - scale)));
                double red = ((To.R * scale) + (From.R * (1.0 - scale)));

                //ordered dithering of color
                //source: http://en.wikipedia.org/wiki/Ordered_dithering
                buffer[x + line * stride] = (byte)(blue + bayerMatrixCoefficient * bayerMatrix_[x % bayerMatrixSize, line % bayerMatrixSize]);
                buffer[x + line * stride + 1] = (byte)(green + bayerMatrixCoefficient * bayerMatrix_[x % bayerMatrixSize, line % bayerMatrixSize]);
                buffer[x + line * stride + 2] = (byte)(red + bayerMatrixCoefficient * bayerMatrix_[x % bayerMatrixSize, line % bayerMatrixSize]);
            }
        }

        var image = BitmapSource.Create(width, height, dpix, dpiy, PixelFormats.Bgr24, null, buffer, stride);
        image.Freeze();
        var brush = new ImageBrush(image);
        brush.Freeze();
        return brush;
    }
}

资源字典中的用法:

<local:SmoothLinearGradientBrush x:Key="WindowBackgroundBrush" 
                                 From="{StaticResource WindowBackgroundColorLight}" 
                                 To="{StaticResource WindowBackgroundColorDark}" />

然后是控制风格:

<Style ...>
    <Setter Property="Background" Value="{StaticResource WindowBackgroundBrush}" />
</Style>

答案 2 :(得分:0)

我的另一个答案是廉价而肮脏的选择:

将渐变添加到容器中,给它一个小的负边距,使其稍微溢出,向渐变添加BlurEffect,然后在父容器上启用ClipToBounds。这样,梯度就会以牺牲性能为代价而变得更好。

根据您的使用情况,这可能不太可行。

示例:

<Grid Height="26" Margin="-5,0" ClipToBounds="True">
    <Grid Margin="-5">
        <Grid.Effect>
            <BlurEffect Radius="6" />
        </Grid.Effect>
        <Grid.Background>
            <LinearGradientBrush>
                <GradientStop x:Name="GradientStop7" Color="Magenta" Offset="0.0" />
                <GradientStop x:Name="GradientStop8" Color="DarkOrchid" Offset=".2" />
                <GradientStop x:Name="GradientStop9" Color="Purple" Offset="1" />
            </LinearGradientBrush>
        </Grid.Background>
    </Grid>
</Grid>

负梯度应该等于模糊半径,以便它不会在边缘变得透明。