Hi all,
as you see in previous brush there is lines in the middle,
it isn't so smooth
how to make it smooth? (how to remove that lines)
i create it with blend
<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>
The banding is an artefact of the gradient algorithm. It has to break the area in to bands each filled with a slightly different colour. The edges are in fact an optical illusion which has the effect of making them more visible than you would think. To reduce this effect you need to reduce the width of each band.
The solutions are:
I do realise that these solutions are either a) not possible or b) not practical. This is a problem you are going to have to live with.
One practical solution might be to replace the brush with an image created in Photoshop or other image processing package. This might give you an image with less banding - but then you are restricted to the size of the image - you can't grow it without pixelation.
Some time ago I wrote smooth linear gradient for my WPF project. It removes the banding, but there are two caveats:
{DynamicResource}
.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).
/// <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;
}
}
Usage in resource dictionary:
<local:SmoothLinearGradientBrush x:Key="WindowBackgroundBrush"
From="{StaticResource WindowBackgroundColorLight}"
To="{StaticResource WindowBackgroundColorDark}" />
and then in control style:
<Style ...>
<Setter Property="Background" Value="{StaticResource WindowBackgroundBrush}" />
</Style>
A cheap and dirty option from another answer of mine is this:
Add the gradient to a container, give it a small negative margin so it spills over a little, add a BlurEffect to the gradient, and then turn on ClipToBounds on the parent container. This way the gradient evens out a bit nicer at the expense of performance.
Depending on your use case, this may not be viable, however.
Example:
<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>
The negative gradient should be equal to the blur radius so that it doesn't become transparent on the edges.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With