Преобразование байтов в массив изображений
Я хочу преобразовать массив байтов в изображение.
Это код моей базы данных, откуда я получаю байтовый массив:
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.
Как я могу исправить то, что вызывает это исключение?
15 ответов
Вы дважды записываете в свой поток памяти, а также не избавляетесь от потока после использования. Вы также просите декодер изображений применить встроенную коррекцию цвета.
Попробуйте это вместо этого:
using (var ms = new MemoryStream(byteArrayIn))
{
return Image.FromStream(ms);
}
Может быть, я что-то упустил, но для меня этот однострочник прекрасно работает с байтовым массивом, который содержит изображение файла JPEG.
Image x = (Bitmap)((new ImageConverter()).ConvertFrom(jpegByteArray));
РЕДАКТИРОВАТЬ:
Смотрите здесь для обновленной версии этого ответа: Как преобразовать изображение в байтовом массиве
public Image byteArrayToImage(byte[] bytesArr)
{
MemoryStream memstr = new MemoryStream(bytesArr);
Image img = Image.FromStream(memstr);
return img;
}
Я хотел бы отметить, что в решении @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;
}
}
Чтобы проиллюстрировать, к чему это может привести, давайте сгенерируем 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
, мы получим следующее изображение. Смещение изображения, потому что часть изображения была записана в байты заполнения, что было проигнорировано. И именно поэтому последний ряд неполон:
Но если мы будем копировать строковый указатель сдвига строки за bmpData.Stride
значение, действительное изображение будет сгенерировано:
Страйд также может быть отрицательным:
Если шаг положительный, растровое изображение идет сверху вниз. Если шаг отрицательный, растровое изображение идет снизу вверх.
Но я не работал с такими изображениями, и это за пределами моей заметки.
Связанный ответ: C# - RGB-буфер из Bitmap отличается от C++
Все представленные ответы предполагают, что байтовый массив содержит данные в представлении известного формата файла, например: gif, png или jpg. Но у меня недавно была проблема, пытаясь преобразовать byte[]
s, содержащие линеаризованную информацию BGRA, эффективно в 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;
}
}
Это небольшой вариант решения, которое было размещено на этом сайте.
В одной строке:
Image.FromStream(new MemoryStream(byteArrayIn));
Попробуйте (ОБНОВЛЕНИЕ)
MemoryStream ms = new MemoryStream(byteArrayIn,0,byteArrayIn.Length);
ms.Position = 0; // this is important
returnImage = Image.FromStream(ms,true);
Существует простой подход, как показано ниже, вы можете использовать метод изображения 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;
}
Один лайнер:
Image bmp = (Bitmap)((new ImageConverter()).ConvertFrom(imageBytes));
Это вдохновлено ответом Хольстебро и комментариями здесь: получение объекта Image из байтового массива
Bitmap newBitmap;
using (MemoryStream memoryStream = new MemoryStream(byteArrayIn))
using (Image newImage = Image.FromStream(memoryStream))
newBitmap = new Bitmap(newImage);
return newBitmap;
Вы не объявили returnImage как какую-либо переменную:)
Это должно помочь:
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;
}
В большинстве случаев, когда это происходит, это плохие данные в столбце 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'))
Сначала установите этот пакет:
Установочный пакет SixLabors.ImageSharp -Version 1.0.0-beta0007
[SixLabors.ImageSharp][1] [1]: https://www.nuget.org/packages/SixLabors.ImageSharp
Затем используйте код ниже для преобразования массива байтов в изображение:
Image<Rgba32> image = Image.Load(byteArray);
Для получения ImageFormat используйте приведенный ниже код:
IImageFormat format = Image.DetectFormat(byteArray);
Для изменения изображения используйте код ниже:
image.Mutate(x => x.Resize(new Size(1280, 960)));
Я предлагаю использовать ImageSharp
Image<Bgra32> image = SixLabors.ImageSharp.Image.LoadPixelData<Bgra32>
(byteArray
, pageWidth
, pageHeight);
Я нашел это ребята Конвертировать массив в изображение
private void button1_Click(object sender, EventArgs e)
{
try
{
string hasil = "D:\\coba1000.jpg";
System.IO.File.WriteAllBytes(@hasil, bytestosend);
pictureBox1.ImageLocation = @hasil;
}
catch { }
}