如何将 48bpp 图像的原始数据加载到位图中?

2024-01-21

我问了一个与 24bpp 图像有关的类似问题here https://stackoverflow.com/q/15254990/1039947但我正在使用那里描述的技术并遇到了第二个问题,这次与 48bpp 有关......

我有一个byte[]包含 16 位颜色深度图像。因此,从图像的左上角到右下角依次有两个字节表示红色,两个字节表示绿色,两个字节表示蓝色。我正在将其加载到Bitmap像这样(考虑到步幅等):

byte[] data = ReadRawData();

// Swap from rgb to bgr
for (int i = 5; i < data.Length; i+=6)
{
   var r1 = data[i - 5];
   var r2 = data[i - 4];

   var b1 = data[i - 1];
   var b2 = data[i];

   data[i - 5] = b1;
   data[i - 4] = b2;

   data[i - 1] = r1;
   data[i] = r2;
}

// Load into a bitmap (I know the width and height, and the format
using (var b = new Bitmap(157, 196, PixelFormat.Format48bppRgb))
{
  var bmpData = b.LockBits(new Rectangle(0, 0, b.Width, b.Height),
    ImageLockMode.ReadWrite, b.PixelFormat);

  // Here we loop through each line and make sure it is padded to
  // the stride length
  var bytesPerLine = b.Width * 6;
  for (int i = 0; i < b.Height; i++)
  {
    IntPtr offset = bmpData.Scan0 + i * bmpData.Stride;
    Marshal.Copy(data, i * bytesPerLine, offset, bytesPerLine);
    int padding = bmpData.Stride - bytesPerLine;

    if (padding > 0)
    {
      var pad = new byte[padding];
      Marshal.Copy(pad, 0, offset + bytesPerLine, padding);
    }
  }
  b.UnlockBits(bmpData);
  // Done so save
  b.Save("c:\\out.tiff", ImageFormat.Tiff);
}

它产生这个图像:

不过,该图像不正确,它应该如下所示:

所以,我的问题是,我做错了什么?


Update

如果我在出现字节顺序问题时切换 r1,r2 和 b1,b2 (以及绿色的),但它会像这样绘制图像:

(所以仍然不对——但这是否给我们提供了关于正在发生的事情的线索?)

我已经在github上放了一个文件here https://github.com/kmp1/misc/blob/master/data16.bin这是原始数据,因此您可以将其保存到磁盘上,然后这个小方法将打开它:

private static byte[] ReadRawData()
{
    byte[] data;
    using (var ms = new MemoryStream())
    {
        using (var f = File.OpenRead("c:\\data16.bin"))
        {
            byte[] buffer = new byte[2048];
            int read;
            while ((read = f.Read(buffer, 0, buffer.Length)) > 0)
            {
                   ms.Write(buffer, 0, read);
            }
        }
        data = ms.ToArray();
    }
    return data;
}

如果我需要使用 WPF 库,那对我来说没问题。


Update 2

因此,正如评论中所建议的,我想出了一些代码来生成一个我可以推理的字节数组。

因此,我所做的是输出一个长度为 196 * 200 * 6 的字节数组,这样我将得到一个宽 196 像素、高 200 像素、每个像素 6 字节的图像(这个大小很方便,因为它足够大)看看,这并不意味着我必须费心处理跨步的事情)。然后我决定将图片分成 4 个垂直条纹,每个条纹的字节为:

  • 0x00, 0x00,0x00, 0x00, 0xFF, 0xFF
  • 0x00、0x00、0x00、0x00、0x00、0xFF
  • 0x00、0x00、0x00、0x00、0xFF、0x00
  • 0x00, 0x00, 0x00, 0x00, 0x00, 0x00

这应该意味着我可以看到颜色之间的差异,对吧?好吧,我实际上得到的是这个,那么我做错了什么?:

这是我生成上图的代码:

using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Runtime.InteropServices;

namespace ImagePlayingApplication
{
    class Program
    {
        static void Main(string[] args)
        {
            const int width = 196;
            const int height = 200;
            const int columnWidth = width / 4;
            const int bytesPerPixel = 6;

            var data = new byte[width * height * bytesPerPixel];
            for (int y = 0; y < height; y++)
            {
                for (int x = 0; x < width * bytesPerPixel; x += bytesPerPixel)
                {
                    int i = y * width * bytesPerPixel + x;

                    // Blue and Green components
                    // always 0x00 since we are just
                    // interested in red
                    data[i] = 0x00;
                    data[i + 1] = 0x00;
                    data[i + 2] = 0x00;
                    data[i + 3] = 0x00;

                    if (x < columnWidth * bytesPerPixel)
                    { 
                        // Left most column, full red
                        data[i + 4] = 0xFF;
                        data[i + 5] = 0xFF;
                    }
                    else if (x < columnWidth * bytesPerPixel * 2)
                    {
                        // Next left, half red
                        data[i + 4] = 0x00;
                        data[i + 5] = 0xFF;
                    }
                    else if (x < columnWidth * bytesPerPixel * 3)
                    {
                        // Next left, other half red
                        data[i + 4] = 0xFF;
                        data[i + 5] = 0x00;
                    }
                    else
                    {
                        // Final column, no red
                        data[i + 4] = 0x00;
                        data[i + 5] = 0x00;
                    }
                }
            }

            using (var b = new Bitmap(width, 
                                      height, 
                                      PixelFormat.Format48bppRgb))
            {
                var bmpData = b.LockBits(
                    new Rectangle(0, 0, b.Width, b.Height), 
                    ImageLockMode.ReadWrite, 
                    b.PixelFormat);
                Marshal.Copy(data, 0, bmpData.Scan0, data.Length);
                b.UnlockBits(bmpData);

                b.Save(@"c:\users\public\stripes2.tiff", ImageFormat.Tiff);
            }
        }
    }
}

那么,有人知道如何将此处描述的字节数组转换为正确的位图吗?正如我所说,如果 WPF 中有任何内容可以提供帮助,那很好,或者我可能需要将其转换为,我不知道 64bppargb 格式或其他格式?


所以我已经弄清楚了如何做到这一点,但它并不是很完美......

如果我添加参考文献System.Xaml, PresentationCore and WindowsBase并使用 WPF 图像类作为中间步骤我可以得到Bitmap http://msdn.microsoft.com/en-us/library/system.drawing.bitmap.aspx,像这样(使用data.bin https://github.com/kmp1/misc/blob/master/data16.bin问题中链接的文件和ReadRawData方法):

// Declare what we know
const int width = 157;
const int height = 196;
const double dpi = 50;
var format = PixelFormats.Rgb48;
int stride = (width * format.BitsPerPixel + 7) / 8;

// Get the data (see the question for this method)
var data = ReadRawData();

// Now put the data into a WiteableBitmap
var wb = new WriteableBitmap(width, height, dpi, dpi, format, null);
wb.WritePixels(new Int32Rect(0, 0, width, height), data, stride, 0);

// Encode as a TIFF
var enc = new TiffBitmapEncoder { Compression = TiffCompressOption.None };
enc.Frames.Add(BitmapFrame.Create(wb));

// And convert to a bitmap
using (var ms = new MemoryStream())
{
    enc.Save(ms);

    using (var bmp = new Bitmap(ms))
    {
        // Blergh, I feel dirty!
        bmp.Save("c:\\works.tiff", ImageFormat.Tiff);
    }
}

瞧!

我想我在我的项目中要做的就是放弃Windows.Drawing完全考虑到这个问题和整个步伐疼痛 https://stackoverflow.com/q/15254990/1039947事实上 RGB 实际上是 BGR(基本上我厌倦了它)。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何将 48bpp 图像的原始数据加载到位图中? 的相关文章

随机推荐