본문 바로가기

C++/API | MFC

05. API 응용 - 비트맵과 블록 전송

용어 정리

비트맵 : 이미지를 저장하고 있는 GDI 오브젝트

GDI(Graphic Device Interface) : 모든 출력 장치를 제어하는 윈도우 핵심 모듈 중 하나

GDIOBJ : 출력을 위해 사용되는 도구(펜, 브러쉬, 폰트, 비트맵 등 보통 핸들로 다룹니다.)

DC(Device Context) : 화면 출력에 필요한 도구를 모아놓고 각종 출력 설정을 적용한 최후의 도구 

DDB : 장치에 의존적인 비트맵 포맷 형식

DIB : 장치에 독립적인 비트맵 포맷 형식

 

기존 비트맵을 흑색으로 출력하거나 DC에서 DC에 비트연산을 적용하는 등의 부가적인 방법은 생략하겠습니다.

(블록전송의 경우 고속 복사만 사용하도록 하겠습니다.)

 

 

 

비트맵의 경우 펜, 브러쉬 같은 범용적인 오브젝트와 다르게

메모리에 올리는 양이 많으며, 수많은 종류의 비트맵을 사용하게 됩니다.

 

따라서 각각의 비트맵을 DC에 담아 놓는 비트맵 클래스

비트맵 클래스를 관리하는 매니저(중재자 패턴)를 사용할 것입니다.

 

 

LoadedBitmap.h

class CLoadedBitmap
{
public:
	CLoadedBitmap();
	~CLoadedBitmap();

public:
	HDC Get_MemDC() { return m_hMemDC; }
	void Load_Bmp(const TCHAR* _pFilePath);
	void Release();

private:
	HDC			m_hMemDC;
	HBITMAP		m_hBitmap;
	HBITMAP		m_hOldBmp;
};

 

LoadedBitmap.cpp

#include "stdafx.h"
#include "LoadedBitmap.h"


CLoadedBitmap::CLoadedBitmap()
{
}


CLoadedBitmap::~CLoadedBitmap()
{
}

void CLoadedBitmap::Load_Bmp(const TCHAR* _pFilePath)
{
	HDC hDC = GetDC(g_hWnd);
	m_hMemDC = CreateCompatibleDC(hDC);
	ReleaseDC(g_hWnd, hDC);

	m_hBitmap = (HBITMAP)LoadImage(NULL, _pFilePath, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_CREATEDIBSECTION);

	m_hOldBmp = (HBITMAP)SelectObject(m_hMemDC, m_hBitmap);
}

void CLoadedBitmap::Release()
{
	SelectObject(m_hMemDC, m_hOldBmp);
	DeleteObject(m_hBitmap);
	DeleteDC(m_hMemDC);
}

 

BmpMgr.h

 

class CLoadedBitmap;
class CBmpMgr
{
private:
	CBmpMgr();
	~CBmpMgr();

public:
	void Insert_Bmp(const TCHAR* _pFilePath, const TCHAR* _pImageKey);
	HDC Find_Image(const TCHAR* _pImageKey);
	void Release();

public:
	static CBmpMgr* Get_Instance()
	{
		if (!m_pInstance)
			m_pInstance = new CBmpMgr;
		return m_pInstance;
	}
	static void Destroy_Instance()
	{
    		if(m_pInstance)
        	{
        		delete m_pInstance;
          	  	m_pInstance = nullptr;
        	}
	}

private:
	static CBmpMgr*					m_pInstance;
	map<const TCHAR*, CLoadedBitmap*>		m_mapBit;
};

 

BmpMgr.cpp

 

#include "BmpMgr.h"
#include "LoadedBitmap.h"

CBmpMgr* CBmpMgr::m_pInstance = nullptr;
CBmpMgr::CBmpMgr()
{
}


CBmpMgr::~CBmpMgr()
{
	Release();
}

HDC CBmpMgr::Insert_Bmp(const TCHAR * _pFilePath, const TCHAR * _pImageKey)
{
	auto iter = find_if(m_mapBit.begin(), m_mapBit.end(), CStringCMP(_pImageKey));

	if (m_mapBit.end() == iter)
	{
		CLoadedBitmap* pBmp = new CMyBitmap;
		pBmp->Load_Bmp(_pFilePath);

		m_mapBit.emplace(_pImageKey, pBmp);
	}
    return iter->second->Get_MemDC();
}

HDC CBmpMgr::Find_Image(const TCHAR * _pImageKey)
{
	auto iter = find_if(m_mapBit.begin(), m_mapBit.end(), CStringCMP(_pImageKey));

	if (m_mapBit.end() == iter)
		return nullptr;

	return iter->second->Get_MemDC();
}

void CBmpMgr::Release()
{
	for (auto& iter : m_mapBit)
	{
		if (nullptr != iter.second)
		{
        		delete iter.second;
            		iter.second = nullptr;
        	}
	}
	m_mapBit.clear();
}

 

사용법

 

void CTest::Init()
{
	CBmpMgr::Get_Instance()->Insert_Bmp(L"TEST");
	m_hBackDC = CBmpMgr::Get_Instance()->Insert_Bmp(L"Background");
}

void CTest::Render()
{
	m_hMemDC = CBmpMgr::Get_Instance()->Find_Image(L"TEST");
	GdiTransparentBlt(m_hBackDC, m_tRect.left + iScrollX, m_tRect.top, m_tInfo.iCX, m_tInfo.iCY, 
    			hMemDC, 491 + ((min(4, m_iSpriteCount / 3)) * 49), 516, 48, 48, RGB(255, 0, 255));
}
	

특정 클래스에서 비트맵을 출력하려면 DC의 핸들을 받아 둔 후 블록 전송 함수를 사용하시면 됩니다.

 

 

StretchBlt나 TransparentBlt 등의 원시적인(?) 함수를 사용하려면

 

#pragma comment (lib, "Msimg32.lib")

 

이러한 전처리로 파일을 참조하도록 해야 하지만

함수 앞에 Gdi를 붙여 개선된버전의 블록 전송 함수를 사용한다면 위와같은 키워드는 필요 없습니다. (추천)

 

 

비트맵 툴의 경우 크기가 상당하기 때문에 부분적으로만 제공하도록 하겠습니다.

void CBitmapTool::DrawOriginBit(HDC _hDC, int _x, int _y, HDC _hMemDC)
{
	HDC MemDC;
	HBITMAP OldBit;
	int bx, by;
	BITMAP bit;

	MemDC = CreateCompatibleDC(_hDC);
	OldBit = (HBITMAP)SelectObject(MemDC, m_hObj);

	GetObject(m_hObj, sizeof(BITMAP), &bit);
	bx = bit.bmWidth;
	by = bit.bmHeight;

	BitBlt(_hDC, _x, _y, bx, by, _hMemDC, 0, 0, SRCCOPY);

	SelectObject(MemDC, OldBit);
	DeleteDC(MemDC);
}

비트맵의 원본 크기를 측정하여 _x, _y 위치에 출력하는 함수입니다.

 

void CBitmapTool::DrawPartBit(HDC _hDestDC, int _iDestX, int _iDestY, int _iDestW, int _iDestH, HDC _hMemDC, int _iSrcX, int _iSrcY, DWORD _dwRop)
{
	HDC MemDC;
	HBITMAP OldBit;

	MemDC = CreateCompatibleDC(m_hDC);
	OldBit = (HBITMAP)SelectObject(MemDC, m_hObj);


	BitBlt(_hDestDC, _iDestX, _iDestY, _iDestW, _iDestH, _hMemDC, _iSrcX, _iSrcY, SRCCOPY);

	SelectObject(MemDC, OldBit);
	DeleteDC(MemDC);
}

비트맵의 출력 크기를 조정할 수 있는 함수입니다.

 

 

void CBitmapTool::DrawStretchBit(HDC _hDestDC, int _iDestX, int _iDestY, int _iDestW, int _iDestH, HDC _hMemDC, int _iSrcX, int _iSrcY, int _iSrcW, int _iSrcH, DWORD _dwRop)
{
	HDC MemDC;
	HBITMAP OldBit;

	MemDC = CreateCompatibleDC(m_hDC);
	OldBit = (HBITMAP)SelectObject(MemDC, m_hObj);

	GdiStretchBlt(_hDestDC, _iDestX, _iDestY, _iDestW, _iDestH, _hMemDC, _iSrcX, _iSrcY, _iSrcW, _iSrcH, SRCCOPY);

	SelectObject(MemDC, OldBit);
	DeleteDC(MemDC);
}

 

원본 비트맵의 사각영역을 원하는 크기만큼 늘여 출력할 수 있는 함수입니다.

 

void CBitmapTool::DrawTransBit(HDC _hDestDC, int _iDestX, int _iDestY, int _iDestW, int _iDestH, HDC _hMemDC, int _iSrcX, int _iSrcY, int _iSrcW, int _iSrcH, COLORREF _rClr)
{
	HDC MemDC;
	HBITMAP OldBit;

	MemDC = CreateCompatibleDC(m_hDC);
	OldBit = (HBITMAP)SelectObject(MemDC, m_hObj);

	GdiTransparentBlt(_hDestDC, _iDestX, _iDestY, _iDestW, _iDestH, _hMemDC, _iSrcX, _iSrcY, _iSrcW, _iSrcH, _rClr);

	SelectObject(MemDC, OldBit);
	DeleteDC(MemDC);
}

 

원본 비트맵의 특정색을 투명화하고 크기를 늘여 출력할 수 있는 함수입니다.

 

void CBitmapTool::DrawAlphaBit(HDC _hDestDC, int _iDestX, int _iDestY, int _iDestW, int _iDestH, HDC _hMemDC, int _iSrcX, int _iSrcY, int _iSrcW, int _iSrcH, int _iAlpha, int _iBitOp)
{
	HDC MemDC;
	HBITMAP OldBit;

	MemDC = CreateCompatibleDC(m_hDC);
	OldBit = (HBITMAP)SelectObject(MemDC, m_hObj);

	BLENDFUNCTION bf;
	bf.AlphaFormat = _iBitOp;			// 일반 이미지는 0
	//bf.AlphaFormat = AC_SRC_ALPHA;	// 32bit 비트맵인 경우
	bf.BlendFlags = 0;
	bf.BlendOp = AC_SRC_OVER;
	bf.SourceConstantAlpha = _iAlpha;
	
	GdiAlphaBlend(_hDestDC, _iDestX, _iDestY, _iDestW, _iDestH, _hMemDC, _iSrcX, _iSrcY, _iSrcW, _iSrcH, bf);

	SelectObject(MemDC, OldBit);
	DeleteDC(MemDC);
}

 

비트맵에 알파값을 주어 반투명값을 줄 수 있는 함수입니다.