I need to mask image from memory buffers (rectangle area filled with black). So I naively re-use the Bitmap class with ImageFormat.MemoryBmp for my API. This works quite well on my local machine:
public static void MaskBitmap(Bitmap input, Rectangle maskRegion)
{
var bytesPerPixel = Image.GetPixelFormatSize(input.PixelFormat) / 8;
var row = new byte[maskRegion.Width * bytesPerPixel];
var maskData = input.LockBits(maskRegion, ImageLockMode.WriteOnly, input.PixelFormat);
for (var i = 0; i < maskData.Height; i)
{
Marshal.Copy(row, 0, maskData.Scan0 (i * maskData.Stride), row.Length);
}
input.UnlockBits(maskData);
}
However when deploying to production it turns out that the following throw a NotImplementedException
:
var image16 = new Bitmap(512, 512, PixelFormat.Format16bppGrayScale);
I eventually tracked it down to here:
So my question is: is there any existing class in c# that I can re-use to hold images of pixelformat type:
- PixelFormat.Format8bppIndexed:
- PixelFormat.Format16bppGrayScale:
- PixelFormat.Format24bppRgb:
I know GDI does not support saving/displaying 16bits image, I simply need a memory structure with image-style access.
Just for reference, I tried the following hack:
var image = new Bitmap(512,512,PixelFormat.Format24bppRgb);
image.Flags = ImageFlags.ColorSpaceGray;
But Flags
is read-only.
CodePudding user response:
I think the Wpf bitmaps should support 16-bit grayscale.
However, most systems I have worked on that uses 16-bit grayscale images uses a custom data type. Something like:
public class My16BitImage{
public ushort[] Data {get;}
public int Width {get;}
public int Height {get;}
}
Note that for displaying the image you most probably need to convert it to an 8-bit image anyway, and you probably need to scale the values to make the max/min values map to the largest/smallest 8 bit values.
CodePudding user response:
As you could see, the GDI Bitmap
does not support the 16bpp grayscale pixel format on Linux at all, and actually its support is quite limited on Windows, too. Once I collected the limitations for both platforms, see the table under the Restrictions of Possible Pixel Formats on Different Platforms section here.
I need to mask image from memory buffers
To use completely managed in-memory representation of a bitmap both on Linux and Windows, you can use this library (disclaimer: written by me). You can create a 16bpp grayscale bitmap data by the BitmapDataFactory.CreateBitmapData
method, which returns an IReadWriteBitmapData
that allows a lot of managed operations (see the link that enlists the usable extension methods). You can even convert it to an actual Bitmap
by the ToBitmap
extension, but on Linux this converts the result to a Bitmap
with 24bpp RGB pixel format.
As for the 8bpp indexed and 24bpp RGB formats, these are supported by the native Bitmap
also on Linux, but please note that starting with version .NET 6 System.Drawing
will be supported only on Windows by default. Microsoft recommends using other libraries instead, but you can still enable the Unix support by adding "System.Drawing.EnableUnixSupport": true
to runtimeconfig.json
. Or, if you decide to use my library I mentioned above, just call DrawingModule.Initialize()
before anything else, which enables the Unix support without editing any config files.