字节数组到图像转换

Tan*_*man 90 c# arrays byte bytebuffer

我想将字节数组转换为图像.

这是我获取字节数组的数据库代码:

public void Get_Finger_print()
{
    try
    {
        using (SqlConnection thisConnection = new SqlConnection(@"Data Source=" + System.Environment.MachineName + "\\SQLEXPRESS;Initial Catalog=Image_Scanning;Integrated Security=SSPI "))
        {
            thisConnection.Open();
            string query = "select pic from Image_tbl";// where Name='" + name + "'";
            SqlCommand cmd = new SqlCommand(query, thisConnection);
            byte[] image =(byte[]) cmd.ExecuteScalar();
            Image newImage = byteArrayToImage(image);
            Picture.Image = newImage;
            //return image;
        }
    }
    catch (Exception) { }
    //return null;
}
Run Code Online (Sandbox Code Playgroud)

我的转换代码:

public Image byteArrayToImage(byte[] byteArrayIn)
{
    try
    {
        MemoryStream ms = new MemoryStream(byteArrayIn,0,byteArrayIn.Length);
        ms.Write(byteArrayIn, 0, byteArrayIn.Length);
        returnImage = Image.FromStream(ms,true);//Exception occurs here
    }
    catch { }
    return returnImage;
}
Run Code Online (Sandbox Code Playgroud)

当我通过注释到达该行时,会发生以下异常: Parameter is not valid.

如何解决导致此异常的问题?

Hol*_*roe 101

您正在两次写入内存流,也没有在使用后丢弃流.您还要求图像解码器应用嵌入式颜色校正.

试试这个:

using (var ms = new MemoryStream(byteArrayIn))
{
    return Image.FromStream(ms);
}
Run Code Online (Sandbox Code Playgroud)

  • 这违反了MSDN中针对Image.FromStream()的规范,其中说明"您必须在图像的生命周期内保持流打开".另见http://stackoverflow.com/questions/3290060/getting-an-image-object-from-a-byte-array (24认同)

Ren*_*Pet 80

也许我错过了一些东西,但对我来说,这个单行程序可以正常工作,其中包含一个包含JPEG文件图像的字节数组.

Image x = (Bitmap)((new ImageConverter()).ConvertFrom(jpegByteArray));
Run Code Online (Sandbox Code Playgroud)

编辑:

请参阅此处获取此答案的更新版本:如何在字节数组中转换图像

  • 啊啊谢谢,终于有一个好的答案了。为什么这么多答案都带有内存流,这给我带来了很多问题。多谢 ! (2认同)

Ali*_* Gh 13

public Image byteArrayToImage(byte[] bytesArr)
{
    using (MemoryStream memstr = new MemoryStream(bytesArr))
    {
        Image img = Image.FromStream(memstr);
        return img;
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 这对 3 年前发布的[现有答案](/sf/answers/642184861/)没有任何增加,并且遇到了过早处置流的相同问题。 (2认同)

lor*_*ond 8

我想注意@isaias-b提供的解决方案中存在一个错误.

该解决方案假设stride等于行长度.但并非总是如此.由于GDI执行的内存对齐,步幅可能大于行长度.必须考虑到这一点.否则将生成无效的移位图像.每行中的填充字节将被忽略.

步幅是单行像素(扫描线)的宽度,四舍五入到四字节边界.

固定代码:

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

public static class ImageExtensions
{
    public static Image ImageFromRawBgraArray(this byte[] arr, int width, int height, PixelFormat pixelFormat)
    {
        var output = new Bitmap(width, height, pixelFormat);
        var rect = new Rectangle(0, 0, width, height);
        var bmpData = output.LockBits(rect, ImageLockMode.ReadWrite, output.PixelFormat);

        // Row-by-row copy
        var arrRowLength = width * Image.GetPixelFormatSize(output.PixelFormat) / 8;
        var ptr = bmpData.Scan0;
        for (var i = 0; i < height; i++)
        {
            Marshal.Copy(arr, i * arrRowLength, ptr, arrRowLength);
            ptr += bmpData.Stride;
        }

        output.UnlockBits(bmpData);
        return output;
    }
}
Run Code Online (Sandbox Code Playgroud)

为了说明它可以导致什么,让我们生成PixelFormat.Format24bppRgb渐变图像101x101:

var width = 101;
var height = 101;
var gradient = new byte[width * height * 3 /* bytes per pixel */];
for (int i = 0, pixel = 0; i < gradient.Length; i++, pixel = i / 3)
{
    var x = pixel % height;
    var y = (pixel - x) / width;
    gradient[i] = (byte)((x / (double)(width - 1) + y / (double)(height - 1)) / 2d * 255);
}
Run Code Online (Sandbox Code Playgroud)

如果我们将整个数组按原样复制到指向的地址bmpData.Scan0,我们将获得以下图像.图像移位是因为部分图像被写入填充字节,被忽略了.这就是为什么最后一行不完整的原因:

大步被忽视了

但是如果我们将逐行复制逐行移位目标指针bmpData.Stride,将生成有效的imaged:

大步考虑到了

步幅也可能是负面的:

如果步幅为正,则位图为自上而下.如果步幅为负,则位图自下而上.

但我没有使用过这样的图像,这超出了我的注意.

相关回答:C# - Bitmap中的RGB Buffer与C++不同


小智 8

Image.FromStream(new MemoryStream(byteArrayIn));
Run Code Online (Sandbox Code Playgroud)


Ali*_*Ali 6

有一个简单的方法如下,你可以使用FromStream图像的方法来做伎俩,只记得使用System.Drawing;

// using image object not file 
public byte[] imageToByteArray(Image imageIn)
{
    MemoryStream ms = new MemoryStream();
    imageIn.Save(ms,System.Drawing.Imaging.ImageFormat.Gif);
    return ms.ToArray();
}

public Image byteArrayToImage(byte[] byteArrayIn)
{
    MemoryStream ms = new MemoryStream(byteArrayIn);
    Image returnImage = Image.FromStream(ms);
    return returnImage;
}
Run Code Online (Sandbox Code Playgroud)


Yah*_*hia 5

尝试(更新)

MemoryStream ms = new MemoryStream(byteArrayIn,0,byteArrayIn.Length);
ms.Position = 0; // this is important
returnImage = Image.FromStream(ms,true);
Run Code Online (Sandbox Code Playgroud)

  • 在使用相同的字节数组初始化字节数组后,将字节数组写入内存流是没有意义的.实际上我不确定MemoryStream是否允许写入超出构造函数中指定的长度. (2认同)

isa*_*s-b 5

所有给出的答案都假设字节数组包含已知文件格式表示的数据,如:gif,png或jpg.但是我最近在尝试将byte[]包含线性化BGRA信息的s 转换为Image对象时遇到了问题.以下代码使用Bitmap对象解决它.

using System.Drawing;
using System.Drawing.Imaging;
using System.Runtime.InteropServices;
public static class Extensions
{
    public static Image ImageFromRawBgraArray(
        this byte[] arr, int width, int height)
    {
        var output = new Bitmap(width, height);
        var rect = new Rectangle(0, 0, width, height);
        var bmpData = output.LockBits(rect, 
            ImageLockMode.ReadWrite, output.PixelFormat);
        var ptr = bmpData.Scan0;
        Marshal.Copy(arr, 0, ptr, arr.Length);
        output.UnlockBits(bmpData);
        return output;
    }
}
Run Code Online (Sandbox Code Playgroud)

这是在此网站上发布的解决方案的略微变化.

  • 感谢您添加所有需要的“使用”。大多数人忘记了这一点,找到它们是一种痛苦。 (2认同)