情報アイランド

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

C#でWIN32API step15 画像描画(その3)

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

step9:FPSを測定する

step10:図形描画

step11:文字描画(その1)

step12:文字描画(その2)

step13:画像描画(その1)

step14:画像描画(その2)

今回はビットマップ以外の形式の画像(JPEG、GIF)を描画してみます。JPEGやGIF形式の画像を描画する場合は(WIN32APIではありませんが)OLEオートメーションのIPictureを使用します。

Visual Studioから、OLEオートメーションの参照を追加して、それを利用してみましょう。

「参照の追加」から「OLE Automation」を選択し追加します。

注意:.NET Framework 4からは相互運用機能アセンブリではなく埋め込まれた相互運用機能型が使用されるようになっています。この場合、コード内で使用しているCOM型だけがアセンブリに埋め込まれます。

最初に、IPicture格納用の変数を定義しておきます。

private static stdole.IPicture ipicture = null;

WM_CREATEメッセージプロシージャでOleLoadPictureFile関数を使ってビットマップデータを読み込みます。

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;

    object lplpdispPicture = null;
    try
    {
        WIN32.Draw.OleLoadPictureFile(openfilename.lpstrFile, out lplpdispPicture);
    }
    catch (Exception ex)
    {
        Console.WriteLine(ex.ToString());
    }
    ipicture = (stdole.IPicture)lplpdispPicture;

    Console.WriteLine(ipicture.Width.ToString());
    Console.WriteLine(ipicture.Height.ToString());

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

    return IntPtr.Zero;
}

WM_PAINTメッセージプロシージャで描画を行います。Render関数を使用しますが、転送先の座標と寸法はピクセル単位で、また、転送元の座標と寸法は0.01mm単位で指定する必要があり、関数内でそのための変換を行っています。MulDiv関数は画像などの大きさの変換によく使用されます。また、画像データは上下反転しているため、転送元の座標と寸法は下から上に向って指定せねばなりません。

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);

    while (fps.results.Count > 0)
        fps2 = "FPS=" + fps.results.Dequeue();

    WIN32.Window.RECT rect = new WIN32.Window.RECT();
    rect.left = 0;
    rect.top = 0;
    rect.right = 100;
    rect.bottom = 100;
    WIN32.Draw.DrawText(hdc, fps2, fps2.Length, ref rect, 0);

    ipicture.Render(hdc.ToInt32(), 0, 0, WIN32.Common.MulDiv(ipicture.Width, WIN32.Draw.GetDeviceCaps(hdc, WIN32.Draw.LOGPIXELSX), 2540), WIN32.Common.MulDiv(ipicture.Height, WIN32.Draw.GetDeviceCaps(hdc, WIN32.Draw.LOGPIXELSY), 2540), 0, ipicture.Height - 1, ipicture.Width, -ipicture.Height, IntPtr.Zero);

    return IntPtr.Zero;
}

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

using System;
using System.Runtime.InteropServices;

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

        [DllImport("kernel32.dll")]
        public static extern int MulDiv(int nNumber, int nNumerator, int nDenominator);

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

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

        [DllImport("oleaut32.dll")]
        public static extern int OleLoadPictureFile(object varFileName, [MarshalAs(UnmanagedType.IDispatch)] out object lplpdispPicture);

        [DllImport("gdi32.dll")]
        public static extern int GetDeviceCaps(IntPtr hdc, int nIndex);

    (省略)

        public const int DRIVERVERSION = 0;
        public const int TECHNOLOGY = 2;
        public const int HORZSIZE = 4;
        public const int VERTSIZE = 6;
        public const int HORZRES = 8;
        public const int VERTRES = 10;
        public const int BITSPIXEL = 12;
        public const int PLANES = 14;
        public const int NUMBRUSHES = 16;
        public const int NUMPENS = 18;
        public const int NUMMARKERS = 20;
        public const int NUMFONTS = 22;
        public const int NUMCOLORS = 24;
        public const int PDEVICESIZE = 26;
        public const int CURVECAPS = 28;
        public const int LINECAPS = 30;
        public const int POLYGONALCAPS = 32;
        public const int TEXTCAPS = 34;
        public const int CLIPCAPS = 36;
        public const int RASTERCAPS = 38;
        public const int ASPECTX = 40;
        public const int ASPECTY = 42;
        public const int ASPECTXY = 44;
        public const int LOGPIXELSX = 88;
        public const int LOGPIXELSY = 90;
        public const int SIZEPALETTE = 104;
        public const int NUMRESERVED = 106;
        public const int COLORRES = 108;
        public const int PHYSICALWIDTH = 110;
        public const int PHYSICALHEIGHT = 111;
        public const int PHYSICALOFFSETX = 112;
        public const int PHYSICALOFFSETY = 113;
        public const int SCALINGFACTORX = 114;
        public const int SCALINGFACTORY = 115;
        public const int VREFRESH = 116;
        public const int DESKTOPVERTRES = 117;
        public const int DESKTOPHORZRES = 118;
        public const int BLTALIGNMENT = 119;
    }
}

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

因みに、転送元の座標と寸法を上から下に指定すると画像が上下反転して描画されます。

ipicture.Render(hdc.ToInt32(), 0, 0, WIN32.Common.MulDiv(ipicture.Width, WIN32.Draw.GetDeviceCaps(hdc, WIN32.Draw.LOGPIXELSX), 2540), WIN32.Common.MulDiv(ipicture.Height, WIN32.Draw.GetDeviceCaps(hdc, WIN32.Draw.LOGPIXELSY), 2540), 0, 0, ipicture.Width, ipicture.Height, IntPtr.Zero);

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

-C#, WIN32API