바이트 배열에서 이미지로 변환


101

바이트 배열을 이미지로 변환하고 싶습니다.

이것은 바이트 배열을 얻는 데이터베이스 코드입니다.

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.

이 예외의 원인을 어떻게 해결할 수 있습니까?


쿼리의 이미지 바이트가 유효한지 확인 했습니까? File.WriteAllBytes ( "myimage.jpg", byteArrayIn)를 수행하여 확인할 수 있습니다.
Holstebroe

답변:


110

메모리 스트림에 두 번 쓰고 있으며 사용 후 스트림을 폐기하지 않습니다. 또한 이미지 디코더에 내장 된 색상 보정을 적용하도록 요청합니다.

대신 이것을 시도하십시오.

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

초기화 후에 명시 적으로 메모리 스트림을 쓸 수 없도록 만들 수도 있습니다. new MemoryStream (byteArrayIn, false)
Holstebroe

28
이는 MSDN의 Image.FromStream () 사양에 위배됩니다. 여기에서 "이미지 수명 동안 스트림을 열어 두어야합니다." 참조 stackoverflow.com/questions/3290060/…
RenniePet 2013 년

81

아마도 내가 뭔가를 놓치고 있지만이 한 줄짜리 줄은 JPEG 파일의 이미지를 포함하는 바이트 배열에서 잘 작동합니다.

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

편집하다:

이 답변의 업데이트 된 버전은 여기를 참조하십시오 : 바이트 배열에서 이미지를 변환하는 방법


AAAh 감사합니다. 마지막으로 좋은 답변입니다. 메모리 스트림에 대한 답변이 많은 이유는 나에게 많은 문제를 일으킨다. 고마워요!
Julian50

좋은 대답입니다! 이것은 별도의 기능에서 사용할 수 있지만 MemoryStream을 사용하는 다른 모든 제안은 사용할 수 없습니다 (Stream은 Image의 수명 동안 열려 있어야 함)
A_L

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

일반적으로 좋은 생각은 아니지만 메모리 스트림 앞에 GC.Collect ()를 넣습니다. 대용량 그래픽 파일을 메모리에 바이트 배열로 미리로드 한 다음 보는 동안 이미지로 변환 할 때 메모리가 부족했습니다.
Kayot 2011

9

@ isaias-b에서 제공하는 솔루션에 버그가 있음을 알고 싶습니다.

이 솔루션 stride은 행 길이와 같다고 가정합니다 . 그러나 항상 사실은 아닙니다. GDI에 의해 수행되는 메모리 정렬로 인해 스트라이드는 행 길이보다 클 수 있습니다. 이 점을 고려해야합니다. 그렇지 않으면 잘못된 이동 이미지가 생성됩니다. 각 행의 패딩 바이트는 무시됩니다.

스트라이드는 단일 행 픽셀 (스캔 라인)의 너비이며 4 바이트 경계로 반올림됩니다.

고정 코드 :

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 #-C ++와 다른 비트 맵의 ​​RGB 버퍼


6

제시된 모든 답변은 바이트 배열에 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;
    }
}

이것은 이 사이트 에 게시 된 솔루션의 약간 변형입니다 .


참조로 MSDN : Bitmap (Int32, Int32) : "이 생성자는 PixelFormat 열거 값이 Format32bppArgb 인 비트 맵을 만듭니다.", 즉 byte [0]은 파란색, byte [1]은 녹색, byte [2]는 빨간색입니다. , byte [3]은 알파, byte [4]는 파란색 등입니다.
brk

1
필요한 "사용"을 모두 추가해 주셔서 감사합니다. 대부분의 사람들은 그것을 잊어 버리고 그것들을 모두 찾는 것은 고통 스럽습니다.
Casey Crookston

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

5

시도 (업데이트)

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

2
동일한 바이트 배열로 초기화 된 후 바이트 배열을 메모리 스트림에 쓰는 것은 거의 의미가 없습니다. 실제로 MemoryStream이 생성자에 지정된 길이 이상으로 쓸 수 있는지 확실하지 않습니다.
Holstebroe

2

어떤 종류의 변수로도 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;
}

1
코드는 아이디어로 유용하지만 물론 작성된대로 작동하지 않습니다. returnImage는 try / catch 섹션 외부에서 선언해야합니다. 또한 returnImage는 'catch'에서 인스턴스화되어야합니다. 단일 픽셀 비트 맵을 만듭니다. var image = new Bitmap (1, 1); MemoryStream 스트림 = new MemoryStream (); image.Save (스트림, ImageFormat.Jpeg); stream.Position = 0;
Reid



0

이런 일이 발생하는 대부분의 경우 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'))

0

먼저이 패키지 설치 :

Install-Package SixLabors.ImageSharp-버전 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)));
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.