web-dev-qa-db-ja.com

バイト配列から画像への変換

バイト配列を画像に変換したい。

これは、バイト配列を取得するデータベースコードです。

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.

この例外の原因を修正するにはどうすればよいですか?

81

メモリストリームに2回書き込みます。また、使用後にストリームを破棄していません。また、画像デコーダに埋め込み色補正を適用するよう求めています。

代わりにこれを試してください:

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

たぶん何かが足りないかもしれませんが、私にとっては、このワンライナーはJPEGファイルの画像を含むバイト配列でうまく機能します。

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

編集:

この回答の更新版については、こちらをご覧ください。 バイト配列の画像を変換する方法

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

@ isaias-bが提供するソリューションにはバグがあることに注意してください。

このソリューションでは、 stride が行の長さに等しいと仮定しています。しかし、それは常に真実ではありません。 GDIによって実行されるメモリアライメントにより、ストライドは行の長さより大きくなる可能性があります。これを考慮する必要があります。そうでない場合、無効なシフト画像が生成されます。各行のパディングバイトは無視されます。

ストライドは、1バイトのピクセル(スキャンライン)の幅で、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が指すアドレスに配列全体をそのままコピーすると、次の画像が得られます。画像の一部がパディングバイトに書き込まれたために画像がシフトしましたが、これは無視されました。また、それが最後の行が不完全な理由です:

stride ignored

しかし、行ごとにシフトする宛先ポインターをbmpData.Stride値でコピーする場合、有効な画像が生成されます:

stride taken into account

また、ストライドは負になる場合があります。

ストライドが正の場合、ビットマップはトップダウンです。ストライドが負の場合、ビットマップはボトムアップです。

しかし、私はそのような画像で作業していませんでしたし、これは私のノートを超えています。

関連回答: C#-C++とは異なるビットマップのRGBバッファー

7
lorond

以下のような簡単なアプローチがあります。画像の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;
}
6
Ali

提示されたすべての回答は、バイト配列にgif、png、jpgなどの既知のファイル形式表現のデータが含まれていることを前提としています。しかし、最近、線形化されたBGRA情報を含むbyte[]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;
    }
}

これは このサイト に投稿されたソリューションのわずかなバリエーションです。

5
isaias-b

試してください(UPDATE)

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

これは、ホルステブロの答えと、ここでのコメントに触発されています: バイト配列から画像オブジェクトを取得する

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

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

ほとんどの場合、これは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
GPGVM