C# と VB.NET の質問掲示板

ASP.NET、C++/CLI、Java 何でもどうぞ

C# と VB.NET の入門サイト

Re[6]: C#でBitBltを使う方法


(過去ログ 77 を表示中)

[トピック内 7 記事 (1 - 7 表示)]  << 0 >>

■45323 / inTopicNo.1)  C#でBitBltを使う方法
  
□投稿者/ ぽん (6回)-(2010/01/10(Sun) 03:04:00)

分類:[C#] 

C#でBitBltを使用して画像を描画したいと思い
下記のようにソースを書いてみたのですが
画像が表示されずに、真っ黒になってしまいます。

BitBltのリターンコードは1が返ってきているので
エラーでは無いと思うのですが、何処が間違っているのでしょうか?
宜しくお願いします。


namespace test
{
    public partial class Form2 : Form
    {
        const int SRCCOPY = 0xcc0020;

        [System.Runtime.InteropServices.DllImportAttribute("gdi32.dll")]
        private static extern int BitBlt(
          IntPtr hdcDest,     // handle to destination DC (device context)
          int nXDest,         // x-coord of destination upper-left corner
          int nYDest,         // y-coord of destination upper-left corner
          int nWidth,         // width of destination rectangle
          int nHeight,        // height of destination rectangle
          IntPtr hdcSrc,      // handle to source DC
          int nXSrc,          // x-coordinate of source upper-left corner
          int nYSrc,          // y-coordinate of source upper-left corner
          System.Int32 dwRop  // raster operation code
          );

        Bitmap _drawImage;
        Graphics _gdraw;

        public Form2()
        {
            InitializeComponent();
            _drawImage = new Bitmap(panel1.ClientSize.Width, panel1.ClientSize.Height);
            _gdraw = Graphics.FromImage(_drawImage);

        }

        private void Form2_Load(object sender, EventArgs e)
        {
            Bitmap img;
            img = new Bitmap(@"C:\無題1.bmp");
            _gdraw.DrawImage(img, new Point());

            img = new Bitmap(@"C:\無題2.bmp");
            _gdraw.DrawImage(img, new Point(100,0));

        }

        private void panel1_Paint(object sender, PaintEventArgs e)
        {
            Graphics g = e.Graphics;

#if false
            //DrawImageで描画
            g.DrawImage(_drawImage, new Point());

#else
            //BitBltで描画
            IntPtr dstHDC = g.GetHdc();
            IntPtr srcHDC = _gdraw.GetHdc();

            int rc = BitBlt(dstHDC, 0, 0, _drawImage.Width, _drawImage.Height, srcHDC, 0, 0, SRCCOPY);

            g.ReleaseHdc(dstHDC);
            _gdraw.ReleaseHdc(srcHDC);

            if (rc == 0)
                System.Diagnostics.Debug.WriteLine("Err");
#endif
        }
    }
}

引用返信 編集キー/
■45325 / inTopicNo.2)  Re[1]: C#でBitBltを使う方法
□投稿者/ Hongliang (539回)-(2010/01/10(Sun) 09:03:22)
2010/01/10(Sun) 09:05:40 編集(投稿者)

_srcHDC に、_drawImage.GetHbitmap() で取得した HBITMAP を SelectObject すればどうでしょう?
// フィールドにおいておくのは HBITMAP にして、Graphics/HDC は毎回作ってもコストは大したことなかったと思います。
引用返信 編集キー/
■45354 / inTopicNo.3)  Re[2]: C#でBitBltを使う方法
□投稿者/ ぽん (7回)-(2010/01/11(Mon) 01:38:00)
No45325 (Hongliang さん) に返信
> 2010/01/10(Sun) 09:05:40 編集(投稿者)
> 
> _srcHDC に、_drawImage.GetHbitmap() で取得した HBITMAP を SelectObject すればどうでしょう?
> // フィールドにおいておくのは HBITMAP にして、Graphics/HDC は毎回作ってもコストは大したことなかったと思います。

_drawImage.GetHbitmap()はコストが掛かるので外出しにしたほうが
良いということでしょうか?
APIを直接使ったことが無いため余り理解できてません。



以下のようにソースを変更すると絵は描画させたのですが
パネルのバックカラーがDrawImageで描画したものと
BitBltを使用したもので違ってしまいます。
(パネルのバックカラーはデフォルトのままで変更していません)

あと2回目にSelectObjectをしている箇所の引数でsrcHDCを
渡しているのですがdstHDCかもと悩んでいます


        private void panel1_Paint(object sender, PaintEventArgs e)
        {
            Graphics g = e.Graphics;

#if false
            //DrawImageで描画
            g.DrawImage(_drawImage, new Point());

#else
            //BitBltで描画
            IntPtr dstHDC = g.GetHdc();
            IntPtr srcHDC = _gdraw.GetHdc();

            IntPtr hBmpSrc = _drawImage.GetHbitmap();
            //セットされていたものを一応保存
            IntPtr hBmpSrcBackup = SelectObject(srcHDC, hBmpSrc);

            int rc = BitBlt(dstHDC, 0, 0, _drawImage.Width, _drawImage.Height, srcHDC, 0, 0, SRCCOPY);


            if (rc == 0)
                System.Diagnostics.Debug.WriteLine("Err");
            else
                System.Diagnostics.Debug.WriteLine(rc.ToString());

            //セットされていたものを戻しておく
            SelectObject(srcHDC, hBmpSrcBackup);  //引数があってるか不明
            DeleteObject(hBmpSrc);
            
            g.ReleaseHdc(dstHDC);
            _gdraw.ReleaseHdc(srcHDC);
#endif
        }

引用返信 編集キー/
■45357 / inTopicNo.4)  Re[3]: C#でBitBltを使う方法
□投稿者/ Hongliang (541回)-(2010/01/11(Mon) 02:50:20)
> _drawImage.GetHbitmap()はコストが掛かるので外出しにしたほうが
> 良いということでしょうか?
> APIを直接使ったことが無いため余り理解できてません。
私のおぼろな記憶によるものなので、どの処理にどれだけ時間が掛かっているかは実際に Stopwatch クラスなどを使って計測してください。
その結果別にキャッシュしなくてもいいやという結論になるかも知れません。

> パネルのバックカラーがDrawImageで描画したものと
> BitBltを使用したもので違ってしまいます。
> (パネルのバックカラーはデフォルトのままで変更していません)
これだけではなんのことやらさっぱりです。
どう違っているのか、_drawImage というのがどういう画像なのか(透明であることを期待する部分があったりするのか?)、といった辺りが分からないと答えようがありません。

> あと2回目にSelectObjectをしている箇所の引数でsrcHDCを
> 渡しているのですがdstHDCかもと悩んでいます
セットされていたのを「戻す」んですから、元々セットされていたやつにセットされていたものをセットし直すのは実に自然だと思いますが、なぜ dstHDC かもと思ったのでしょうか?
引用返信 編集キー/
■45358 / inTopicNo.5)  Re[4]: C#でBitBltを使う方法
□投稿者/ ぽん (8回)-(2010/01/11(Mon) 03:42:43)
No45357 (Hongliang さん) に返信
> 私のおぼろな記憶によるものなので、どの処理にどれだけ時間が掛かっているかは実際に Stopwatch クラスなどを使って計測してください。
> その結果別にキャッシュしなくてもいいやという結論になるかも知れません。

アドバイスありがとうございます。処理時間が問題になってから計測してみます。

> どう違っているのか、_drawImage というのがどういう画像なのか(透明であることを期待する部分があったりするのか?)、といった辺りが分からないと答えようがありません。
> 

DrawImageメソッドの場合は無題1.bmpと無題2.bmpを描画していない
余白の部分(パネルのバックカラー)がウィンドウのバックカラーと
同じグレーなのですがBitBltで描画したものは濃いグレーになっています。
2枚のビットマップを描画していない部分は透明なので
元のパネルのバックカラーが出ると思っていました。

________________________
|          |        |    |
|          |        |    |
|   無題1  |  無題2 | *  | <===の*の領域がBitBltの場合に濃いグレーになる
|          |        |    |
|          |        |    |
------------------------

>>あと2回目にSelectObjectをしている箇所の引数でsrcHDCを
>>渡しているのですがdstHDCかもと悩んでいます
> セットされていたのを「戻す」んですから、元々セットされていたやつにセットされていたものをセットし直すのは実に自然だと思いますが、なぜ dstHDC かもと思ったのでしょうか?

もともと選択されていたオブジェクトのハンドルはSelectObjectのリターンで戻ってきますが
もともと使用していたデバイスコンテキストのハンドルとは
何だろうと思い、e.Graphicsから取得したデバイスコンテキストのハンドルが
そうなのかなと思ったのです。




引用返信 編集キー/
■45359 / inTopicNo.6)  Re[5]: C#でBitBltを使う方法
□投稿者/ Hongliang (542回)-(2010/01/11(Mon) 04:38:40)
> DrawImageメソッドの場合は無題1.bmpと無題2.bmpを描画していない
> 余白の部分(パネルのバックカラー)がウィンドウのバックカラーと
> 同じグレーなのですがBitBltで描画したものは濃いグレーになっています。
> 2枚のビットマップを描画していない部分は透明なので
> 元のパネルのバックカラーが出ると思っていました。
BitBlt は透明色を直接サポートしていませんからね。
マスクを使うとか(「BitBlt 透明」などで検索してみてください)、AlphaBlend するとか(GetHbitmap の引数に Color.FromArgb(0) などを渡すとアルファを維持した HBITMAP が取得できるみたいです)、などの手段が必要になるでしょう。
引用返信 編集キー/
■45361 / inTopicNo.7)  Re[6]: C#でBitBltを使う方法
□投稿者/ ぽん (9回)-(2010/01/11(Mon) 07:41:36)
今回のサンプルでは _drawImageを初期化時にパネルのバックカラーで
塗ることで解決しました。

        public Form2()
        {
            InitializeComponent();
            _drawImage = new Bitmap(panel1.ClientSize.Width, panel1.ClientSize.Height);
            _gdraw = Graphics.FromImage(_drawImage);
            _gdraw.Clear(panel1.BackColor);

        }


そもそもBitBlt自体をDrawImageメソッドの高速版と
単純に思っていたことが根本的な間違いでした。


読み込んだビットマップに透明色が含まれている場合
マスク処理を使って画像を合成しないといけない事も理解できました。

いろいろアドバイス有難うございました。


解決済み
引用返信 編集キー/


トピック内ページ移動 / << 0 >>

このトピックに書きこむ

過去ログには書き込み不可

管理者用

- Child Tree -