I'm a beginner regarding Paint.net plugins. I just wrote a Floyd-Steinberg dithering effect, and it works mostly fine. The only problem is that there are visible seams for images larger than about 128x128. I suspect this is due to Paint.NET calling the render function multiple times, which results in artifacts between different rendering regions, since the color error is not correctly dispersed between each.
Even in JPEG form, these seams are visible.
The only way I can think to remedy this would be to force a single call to the render function, but I have no idea how to do that. I'm well aware that such a solution would slow down the effect by a significant amount of time. Of course, if there's a better answer, I'm open to any ideas.
Here's the code. I'd like to fix this issue before properly refactoring, so I apologize for the mess.
void Render(Surface dst, Surface src, Rectangle rect)
{
#if DEBUG
Debug.WriteLine("Start");
#endif
ColorBgra PrimaryColor = EnvironmentParameters.PrimaryColor;
ColorBgra SecondaryColor = EnvironmentParameters.SecondaryColor;
ColorBgra CurrentPixel, newCol;
int brightness;
float e;
int[,] propagate = {{1, 0, 7}, {-1, 1, 3}, {0, 1, 5}, {1, 1, 1}}; //Floyd-Steinberg filter
for (int y = rect.Top; y < rect.Bottom; y++)
{
if (IsCancelRequested) return;
for (int x = rect.Left; x < rect.Right; x++)
{
dst[x,y] = src[x,y]; //Copy all pixels to dst, we'll need to edit them on the fly
}
}
for (int y = rect.Top; y < rect.Bottom; y++)
{
if (IsCancelRequested) return;
for (int x = rect.Left; x < rect.Right; x++)
{
//Change current color to white or black with threshold
CurrentPixel = dst[x,y];
brightness = HsvColor.FromColor(CurrentPixel).Value;
newCol = brightness <= 50 ? PrimaryColor : SecondaryColor;
newCol.A = CurrentPixel.A;
dst[x,y] = newCol;
//Calculate error
e = 1f/16f * (brightness <= 50 ? brightness : brightness - 100);
for (int i = 0; i < propagate.GetLength(0); i++) {
int dx = propagate[i, 0] + x;
int dy = propagate[i, 1] + y;
float de = propagate[i, 2] * e;
if (dx < rect.Right && dx >= rect.Left && dy < rect.Bottom && dy >= rect.Top)
{
//Disperse current error based on filter
HsvColor col = HsvColor.FromColor(dst[dx,dy]);
col.Value = (int)Math.Max(0, Math.Min(100, col.Value + de));
ColorBgra bruh = ColorBgra.FromColor(col.ToColor());
dst[dx,dy] = bruh;
}
}
}
}
#if DEBUG
Debug.WriteLine("Done");
#endif
}