I am currently working on an automatically generated Ribbon bar with buttons that have colored icons. For that, I have a list of colors provided when generating the icon, and need to create an ImageSource out of it to display the icon.
I've found a (hopefully) good way to do it by using the BitmapSource.Create
method to create a bitmap-based image source. Sadly, this API seems to be really low-level, which gives me headaches to implement my needs.
That's why I am asking here now.
I got it working to just draw a plain color. I even got the top and lower border working by changing the pixel array, but I can't for the life of it get the left and right border correct.
I tried a lot, and it currently looks like this:
But before I explain more, I am going ahead to show my relevant code.
public virtual ImageSource OneColorImage(Color color, (Color Color, int Size)? border = null, int size = 32)
{
const int dpi = 96;
var pixelFormat = PixelFormats.Indexed1;
var stride = CalculateStride(pixelFormat.BitsPerPixel, size);
var pixels = new byte[size * stride];
var colors = new List<Color> { color };
if (border.HasValue)
{
var (borderColor, borderSize) = border.Value;
// Add the border color to the palette.
colors.Add(borderColor);
// Now go over all pixels and specify the byte explicitly
for (var y = 0; y < size; y++)
{
for (var x = 0; x < stride; x++)
{
var i = x + y * stride;
// Top and bottom border
if (y < borderSize || y >= size - borderSize)
pixels[i] = 0xff;
// Left and right border
else if (x % stride < borderSize || x % stride >= stride - borderSize)
pixels[i] = 0xff;
// Else background color
else
pixels[i] = 0x00;
}
}
}
var palette = new BitmapPalette(colors);
var image = BitmapSource.Create(size, size, dpi, dpi, pixelFormat, palette, pixels, stride);
return new CachedBitmap(image, BitmapCreateOptions.None, BitmapCacheOption.Default);
}
public virtual int CalculateStride(int bitsPerPixel, int width)
{
var bytesPerPixel = (bitsPerPixel + 7) / 8;
var stride = 4 * ((width * bytesPerPixel + 3) / 4);
return stride;
}
I've googled a lot to get this working, learned how to calculate the stride
and what it means, but I still seem to miss something.
I want to specify those two colors and create the bitmap color palette based on those colors, then just set the switch to one color or the other, that's why I am using the PixelFormats.Indexed1
format, because it is just for a two-color bitmap.
I guess I can remove some abstraction of this method by just using fixed values for this format, but I want to make it a little more abstract if I am going to change the pixel format to more colors in the future for example, thus the stride calculation etc.
Pretty sure I am missing something with the difference between width
and stride
when looking for the left and right border, or I don't understand how the bytes inside a single row (stride) work and have to set the bits, not the bytes...
Any help appreciated, I am stuck after trying for hours.