StretchBlt について

タグの編集
投稿者 反る戸  (社会人) 投稿日時 2010/2/7 00:32:57
はじめまして

 VB2005のProfessional Edition を使用しています。VB2005でStretchBltを
使用したいと思い、ネットで検索した所下記のページを見つけました。
http://standardization.at.webry.info/200810/article_2.html

 このページのソースを参考に以下のようなプログラムを作成してみました。
フォームにピクチャーボックス2つとボタン1つを貼っています。

 このコードでは、ピクチャーボックスからデバイスコンテキストを取得して
いますが、それですとスクリーンのデバイスコンテキストになっているようで、
PictutureBox1の上にPictureBox2が重なる部分ではPictureBox2の背景が転送さ
れ、更にはフォームをはみ出てデスクトップや別のアプリのウィンドウの一部
が画像として転送されてしまいます。

Public Class Form1
    Private Declare Function StretchBlt Lib "gdi32" Alias "StretchBlt" _
        (ByVal hdc As IntegerByVal x As IntegerByVal y As Integer, _
        ByVal nWidth As IntegerByVal nHeight As Integer, _
        ByVal hSrcDC As Integer, _
        ByVal xSrc As IntegerByVal ySrc As Integer, _
        ByVal nSrcWidth As IntegerByVal nSrcHeight As Integer, _
        ByVal dwRop As IntegerAs Integer
    Private Const SRCCOPY = &HCC0020 ' (DWORD) dest = source 

    Private x As Integer
    Private y As Integer

    Private Sub Form1_Load(ByVal sender As Object, _
                ByVal e As System.EventArgs) Handles Me.Load
        Dim gr1 As Graphics
        Dim gr2 As Graphics
        Me.PictureBox1.Image = New Bitmap(480, 256)
        Me.PictureBox1.Width = Me.PictureBox1.Image.Width
        Me.PictureBox1.Height = Me.PictureBox1.Image.Height
        gr1 = Graphics.FromImage(Me.PictureBox1.Image)
        gr1.DrawImage(Image.FromFile("..\..\..\chipset13.png"), 0, 0)
        gr1.Dispose()
        Me.PictureBox2.Image = New Bitmap(32, 32)
        x = 0
        y = 0
    End Sub

    Private Sub Button1_Click(ByVal sender As System.Object, _
                ByVal e As System.EventArgs) Handles Button1.Click
        Dim g1 As Graphics = PictureBox1.CreateGraphics()
        Dim g2 As Graphics = PictureBox2.CreateGraphics()
        Dim srcdc As IntPtr = g1.GetHdc()
        Dim destdc As IntPtr = g2.GetHdc()
        Dim retval As Integer
        retval = StretchBlt(destdc, 0, 0, 32, 32, _
                            srcdc, x, y, 16, 16, SRCCOPY)
        g2.ReleaseHdc(destdc)
        g1.ReleaseHdc(srcdc)
        g2.Dispose()
        g1.Dispose()

        x += 16
        If x > 320 Then
            x = 0
            y += 16
        End If
    End Sub
End Class


 試しに、ピクチャーボックスのImageからGraphicsを作成してみました
が、それだと真っ黒な四角が描画されます。
 メモリデバイスコンテキストを作らなければ駄目なのかと思い、srcdcの
生成を以下のようにしてみました。
        Dim srcdc As IntPtr = CreateCompatibleDC(destdc)
        Dim hbmSrc As IntPtr = DirectCast(Me.PictureBox1.Image, _
                               Bitmap).GetHbitmap()
        SelectObject(srcdc, hbmSrc)

 ソース側はこれでうまくいき、PictureBox1のImageの内容を転送できる
ようになりました。
 しかし、デスティネーション側はピクチャーボックスのGraphicsを使用
しないとうまくいきません。Imageをデスティネーションにする方法はない
のでしょうか?
投稿者 (削除されました)  () 投稿日時 2010/2/7 17:56:12
(削除されました)
投稿者 (削除されました)  () 投稿日時 2010/2/7 20:52:31
(削除されました)
投稿者 (削除されました)  () 投稿日時 2010/2/7 20:57:13
(削除されました)
投稿者 (削除されました)  () 投稿日時 2010/2/7 23:33:46
(削除されました)
投稿者 (削除されました)  () 投稿日時 2010/2/8 00:16:52
(削除されました)
投稿者 あにす  (社会人) 投稿日時 2010/2/8 08:35:38
いまいちやりたいことが見えないのですが、こういうことでしょうか?

Public Class Form1
    Private Sub Form1_Load(ByVal sender As Object, _
                ByVal e As System.EventArgs) Handles Me.Load

        Me.PictureBox1.Image = Image.FromFile("..\..\..\chipset13.png")
    End Sub

    Private Sub Button1_Click(ByVal sender As System.Object, _
                              ByVal e As System.EventArgs) Handles Button1.Click

        Dim img As New Bitmap(32, 32)

        Using g As Graphics = Graphics.FromImage(img)
            g.DrawImage(Me.PictureBox1.Image, New Rectangle(0, 0, 32, 32), _
                        New Rectangle(0, 0, 16, 16), GraphicsUnit.Pixel)
        End Using

        Me.PictureBox2.Image = img
    End Sub
End Class


これでよければ、StretchBlt関数は使わなくて済みます。
投稿者 反る戸  (社会人) 投稿日時 2010/2/9 03:38:19
あにすさんレスありがとうございます。
>いまいちやりたいことが見えないのですが、
質問の仕方が悪く、申し訳ございません。

 やりたいことは、
 PictureBox1.ImageからPictureBox2.ImageへのStretchBltを使用した
拡大転送です。

 最初はDrawImageでやっていたのですが、思うような拡大が出来ません
でした。これに関しても色々試行錯誤はしておりまして、お聞きしたい
ことは有るのですが、このスレッドではStretchBltに限定してご助言を
頂戴したいと思っております。。恐縮ですが、DrawImageについては、別
のスレッドで新たに質問させて 下さい。
投稿者 (削除されました)  () 投稿日時 2010/2/9 04:27:23
(削除されました)
投稿者 cupid  (社会人) 投稿日時 2010/2/9 19:55:27
「StretchBlt」って固有名詞じゃないのかな?
それに普通、ドットネットでグラフィックを扱う場合、
「デバイスコンテキスト」を考える必要ないと思うけど。
投稿者 (削除されました)  () 投稿日時 2010/2/10 03:50:13
(削除されました)
投稿者 反る戸  (社会人) 投稿日時 2010/2/10 03:53:26
直前の削除は私です。申し訳ありません。

cupidさん、レスありがとうございます。
>それに普通、ドットネットでグラフィックを扱う場合、
>「デバイスコンテキスト」を考える必要ないと思うけど。 
 おっしゃることはごもっともなのですが、敢えてWindowsのAPIを使うとすれば、
ということでご助言いただけるとありがたいです。
投稿者 (削除されました)  () 投稿日時 2010/2/10 04:04:27
(削除されました)
投稿者 反る戸  (社会人) 投稿日時 2010/2/10 07:31:33
自己解決しました。以下のURLに答えがありました。
http://dobon.net/vb/bbs/log3-39/24003.html#ID24003

 こういうことだったようです。
1.GraphicsはImageから取得してよいが、転送元のデバイスコンテキストは
 BitmapからGetHbitmap()で作成したbmpのハンドルをSelectObjectで選択して
 やらなければならない。
2.転送先のデバイスコンテキストでSelectObjectを使ってはいけない。

 質問時のコードのButton1_Clickを以下のように修正するとうまくいきました。
SelectObject()とDeleteObject()の宣言は別に追加していますが。

    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        Dim g1 As Graphics = Graphics.FromImage(PictureBox1.Image)
        Dim g2 As Graphics = Graphics.FromImage(PictureBox2.Image)

        g2.DrawRectangle(Pens.BlueViolet, 2, 2, 26, 26)

        Dim srcDc As IntPtr = g1.GetHdc()
        Dim destDc As IntPtr = g2.GetHdc()
        Dim srcHbmp As IntPtr = DirectCast(Me.PictureBox1.Image, Bitmap).GetHbitmap()
        SelectObject(srcDc, srcHbmp)

        Dim retval As Integer
        retval = StretchBlt(destdc, 0, 0, 32, 32, srcdc, x, y, 16, 16, SRCCOPY)

        DeleteObject(srcHbmp)
        g2.ReleaseHdc(destdc)
        g1.ReleaseHdc(srcdc)
        g2.Dispose()
        g1.Dispose()
        Refresh()
        x += 16
        If x > 320 Then
            x = 0
            y += 16
        End If
    End Sub

 お騒がせしました。今後ともよろしくお願いします。
投稿者 (削除されました)  () 投稿日時 2010/2/10 07:35:00
(削除されました)
投稿者 (削除されました)  () 投稿日時 2010/2/11 05:16:10
(削除されました)
投稿者 (削除されました)  () 投稿日時 2010/2/11 05:18:12
(削除されました)