how to make the brush smooth without lines in the middle

前端 未结 3 755
醉梦人生
醉梦人生 2020-12-06 13:34

\"enter

Hi all, as you see in previous brush there is lines in the middle,
it isn

3条回答
  •  青春惊慌失措
    2020-12-06 14:12

    Some time ago I wrote smooth linear gradient for my WPF project. It removes the banding, but there are two caveats:

    • It cannot be used for databound colors or {DynamicResource}.
    • It currently supports only vertical gradient, as that was all I needed

    It is implemented as dynamicly created ImageBrush, using Ordered Dithering. Additionaly, it is also a MarkupExtension, as one cannot simply inherit any Brush class (the're all sealed).

    /// 
    /// Brush that lets you draw vertical linear gradient without banding.
    /// 
    [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);
        }
    
        /// 
        /// Gradient color at the top
        /// 
        public Color From { get; set; }
    
        /// 
        /// Gradient color at the bottom
        /// 
        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;
        }
    }
    

    Usage in resource dictionary:

    
    

    and then in control style:

    
    

提交回复
热议问题