BitBlt

GetPixel() 関数, SetPixel() 関数でプログラムすると実行速度が気になります。
そこで Win32 API を使うのですが、最初に BitBlt() 関数を使って描画してみましょう。

前田稔(Maeda Minoru)の超初心者のプログラム入門

プログラムの説明

  1. BitBlt で画像を描画する image.cs のソースコードです。
    //★ BitBlt で描画    前田 稔
    using System;
    using System.Drawing;
    using System.Windows.Forms;
    using System.Runtime.InteropServices;
    using System.Diagnostics;
    
    public class MyForm : Form
    {    Face   App;
    
        public MyForm()
        {
            BackColor = SystemColors.AppWorkspace;
            App = new Face();
            float hdpi = App.m_bmp.HorizontalResolution;
            float vdpi = App.m_bmp.VerticalResolution;
            Width = App.m_bmp.Width * 96 / (int)hdpi;
            Height = (App.m_bmp.Height + 32) * 96 / (int)vdpi;
            Paint += new PaintEventHandler(MyHandler);
         }
    
        private void MyHandler(object sender, PaintEventArgs e)
        {
            Graphics g = e.Graphics;
            if (App.m_bmp == null)  Application.Exit();
            App.ViewWin32(g,0,0);
            //App.View(g, 0, 0);
        }
    }
    
    //☆ Face Object Class
    class Face
    {
        public  Bitmap  m_bmp;
        string  ImgFile = "";
        const int SRCCOPY = 0xcc0020;
    
        [DllImport("gdi32.dll")]
        private static extern int BitBlt(IntPtr hDestDC,
            int x, int y, int nWidth, int nHeight,
            IntPtr hSrcDC, int xSrc, int ySrc, int dwRop);
    
        [DllImport("gdi32.dll")]
        public static extern int SelectObject(IntPtr hdc, IntPtr hbmp);
    
        [DllImport("gdi32.dll")]
        public static extern int DeleteObject(IntPtr hdc);
    
        // Constructor
        public Face()
        {
            OpenFileDialog opendlg = new OpenFileDialog();
            opendlg.Filter = "画像ファイル (*.bmp)|*.bmp|すべてのファイル (*.*)|*.*";
            if (opendlg.ShowDialog() == DialogResult.OK)
            { ImgFile = opendlg.FileName; }
            try
            { m_bmp = new Bitmap(ImgFile); }
            catch
            {
                MessageBox.Show("画像ファイルが読めません!", ImgFile);
                return;
            }
        }
    
        // 画像を描画
        public void View(Graphics g, int x, int y)
        {
            if (m_bmp != null)  g.DrawImage(m_bmp, x, y);
        }
    
        public void ViewWin32(Graphics g, int x, int y)
        {
            IntPtr hDC = g.GetHdc();
            IntPtr hBmpSrc = m_bmp.GetHbitmap();
            Graphics gdraw = Graphics.FromImage(m_bmp);
            IntPtr srcHDC = gdraw.GetHdc();
            SelectObject(srcHDC, hBmpSrc);
            BitBlt(hDC, x, y, m_bmp.Width, m_bmp.Height, srcHDC, 0, 0, SRCCOPY);
            DeleteObject(hBmpSrc);
            g.ReleaseHdc(hDC);
            gdraw.ReleaseHdc(srcHDC);
        }
    }
    
    class image01
    {
        [STAThread]
        public static void Main()
        {
            MyForm mf = new MyForm();
            Application.Run(mf);
        }
    }
    
  2. Win32 API を使うに当たっては Image Guid を参照して下さい。
    今回はポインターを使用しないので unsafe の設定は不要です。
    Win32 API を使うので Runtime.InteropServices を取り込んで下さい。
    Debug.Write を使うので System.Diagnostics を取り込んで下さい。
    using System.Runtime.InteropServices;
    using System.Diagnostics;
    
  3. MyForm では Face Class を生成して、コンストラクタから画像を入力します。
    画像サイズに合わせてウインドウの大きさを設定しています。
        public MyForm()
        {
            BackColor = SystemColors.AppWorkspace;
            App = new Face();
            float hdpi = App.m_bmp.HorizontalResolution;
            float vdpi = App.m_bmp.VerticalResolution;
            Width = App.m_bmp.Width * 96 / (int)hdpi;
            Height = (App.m_bmp.Height + 32) * 96 / (int)vdpi;
            Paint += new PaintEventHandler(MyHandler);
         }
    
  4. MyHandler で画像を描画します。
    App.View() がC#の描画関数で、App.ViewWin32() が BitBlt で描画する関数です。
    BitBlt で描画したときは「ピクセル/インチ」が考慮されないようで、画像サイズとウインドウサイズが合わない場合があります。
    View() で描画すると「ピクセル/インチ」が考慮されるようです。
    96 DPI の画像と、96 DPI 以外の画像を BitBlt で描画してみて下さい。
        private void MyHandler(object sender, PaintEventArgs e)
        {
            Graphics g = e.Graphics;
            if (App.m_bmp == null)  Application.Exit();
            App.ViewWin32(g,0,0);
            //App.View(g, 0, 0);
        }
    
  5. Bitmap m_bmp; が画像を入力する領域です。
    C#から呼び出す Win32 API の関数を宣言します。
        public  Bitmap  m_bmp;
        const int SRCCOPY = 0xcc0020;
    
        [DllImport("gdi32.dll")]
        private static extern int BitBlt(IntPtr hDestDC,
            int x, int y, int nWidth, int nHeight,
            IntPtr hSrcDC, int xSrc, int ySrc, int dwRop);
    
        [DllImport("gdi32.dll")]
        public static extern int SelectObject(IntPtr hdc, IntPtr hbmp);
    
        [DllImport("gdi32.dll")]
        public static extern int DeleteObject(IntPtr hdc);
    
  6. ViewWin32() が BitBlt() を使って画像を描画する関数です。
    hDC が画像の受け取り側の DC で、srcHDC が Image が格納されている送り側の DC です。
    SelectObject() で設定してから BitBlt() で描画して下さい。
    描画が終わると取得した DC(デバイスコンテキスト)を開放します。
        public void ViewWin32(Graphics g, int x, int y)
        {
            IntPtr hDC = g.GetHdc();
            IntPtr hBmpSrc = m_bmp.GetHbitmap();
            Graphics gdraw = Graphics.FromImage(m_bmp);
            IntPtr srcHDC = gdraw.GetHdc();
            SelectObject(srcHDC, hBmpSrc);
            BitBlt(hDC, x, y, m_bmp.Width, m_bmp.Height, srcHDC, 0, 0, SRCCOPY);
            DeleteObject(hBmpSrc);
            g.ReleaseHdc(hDC);
            gdraw.ReleaseHdc(srcHDC);
        }
    

[Next Chapter ↓] GetDIBits
[Previous Chapter ↑] Line をピックアップ

超初心者のプログラム入門(C# Frame Work)