GetDIBits

Win32 API の GetDIBits でピクセルデータを取得します。

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

プログラムの説明

  1. GetDIBits でピクセルデータを取得して印字する image.cs のソースコードです。
    //★ GetDIBits でピクセルを取得    前田 稔
    using System;
    using System.Drawing;
    using System.Windows.Forms;
    using System.Runtime.InteropServices;
    using System.Diagnostics;
    
    struct BITMAPINFOHEADER
    {
        public UInt32 biSize;
        public Int32 biWidth;
        public Int32 biHeight;
        public UInt16 biPlanes;
        public UInt16 biBitCount;
        public UInt32 biCompression;
        public UInt32 biSizeImage;
        public Int32 biXPelsPerMeter;
        public Int32 biYPelsPerMeter;
        public UInt32 biClrUsed;
        public UInt32 biClrImportant;
    };
    unsafe struct BITMAPINFO
    {
        public BITMAPINFOHEADER bmih;
        public fixed UInt32 bmiColors[1];
    };
    
    public class MyForm : Form
    {   Face    App;
    
        public MyForm()
        {
            App = new Face("c:\\data\\test\\test16.bmp");
            Paint += new PaintEventHandler(MyHandler);
        }
    
        private void MyHandler(object sender, PaintEventArgs e)
        {
            Graphics g = e.Graphics;
            if (App.m_bmp == null)  Application.Exit();
            App.View(g,0,0);
        }
    }
    
    //☆ Face Object Class
    class Face
    {
        public      Bitmap  m_bmp;
        byte[]      m_p;
    
        public const int BI_RGB = 0;
        public const int DIB_RGB_COLORS = 0;
    
        [DllImport("User32.Dll")]
        public static extern IntPtr GetDC(IntPtr hwnd);
    
        [DllImport("User32.Dll")]
        public static extern int ReleaseDC(IntPtr hwnd, IntPtr hdc);
    
        [DllImport("gdi32.dll")]
        public static extern int GetDIBits(IntPtr hdc, IntPtr hbmp, UInt32 uStartScan, UInt32 cScanLines, IntPtr lpvBits, IntPtr lpbi, UInt32 uUsage);
    
        // Constructor
        unsafe public Face(string ImgFile)
        {
            try
            {   m_bmp = new Bitmap(ImgFile);    }
            catch
            {   MessageBox.Show("画像ファイルが読めません!", ImgFile);
                return ;
            }
            Debug.Write("Width:" + m_bmp.Width + "  Hight:" + m_bmp.Height + "\n");
            m_p = new byte[m_bmp.Width*m_bmp.Height*4];
    
            BITMAPINFO  bi = new BITMAPINFO();
            bi.bmih.biSize = (UInt32)sizeof(BITMAPINFOHEADER);
            bi.bmih.biPlanes = (UInt16)1;
            bi.bmih.biCompression = BI_RGB;
            bi.bmih.biBitCount = 32;
            bi.bmih.biWidth = m_bmp.Width;
            bi.bmih.biHeight = m_bmp.Height;
    
            IntPtr hbitmap = m_bmp.GetHbitmap();
            IntPtr hdc = GetDC(IntPtr.Zero);
            fixed(void* lpvBits = m_p)
            {
                if (GetDIBits(hdc, hbitmap, 0, (UInt32)m_bmp.Height, (IntPtr)lpvBits, new IntPtr(&bi), DIB_RGB_COLORS) == 0)
                    MessageBox.Show("GetDIBits error");
            }
            ReleaseDC(IntPtr.Zero, hdc);
            for(int y=0; y<m_bmp.Height; y++)
            {   for(int x=0; x<m_bmp.Width; x++)
                {
                    int idx= (y*m_bmp.Width+x)*4;
                    byte B = m_p[idx];
                    byte G = m_p[idx+1];
                    byte R = m_p[idx+2];
                    byte A = m_p[idx+3];
                    Debug.Write("BGRA: " + B + ", " + G + ", " + R + ", " + A + "\n");
                }
                Debug.Write("--------\n");
            }
        }
    
        // 画像を描画
        public void View(Graphics g, int x, int y)
        {
            if (m_bmp != null) g.DrawImage(m_bmp, x, y);
        }
    }
    
    class image01
    {
        public static void Main()
        {
            MyForm mf = new MyForm();
            Application.Run(mf);
        }
    }
    
  2. Win32 API を使うので Runtime.InteropServices を取り込んで下さい。
    Debug.Write を使うので System.Diagnostics を取り込んで下さい。
    using System.Runtime.InteropServices;
    using System.Diagnostics;
    
  3. MyForm では Face Class を生成して、コンストラクタから画像(c:\data\test\test16.bmp)を入力します。
    シンプルに作成するために、付加的なコードを省略しています。
        public MyForm()
        {
            App = new Face("c:\\data\\test\\test16.bmp");
            Paint += new PaintEventHandler(MyHandler);
        }
    
  4. MyHandler で画像(test16.bmp)を描画します。
    test16.bmp はページ先頭のテスト用に作成した 16*16 ピクセルの小さな画像です。
        private void MyHandler(object sender, PaintEventArgs e)
        {
            Graphics g = e.Graphics;
            if (App.m_bmp == null)  Application.Exit();
            App.View(g,0,0);
        }
    
  5. Bitmap m_bmp; が画像を入力する領域です。
    m_p がピクセルデータを取得する領域です。
    C#から呼び出す Win32 API の関数を宣言します。
        public      Bitmap  m_bmp;
        byte[]      m_p;
    
        public const int BI_RGB = 0;
        public const int DIB_RGB_COLORS = 0;
    
        [DllImport("User32.Dll")]
        public static extern IntPtr GetDC(IntPtr hwnd);
    
        [DllImport("User32.Dll")]
        public static extern int ReleaseDC(IntPtr hwnd, IntPtr hdc);
    
        [DllImport("gdi32.dll")]
        public static extern int GetDIBits(IntPtr hdc, IntPtr hbmp, UInt32 uStartScan,
            UInt32 cScanLines, IntPtr lpvBits, IntPtr lpbi, UInt32 uUsage);
    
  6. ポインターを使用するので Face Class の Constructor に unsafe を設定して下さい。
    ImgFile で渡された画像を入力します。
    m_p に new byte[] で領域を割り当てて、GetDIBits() でピクセルデータを取得します。
    BITMAPINFO 構造体にパラメータを設定して GetDIBits() を呼び出します。
    fixed(void* lpvBits = m_p) で指定した m_p がピクセルデータを設定する領域です。
    取得したピクセルデータを Debug.Write() で印字します。
        // Constructor
        unsafe public Face(string ImgFile)
        {
            try
            {   m_bmp = new Bitmap(ImgFile);    }
            catch
            {   MessageBox.Show("画像ファイルが読めません!", ImgFile);
                return ;
            }
            Debug.Write("Width:" + m_bmp.Width + "  Hight:" + m_bmp.Height + "\n");
            m_p = new byte[m_bmp.Width*m_bmp.Height*4];
    
            BITMAPINFO  bi = new BITMAPINFO();
            bi.bmih.biSize = (UInt32)sizeof(BITMAPINFOHEADER);
            bi.bmih.biPlanes = (UInt16)1;
            bi.bmih.biCompression = BI_RGB;
            bi.bmih.biBitCount = 32;
            bi.bmih.biWidth = m_bmp.Width;
            bi.bmih.biHeight = m_bmp.Height;
    
            IntPtr hbitmap = m_bmp.GetHbitmap();
            IntPtr hdc = GetDC(IntPtr.Zero);
            fixed(void* lpvBits = m_p)
            {
                if (GetDIBits(hdc, hbitmap, 0, (UInt32)m_bmp.Height, (IntPtr)lpvBits, new IntPtr(&bi), DIB_RGB_COLORS) == 0)
                    MessageBox.Show("GetDIBits error");
            }
            ReleaseDC(IntPtr.Zero, hdc);
            for(int y=0; y<m_bmp.Height; y++)
            {   for(int x=0; x<m_bmp.Width; x++)
                {
                    int idx= (y*m_bmp.Width+x)*4;
                    byte B = m_p[idx];
                    byte G = m_p[idx+1];
                    byte R = m_p[idx+2];
                    byte A = m_p[idx+3];
                    Debug.Write("BGRA: " + B + ", " + G + ", " + R + ", " + A + "\n");
                }
                Debug.Write("--------\n");
            }
        }
    

[Next Chapter ↓] W32 三原色
[Previous Chapter ↑] BitBlt

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