- - PR -
DIBからSystem.Drawing.Bitmapを作成
投稿者 | 投稿内容 |
---|---|
|
投稿日時: 2005-03-07 21:31
環境[Windows XP]
言語[VC++.NET] 分類[.NET] 初めて書き込みます。 以前より、この掲示板を参考にさせていただいています。 現在、アンマネージなサードパーティのDLL(VC6で作成)をラップする VC++.NETのDLLを作成しています。 このアンマネージなDLLのメソッドのひとつに、そのDLLが作成した ビットマップ(DIB形式)のハンドラ(hDIB)を返却する関数があり、 このハンドラから、 「System.Drawing.Bitmap」オブジェクトを 作成したいと考えています。 以下のように書いてみましたが、 返却されるBitmapオブジェクトは、まったく異なるもの(ほとんどが黒いまま)になってしまいます。 -----ソースここから /* DLLから返却されたhDIBを引数にとり、DIBをBITMAPに変換する */ Bitmap* WrapDll::Hoge::CopyStructToBmp(HANDLE pDIB) { // 変数の宣言 LPVOID pMem; // CARD_IMAGE BMI; // BITMAPINFOのbmiColorの要素数を変えた構造体 CARD_IMAGE* pBMI; // BITMAPINFOのポインタ int width; // 幅 int height; // 高さ Bitmap* bmp; // ビットマップ(マネージ) BitmapData* bmpdata; // ビットマップのデータ部分(マネージ) IntPtr pbd; // ビットマップのデータ部分の先頭(マネージ) System::Drawing::Rectangle rect; // 矩形の構造体(マネージ) int i; // カウンタ try { // 格納用の構造体のポインタを取得 pBMI = &BMI; // HANDLEからメモリポインタを取得 pMem = (BITMAPINFO*)GlobalLock(pDIB); // メモリを判定 if ( pMem != NULL ) { // ハンドラから読み込む MoveMemory(pBMI, pMem, sizeof(BMI)); // 幅と高さを取得 width = (int)pBMI->bmiHeader.biWidth; height = (int)pBMI->bmiHeader.biHeight; // マネージなビットマップオブジェクトを作成 bmp = new Bitmap(width, height, PixelFormat::Format4bppIndexed); // 画像の四隅を表す構造体に値をセット(構造体のメソッドによりセット) rect.set_X(0); rect.set_Y(0); rect.set_Width(width); rect.set_Height(height); // 読み書きできるモードで全域をロックし、BitmapDataオブジェクトを作成 bmpdata = bmp->LockBits( rect, ImageLockMode::ReadWrite, PixelFormat::Format4bppIndexed ); // ビットマップデータの先頭アドレスを取得 pbd = bmpdata->Scan0; // BITOMAPINFO構造体のデータ部分を読み込んでBitmapオブジェクトに書き込む for ( i = 0; i < sizeof(pBMI->bmiColors); i++ ) { Marshal::WriteByte(pbd, i, pBDT + i); } // アンロック bmp->UnlockBits(bmpdata); } // アンロック GlobalUnlock(pDIB); // 戻り値の返却 return bmp; } catch (Exception* e) { // 丸投げ throw e; } }; -----ソースここまで bmiHeaderの各要素が取得できているので、渡されたハンドラから、 データは渡ってきていると思うのですが... アドバイスよろしくお願いします。 ※ちなみにこのアンマネージなDLLは、VB6.0から呼んだ場合、StretchDIBitsで DIB画像を表示する仕様になっています。 [ メッセージ編集済み 編集者: Mecky 編集日時 2005-03-07 21:33 ] [ メッセージ編集済み 編集者: Mecky 編集日時 2005-03-07 21:34 ] |
|
投稿日時: 2005-03-08 08:58
試していませんが、.NET 247によると、
・System.Drawing.Bitmap を作る ・LockBits ・CopyMemory と書いてありますね。 あと、 new Bitmap(int, int, int, PixelFormat, IntPtr) でもいけると書いてあります。 |
|
投稿日時: 2005-03-08 09:34
にしざき様、ありがとうございます。
いただいた情報の方を見てみます。 >new Bitmap(int, int, int, PixelFormat, IntPtr) は、3番目の引数の「stride」の求め方がはっきりせず、 一度断念してます... |
|
投稿日時: 2005-03-08 09:54
> 3番目の引数の「stride」の求め方がはっきりせず
確か、昔の記憶では ((biWidth * biPlanes * biBitCount + 31) / 32) * 4 とかじゃなかったっけ? 細かいところは覚えていませんが。 4バイト境界に合わせるっぽいので修正。 [ メッセージ編集済み 編集者: にしざき 編集日時 2005-03-08 09:59 ] |
|
投稿日時: 2005-03-08 10:02
もしくは
biSizeImage / abs(biHeight) でもいいのかもしれない。 |
|
投稿日時: 2005-03-08 10:41
にしざき様、何度もご返答ありがとうございます。
私の方も「Stride」の計算方法をしらべてみましたが、MSDNによると、 >DIB のサイズは、stride * height として計算される。 >stride は、幅 * ピクセルごとのビット/8 を最も近い >DWORD アラインメントに切り上げた値、height は、biHeight の絶対値である。 なんだそうです。 #あまりBitmapの仕様が理解できていないのかも... ちょっとこれから、別の作業に入ることになったので、 今までいただいた情報を元に夕方にでも、もう一度トライしてみます。 |
|
投稿日時: 2005-03-08 11:02
>DIB のサイズは、stride * height として計算される。
これから逆算したのが biSizeImage / abs(biHeight) で、 >stride は、幅 * ピクセルごとのビット/8 を最も近い >DWORD アラインメントに切り上げた値、height は、biHeight の絶対値である。 これから計算したのが ((biWidth * biPlanes * biBitCount + 31) / 32) * 4 (いまさら biPlanes != 1 のデータってあるの?) です。 どちらも同じ値になるはずなんですけど、ならなければ式が間違っています。 あ、プレーンって行ごとじゃなかったっけ?だったら式の biPlanes がいらないんだけど… [ メッセージ編集済み 編集者: にしざき 編集日時 2005-03-08 11:04 ] |
|
投稿日時: 2005-03-08 16:47
どうも、お世話になります。
Strideの計算方法をご教授いただいたおかげで、コンストラクタ new Bitmap(int, int, int, PixelFormat, IntPtr) を利用することで画像の取得はできたようです。 #内容を検証するため、画像をファイルに保存しようとしてますが、 ちょっとハマり気味... で、DIBのハンドラから取得したBITMAPINFOHEADERの内容を確認してみたところ、 biSizeImage / abs(biHeight) の方で、それっぽい値が取得できたので、とりあえずその値を使用してます。 ファイル内容の検証ができたら、また報告します。 |