简体   繁体   中英

Structure for holding a 16bits grayscale image

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.

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.

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.

Example:

var image16 = BitmapDataFactory.CreateBitmapData(new Size(512, 512), PixelFormat.Format16bppGrayScale);
var row = image16.FirstRow;
do
{
    for (int x = 0; x < image16.Width; x++)
    {
        // row[x] uses a Color32 structure (8 bit per color) but raw access
        // enables you to use the full 16-bit color range:
        row.WriteRaw<ushort>(x, 32768); // 50% gray
    }
} while (row.MoveNextRow());


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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM