モノクロビットマップの作り方

解決


とし  2005-08-09 14:28:46  No: 91361

モノクロビットマップを作り、そこに文字や絵を書き、ビットマップデータを取得しようとしています。
しかし、テスト段階でうまくいきません。
確認の段階でフォームに文字表示されません。
vb.net2003です。
win32クラスはAPIの呼び出しを定義したクラスです。

Dim PaperWidth As Integer = Me.ClientSize.Width
Dim PaperHeight As Integer = Me.ClientSize.Height

'モノクロDIBを作る
Dim bmi As win32.BITMAPINFO
With bmi.bmiHeader
  .biSize = Marshal.SizeOf(bmi.bmiHeader)
  .biWidth = PaperWidth
  .biHeight = PaperHeight
  .biPlanes = 1
  .biBitCount = 8
  .biCompression = win32.BI_RGB
End With
Dim adr As IntPtr
Dim hDC As IntPtr = win32.CreateCompatibleDC(IntPtr.Zero)
Dim hDIB As IntPtr = win32.CreateDIBSection(hDC, bmi, win32.DIB_RGB_COLORS, adr, IntPtr.Zero, 0)
Dim holdbmp As IntPtr = win32.SelectObject(hDC, hDIB)

'文字を書く
Dim msg As String = "test"
win32.TextOut(hDC, 0, 0, msg, Len(msg))

'確認
win32.BitBlt(Me.Handle, 0, 0, Me.ClientSize.Width, Me.ClientSize.Height, hDC, 0, 0, win32.SRCCOPY)

win32.SelectObject(hDC, holdbmp)
win32.DeleteDC(hDC)
win32.DeleteObject(hDC)


とし  2005-08-09 14:35:23  No: 91362

自己修正です。
 .biBitCount = 1
です。
パラメータを色々変えてみた時の直し忘れです、すみません。


K.J.K.  2005-08-09 17:56:01  No: 91363

CreateDIBSectionを使うのならば、ColorTableも設定してください。


とし  2005-08-09 23:17:52  No: 91364

bmiColorsを下のように設定してみましたが
やはり何も表示しません。

With .bmiColors
  .rgbRed = 255
  .rgbGreen = 255
  .rgbBlue = 255
End With


K.J.K.  2005-08-10 04:59:44  No: 91365

そりゃBITMAPINFO.bmiColorsをいくら弄ったって無駄でしょう。
API関数のSetDIBColorTableについて調べてください。


とし  2005-08-10 16:13:05  No: 91366

SetDIBColorTableをキーワードに検索したら、色々わかった事と、わからない事ができました。

まず確認表示のBitBlt自体が間違っていました。
うまくいかない人は「画面が黒くなる」と書いてありましたが、私の場合は何も変わらなかった。
で、BitBltの戻り値を調べたら、0になっていて、"System.ComponentModel.Win32Exception: ハンドルが無効です。"
のエラーが帰ってきてました。
で、下のように変更しました。

'確認
Dim hDst As IntPtr = win32.GetDC(PictureBox1.Handle)
res = win32.BitBlt(hDst, 0, 0, PictureBox1.Width, PictureBox1.Height, hDC, 0, 0, win32.SRCCOPY)
win32.ReleaseDC(dstObj.Handle, hDst)

これで「間違った結果」を「表示」することはできるようになりました。
ちなみにform自体に表示するのはやめて、form上のPictureBox1に表示することにしました。
文字は表示するのですが、まだ色がおかしい。

で、調べている時にわかったのですが、BITMAPINFO構造体のRGBQUADを、

  'RGBQUAD構造体
  <StructLayout(LayoutKind.Sequential)> _
   Public Structure RGBQUAD
    Dim rgbBlue As Byte     '青の濃さ
    Dim rgbGreen As Byte   '緑の濃さ
    Dim rgbRed As Byte     '赤の濃さ
    Dim rgbReserved As Byte     '未使用(常に0)
  End Structure

  'BITMAPINFO構造体
  <StructLayout(LayoutKind.Sequential)> _
   Public Structure BITMAPINFO
    Dim bmiHeader As BITMAPINFOHEADER
    Dim bmiColors As RGBQUAD
  End Structure

と定義していたのですが、Dim bmiColors() As RGBQUAD でなくてはならない事がわかりました。
で、今のところここまでですが、大きな進歩です。
ありがとうございます、K.J.K. さん。


とし  2005-08-10 18:37:14  No: 91367

解決したけど、わからない事ができました。

SetDIBColorTableで正しい色にできました。
でも、それ以前にCreateDIBSectionで正しいパラメータを与えてやれば、正しい色のDIBを作ってくれるのも(たぶん)わかりました。
ただし、

'BITMAPINFO構造体
<StructLayout(LayoutKind.Sequential)> _
Public Structure BITMAPINFO
  Dim bmiHeader As BITMAPINFOHEADER
  Dim bmiColors() As RGBQUAD
End Structure

で、プログラムでredimしてやるのではだめでした。
これではbmiColors()へのポインタが入ってしまうようです(たぶん、サイズが変わらないから)

'BITMAPINFO構造体
<StructLayout(LayoutKind.Sequential)> _
Public Structure BITMAPINFO
  Dim bmiHeader As BITMAPINFOHEADER
  Dim bmiColors0 As RGBQUAD
  Dim bmiColors1 As RGBQUAD
End Structure

で、2つの色を別々に設定してやることで可能になりました。
しかし、これでは2色専用になってしまいます。
可変長の構造体の宣言はできない(調べた限り)ので、これを回避する方法は無いのでしょうか?


K.J.K.  2005-08-10 21:29:29  No: 91368

<MarshalAs(UnmanagedType.ByValArray, SizeConst:=256)>


とし  2005-08-10 23:30:52  No: 91369

><MarshalAs(UnmanagedType.ByValArray, SizeConst:=256)>
おお、できそう。
でも、アンマネージとかマーシャリングとか、わからない言葉が飛びかってます。
とりあえず、当初の問題は解決したので、「解決」押しておきます。
ありがとうございました、K.J.K. さん。


とし  2005-08-11 13:32:16  No: 91370

<MarshalAs(UnmanagedType.ByValArray, SizeConst:=256)> dim bmiColors() As RGBQUAD
としたら、
"型 BITMAPINFO はアンマネージ構造体として集成できません。有効なサイズ、またはオフセットの計算ができません。"
といわれました。
<MarshalAs(UnmanagedType.ByValArray, SizeConst:=256)> dim bmiColors() As Integer
なら通るんですが。


とし  2005-08-11 13:39:32  No: 91371

すみません、integerでも、CreateDIBSectionの所で、
"埋め込まれた配列インスタンスがレイアウトで宣言された長さと一致しないため、型を集成できませんでした。"
といわれて、やっぱりダメでした。


K.J.K.  2005-08-11 18:04:39  No: 91372

http://msdn.microsoft.com/library/en-us/cpguide/html/cpconstructssample.asp


とし  2005-08-12 02:39:20  No: 91373

やっぱりだめです。
構造体を持つ構造体、整数配列を持つ構造体なら大丈夫みたいなんですが、構造体の配列を持つ構造体はエラーが起きます。
ちなみに、
http://msdn.microsoft.com/library/en-us/cpguide/html/cpconstructssample.asp
は無理なので、
http://www.microsoft.com/japan/msdn/library/default.asp?url=/japan/msdn/library/ja/netstart/html/sdkstart.asp
を見ました。
と言っても、内容が理解しきれないのですが。

<StructLayout(LayoutKind.Sequential)> _
Public Structure myStruct
  Public val As Integer
End Structure

<StructLayout(LayoutKind.Sequential)> _
Public Structure myStruct2
  Public data As myStruct
End Structure

<StructLayout(LayoutKind.Sequential)> _
Public Structure myStruct3
  <MarshalAs(UnmanagedType.ByValArray, SizeConst:=2)> _
  Public data As Integer()
End Structure

<StructLayout(LayoutKind.Sequential)> _
Public Structure myStruct4
  <MarshalAs(UnmanagedType.ByValArray, SizeConst:=2)> _
  Public data As myStruct()
End Structure

Sub test()
  Dim st1 As myStruct
  MessageBox.Show(Marshal.SizeOf(st1))

  Dim st2 As myStruct2
  MessageBox.Show(Marshal.SizeOf(st2))

  Dim st3 As myStruct3
  Dim dt3(1) As Integer
  st3.data = dt3
  MessageBox.Show(Marshal.SizeOf(st3))

  Dim st4 As myStruct4
  Dim dt4(1) As myStruct
  st4.data = dt4
  MessageBox.Show(Marshal.SizeOf(st4.data(0)))
  MessageBox.Show(Marshal.SizeOf(st4))    '<-ここだけダメ
End Sub


とし  2005-08-12 02:47:11  No: 91374

URL間違った。
http://www.microsoft.com/japan/msdn/library/ja/cpguide/html/cpconStructsSample.asp
です。


K.J.K.  2005-08-12 03:59:44  No: 91375

ですからmyStruct3の段階で止めて、RGBQUADを使わず、
Integerなどとして受けてしまえばいいのでは。


とし  2005-08-12 11:50:51  No: 91376

うーん、それが正解だったのか。
ありがとうございました。
2回目の「解決」チェックしてみよう、どうなるだろう。


※返信する前に利用規約をご確認ください。

※Google reCAPTCHA認証からCloudflare Turnstile認証へ変更しました。






  このエントリーをはてなブックマークに追加