🧼C, C++/WinAPI, UX(UI)

HDC를 이미지로 저장 (HDC -> HBITMAP) - C++ / GDI+

Mawile 2021. 4. 29.
728x90

개발환경 >> Visual Studio

언어 >> C++17이상

운영체제 >> Windows10


 

안녕하세요~!!

이번에 시험이 끝난기분으로 만들어본 예제입니다!

우선은 HDC라는 것은 WINAPI GDI에서 그림판?? 미술로따지면 스케치북 같은 개념입니다!

그러한 스케치북에다가 그린그림을 실제 사진파일로 출력하는 예제입니다!!

저가 결심한게 있는데, 이러한 강좌나 예제글을 진행할때는 소스코드에 주석을 최대한 자세하게 달려구요!

 

 

[ 예제(HDC를 이미지로 저장) ]

#pragma comment(lib, "gdiplus.lib") //gdiplus 라이브러리사용링킹입니다.

#include <windows.h> //윈도우api사용!
#include <gdiplus.h> //gdi+사용!
#include <conio.h> //getch()메서드 사용!

/* 인자로 전달받은 clsid에 특정 포맷형식값을 전달하는 메서드입니다! */
void Encoding(CLSID* clsid) {
	UINT num, size;
	Gdiplus::GetImageEncodersSize(&num, &size); //인코더크기구하기
	Gdiplus::ImageCodecInfo* codec = new Gdiplus::ImageCodecInfo[size]; //특정크기만큼 코덱객체 동적할당
	Gdiplus::GetImageEncoders(num, size, codec); //이미지인코딩정보 구하기

	for (int i = 0; i < num; i++) { //for문으로 순회하면서
    
    /*
    
    [ 존재하는 이미지포맷 형식 ]
    image/bmp
    image/jpeg
    image/gif
    image/tiff
    image/png

    */
    
		if (!wcscmp(L"image/jpeg", codec[i].MimeType)) { //만약 jpeg형식 포맷형식이 있다면
			*clsid = codec[i].Clsid; //그때의 clsid값을 대입하고
			break; //for문 나가기(값을 찾았으니까)
		}
	}

	delete[] codec; //메모리누수방지
}

/* 인자로전달받은 hbitmap을 파일로 저장!! */
void hdcTofile(HBITMAP hBit) { //정확히는 hbitmap -> file
	CLSID clsid; //clsid
	Gdiplus::Bitmap* bit = new Gdiplus::Bitmap(500, 500); //내용이없는 빈 500x500의 비트맵객체생성
	Encoding(&clsid); //clsid에다가 jpeg에 대한 인코딩정보 넣기
	bit = bit->FromHBITMAP(hBit, 0); //hbitmap내용을 통하여 bit라는 비트맵객체에 값대입
	bit->Save(L"test.jpg", &clsid); //파일로 저장
}

int main(void) {
	ULONG_PTR ptr; //gdi+상태정보저장을 위한 포인터객체
	RECT	rect = { 0, 0, 500, 500 }, //비트맵크기
			rect_tmp = { 50, 50, 200, 200 }; //텍스트내용
	Gdiplus::GdiplusStartupInput inp; //gdi+시작에대한 입력값 객체
	Gdiplus::GdiplusStartup(&ptr, &inp, 0); //gdi+시작
	
	HDC hdc = GetDC(GetConsoleWindow()); //콘솔창에대한 핸들값을 hdc로 변환하여 저장(콘솔창에 출력될 스케치북)
	HDC MemoryDC = CreateCompatibleDC(hdc); //그릴수있는 dc생성(파일로 출력될 스케치북)
	HBITMAP hBit = CreateCompatibleBitmap(hdc, 500, 500); //그릴수있는 bitmap생성
	SelectObject(MemoryDC, hBit); //윗윗줄에 생성한 dc에다가 윗줄에서 생성한 bitmap연결
	HBRUSH hBrush = CreateSolidBrush(RGB(255, 0, 0)); //빨간색 브러쉬만들기
	HFONT hFont = CreateFontW(20, 5, 0, 0, FW_BOLD, 0, 0, 0, 0, 0, 0, 20, 0, L"굴림체"); //굴림체의 굵은 20x5크기의 폰트만들기


	HGDIOBJ obj1 = SelectObject(MemoryDC, hFont); //파일로출력될 dc에 폰트적용
	HGDIOBJ obj2 = SelectObject(MemoryDC, hBrush); //파일로출력될 dc에 브러쉬적용
	Rectangle(MemoryDC, 0, 0, 200, 200); //메모리dc에다가 200x200크기의 사각형 그리기
	DrawText(MemoryDC, L"test", -1, &rect_tmp, DT_CENTER | DT_WORDBREAK); //"test"라는 내용의 텍스트그리기

	HGDIOBJ obj3 = SelectObject(hdc, hBrush); //콘솔창으로출력될 dc에 브러쉬적용
	Rectangle(hdc, 0, 0, 200, 200); //dc에다가 200x200크기의 사각형 그리기
	DrawText(hdc, L"test", -1, &rect_tmp, DT_CENTER | DT_WORDBREAK); //"test"라는 내용의 텍스트그리기


	BitBlt(hdc, 0, 0 ,500, 500, MemoryDC, 0, 0, SRCCOPY);
    /*
    사실 이거는 여기서는 굳이 사용할 필요없습니다
    왜냐하면 위 메서드는 왼쪽에있는 dc에다가 오른쪽에있는 dc의 내용을 그리는건데
    (쉽게말하면 파일로출력될 스케치북의 그림을 콘솔창에 출력될 스케치북에 따라그리는 부분)
    위와같이 MemoryDC와 hdc둘다 똑같이 그려놨기때문입니다.
    */
    
	hdcTofile(hBit); //실제 픽셀정보는 hBit에 있으므로 전달!!
	
	SelectObject(MemoryDC, obj1); //메모리누수방지용
	DeleteObject(hFont); //메모리누수방지용
	SelectObject(MemoryDC, obj2); //메모리누수방지용
	SelectObject(hdc, obj3); //메모리누수방지용
	DeleteObject(hBrush); //메모리누수방지용
	DeleteDC(MemoryDC); //메모리누수방지용
	ReleaseDC(GetConsoleWindow(), hdc); //메모리누수방지용
	
	_getch(); //콘솔창 멈추기
}

 

 

으악!!! 주석달기 엄청힘드네 ㅠㅠㅠㅠㅠ

 

자 ~!!! 이제 프로그램을 실행해보겠습니다!!

 

 

 

와우~!!!

저가 처음 설계했던 500x500의 빈 비트맵에다가 200x200의 빨간색 사각형과

(50,50) 좌표다가 "test"라는 택스트가 그려져있는 그림이 만들어졌습니다!!!!

 

 

그 사진입니다!

만약에 저기서 텍스트에 배경색과 텍스트색을 바꾸고 싶다면 "SetbkColor메서드와 SetTextColor메서드를 사용하시면 됩니다!!!"

 

 

이것만 있으면 저번에 포스팅했던 "이미지 픽셀정보 직렬화"이라는 글에서 설명드렸던 소스와 결합하여

실시간으로 그림을 그려가지고 서로 정보를 전달하는 "캐치마인드"게임을 구현할 수 있습니다.

 

 


 

 

그럼 안녕~!!!!

728x90

'🧼C, C++ > WinAPI, UX(UI)' 카테고리의 다른 글

이벤트 제어 c/c++  (0) 2021.09.10
GDI+ 강좌 총정리  (0) 2021.04.22
이미지 픽셀정보 직렬화 - C++ / GDI+  (0) 2021.04.15
png파일 출력하기 WINAPI C++  (0) 2021.04.13
파일 자가복제 C++ #2  (0) 2020.11.23

댓글