- PR -

DIBからSystem.Drawing.Bitmapを作成

投稿者投稿内容
Mecky
会議室デビュー日: 2005/03/07
投稿数: 9
投稿日時: 2005-03-09 08:59
おはようございます。

昨晩、ご助言いただいた内容を含めていろいろと調べたのですが、
Bitmapの保存のところで完全にハマり、内容の検証はできていない状態です。

new Bitmap(int, int, int, PixelFormat, IntPtr)
を使ってBitmapを作成したものをウォッチしたところ、
BitmapオブジェクトのrawDataの属性が「未定義の値」となっていて、
どうもBitmapオブジェクトとしてはおかしい状態にあると推測しています。

ちょっと別の方法(アンマネージな方法)でDIBをファイルに保存してみて、
そのファイルをBitmapとして読み込めるかどうかの検証を先に行う方向ですすめたいと思います。

また、結果をご報告します。
Mecky
会議室デビュー日: 2005/03/07
投稿数: 9
投稿日時: 2005-03-15 13:31
[解決]
とても時間がかかってしまいましたが、なんとかBitmapオブジェクトを作成できるようになりました。
DIBはビットデータが反対になってるので、そこは考慮してませんが...

私のビットデータの考え方の理解度にも問題があったようです。

にしざき様、ヒントをいただき、ありがとうございました。

-----ソースここから
/*
DLLから返却されたhDIBを引数にとり、DIBをBITMAPに変換する
*/
Bitmap* WrapCrdScn::CertScan::CopyStructToBmp(HANDLE hDIB)
{
int len; // ハンドルから取得する長さ
int width; // 幅
int height; // 高さ
int stride; // ストライド
int size; // イメージのサイズ
LPVOID pDIB; // ローカルポインタ

BITMAPINFO* pBMI; // DIBハンドラから読み込んだBITMAPINFOHEADERのポインタ
unsigned char* pBMD; // DIBハンドラから読み込んだデータ部分のポインタ
System::Drawing::Rectangle rect; // 矩形オブジェクト

Bitmap* bmp; // 返却用のBitmapオブジェクト
BitmapData* bd; // Bitmapオブジェクト内のデータ部分
IntPtr pbd; // ↑のポインタ
int i; // カウンタ
int j;

// ファイル
String* file = __gc new String("hoge.bmp");

try {
// 引数のハンドラを判定
if ( hDIB == NULL ) {
// この処理ですでに画像が取得できない場合はエラー
throw new Exception(MSG_IMGNOTREAD);
}
// ハンドルから取得する長さ
// この部分でBITMAPINFOを取得する
len = sizeof(BITMAPINFOHEADER) + (sizeof(RGBQUAD) * MAX_RGB_COLORS);

// pDIBから読み込むためのポインタ
pBMI = (BITMAPINFO*) new BYTE[len];
// アンマネージな方法でHANDLEをロック
pDIB = (BITMAPINFO*) GlobalLock(hDIB);

// 判定
if ( pDIB != NULL ) {
// ハンドラからポインタにメモリ内の領域を移動
// 移動するのは、BITMAPINFOHEADER + RGBQUAD * 256
MoveMemory(pBMI, pDIB, len);

// 後で使用するため、幅、高さ、ストライド、画像サイズを求める
width = (int)pBMI->bmiHeader.biWidth;
height = (int)pBMI->bmiHeader.biHeight;
stride = (int)pBMI->bmiHeader.biSizeImage / abs((int)pBMI->bmiHeader.biHeight);
size = (int)pBMI->bmiHeader.biSizeImage;

// マネージなBitmapオブジェクトを作成(ここではハコのみを作成)
bmp = new Bitmap(width, height, PixelFormat::Format8bppIndexed);
// 矩形を選択(全領域)
rect.set_X(0);
rect.set_Y(0);
rect.set_Width(width);
rect.set_Height(height);
// 選択領域をロックする
bd = bmp->LockBits(rect, ImageLockMode::WriteOnly, PixelFormat::Format8bppIndexed);
// データ部分の先頭のポインタを取得
pbd = bd->Scan0;
//// DIBのデータ部分のポインタ、構造体の長さ分を進めたもの
pBMD = (unsigned char*)((int)pDIB + len);
//// 1バイトずつ書き込み、上下左右が判定しているので注意
j = 0;
for ( i = 0; i < size; i++ ) {
Marshal::WriteByte(pbd, j, *(pBMD++));
j++;
}

// アンロック
bmp->UnlockBits(bd);
// 戻り値の返却
return bmp;

} else {
// ポインタが取得できない場合
throw new Exception(MSG_CANTGETMEM);
}

}
catch (Exception* e) {
// 丸投げ
throw e;
}
__finally {
// アンロック
GlobalUnlock(hDIB);
}
};


[ メッセージ編集済み 編集者: Mecky 編集日時 2005-03-15 13:34 ]
にしざき
ぬし
会議室デビュー日: 2003/06/30
投稿数: 304
投稿日時: 2005-03-15 14:40
ちと気になったんですが、
> BitmapオブジェクトのrawDataの属性が「未定義の値」となっていて、
> どうもBitmapオブジェクトとしてはおかしい状態にあると推測しています。
を確認した場面は Bitmap オブジェクトを作成した直後ですか?

もしかして、単にGlobalLock したバッファをコピーしてから使えばできるかもしれないとか考えているので。
Mecky
会議室デビュー日: 2005/03/07
投稿数: 9
投稿日時: 2005-03-15 16:21
検証に時間がかかったにもかかわらずお付き合いいただいてありがとうございます。

>> BitmapオブジェクトのrawDataの属性が「未定義の値」となっていて、
>を確認した場面は Bitmap オブジェクトを作成した直後ですか?

そうです。

> 単にGlobalLock したバッファをコピーしてから

コンストラクタなので、てっきりデータもセットされると理解しているのですが、
もしかして私は間違ってるのでしょうか?

#このDLLのメーカにいろいろと問い合わせましたが、カラーパレットなんかの
問題もあるようで、
結局MemoryStreamにファイルとして出力する方向で再検討します...

スキルアップ/キャリアアップ(JOB@IT)