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


100

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

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

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

回答:


109

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

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

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

あなたはまた、明示的に初期化した後、メモリストリーム書き込み不可をすることができる新しいのMemoryStream(byteArrayIn、偽)
Holstebroe

28
これは、MSDNのImage.FromStream()の仕様に違反しています。「Imageの存続期間中、ストリームを開いたままにしておく必要がある」とあります。stackoverflow.com/questions/3290060/…
RenniePet 2013年

81

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

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

編集:

この回答の更新バージョンについては、こちらを参照してください:画像をバイト配列に変換する方法


AAAhありがとう、最後に良い答え。なぜメモリストリームでこれほど多くの回答が得られるのか、それが私に多くの問題を引き起こしています。どうもありがとう !
Julian50 2015年

いい答えだ!これは別の関数で使用できますが、MemoryStreamを使用する他のすべての提案は使用できません(ストリームはイメージの存続期間中開いたままにする必要があります)
A_L

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

通常は良い考えではありませんが、GC.Collect()をメモリストリームの前に配置します。大量の大きなグラフィックファイルをバイト配列としてメモリにプリロードし、表示中に画像に変換すると、メモリが不足していました。
Kayot 2017年

9

@ 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すると、次の画像が得られます。画像の一部がパディングバイトに書き込まれたため、画像シフトは無視されました。また、それが最後の行が不完全な理由です。

無視されたストライド

しかし、bmpData.Stride値ごとに行ごとにシフトする宛先ポインターをコピーすると、有効なイメージが生成されます。

考慮されるストライド

ストライドも負になることがあります。

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

しかし、私はそのような画像を扱っていませんでした、そしてこれは私の注意を超えています。

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


6

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

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


参照MSDN:Bitmap(Int32、Int32): "このコンストラクタは、PixelFormat列挙値がFormat32bppArgbのビットマップを作成します。"つまり、byte [0]は青、byte [1]は緑、byte [2]は赤です、byte [3]はアルファ、byte [4]は青などです。
BRK

1
必要な「使用」をすべて追加していただきありがとうございます。ほとんどの人はそれを忘れて、それらすべてを見つけるのは苦痛です。
Casey Crookston、2018年

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、2012

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ストリーム=新しいMemoryStream(); image.Save(stream、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

このパッケージを最初にインストールします。

インストールパッケージSixLabors.ImageSharp-バージョン1.0.0-beta0007

[SixLabors.ImageSharp] [1] [1]:https ://www.nuget.org/packages/SixLabors.ImageSharp

次に、バイト配列をイメージにキャストするために以下のコードを使用します。

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

Get ImageFormatをコードの下で使用する場合:

IImageFormat format = Image.DetectFormat(byteArray);

下記のコードでMutate画像を使用する場合:

image.Mutate(x => x.Resize(new Size(1280, 960)));
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.