如何从字节数组创建位图?

Posted

技术标签:

【中文标题】如何从字节数组创建位图?【英文标题】:How to create bitmap from byte array? 【发布时间】:2014-02-28 14:15:17 【问题描述】:

我搜索了有关字节数组的所有问题,但总是失败。我从来没有编写过 c#,我是这方面的新手。你能帮我如何从字节数组制作图像文件吗?

这是我的函数,它将字节存储在名为 imageData 的数组中

public void imageReady( byte[] imageData, int fWidth, int fHeight))

【问题讨论】:

【参考方案1】:

您需要将这些bytes 放入MemoryStream

Bitmap bmp;
using (var ms = new MemoryStream(imageData))

    bmp = new Bitmap(ms);

使用 Bitmap(Stream stream) 构造函数重载。

更新:请记住,根据文档和我一直在阅读的源代码,ArgumentException 将在这些条件下抛出:

stream does not contain image data or is null.
-or-
stream contains a PNG image file with a single dimension greater than 65,535 pixels.

【讨论】:

然后写 bmp.Save(c:\\image.jpg); 就够了?? 我收到与@mario 的答案相同的错误消息:System.Drawing.dll 中发生“System.ArgumentException”类型的未处理异常附加信息:参数无效 @goGud,在哪一行? 不!不要丢弃流!来自Bitmap(Stream):“您必须在位图的生命周期内保持流打开。” 正如@piedar 指出的那样,在处理位图之前不应关闭/处理流。但是,如果您使用的是MemoryStream,那么您不必担心会关闭它,因为MemoryStream 在被处理时实际上并没有做任何事情。 System.Drawing.ImageConverter.ConvertFrom 方法实际上利用了这一事实,因此做出这样的假设似乎是安全的。做,只需var bmp = new Bitmap(new MemoryStream(imageData)); 就足够了。【参考方案2】:

各位,谢谢你们的帮助。我认为所有这些答案都有效。但是我认为我的字节数组包含原始字节。这就是为什么所有这些解决方案都不适用于我的代码。

但是我找到了解决方案。也许这个解决方案可以帮助其他像我一样遇到问题的程序员

static byte[] PadLines(byte[] bytes, int rows, int columns) 
   int currentStride = columns; // 3
   int newStride = columns;  // 4
   byte[] newBytes = new byte[newStride * rows];
   for (int i = 0; i < rows; i++)
       Buffer.BlockCopy(bytes, currentStride * i, newBytes, newStride * i, currentStride);
   return newBytes;
 

 int columns = imageWidth;
 int rows = imageHeight;
 int stride = columns;
 byte[] newbytes = PadLines(imageData, rows, columns);

 Bitmap im = new Bitmap(columns, rows, stride, 
          PixelFormat.Format8bppIndexed, 
          Marshal.UnsafeAddrOfPinnedArrayElement(newbytes, 0));

 im.Save("C:\\Users\\musa\\Documents\\Hobby\\image21.bmp");

此解决方案适用于 8bit 256 bpp (Format8bppIndexed)。如果您的图片有其他格式,您应该更改PixelFormat

现在颜色有问题。一旦我解决了这个问题,我将为其他用户编辑我的答案。

*PS = 我不确定步幅值,但对于 8 位,它应该等于列。

这个功能也适用于我。这个功能将 8 位灰度图像复制到 32 位布局中。

public void SaveBitmap(string fileName, int width, int height, byte[] imageData)
        

            byte[] data = new byte[width * height * 4];

            int o = 0;

            for (int i = 0; i < width * height; i++)
            
                byte value = imageData[i];


                data[o++] = value;
                data[o++] = value;
                data[o++] = value;
                data[o++] = 0; 
            

            unsafe
            
                fixed (byte* ptr = data)
                

                    using (Bitmap image = new Bitmap(width, height, width * 4,
                                PixelFormat.Format32bppRgb, new IntPtr(ptr)))
                    

                        image.Save(Path.ChangeExtension(fileName, ".jpg"));
                    
                
            
        

【讨论】:

嗨,goGud。您不需要填充数据,“Format32bppRgb”每个像素使用 4 个字节(或顾名思义,每个像素 32 位,8 位 == 1 个字节)。 “Format32bppRgb”实际上是 RGBX,而您的数据似乎存储为“RGB”,因此每个像素 3 个字节尝试 Format24bppRGB,这将是每个像素 3 个字节。并且您的步幅将是 width * 3 最后值得一提的是 IntPtr 部分,您必须单独引用它...如果您希望位图持续存在,我建议您查看这篇文章:***.com/questions/6782489/… 内部位图宽度可以被四整除。步幅通常是位深度 * 宽度,但如果不能被 4 整除,则会被填充。【参考方案3】:

可以这么简单:

var ms = new MemoryStream(imageData);
System.Drawing.Image image = Image.FromStream(ms);

image.Save("c:\\image.jpg");

测试一下:

byte[] imageData;

// Create the byte array.
var originalImage = Image.FromFile(@"C:\original.jpg");
using (var ms = new MemoryStream())

    originalImage.Save(ms, ImageFormat.Jpeg);
    imageData = ms.ToArray();


// Convert back to image.
using (var ms = new MemoryStream(imageData))

    Image image = Image.FromStream(ms);
    image.Save(@"C:\newImage.jpg");

【讨论】:

+1 展示了另一种使用 static 访问器为猫剥皮的方法,但是是的,您需要将 MemoryStream 包裹在 using 中。 @goGud 我已经更新了答案。 System.Windows.Controls.Image 是一个显示图像的控件。这里使用的是 System.Drawing.Image 类。 我有最后一个问题,我认为它会结束。当我使用您的代码时,我在调试时收到此错误。 System.Drawing.dll 中出现“System.ArgumentException”类型的未处理异常附加信息:参数无效。 @goGud 听起来您发送到Image.FromStream 方法的字节数组不是有效图像。 这里的问题是它不是问题中的原始 RGB 流。要检索没有给出尺寸的数据,它会像保存任何对象一样保存图像,其中对象本身已经是带有化妆的图像(例如尺寸像素格式等)。【参考方案4】:

此外,您可以简单地将byte array 转换为Bitmap

var bmp = new Bitmap(new MemoryStream(imgByte));

您也可以直接从文件路径获取Bitmap

Bitmap bmp = new Bitmap(Image.FromFile(filePath));

【讨论】:

以上是关于如何从字节数组创建位图?的主要内容,如果未能解决你的问题,请参考以下文章

如何将从 C++ 发送的 cv::MAT 字节数组转换为 Java 中的位图?

在 Android 上旋转 YUV 字节数组

如何将字节数组转换为位图实例 (.NET)?

如何将字节数组中的图像文件数据转换为位图?

将NV21字节数组转换为位图可读格式[重复]

如何将字节数组一个活动传递给另一个android [重复]