by WebSurfer
2021年6月4日 14:51
Microsoft のサンプル SQL Server データベース Northwind の Employees テーブルの Photo フィールドの画像データを取得して表示する方法を書きます。
アプリから Photo フィールドのバイト列データを取得するのは ADO.NET + SqlClient を使って可能です。問題はそのバイト列を加工して jpg とか png 形式にすることで、それをどうしたらよいかという話です。
Photo フィールドの画像データは Bitmap 形式のバイト列なのですが、ネットの記事 Displaying images in SAPUI5 received from the Northwind OData service によると "The 78 superfluous bytes are a proprietary OLE header that Access creates when saving bitmaps." という余計なものが付いています。(Microsoft のドキュメントもそのような情報があったのですが行方不明)
実際、Photo フィールドのバイト列を取得してそれをそのまま stream に変換し、new Bitmap(stream) で Bitmap オブジェクトを取得しようとすると ArgumentException がスローされます。下のサンプルコードでコメントアウトした部分を見てください。
ということで、Photo フィールドのバイト列を stream に変換するとき最初の 78 バイトをスキップしてやる必要があります。それは MemoryStream(Byte[], Int32, Int32) コンストラクタを使って可能です。
以下にそのサンプルコードを載せておきます。上の画像の Photo を表示するのに使った HTTP ジェネリックハンドラで、Employees テーブルの Photo データを取得して、最初の 78 バイトをスキップして MemoryStream を作り、new Bitmap(stream) で Bitmap オブジェクトを取得し、Bitmap.Save メソッドで jpg 形式にして HTTP 応答ストリームに書き込んでいます。
using System.Web;
using System.Web.Configuration;
using System.Data.SqlClient;
using System.IO;
using System.Drawing;
using System.Drawing.Imaging;
namespace WebApplication1
{
public class EmployeePhotoHandler : IHttpHandler
{
public void ProcessRequest(HttpContext context)
{
string id = context.Request.QueryString["id"];
context.Response.ContentType = "image/jpeg";
byte[] phote;
int employeeId;
if (!string.IsNullOrEmpty(id) && int.TryParse(id, out employeeId))
{
var connString = WebConfigurationManager
.ConnectionStrings["NORTHWINDConnectionString"]
.ConnectionString;
var query = "SELECT photo FROM Employees WHERE EmployeeID = @ID";
using (var connection = new SqlConnection(connString))
{
using (var command = new SqlCommand(query, connection))
{
command.Parameters.AddWithValue("@ID", employeeId);
connection.Open();
phote = (byte[])command.ExecuteScalar();
}
}
// これはダメ
// new Bitmap(stream) で ArgumentException がスローされる
// "使用されたパラメーターが有効ではありません。"
//using (var stream = new MemoryStream(phote))
//{
// using (var bitmap = new Bitmap(stream))
// {
// bitmap.Save(context.Response.OutputStream, ImageFormat.Jpeg);
// }
//}
// これは OK
// The 78 superfluous bytes are a proprietary OLE header that Access
// creates when saving bitmaps. ・・・ということで最初の 78 バイトは
// スキップしないと有効な Bitmap 形式とはみなされないらしい
using (var stream = new MemoryStream(phote, 78, phote.Length - 78))
{
using (var bitmap = new Bitmap(stream))
{
bitmap.Save(context.Response.OutputStream, ImageFormat.Jpeg);
}
}
}
}
public bool IsReusable
{
get
{
return false;
}
}
}
}