Преобразование байтового массива в изображение

Я хочу преобразовать байтовый массив в изображение.

Это код моей базы данных, откуда я получаю массив байтов:

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.

Как я могу исправить то, что вызывает это исключение?


person Tanzeel ur Rahman    schedule 07.02.2012    source источник
comment
Вы проверили правильность байтов изображения в вашем запросе? Вы можете сделать File.WriteAllBytes (myimage.jpg, byteArrayIn) для проверки.   -  person Holstebroe    schedule 07.02.2012


Ответы (13)


Вы дважды записываете в свой поток памяти, а также не удаляете поток после использования. Вы также просите декодер изображения применить встроенную цветокоррекцию.

Попробуйте вместо этого:

using (var ms = new MemoryStream(byteArrayIn))
{
    return Image.FromStream(ms);
}
person Holstebroe    schedule 07.02.2012
comment
Вы также можете явно сделать поток памяти недоступным для записи после инициализации: new MemoryStream (byteArrayIn, false) - person Holstebroe; 07.02.2012
comment
Это нарушает спецификацию MSDN для Image.FromStream (), где говорится, что вы должны держать поток открытым в течение всего времени существования изображения. См. Также http://stackoverflow.com/questions/3290060/getting-an-image-object-from-a-byte-array - person RenniePet; 09.01.2013

Возможно, мне что-то не хватает, но для меня этот однострочный файл отлично работает с байтовым массивом, который содержит изображение файла JPEG.

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

РЕДАКТИРОВАТЬ:

См. Обновленную версию этого ответа: Как преобразовать изображение в байтовом массиве

person RenniePet    schedule 03.02.2013
comment
ААА, спасибо, наконец-то хороший ответ. Почему так много ответов с потоком памяти, это вызывает у меня столько проблем. большое спасибо ! - person Julian50; 30.06.2015
comment
Хороший ответ! это можно использовать в отдельной функции, тогда как все другие предложения, использующие MemoryStream, не могут (поток должен оставаться открытым в течение всего времени существования изображения) - person A_L; 18.08.2016

Хочу отметить, что в решении @ 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 из растрового изображения отличается из C ++

person lorond    schedule 22.07.2016

попробуйте (ОБНОВЛЕНИЕ)

MemoryStream ms = new MemoryStream(byteArrayIn,0,byteArrayIn.Length);
ms.Position = 0; // this is important
returnImage = Image.FromStream(ms,true);
person Yahia    schedule 07.02.2012
comment
Нет смысла записывать массив байтов в поток памяти после того, как он был инициализирован тем же массивом байтов. На самом деле я не уверен, что MemoryStream позволяет писать сверх длины, указанной в конструкторе. - person Holstebroe; 07.02.2012

Все представленные ответы предполагают, что байтовый массив содержит данные в представлении известного формата файла, например: 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;
    }
}

Это небольшой вариант решения, опубликованного на этот сайт.

person isaias-b    schedule 19.06.2014
comment
в качестве ссылки MSDN: Bitmap (Int32, Int32): этот конструктор создает Bitmap со значением перечисления PixelFormat Format32bppArgb., что означает, что байт [0] синий, байт [1] зеленый, байт [2] красный, байт [3] - это альфа, байт [4] - синий, и так далее. - person kbridge4096; 13.01.2018
comment
СПАСИБО за то, что добавили все необходимое. Большинство людей забывают об этом, и будет больно найти их всех. - person Casey Crookston; 02.05.2018

есть простой подход, как показано ниже, вы можете использовать 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;
}
person Ali    schedule 26.01.2018

В одной строке:

Image.FromStream(new MemoryStream(byteArrayIn));
person TiyebM    schedule 20.09.2020
comment
Работает нормально :-). - person Thulasiram; 22.05.2021

Вы не объявили 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;
}
person LeeCambl    schedule 17.02.2014
comment
Код полезен как идея, но, конечно, не будет работать так, как написано. returnImage должен быть объявлен вне секции try / catch. Также необходимо создать экземпляр returnImage в 'catch' - я создаю растровое изображение в один пиксель: var image = new Bitmap (1, 1); MemoryStream stream = новый MemoryStream (); image.Save (поток, ImageFormat.Jpeg); stream.Position = 0; - person Reid; 11.06.2017

Это вдохновлено ответом Холстебро и комментариями здесь: Получение объекта изображения из байтовый массив

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

Один лайнер:

Image bmp = (Bitmap)((new ImageConverter()).ConvertFrom(imageBytes));
person Vinnie Amir    schedule 06.11.2019

В большинстве случаев это происходит из-за неверных данных в столбце 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'))
person GPGVM    schedule 06.02.2013

Сначала установите этот пакет:

Установочный пакет 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);

Для Mutate Image используйте код ниже:

image.Mutate(x => x.Resize(new Size(1280, 960)));
person Amin Golmahalle    schedule 13.11.2019

person    schedule
comment
Хотя обычно это не очень хорошая идея, я помещаю GC.Collect () перед потоком памяти. Мне не хватало памяти, когда я предварительно загрузил в память множество больших графических файлов в виде байтовых массивов, а затем превратил их в изображения во время просмотра. - person Kayot; 06.11.2017