2013-03-08 69 views
7

我问过类似的问题和24bpp图像here这样做,但我使用有描述的技术,并有第二个问题,这个时候做48bpp ...如何将48bpp图像的原始数据加载到位图中?

我有一个包含16位色彩深度的byte[]图片。所以从图像的左上角到右下角依次有两个字节红色,两个绿色和两个蓝色。我加载此为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); 
} 

它产生这一形象:

wrong image

的图像是不正确的,但是,它应该是这样的:

correct image

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


更新

如果我换了R1,R2和B1,B2(和绿色的)中的字节序问题的情况下,但随后绘制这样的形象:

endianness switch

(所以仍然没有正确的 - 但是这给我们一个线索是什么也许是怎么回事?)

我已经把文件了GitHub上here这是原始数据,这样就可以保存下来,为您的磁盘,然后这个小方法打开它:

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库相反,这对我来说很好。


更新2

所以,在意见提出,我想出了一些代码生成的字节数组,我可以推理。因此,我所做的是输出一个长度为196 * 200 * 6的字节数组,这样我就可以得到一幅宽196像素,高200像,每像素6字节的图像(这个大小非常方便它足够大,看到一个并不意味着我不得不打扰的步幅)。然后我决定,我将分割的图片分成4个垂直条纹,其中用于每个条带的字节为:

  • 0x00时,0×00,0x00时,0×00,为0xFF,0xFF的
  • 0x00时,0×00,0×00,为0x00,0x00时,0xFF的
  • 为0x00,0x00时,为0x00,0x00时,为0xFF,0×00
  • 为0x00,0x00时,0×00,0×00,0×00,0×00

这应该意味着我可以看到颜色之间的差别对?那么,事实上,我是这样的,所以我在做什么错?:

After second attempt

这里是我的代码所产生的上图:

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格式或其他什么?

+0

你可以发布一个完整的程序/例子,包括图像数据,作为文件(链接)还是用C#声明的字节数组?如果他们能够复制你的示例代码并运行在Visual Studio或LINQPad或类似的代码中,它将有助于未来的帮助者。 – 2013-03-08 19:52:11

+2

可能是Big-Endian/Little-Endian问题?尝试反转r1/r2和b1/b2。 – 2013-03-08 20:56:21

+0

我知道48 bpp图像不直接支持。看到http://stackoverflow.com/q/7276212/56778 – 2013-03-08 23:54:42

回答

2

所以我已经找到了如何做到这一点,但它不是真正的完美......

如果我添加引用了System.XamlPresentationCoreWindowsBase和使用WPF图像类作为一个中间步骤,我可以得到到Bitmap,像这样(使用data.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); 
    } 
} 

等瞧!

works.tiff

我想我会在我的项目做的是沟Windows.Drawing完全放弃这个问题,整个pain with the stride和事实,即RGB实际上是BGR(基本上我都腻了)。

相关问题