Direct2D를 사용하여 프로그램을 할 때 이미지 파일에서 이미지를 읽거나 저장하려면
WIC(Windows Imaging Component)를 사용해야함.
WIC 객체로 이미지 파일을 읽어서 Direct2D용 이미지로 변환하고 사용함.
// Direct2D를 사용하기 위한 파일 포함.
#include <d2d1.h>
#include <wincodec.h>
#pragma comment(lib, "D2D1.lib")
using namespace D2D1;
// Direct2D를 구성하는 각종 객체를 생성하는 객체
ID2D1Factory* gp_factory;
// Direct2D에서 윈도우의 클라이언트 영역에 그림을 그릴 객체
ID2D1HwndRenderTarget* gp_render_target;
// Direct2D의 기본 render target에서 사용가능한 기본 비트맵 객체
ID2D1Bitmap* gp_bitmap;
// 읽어들인 PNG 이미지를 출력할 좌표를 저장할 변수 선언
D2D1_RECT_F g_image_rect;
int LoadMyImage(ID2D1RenderTarget* ap_target, const wchar_t* ap_path)
{
// 기존에 읽은 이미지가 있으면 해당 이미지를 제거
if (gp_bitmap != NULL)
{
gp_bitmap->Release();
gp_bitmap = NULL;
}
// WIC관련 객체를 생성하기 위한 Factory 객체 선언
IWICImagingFactory* p_wic_factory;
// WIC 객체를 생성하기 위한 Factory 객체를 생성
CoCreateInstance(CLSID_WICImagingFactory, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&p_wic_factory));
// 압축된 이미지를 해제할 객체
IWICBitmapDecoder *p_decoder;
// 특정 그림을 선택한 객체
IWICBitmapFrameDecode *p_frame;
// 이미지 변환 객체
IWICFormatConverter *p_converter;
// 그림 파일을 읽은 결과 값 (0이면 그림 읽기 실패, 1이면 그림 읽기 성공)
int result = 0;
// WIC용 Factory 객체를 사용하여 이미지 압축 해제를 위한 객체를 생성
if (S_OK == p_wic_factory->CreateDecoderFromFilename(ap_path, NULL, GENERIC_READ, WICDecodeMetadataCacheOnDemand, &p_decoder)) {
// 파일을 구성하는 이미지 중에서 첫번째 이미지를 선택한다.
if (S_OK == p_decoder->GetFrame(0, &p_frame))
{
// IWICBitmap형식의 비트맵을 ID2D1Bitmap. 형식으로 변환하기 위한 객체 생성
if (S_OK == p_wic_factory->CreateFormatConverter(&p_converter))
{
// 선택된 그림을 어떤 형식의 비트맵으로 변환할 것인지 설정
if (S_OK == p_converter->Initialize(p_frame, GUID_WICPixelFormat32bppPBGRA, WICBitmapDitherTypeNone, NULL, 0.0f, WICBitmapPaletteTypeCustom))
{
// IWICBitmap 형식의 비트맵으로 ID2D1Bitmap 객체를 생성
if (S_OK == ap_target->CreateBitmapFromWicBitmap(p_converter, NULL, &gp_bitmap)) result = 1; // 성공적으로 생성한 경우
}
// 이미지 변환 객체 제거
p_converter->Release();
}
// 그림파일에 있는 이미지를 선택하기 위해 사용한 객체 제거
p_frame->Release();
}
// 압축을 해제하기 위해 생성한 객체 제거
p_decoder->Release();
}
// WIC를 사용하기 위해 만들었던 Factory 객체 제거
p_wic_factory->Release();
return result; // PNG 파일을 읽은 결과를 반환한다.
}
void OnCreateRenderTarget(HWND hWnd)
{
RECT r;
GetClientRect(hWnd, &r);
// 지정한 윈도우의 클라이언트 영역에 그림을 그리기 위한 Render Target을 생성.
gp_factory->CreateHwndRenderTarget(RenderTargetProperties(),
HwndRenderTargetProperties(hWnd, SizeU(r.right, r.bottom)),
&gp_render_target);
// 윈도우의 클라이언트 영역에 대한 폭과 높이를 g_image_rect 변수에 저장.
g_image_rect.right = (float)r.right;
g_image_rect.bottom = (float)r.bottom;
// .png 파일을 읽어서 gp_bitmap 객체에 이미지를 생성.
LoadMyImage(gp_render_target, L"pattern.png");
}
void OnPaintRenderTarget()
{
// Direct2D의 Render Target을 사용해서 그림 그리기를 시작.
gp_render_target->BeginDraw();
// 이미지가 정상적으로 읽혀져 생성되어 있다면 DrawBitmap 함수를 사용하여
// 화면에 gp_bitmap에 저장된 이미지를 출력.
if (gp_bitmap != NULL)
{
gp_render_target->DrawBitmap(gp_bitmap, &g_image_rect);
}
else
{
// 이미지를 읽지 못했다면 화면이 검은색으로 출력되기 때문에 Clear 함수를
// 사용하여 윈도우 전체 영역을 하늘색으로 채운다.
gp_render_target->Clear(ColorF(0.0f, 0.8f, 1.0f));
}
// Render Target을 사용해서 그림 그리기를 중지.
gp_render_target->EndDraw();
}
void OnDestoryRenderTarget()
{
if (gp_render_target != NULL)
{
gp_render_target->Release();
gp_render_target = NULL;
}
}
// 사용자가 메시지를 처리하는 함수.
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
// HDC h_screen_dc = ::GetDC(NULL); // 모니터 전체 화면용 DC
HDC h_dc = ::GetDC(hWnd); // 현재 윈도우용 DC
switch (message)
{
case WM_CREATE:
OnCreateRenderTarget(hWnd);
break;
case WM_PAINT:
// WM_PAINT가 다시 발생하지 않게 처리.
ValidateRect(hWnd, NULL);
OnPaintRenderTarget();
break;
case WM_LBUTTONDOWN:
break;
case WM_DESTROY:
OnDestoryRenderTarget();
// 프로그램 종료
PostQuitMessage(0);
break;
default:
// 자신이 처리하지 않는 메시지들의 기본 작업을 대신 처리해주는 함수.
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
int APIENTRY wWinMain(_In_ HINSTANCE hInstance, // 프로그램의 instance 핸들 값.
_In_opt_ HINSTANCE hPrevInstance, // 현재 사용안함. 항상 NULL.
_In_ LPWSTR lpCmdLine, // 하나의 문자열로 실행인자가 전달됨.
_In_ int nCmdShow) // 초기 기작 형식이 전달됨.
{
// 컴포넌트를 사용할 수 있도록 프로그램을 초기화.
CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
// Direct2D를 위한 factory 객체를 생성.
if(S_OK != D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, &gp_factory))
return 0;
// 윈도우 클래스 등록
WNDCLASSEXW wcex;
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = WndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = hInstance;
wcex.hIcon = LoadIcon(hInstance, IDI_APPLICATION);
wcex.hCursor = LoadCursor(nullptr, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)CreateSolidBrush(RGB(244, 176, 77)); // 바둑판 컬러 설정
wcex.lpszMenuName = IDI_APPLICATION;
wcex.lpszClassName = L"MyWindow";
wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));
RegisterClassExW(&wcex);
// 윈도우 생성
HWND hWnd = CreateWindowW(L"MyWindow", L"scriptplay.tistory.com", WS_OVERLAPPEDWINDOW,
50, 50, 600, 600, nullptr, nullptr, hInstance, nullptr);
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
// 프로그램에 전달된 메시지를 번역하고 실행하는 작업.
MSG msg;
while (GetMessage(&msg, nullptr, 0, 0)) // 메시지를 큐에서 읽는 함수.
{
TranslateMessage(&msg); // 가상 키 메시지이면 ASCII 형태의 메시지를 추가로 생성.
DispatchMessage(&msg); // 변환된 메시지를 처리하는 함수.
}
// 읽어들인 그림 이미지가 있다면 제거.
if (gp_bitmap != NULL)
gp_bitmap->Release();
// 사용하던 Factory 객체를 제거.
gp_factory->Release();
// 컴포넌트 사용을 해제.
CoUninitialize();
return (int) msg.wParam;
}
|
cs |
'::public > 윈도우즈 응용 프로그래밍' 카테고리의 다른 글
Direct2D - 변환 (0) | 2019.09.26 |
---|---|
Direct2D - 렌더타겟 (0) | 2019.09.26 |
Direct2D - 오목 만들기 (0) | 2019.09.25 |
Direct2D 사용하기 (0) | 2019.09.25 |
Direct2D (0) | 2019.09.25 |