GDI+を使うとBMP, GIF, JPEG, PNG, TIFF, EMF形式の画像ファイルを簡単に
取り扱うことができます。
まずは、ImageクラスのコンストラクタでImageオブジェクトを作ります。
次にGraphicsクラスのDrawImageメソッドを呼び出すだけです。
Image( const WCHAR* filename, BOOL useEmbeddedColorManagement );filenameには、ファイル名を指定します。ここで注意すべき点は ファイル名の指定にはUnicodeを使うという点です。
useEmbeddedColorManagementには、色補正をするかどうかを指定します。省略可能です。
Status DrawImage( Image* image, INT x, INT y );imageは、Imageオブジェクトへのポインタです。
x, yは表示するイメージの左上の座標をどこから表示するかを指定します。
左の図はgifファイルの画像を表示したところです。ウィンドウサイズは手動で
調整しています。
では、プログラムを見てみましょう。
// gdiplus02.rcの一部
/////////////////////////////////////////////////////////////////////////////
//
// Menu
//
MYMENU MENU
BEGIN
POPUP "ファイル(&F)"
BEGIN
MENUITEM "画像ファイルを開く(&O)", IDM_OPEN
MENUITEM SEPARATOR
MENUITEM "終了(&X)", IDM_END
END
END
単なるメニューのリソース・スクリプトです。
// gdiplus02.cpp
#include <windows.h>
#include <gdiplus.h>
#include "resource.h"
using namespace Gdiplus;
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
ATOM InitApp(HINSTANCE);
BOOL InitInstance(HINSTANCE, int);
void OnPaint(HDC, HWND);
int MyOpenFile(HWND);
GdiplusStartupInput gdiSI;
ULONG_PTR gdiToken;
char szClassName[] = "gdiplus02"; //ウィンドウクラス
char szFile[MAX_PATH], szFileTitle[64];
int WINAPI WinMain(HINSTANCE hCurInst, HINSTANCE hPrevInst,
LPSTR lpsCmdLine, int nCmdShow)
{
MSG msg;
BOOL bRet;
GdiplusStartup(&gdiToken, &gdiSI, NULL);
if (!InitApp(hCurInst))
return FALSE;
if (!InitInstance(hCurInst, nCmdShow))
return FALSE;
while ((bRet = GetMessage(&msg, NULL, 0, 0)) != 0) {
if (bRet == -1) {
break;
} else {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
GdiplusShutdown(gdiToken);
return (int)msg.wParam;
}
//ウィンドウ・クラスの登録
ATOM InitApp(HINSTANCE hInst)
{
WNDCLASSEX wc;
wc.cbSize = sizeof(WNDCLASSEX);
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = WndProc; //プロシージャ名
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInst;//インスタンス
wc.hIcon = (HICON)LoadImage(NULL,
MAKEINTRESOURCE(IDI_APPLICATION),
IMAGE_ICON,
0,
0,
LR_DEFAULTSIZE | LR_SHARED);
wc.hCursor = (HCURSOR)LoadImage(NULL,
MAKEINTRESOURCE(IDC_ARROW),
IMAGE_CURSOR,
0,
0,
LR_DEFAULTSIZE | LR_SHARED);
wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
wc.lpszMenuName = "MYMENU"; //メニュー名
wc.lpszClassName = (LPCSTR)szClassName;
wc.hIconSm = (HICON)LoadImage(NULL,
MAKEINTRESOURCE(IDI_APPLICATION),
IMAGE_ICON,
0,
0,
LR_DEFAULTSIZE | LR_SHARED);
return (RegisterClassEx(&wc));
}
//ウィンドウの生成
BOOL InitInstance(HINSTANCE hInst, int nCmdShow)
{
HWND hWnd;
hWnd = CreateWindow(szClassName,
"猫でもわかるGDI+", //タイトルバーにこの名前が表示されます
WS_OVERLAPPEDWINDOW, //ウィンドウの種類
CW_USEDEFAULT, //X座標
CW_USEDEFAULT, //Y座標
CW_USEDEFAULT, //幅
CW_USEDEFAULT, //高さ
NULL, //親ウィンドウのハンドル、親を作るときはNULL
NULL, //メニューハンドル、クラスメニューを使うときはNULL
hInst, //インスタンスハンドル
NULL);
if (!hWnd)
return FALSE;
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
return TRUE;
}
//ウィンドウプロシージャ
LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp)
{
int id;
HDC hdc;
PAINTSTRUCT ps;
switch (msg) {
case WM_COMMAND:
switch (LOWORD(wp)) {
case IDM_END:
SendMessage(hWnd, WM_CLOSE, 0, 0);
break;
case IDM_OPEN:
if (MyOpenFile(hWnd) != -1)
InvalidateRect(hWnd, NULL, TRUE);
break;
}
break;
case WM_PAINT:
hdc = BeginPaint(hWnd, &ps);
OnPaint(hdc, hWnd);
EndPaint(hWnd, &ps);
break;
case WM_CLOSE:
id = MessageBox(hWnd,
"終了してもよろしいですか",
"確認",
MB_YESNO | MB_ICONQUESTION);
if (id == IDYES)
DestroyWindow(hWnd);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return (DefWindowProc(hWnd, msg, wp, lp));
}
return 0;
}
ここまでは、別にどうということもないですね。前章でも触れましたがプロジェクトにGdiplus.lib が参加していないとビルドエラーとなります。
void OnPaint(HDC hdc, HWND hWnd)
{
WCHAR wTitle[256];
char szWindowTitle[64];
if (strcmp((char*)szFile, "") != 0) {
Graphics MyGraphics(hdc);
mbstowcs(wTitle, szFile, strlen(szFile)+1);
Image myImage(wTitle);
MyGraphics.DrawImage(&myImage, 0, 0);
strcpy(szWindowTitle, "猫でもわかるGDI+");
strcat(szWindowTitle, "[ ");
strcat(szWindowTitle, szFileTitle);
strcat(szWindowTitle, " ]");
SetWindowText(hWnd, szWindowTitle);
}
return;
}
UNICODEへの変換にはmbstowcs関数が簡単です。
size_t mbstowcs( wchar_t *wcstr, const char *mbstr, size_t count );wcstrには、ワイド文字列のアドレスを指定します。
mbstrには、マルチバイト文字列のアドレスを指定します。
countには、変換対象のマルチバイト文字列の文字数を指定します。
countを大きく指定した場合、途中でヌル文字が見つかった段階で ヌル文字を変換して終了します。count文字数だけ変換してヌル文字が出てこなかった場合は変換後の文字列にヌル文字が付かないため自分で付けてやる必要があります。
画像の表示部分は
Image myImage(wTitle); MyGraphics.DrawImage(&myImage, 0, 0);だけです。ずいぶん簡単ですね。
int MyOpenFile(HWND hWnd)
{
OPENFILENAME of;
memset(&of, 0, sizeof(OPENFILENAME));
of.lStructSize = sizeof(OPENFILENAME);
of.hwndOwner = hWnd;
of.lpstrFilter = "BMP(*.bmp)\0*.bmp\0JPG(*.jpg)\0*.jpg\0GIF(*.gif)\0*.gif\0\0";
of.lpstrFile = szFile;
of.lpstrFileTitle = (char *)szFileTitle;
of.nMaxFile = MAX_PATH;
of.nMaxFileTitle = sizeof(szFileTitle);
of.Flags = OFN_FILEMUSTEXIST | OFN_HIDEREADONLY;
of.lpstrDefExt = "gif";
of.lpstrTitle = "画像のオープン";
if (GetOpenFileName(&of) == 0)
return -1;
return 0;
}
開くファイルを指定するためにコモンダイアログを表示する関数です。このような簡単なプログラムで、いろいろな画像ファイルを閲覧できるようになりました。従来のプログラミングからは想像もできないですね。
Update 30/Aug/2002 By Y.Kumei