C# 字节数组到图像转换

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/9173904/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-09 06:15:20  来源:igfitidea点击:

Byte array to image conversion

c#arraysbytebytebuffer

提问by Tanzeel ur Rahman

I want to convert a byte array to an image.

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

This is my database code from where I get the byte array:

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

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;
}

My conversion code:

我的转换代码:

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;
}

When I reach the line with a comment, the following exception occurs: Parameter is not valid.

当我到达带有注释的行时,会发生以下异常: Parameter is not valid.

How can I fix whatever is causing this exception?

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

回答by Yahia

try (UPDATE)

尝试(更新)

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

回答by Holstebroe

You are writing to your memory stream twice, also you are not disposing the stream after use. You are also asking the image decoder to apply embedded color correction.

您正在写入内存流两次,而且您也没有在使用后处理流。您还要求图像解码器应用嵌入式颜色校正。

Try this instead:

试试这个:

using (var ms = new MemoryStream(byteArrayIn))
{
    return Image.FromStream(ms);
}

回答by RenniePet

This is inspired by Holstebroe's answer, plus comments here: Getting an Image object from a byte array

这受到 Holstebroe 的回答的启发,加上这里的评论:从字节数组中获取图像对象

Bitmap newBitmap;
using (MemoryStream memoryStream = new MemoryStream(byteArrayIn))
    using (Image newImage = Image.FromStream(memoryStream))
        newBitmap = new Bitmap(newImage);
return newBitmap;

回答by RenniePet

Maybe I'm missing something, but for me this one-liner works fine with a byte array that contains an image of a JPEG file.

也许我遗漏了一些东西,但对我来说,这个单行式适用于包含 JPEG 文件图像的字节数组。

Image x = (Bitmap)((new ImageConverter()).ConvertFrom(jpegByteArray));

EDIT:

编辑:

See here for an updated version of this answer: How to convert image in byte array

有关此答案的更新版本,请参见此处:How to convert image in byte array

回答by GPGVM

Most of the time when this happens it is bad data in the SQL column. This is the proper way to insert into an image column:

大多数情况下,发生这种情况的都是 SQL 列中的错误数据。这是插入图像列的正确方法:

INSERT INTO [TableX] (ImgColumn) VALUES (
(SELECT * FROM OPENROWSET(BULK N'C:\....\Picture 010.png', SINGLE_BLOB) as tempimg))

Most people do it incorrectly this way:

大多数人这样做是错误的:

INSERT INTO [TableX] (ImgColumn) VALUES ('C:\....\Picture 010.png'))

回答by LeeCambl

You haven't declared returnImage as any kind of variable :)

您尚未将 returnImage 声明为任何类型的变量 :)

This should help:

这应该有帮助:

public Image byteArrayToImage(byte[] byteArrayIn)
{
    try
    {
        MemoryStream ms = new MemoryStream(byteArrayIn,0,byteArrayIn.Length);
        ms.Write(byteArrayIn, 0, byteArrayIn.Length);
        Image returnImage = Image.FromStream(ms,true);
    }
    catch { }
    return returnImage;
}

回答by isaias-b

All presented answers assume that the byte array contains data in a known file format representation, like: gif, png or jpg. But i recently had a problem trying to convert byte[]s, containing linearized BGRA information, efficiently into Imageobjects. The following code solves it using a Bitmapobject.

所有呈现的答案都假定字节数组包含以已知文件格式表示的数据,例如: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;
    }
}

This is a slightly variation of a solution which was posted on this site.

这是本网站上发布的解决方案的一个稍微变体。

回答by Ali Gh

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

回答by lorond

I'd like to note there is a bug in solution provided by @isaias-b.

我想指出@isaias-b 提供的解决方案中有一个错误。

That solution assume that strideis equal to row length. But it is not always true. Due to memory alignments performed by GDI, stride can be greater then row length. This must be taken into account. Otherwise invalid shifted image will be generated. Padding bytes in each row will be ignored.

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

The stride is the width of a single row of pixels (a scan line), rounded up to a four-byte boundary.

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

Fixed code:

固定代码:

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;
    }
}

To illustrate what it can lead to, let's generate PixelFormat.Format24bppRgbgradient image 101x101:

为了说明它会导致什么,让我们生成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);
}

If we will copy entire array as-is to address pointed by bmpData.Scan0, we will get following image. Image shifting because part of image was written to padding bytes, that was ignored. Also that is why last row is incomplete:

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

stride ignored

忽略大步

But if we will copy row-by-row shifting destination pointer by bmpData.Stridevalue, valid imaged will be generated:

但是,如果我们将逐行按bmpData.Stride值复制移动目标指针,则会生成有效的图像:

stride taken into account

考虑到步幅

Stride also can be negative:

步幅也可以是负数:

If the stride is positive, the bitmap is top-down. If the stride is negative, the bitmap is bottom-up.

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

But I didn't worked with such images and this is beyond my note.

但我没有处理过这样的图像,这超出了我的注意。

Related answer: C# - RGB Buffer from Bitmap different from C++

相关答案:C# - 来自位图的 RGB 缓冲区与 C++ 不同

回答by Ali

there is a simple approach as below, you can use FromStreammethod of an image to do the trick, Just remember to use System.Drawing;

有一个简单的方法如下,你可以使用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;
}