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


70

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

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

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

Answers:


116

您需要将它们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);就足够了。??
goGud 2014年

1
我收到类似@mario的错误消息:System.ArgumentException类型的未处理异常发生在System.Drawing.dll中。附加信息:参数无效
goGud 2014年

@goGud,在哪一行?
Mike Perrenoud 2014年

9
没有!不要丢弃流!来自Bitmap(Stream):“您必须在位图的生存期内保持流打开。”
皮达尔

2
正如@piedar指出的那样,只有在位图处理之后,才应该关闭/处理流。但是,如果您使用MemoryStream,则不必担心会关闭它,因为MemoryStream无论如何,它实际上并不会做任何事情。该System.Drawing.ImageConverter.ConvertFrom方法实际上利用了这一事实,因此进行该假设似乎是安全的。这样做,var bmp = new Bitmap(new MemoryStream(imageData));就足够了。
史蒂文·多格加特18'Feb

29

伙计们感谢您的帮助。我认为所有这些答案都行得通。但是我认为我的字节数组包含原始字节。这就是为什么所有这些解决方案都不适用于我的代码的原因。

但是我找到了解决方案。也许此解决方案可以帮助其他遇到像我这样的问题的编码人员。

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");

该解决方案适用于8位256 bpp(Format8bppIndexed)。如果图像具有其他格式,则应更改PixelFormat

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

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

该功能也对我有用。此功能将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"));
                    }
                }
            }
        }

4
嗨,goGud。您无需填充数据,“ Format32bppRgb”每像素使用4个字节(或名称状态为每个像素32位,8位== 1字节)。“ Format32bppRgb”实际上是RGBX,而您的数据似乎存储为“ RGB”,因此每像素3个字节。尝试Format24bppRGB,这将是每个像素3个字节。并且您的步伐将是width * 3最后值得一提的IntPtr部分,您将必须保留对此的单独引用...如果您希望位图持久存在,我建议您看一下这篇文章:stackoverflow.com/questions/ 6782489 /…
chrispepper1989 2014年

18

可以像这样简单:

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
+1用于显示使用static访问器给猫皮换皮的另一种方法,但是是的,您需要将其MemoryStream包裹在中using
Mike Perrenoud 2014年

1
@goGud我已经更新了答案。System.Windows.Controls.Image是显示图像的控件。在这里,使用的是类System.Drawing.Image
Mario S

是的,我还有最后一个问题,我认为这将结束。当我使用您的代码时,在调试时会收到此错误。System.Drawing.dll中发生了类型为'System.ArgumentException'的未处理异常。其他信息:参数无效。
goGud 2014年

@goGud听起来您要发送给该Image.FromStream方法的字节数组不是有效的图像。
Mario S

1
这里的问题在于,它不是所讨论的原始RGB流。要获取没有给出尺寸的数据,它会保存图像,就像可以保存的任何对象一样,该对象本身已经是带有化妆的图像(例如,尺寸,像素格式等)。
user3800527

0

此外,您可以简单地转换byte arrayBitmap

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

您也可以直接Bitmap文件Path获取。

Bitmap bmp = new Bitmap(Image.FromFile(filePath));
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.