简体   繁体   中英

How do I create a Windows bitmap “from scratch” in C#?

I have some raw sensor data which is in a single dimension byte array. The data is actually in IEEE single precision floating point format. I know the X and Y axis legths and I want to create a Windows Bitmap (greyscale - there is only one colour plane containing luminance data) from my data.

Here's what I'm trying so far:

        var bitmap = new Bitmap(xAxis, yAxis, PixelFormat.Format16bppGrayScale);
        var pixelReader = GetPixelReader(hdu.MandatoryKeywords.BitsPerPixel);
        using (var stream = new MemoryStream(hdu.RawData, writable: false))
            {
            using (var reader = new BinaryReader(stream, Encoding.ASCII))
                {
                for (var y = 0; y < yAxis; y++)
                    {
                    for (var x = 0; x < xAxis; x++)
                        {
                        var pixel = pixelReader(reader);
                        var argb = Color.FromArgb(pixel, pixel, pixel);
                        bitmap.SetPixel(x, y, argb);
                        }
                    }
                }
            }
        return bitmap;

pixelReader is a delegate and defined as:

    private static int ReadIeeeSinglePrecision(BinaryReader reader)
        {
        return (int) reader.ReadSingle();
        }

When I run this code, I get an exception InvalidArgumentException on the line where I try to set the pixel value. I stepped it in the debugger and x=0, y=0 and pixel=0. It doesn't say which argument is invalid or why (thanks Microsoft).

So clearly I'm doing something wrong and actually, I suspect there is probably a more efficient way of going about this. I would appreciate any suggestions. For reasons I can't quite put my finger on, I am finding this code very challenging to write.

OK here is what worked in the end. Based on code taken from Mark Dawson's answer to this question: https://social.msdn.microsoft.com/Forums/vstudio/en-US/10252c05-c4b6-49dc-b2a3-4c1396e2c3ab/writing-a-16bit-grayscale-image?forum=csharpgeneral

private static Bitmap CreateBitmapFromBytes(byte[] pixelValues, int width, int height)
    {
    //Create an image that will hold the image data
    Bitmap pic = new Bitmap(width, height, PixelFormat.Format16bppGrayScale);
    //Get a reference to the images pixel data
    Rectangle dimension = new Rectangle(0, 0, pic.Width, pic.Height);
    BitmapData picData = pic.LockBits(dimension, ImageLockMode.ReadWrite, pic.PixelFormat);
    IntPtr pixelStartAddress = picData.Scan0;
    //Copy the pixel data into the bitmap structure
    System.Runtime.InteropServices.Marshal.Copy(pixelValues, 0, pixelStartAddress, pixelValues.Length);
    pic.UnlockBits(picData);
    return pic;
    }

So then I modified my own code to convert from the IEEE float data into 16 bit integers, and then create the bitmap directly from that, like so:

        var pixelReader = GetPixelReader(hdu.MandatoryKeywords.BitsPerPixel);
        var imageBytes = new byte[xAxis * yAxis * sizeof(Int16)];
        using (var outStream = new MemoryStream(imageBytes, writable: true))
        using (var writer = new BinaryWriter(outStream))
        using (var inStream = new MemoryStream(hdu.RawData, writable: false))
        using (var reader = new BinaryReader(inStream, Encoding.ASCII))
            for (var y = 0; y < yAxis; y++)
                {
                for (var x = 0; x < xAxis; x++)
                    {
                    writer.Write(pixelReader(reader));
                    }
                }
        var bitmap = CreateGreyscaleBitmapFromBytes(imageBytes, xAxis, yAxis);
        return bitmap;

This appears to also address the efficiency problem highlighted in the comments.

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