バイト配列を画像に変換したい。
これは、バイト配列を取得するデータベースコードです。
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.
この例外の原因を修正するにはどうすればよいですか?
メモリストリームに2回書き込みます。また、使用後にストリームを破棄していません。また、画像デコーダに埋め込み色補正を適用するよう求めています。
代わりにこれを試してください:
using (var ms = new MemoryStream(byteArrayIn))
{
return Image.FromStream(ms);
}
たぶん何かが足りないかもしれませんが、私にとっては、このワンライナーはJPEGファイルの画像を含むバイト配列でうまく機能します。
Image x = (Bitmap)((new ImageConverter()).ConvertFrom(jpegByteArray));
編集:
この回答の更新版については、こちらをご覧ください。 バイト配列の画像を変換する方法
public Image byteArrayToImage(byte[] bytesArr)
{
using (MemoryStream memstr = new MemoryStream(bytesArr))
{
Image img = Image.FromStream(memstr);
return img;
}
}
@ 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
値でコピーする場合、有効な画像が生成されます:
また、ストライドは負になる場合があります。
ストライドが正の場合、ビットマップはトップダウンです。ストライドが負の場合、ビットマップはボトムアップです。
しかし、私はそのような画像で作業していませんでしたし、これは私のノートを超えています。
以下のような簡単なアプローチがあります。画像の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;
}
提示されたすべての回答は、バイト配列に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;
}
}
これは このサイト に投稿されたソリューションのわずかなバリエーションです。
試してください(UPDATE)
MemoryStream ms = new MemoryStream(byteArrayIn,0,byteArrayIn.Length);
ms.Position = 0; // this is important
returnImage = Image.FromStream(ms,true);
これは、ホルステブロの答えと、ここでのコメントに触発されています: バイト配列から画像オブジェクトを取得する
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'))