Byte array to image conversion

我想把一个字节数组转换成一个图像。

这是我得到字节数组的数据库代码:

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

我的转换代码:

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

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

我如何修复导致这个异常的东西?

426373 次浏览

试试 (更新)

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

You are writing to your memory stream twice, also you are not disposing the stream after use. 你还要求图像解码器应用嵌入式色彩校正。

试试这个:

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

这是受 Holstebroe 的回答的启发,加上这里的评论: Getting an Image object from a byte array

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

也许我遗漏了一些东西,但是对我来说,这个一行程序可以很好地处理包含 JPEG 文件图像的字节数组。

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

编辑:

在这里可以看到这个答案的更新版本: 如何转换字节数组中的图像

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

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

大多数人这样做是不正确的:

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

您还没有将 returImage 声明为任何类型的变量:)

这应该会有所帮助:

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

所有提供的答案都假设字节数组包含已知文件格式表示的数据,如 gif、 png 或 jpg。但是我最近在尝试将包含线性化 BGRA 信息的 byte[]有效地转换成 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 这个网站.

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

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

该解决方案假设 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;
}
}

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

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

stride ignored

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

stride taken into account

Stride 也可能是消极的:

如果步长为正,则位图为自顶向下。如果步长为负,则位图为自底向上。

但是我没有处理过这样的图像,这超出了我的笔记。

相关答案: 与 C + + 不同的来自 Bitmap 的 RGB 缓冲区

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

One liner:

Image bmp = (Bitmap)((new ImageConverter()).ConvertFrom(imageBytes));

首先安装这个软件包:

Install-Package SixLabors. ImageSharp-Version 1.0.0-beta0007

[ SixLabors. ImageSharp ][1] 返回文章页面【一分钟科普】【一分钟科普】【一分钟科普】【一分钟科普】【一分钟科普】【一分钟科普】【一分钟科普】【一分钟科普】【一分钟科普】【一分钟科普】【一分钟科普】【一分钟科普】【一分钟 https://www.nuget.org/packages/sixlabors 】

然后使用下面的代码为强制字节数组映像:

Image<Rgba32> image = Image.Load(byteArray);

在代码以下使用获取图像格式:

IImageFormat format = Image.DetectFormat(byteArray);

用于变异图像使用以下代码:

image.Mutate(x => x.Resize(new Size(1280, 960)));

一句话:

Image.FromStream(new MemoryStream(byteArrayIn));

I suggest using ImageSharp

Image<Bgra32> image = SixLabors.ImageSharp.Image.LoadPixelData<Bgra32>
(byteArray
, pageWidth
, pageHeight);