情報アイランド

「情報を制する者は世界を制す」をモットーに様々な情報を提供することを目指すブログです。現在はプログラミング関連情報が多めですが、投資関連情報も取り扱っていきたいです。

C#でWIN32API step14 画像描画(その2)

step8:ここまでのまとめ(その1)

step9:FPSを測定する

step10:図形描画

step11:文字描画(その1)

step12:文字描画(その2)

step13:画像描画(その1)

今回はビットマップ画像を別の方法で描画してみます。また、「開く」ダイアログボックスを使って任意のビットマップを開けるようにします。

最初に、ビットマップデータ格納用の変数を定義しておきます。

private static WIN32.Draw.BITMAPFILEHEADER bitmapfileheader = new WIN32.Draw.BITMAPFILEHEADER();
private static WIN32.Draw.BITMAPINFOHEADER bitmapinfoheader = new WIN32.Draw.BITMAPINFOHEADER();
private static byte[] data = null;

WM_CREATEメッセージプロシージャでビットマップデータを読み込みます。今回は典型的な24bitビットマップを開くことを想定していますので、BITMAPFILEHEADER構造体、BITMAPINFOHEADER構造体、byte配列に順番にデータを読み込んでいきます。

また、データを読み込んだ後に一連の情報を表示するようにしています。更に、開いたファイル名が分かるようにウィンドウのタイトルに設定しています。

private static IntPtr WM_CREATE(IntPtr hWnd, uint uMsg, IntPtr wParam, IntPtr lParam)
{
    WIN32.DialogBox.OPENFILENAME openfilename = new WIN32.DialogBox.OPENFILENAME();
    openfilename.lStructSize = (uint)Marshal.SizeOf(openfilename);
    openfilename.hwndOwner = hWnd;
    openfilename.lpstrFilter = "全てのファイル(*.*)\0*.*\0\0";
    openfilename.lpstrFile = new string('\0', 256);
    openfilename.nMaxFile = (uint)openfilename.lpstrFile.Length;
    openfilename.Flags = WIN32.DialogBox.OFN.OFN_FILEMUSTEXIST;
    if (!WIN32.DialogBox.GetOpenFileName(ref openfilename))
        return IntPtr.Zero;

    using (BinaryReader binaryReader = new BinaryReader(File.OpenRead(openfilename.lpstrFile)))
    {
        bitmapfileheader.Read(binaryReader);
        bitmapinfoheader.Read(binaryReader);
        data = binaryReader.ReadBytes((int)bitmapinfoheader.biSizeImage);

        string text = "bfType: " + bitmapfileheader.bfType.ToString() + Environment.NewLine +
            "bfSize: " + bitmapfileheader.bfSize.ToString() + Environment.NewLine +
            "bfReserved1: " + bitmapfileheader.bfReserved1.ToString() + Environment.NewLine +
            "bfReserved2: " + bitmapfileheader.bfReserved2.ToString() + Environment.NewLine +
            "bfOffBits: " + bitmapfileheader.bfOffBits.ToString();

        string text2 = "biSize: " + bitmapinfoheader.biSize.ToString() + Environment.NewLine +
            "biWidth: " + bitmapinfoheader.biWidth.ToString() + Environment.NewLine +
            "biHeight: " + bitmapinfoheader.biHeight.ToString() + Environment.NewLine +
            "biPlanes: " + bitmapinfoheader.biPlanes.ToString() + Environment.NewLine +
            "biBitCount: " + bitmapinfoheader.biBitCount.ToString() + Environment.NewLine +
            "biCopmression: " + bitmapinfoheader.biCopmression.ToString() + Environment.NewLine +
            "biSizeImage: " + bitmapinfoheader.biSizeImage.ToString() + Environment.NewLine +
            "biXPixPerMeter: " + bitmapinfoheader.biXPixPerMeter.ToString() + Environment.NewLine +
            "biYPixPerMeter: " + bitmapinfoheader.biYPixPerMeter.ToString() + Environment.NewLine +
            "biClrUsed: " + bitmapinfoheader.biClrUsed.ToString() + Environment.NewLine +
            "biClrImportant: " + bitmapinfoheader.biClrImportant.ToString();

        Console.WriteLine(text);
        Console.WriteLine();
        Console.WriteLine(text2);
    }

    WIN32.Window.SetWindowText(hWnd, openfilename.lpstrFile);

    return IntPtr.Zero;
}

最後に、WM_PAINTメッセージプロシージャを以下のように変更します。SetDIBitsToDevice関数を使って描画するだけです。

private static IntPtr WM_PAINT(IntPtr hWnd, uint uMsg, IntPtr wParam, IntPtr lParam)
{
    WIN32.Draw.PAINTSTRUCT paintstruct;

    IntPtr hdc = WIN32.Draw.BeginPaint(hWnd, out paintstruct);

    WIN32.Draw.SetDIBitsToDevice(hdc, 0, 0, (uint)bitmapinfoheader.biWidth, (uint)bitmapinfoheader.biHeight, 0, 0, 0, (uint)bitmapinfoheader.biHeight, data, ref bitmapinfoheader, WIN32.Draw.DIB.DIB_RGB_COLORS);

    WIN32.Draw.EndPaint(hWnd, ref paintstruct);

    return IntPtr.Zero;
}

こちらが、P/I用のコードです(前回からの追加部分)。

利便性を考え、BITMAPFILEHEADER構造体とBITMAPINFOHEADER構造体にはReadメソッドとWriteメソッドを実装しました。

using System;
using System.Runtime.InteropServices;
using System.IO;

namespace Anttn.WIN32
{
    public static partial class Draw
    {
    (省略)

        [DllImport("gdi32.dll")]
        public static extern int SetDIBitsToDevice(IntPtr hdc, int XDest, int YDest, uint dwWidth, uint dwHeight, int XSrc, int YSrc, uint uStartScan, uint cScanLines, byte[] lpvBits, [In] ref BITMAPINFOHEADER lpbmi, DIB fuColorUse);

    (省略)

        [StructLayout(LayoutKind.Sequential)]
        public struct BITMAPFILEHEADER
        {
            public ushort bfType;
            public uint bfSize;
            public ushort bfReserved1;
            public ushort bfReserved2;
            public uint bfOffBits;

            public void Read(BinaryReader binaryReader)
            {
                bfType = binaryReader.ReadUInt16();
                bfSize = binaryReader.ReadUInt32();
                bfReserved1 = binaryReader.ReadUInt16();
                bfReserved2 = binaryReader.ReadUInt16();
                bfOffBits = binaryReader.ReadUInt32();
            }

            public void Write(BinaryWriter binaryWriter)
            {
                binaryWriter.Write(bfType);
                binaryWriter.Write(bfSize);
                binaryWriter.Write(bfReserved1);
                binaryWriter.Write(bfReserved2);
                binaryWriter.Write(bfOffBits);
            }
        }

        [StructLayout(LayoutKind.Sequential)]
        public struct BITMAPINFOHEADER
        {
            public uint biSize;
            public int biWidth;
            public int biHeight;
            public ushort biPlanes;
            public ushort biBitCount;
            public uint biCopmression;
            public uint biSizeImage;
            public int biXPixPerMeter;
            public int biYPixPerMeter;
            public uint biClrUsed;
            public uint biClrImportant;

            public void Read(BinaryReader binaryReader)
            {
                biSize = binaryReader.ReadUInt32();
                biWidth = binaryReader.ReadInt32();
                biHeight = binaryReader.ReadInt32();
                biPlanes = binaryReader.ReadUInt16();
                biBitCount = binaryReader.ReadUInt16();
                biCopmression = binaryReader.ReadUInt32();
                biSizeImage = binaryReader.ReadUInt32();
                biXPixPerMeter = binaryReader.ReadInt32();
                biYPixPerMeter = binaryReader.ReadInt32();
                biClrUsed = binaryReader.ReadUInt32();
                biClrImportant = binaryReader.ReadUInt32();
            }

            public void Write(BinaryWriter binaryWriter)
            {
                binaryWriter.Write(biSize);
                binaryWriter.Write(biWidth);
                binaryWriter.Write(biHeight);
                binaryWriter.Write(biPlanes);
                binaryWriter.Write(biBitCount);
                binaryWriter.Write(biCopmression);
                binaryWriter.Write(biSizeImage);
                binaryWriter.Write(biXPixPerMeter);
                binaryWriter.Write(biYPixPerMeter);
                binaryWriter.Write(biClrUsed);
                binaryWriter.Write(biClrImportant);
            }
        }

    (省略)

        public enum DIB : uint
        {
            DIB_RGB_COLORS = 0,
            DIB_PAL_COLORS = 1
        }

    (省略)
    }
}
using System;
using System.Runtime.InteropServices;

namespace Anttn.WIN32
{
    public static partial class DialogBox
    {
    (省略)

        [DllImport("comdlg32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        public static extern bool GetOpenFileName([In, Out] ref OPENFILENAME lpofn);

        public delegate uint OFNHookProc(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam);

        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
        public struct OPENFILENAME
        {
            public uint lStructSize;
            public IntPtr hwndOwner;
            public IntPtr hInstance;
            public string lpstrFilter;
            public string lpstrCustomFilter;
            public uint nMaxCustomFilter;
            public uint nFilterIndex;
            public string lpstrFile;
            public uint nMaxFile;
            public string lpstrFileTitle;
            public uint nMaxFileTitle;
            public string lpstrInitialDir;
            public string lpstrTitle;
            public OFN Flags;
            public ushort nFileOffset;
            public ushort nFileExtension;
            public string lpstrDefExt;
            public IntPtr lCustData;
            public OFNHookProc lpfnHook;
            public string lpTemplateName;
            public IntPtr pvReserved;
            public uint dwReserved;
            public OFN_EX FlagsEx;
        }

    (省略)

        [Flags]
        public enum OFN : uint
        {
            OFN_READONLY = 0x00000001,
            OFN_OVERWRITEPROMPT = 0x00000002,
            OFN_HIDEREADONLY = 0x00000004,
            OFN_NOCHANGEDIR = 0x00000008,
            OFN_SHOWHELP = 0x00000010,
            OFN_ENABLEHOOK = 0x00000020,
            OFN_ENABLETEMPLATE = 0x00000040,
            OFN_ENABLETEMPLATEHANDLE = 0x00000080,
            OFN_NOVALIDATE = 0x00000100,
            OFN_ALLOWMULTISELECT = 0x00000200,
            OFN_EXTENSIONDIFFERENT = 0x00000400,
            OFN_PATHMUSTEXIST = 0x00000800,
            OFN_FILEMUSTEXIST = 0x00001000,
            OFN_CREATEPROMPT = 0x00002000,
            OFN_SHAREAWARE = 0x00004000,
            OFN_NOREADONLYRETURN = 0x00008000,
            OFN_NOTESTFILECREATE = 0x00010000,
            OFN_NONETWORKBUTTON = 0x00020000,
            OFN_NOLONGNAMES = 0x00040000,
            OFN_EXPLORER = 0x00080000,
            OFN_NODEREFERENCELINKS = 0x00100000,
            OFN_LONGNAMES = 0x00200000,
            OFN_ENABLEINCLUDENOTIFY = 0x00400000,
            OFN_ENABLESIZING = 0x00800000,
            OFN_USESHELLITEM = 0x01000000,
            OFN_DONTADDTORECENT = 0x02000000,
            OFN_FORCESHOWHIDDEN = 0x10000000
        }

        [Flags]
        public enum OFN_EX : uint
        {
            OFN_EX_NOPLACESBAR = 0x00000001
        }
    }
}
using System;
using System.Runtime.InteropServices;

namespace Anttn.WIN32
{
    public static partial class Window
    {
    (省略)

        [DllImport("user32.dll", CharSet = CharSet.Auto)]
        public static extern bool SetWindowText(IntPtr hwnd, string lpString);

    (省略)
    }
}

結果は以下のようになります。

pizyumi
プログラミング歴19年のベテランプログラマー。業務システム全般何でも作れます。現在はWeb系の技術を勉強中。
スポンサーリンク

-C#, WIN32API