【问题标题】:How do I create a Windows bitmap "from scratch" in C#?如何在 C# 中“从头开始”创建 Windows 位图?
【发布时间】:2016-10-04 06:58:05
【问题描述】:

我有一些原始传感器数据,它们位于一维字节数组中。数据实际上是 IEEE 单精度浮点格式。我知道 X 和 Y 轴的长度,我想从我的数据中创建一个 Windows 位图(灰度 - 只有一个颜色平面包含亮度数据)。

这是我目前正在尝试的:

        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 是一个委托,定义为:

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

当我运行此代码时,我在尝试设置像素值的行上收到异常 InvalidArgumentException。我在调试器中步进了它,x=0、y=0 和像素=0。它没有说明哪个参数无效或为什么无效(感谢 Microsoft)。

很明显我做错了什么,实际上,我怀疑可能有一种更有效的方法来解决这个问题。我将不胜感激任何建议。由于我不能完全确定的原因,我发现这段代码编写起来非常具有挑战性。

【问题讨论】:

  • 不要使用SetPixel 进行批量操作,use LockBits instead。另外,请将 InvalidArgumentException 的 get the exception details 包含在此处。这将有助于找出问题所在。
  • 您是在 argb 中获得了有效的颜色还是只是获得了一个空值?我怀疑您的问题是较早的,但是隐式类型变量掩盖了问题。我强烈建议使用实际类型,而不是在大多数/所有代码中确实不需要时将所有内容定义为 vars。
  • 可能和16bpp格式有关,看看stackoverflow.com/questions/34649745/…
  • 我认为问题可能是 16bppGrayscale 格式可能会在完整的 argb 颜色上窒息。尝试从位图声明中取出像素格式,所以只需 var bitmap = new Bitmap(xAxis, yAxis);
  • 只是这段代码会给你同样的问题var bitmap = new Bitmap(100, 100, PixelFormat.Format16bppGrayScale); var argb = Color.FromArgb(0, 0, 0); bitmap.SetPixel(0, 0, argb);

标签: c# bitmap


【解决方案1】:

好的,这就是最终奏效的方法。基于取自 Mark Dawson 对此问题的回答中的代码: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;
    }

然后我修改了自己的代码,将 IEEE 浮点数据转换为 16 位整数,然后直接从中创建位图,如下所示:

        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;

这似乎也解决了 cmets 中强调的效率问题。

【讨论】:

  • 一旦我尝试显示我创建的图像,它就不起作用了。所以我仍然有办法解决这个问题。当我找到更好的解决方案时,我会更新我的答案。
猜你喜欢
  • 2011-12-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-01-29
  • 1970-01-01
  • 2020-10-12
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多