tagCANDY CGI VBレスキュー(花ちゃん) の Visual Basic 2010 用 掲示板(VB.NET 掲示板) [ツリー表示へ]   [Home]
一括表示(VB.NET VB2005)
タイトルうまくExtFloodFillが使用できません
記事No8474
投稿日: 2008/12/18(Thu) 10:44
投稿者のうち
こんにちは、はじめまして。

ExtFloodFill関数を用いて多角形の背景部分の色をとりあえず変えたいと思っています。
その際にpictureboxからcreategraphicsで作られたgraphics型のハンドラを用いて実行すればちゃんとなるのですが、bitmap型からfromimageで作ったgraphics型のハンドラでは、うまくいきません。(その後picturebox.imageに代入したら、背景が変わっていませんでした)
後の作業で1pixelずつ背景を読み取って線を引こうと思っているのでどうしても背景のみを色を変えたbitmapの画像が欲しいのです。
やはり一度pictureboxの内容をファイルに落としたりして読み込むほうが早いのでしょうか・・・。
どなたかわかる方がいらっしゃいましたらご教授下さい。

コード例:
Dim img As New Bitmap(PictureBox1.Width, PictureBox1.Height)
Dim g As Graphics = Graphics.FromImage(img)
g.DrawArc(Pens.Black, 30, 30, 260, 200, 0, 360)

Dim ret As Integer
'丸の外側を塗りつぶす
ret = ExtFloodFill(g.GetHdc, 0, 0, Color.Black.ToArgb, 0)

    'ピクチャーボックスに入れる
PictureBox1.Image = img
MsgBox(ret)

'ハンドルを解放する
g.ReleaseHdc()

[ツリー表示へ]
タイトルRe: うまくExtFloodFillが使用できません
記事No8476
投稿日: 2008/12/18(Thu) 23:53
投稿者よねKEN
> ExtFloodFill関数を用いて多角形の背景部分の色をとりあえず変えたいと思っています。
> その際にpictureboxからcreategraphicsで作られたgraphics型のハンドラを用いて実行すればちゃんとなるのですが、
> bitmap型からfromimageで作ったgraphics型のハンドラでは、うまくいきません。
>(その後picturebox.imageに代入したら、背景が変わっていませんでした)

私もいろいろ実験コードを書いてみましたが、うまくいきませんでした。
いろいろ検索してみた限りでは、ExtFloodFillを使うには、
Bitmapオブジェクトやhdcやブラシなど全般をWindowsAPIで何とかしないといけないっぽいです。

はっきりとしたところは私も解説できないのですが、
コード例で言うところの、g.DrawArcでの描画とExtFloodFillでの描画が
同一の画用紙上で作業して描かれていない感じなんですよね。

http://www.planetsourcecode.com/vb/scripts/ShowCode.asp?txtCodeId=3977&lngWId=10

↑上記のコードサンプルでは.NET Frameworkのクラスの処理とExtFloodFill関数との
橋渡しのために多くのWindowsAPIを駆使して処理しているようです。

http://www.codeproject.com/KB/GDI-plus/floodfillincsharp.aspx
↑こちらのコードはC#の例ですが、WindowsAPIを使わずに自前でExtFloodFill相当の処理を
実装しているようです。

> 後の作業で1pixelずつ背景を読み取って線を引こうと思っているのでどうしても背景のみを色を変えたbitmapの画像が欲しいのです。
> やはり一度pictureboxの内容をファイルに落としたりして読み込むほうが早いのでしょうか・・・。

たぶんExtFloodFillを使う案である限りは、WindowsAPIをたくさん駆使する方法しかないのではないでしょうか。
(CreateGraphicsで描いた描画内容をなんとかBitmapに取り込む方法があれば、
制限付き(画面が完全に見えている状態でないとNG)で、なんとかなるかもしれませんが。

> コード例:
> Dim img As New Bitmap(PictureBox1.Width, PictureBox1.Height)
> Dim g As Graphics = Graphics.FromImage(img)
> g.DrawArc(Pens.Black, 30, 30, 260, 200, 0, 360)
>
> Dim ret As Integer
> '丸の外側を塗りつぶす
> ret = ExtFloodFill(g.GetHdc, 0, 0, Color.Black.ToArgb, 0)
>
>     'ピクチャーボックスに入れる
> PictureBox1.Image = img
> MsgBox(ret)
>
> 'ハンドルを解放する
> g.ReleaseHdc()

コード例にあるような楕円だけに限って言えば、

Dim img As New Bitmap(PictureBox1.ClientSize.Width, PictureBox1.ClientSize.Height)
PictureBox1.Image = img

Dim g As Graphics = Graphics.FromImage(img)
g.SmoothingMode = Drawing2D.SmoothingMode.HighQuality
g.PixelOffsetMode = PixelOffsetMode.HighQuality

Dim rectF As New RectangleF(30.0F, 30.0F, 260.0F, 200.0F)

g.DrawArc(Pens.Black, rectF, 0, 360)

Dim path As New GraphicsPath()
Dim rectF2 As RectangleF = rectF

rectF2.Inflate(0.5F, 0.5F)

path.AddArc(rectF2, 0, 360)

Dim r As Region = New Region()
r.Exclude(path)
g.FillRegion(Brushes.Orange, r)


PictureBox1.Refresh()
r.Dispose()
g.Dispose()

というような方法で実現することもできますが、
ご質問の内容からするとこれではダメなんでしょうね。

[ツリー表示へ]
タイトルRe^2: うまくExtFloodFillが使用できません
記事No8481
投稿日: 2008/12/19(Fri) 10:17
投稿者のうち
>よねKEN様

> はっきりとしたところは私も解説できないのですが、
> コード例で言うところの、g.DrawArcでの描画とExtFloodFillでの描画が
> 同一の画用紙上で作業して描かれていない感じなんですよね。

CreateGraphicsで作られたgraphicsのみ同一の場所で書かれてるように扱われてるってことですよね・・・。

> たぶんExtFloodFillを使う案である限りは、WindowsAPIをたくさん駆使する方法しかないのではないでしょうか。
> (CreateGraphicsで描いた描画内容をなんとかBitmapに取り込む方法があれば、
> 制限付き(画面が完全に見えている状態でないとNG)で、なんとかなるかもしれませんが。

まずは、上のコードで使われているAPIを調べて試してみて、それでも難しいようなら、なんとかPrintScreenなどで取得しようと思います。

> ご質問の内容からするとこれではダメなんでしょうね。

すみません・・・・基本的にはdrawlineで行い、複雑な描画を行うためにおそらく記入していただいたものでは・・・・・。

上にも書きましたが、まずは上コードのAPIを調べるところから始めようと思います。
よねKEN様、貴重なお時間を割いてまで調べていただいてありがとうございました。
また進展があれば、報告をしたいと思います。

[ツリー表示へ]
タイトルRe^3: うまくExtFloodFillが使用できません
記事No8482
投稿日: 2008/12/19(Fri) 19:16
投稿者Hongliang
あまり GDI には詳しくないのですが。
1) CreateCompatibleDC で互換 DC を作成
2) Bitmap.GetHbitmap で取得した HBITMAP を SelectObject でこの互換 DC に設定
3) 互換 DC に対して(ブラシを選択して) ExtFloodFill
4) 互換 DC から元の DC に BitBlt
と言う手順を踏めば一応いけるみたいです。
使い終わった HBITMAP、互換 DC(あと作ったのならブラシ)の削除を忘れずに。

ところで、Color.ToArgb() で取得できるのは AARRGGBB 形式で、GDI で使用される COLORREF は BBGGRRAA 形式です。
Color から COLORREF への変換は ColorTranslator.ToWin32 メソッドを使用するのがいいでしょう。

[ツリー表示へ]
タイトルRe^4: うまくExtFloodFillが使用できません
記事No8490
投稿日: 2008/12/22(Mon) 11:54
投稿者のうち
>Hongliang様

ご返信ありがとうございます。

よねKEN様に提示していただいたサイトのソースを参考に作った後にHongliang様のご返信
を拝見いたしました。自分の投稿なのに頻繁に確認していなくて申し訳ありません・・・。

> ところで、Color.ToArgb() で取得できるのは AARRGGBB 形式で、GDI で使用される COLORREF は BBGGRRAA 形式です。
> Color から COLORREF への変換は ColorTranslator.ToWin32 メソッドを使用するのがいいでしょう。

画像を扱うプログラミングを作成していて、色の形式に気がつきませんでした・・・。
ご指摘ありがとうございます。

[ツリー表示へ]
タイトルRe: うまくExtFloodFillが使用できません
記事No8491
投稿日: 2008/12/22(Mon) 12:04
投稿者のうち
   Public Function ExtFloodFill_test(ByVal bmp As Bitmap, ByVal hp As Point) As Bitmap

        '元DCと互換DCの作成
        Dim srcDC As IntPtr = CreateCompatibleDC(IntPtr.Zero)
        Dim dstDC As IntPtr = CreateCompatibleDC(IntPtr.Zero)
        Dim dstBMI As BITMAPINFOHEADER

        With dstBMI
            .biBitCount = 24
            .biHeight = bmp.Height
            .biSize = System.Runtime.InteropServices.Marshal.SizeOf(dstBMI)
            .biWidth = bmp.Width
            .biPlanes = 1
        End With

        'ソース画像からハンドルの取得
        Dim get_hbmp As IntPtr = bmp.GetHbitmap

        '元DCに元ソースを選択する。
        Dim Obmp As IntPtr = SelectObject(srcDC, get_hbmp)

        Dim dstbits As IntPtr
        'DIB(デバイスに依存しないbitmap)を作成する
        Dim dstBMP As IntPtr = CreateDIBSection(dstDC, dstBMI, 0, dstbits, 0, 0)

        '互換DCにDIBを選択する。
        Dim Obmp2 As IntPtr = SelectObject(dstDC, dstBMP)

        '元DCから互換DCにコピー
        BitBlt(dstDC, 0, 0, bmp.Width, bmp.Height, srcDC, 0, 0, SRCCOPY)
        GdiFlush()
        '塗りつぶす色
        Dim mBrush As IntPtr = CreateSolidBrush(System.Drawing.ColorTranslator.ToWin32(Color.White))
        '互換DCに作成したブラシを選択する。
        Dim hmm As IntPtr = SelectObject(dstDC, mBrush)
        '互換DCExtFloodFillを使用する
        ExtFloodFill(dstDC, 0, 0, GetPixel(dstDC, 0, 0), 1)
        '戻り値に結果をセットする。
        ExtFloodFill_test = Bitmap.FromHbitmap(dstBMP)

        '使用したものを解放する
        DeleteObject(mBrush)
        DeleteObject(SelectObject(dstDC, mBrush))
        DeleteObject(SelectObject(dstDC, dstBMP))
        DeleteObject(SelectObject(srcDC, get_hbmp))
        DeleteObject(hmm)
        DeleteObject(dstbits)
        DeleteObject(Obmp2)
        DeleteObject(Obmp)
        DeleteObject(dstBMP)
        DeleteDC(dstDC)
        DeleteDC(srcDC)
        get_hbmp = Nothing
        hmm = Nothing
        dstbits = Nothing
        Obmp2 = Nothing
        Obmp = Nothing
        dstBMP = Nothing
        dstDC = Nothing
        srcDC = Nothing
        dstBMI = Nothing

    End Function

よねKEN様に提示していただいたサイトのソースを元に上記のようなコードになりました。
無事、私の思っていた結果を出すことができるコードを書くことが出来ました。
ご返信していただいたよねKEN様、Hongliang様本当にありがとうございました。

[ツリー表示へ]