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

png파일 출력하기 WINAPI C++

Mawile 2021. 4. 13.
728x90

 

 

개발환경 >> Visual Studio

언어 >> C++17이상

운영체제 >> Windows10

 


 

안녕하세요~~!

이번에는 C++17이상에서 기존 winapi에서 BMP파일을 출력하는것이외의 PNG나 JPG같은 이미지파일들을

출력하는 방법에 대해서 포스팅하겠습니다!

우선은 기본적인 winapi에서 png나 jpg같은 이미지파일은 지원을 안해주지만, gdi+를 이용해서 자유자재로 다뤄보겠습니다.

 


GDI+를 이용해서 콘솔창에다가 이미지출력하기
#pragma comment(linker, "/SUBSYSTEM:CONSOLE") //콘솔프로그램으로 만들겠다고 명시
#pragma comment(lib, "gdiplus.lib") //gdiplus라이브러리

#include <sstream> //실행시간 출력을 위한 문자열스트림클래스
#include <chrono> //실행시간 측정을 위한 시간관련클래스
#include <windows.h> //windowsAPI사용을 위한 헤더
#include <gdiplus.h> //gdiplus사용을 위한 헤더
#include <conio.h> //_getch()함수사용을 위한 헤더

void ClsCursor() { //콘솔커서 거슬려서 없애는함수 만들었습니다.
	CONSOLE_CURSOR_INFO curinfo;
	GetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE), &curinfo); //현재 콘솔커서값가져오기
	curinfo.bVisible = FALSE; //안보이게 만들고
	SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE), &curinfo); //콘솔커서설정
}

void gdi(const wchar_t* filepath) {
	ClsCursor();
	HWND hwnd = GetConsoleWindow(); //콘솔창핸들값 구하기
	HDC hdc = GetDC(hwnd); //핸들값으로 DC구하기
	HDC MemoryDC = CreateCompatibleDC(hdc); //사용할수있는 DC생성

	ULONG_PTR ptr; //Gdi+사용을 위한 포인터객체
	Gdiplus::GdiplusStartupInput in; //gdi+입력값객체
	Gdiplus::GdiplusStartup(&ptr, &in, 0); //시작

	std::chrono::time_point start = std::chrono::system_clock::now(); //시간측정시작

	Gdiplus::Image* b = Gdiplus::Image::FromFile(filepath); //이미지객체생성
	Gdiplus::Graphics g(hdc); // DC를 이용한 그래픽객체 생성
	Gdiplus::Rect rect; //위치값
	rect.X = 0; //x좌표
	rect.Y = 0; //y좌표
	rect.Width = b->GetWidth(); //가로길이
	rect.Height = b->GetHeight(); //세로길이
	g.DrawImage(b, rect); //이미지그리기

	ReleaseDC(hwnd, hdc); //메모리누수방지용
	DeleteDC(hdc);
	delete b;
    
	std::chrono::duration<double> d = std::chrono::system_clock::now() - start; //시간측정끝
	std::stringstream ss; //문자열스트림클래스정의
	std::string str; //문자열클래스정의
	ss << "수행하는데걸린시간:" << d.count() << "초"; //문자열스트림에 값넣기
	ss >> str; //문자열스트림의 내용을 문자열에 넣기
	MessageBoxA(0, str.c_str(), "", MB_OK); //메세지박스로 출력

	if (_getch()) return; //콘솔창 멈추기
}

int main() {
	gdiPlus(L"index.png");
}

 

위와 같이 코드를 짰습니다~!

 

 

저는 위의 그림으로 지정했습니다!그러면 실행하면??!??!

 

 

 

 

여러번 실행해보니,,처음에는 0.012 ~ 0.014초정도로

나오다가계속실행하다보니0.009~0.011초가 많이 나왔습니다.

 

근데~! 저가 어디서 들었는데 gdi+랑 gdi를 합치면 속도가 빨라진다는소리를 들어서 이 부분도 직접 구현해보았습니다.

 

 

GDI+랑 GDI를 혼합해서 콘솔창에다가 이미지출력하기
#pragma comment(linker, "/SUBSYSTEM:CONSOLE") //콘솔프로그램으로 만들겠다고 명시
#pragma comment(lib, "gdiplus.lib") //gdiplus라이브러리

#include <sstream> //실행시간 출력을 위한 문자열스트림클래스
#include <chrono> //실행시간 측정을 위한 시간관련클래스
#include <windows.h> //windowsAPI사용을 위한 헤더
#include <gdiplus.h> //gdiplus사용을 위한 헤더
#include <conio.h> //_getch()함수사용을 위한 헤더

void ClsCursor() { //콘솔커서 거슬려서 없애는함수 만들었습니다.
	CONSOLE_CURSOR_INFO curinfo;
	GetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE), &curinfo); //현재 콘솔커서값가져오기
	curinfo.bVisible = FALSE; //안보이게 만들고
	SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE), &curinfo); //콘솔커서설정
}

void gdi(const wchar_t* filepath) {
	ClsCursor();
	HWND hwnd = GetConsoleWindow(); //콘솔창핸들값 구하기
	HDC hdc = GetDC(hwnd); //핸들값으로 DC구하기
	HDC MemoryDC = CreateCompatibleDC(hdc); //사용할수있는 DC생성

	ULONG_PTR ptr; //Gdi+사용을 위한 포인터객체
	Gdiplus::GdiplusStartupInput in; //gdi+입력값객체
	Gdiplus::GdiplusStartup(&ptr, &in, 0); //시작

	std::chrono::time_point start = std::chrono::system_clock::now(); //시간측정시작

	Gdiplus::Bitmap* b = Gdiplus::Bitmap::FromFile(filepath); //파일로부터 비트맵받기
	HBITMAP hBit; //HBITMAP구조체 선언
	b->GetHBITMAP(Gdiplus::Color(0, 0, 0, 0), &hBit); 비트맵정보를 HBITMAP에 복사

	HGDIOBJ obj = SelectObject(MemoryDC, hBit); //MemoryDC에다가 비트맵지정
	BITMAP bit = { 0 }; //비트맵크기를 구하기위한 구조체
	GetObject(hBit, sizeof BITMAP, &bit); //비트맵크기구하기위함
	StretchBlt(hdc, 0, 0, bit.bmWidth, bit.bmHeight,
    	MemoryDC, 0, 0, bit.bmWidth, bit.bmHeight, SRCCOPY); //그리기
	SelectObject(MemoryDC, obj); //밑부분은 메모리누수를 막기위함
	DeleteObject(hBit);
	ReleaseDC(hwnd, MemoryDC);
	DeleteDC(hdc);
	delete b;

	std::chrono::duration<double> d = std::chrono::system_clock::now() - start; //시간측정끝
	std::stringstream ss; //문자열스트림클래스정의
	std::string str; //문자열클래스정의
	ss << "수행하는데걸린시간:" << d.count() << "초"; //문자열스트림에 값넣기
	ss >> str; //문자열스트림의 내용을 문자열에 넣기
	MessageBoxA(0, str.c_str(), "", MB_OK); //메세지박스로 출력

	if (_getch()) return; //콘솔창 멈추기
}

int main() {
	gdi(L"index.png");
}

 

위와 같이 코드를 짰습니다~!

 

 

 

저는 위의 그림으로 지정했습니다!

그러면 실행하면??!??!

 

 

 

 

여러번 실행해보니,,처음에는 0.011~ 0.012초정도로 나오다가

계속실행하다보니0.006~0.008초가 많이 나왔습니다.

 

 

 

 

확실히 GDI+만 썼을때는 0.0010가 많이 나왔고,

GDI+와 GDI를 혼합하여 썼을때는 0.008초가 많이 나오면서

약 0.002초가 절약되었습니다.

이것이 작은수치처럼 보여도 게임과 같이 같은이미지를 여러번 출력하게 된다면

시간이지날수록 그 격차는 점점더 커질수 있겠죠??

 

 


 

궁금한 부분이 있으면 댓글로 질문주세요!그럼 안녕~!~!~!
728x90

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

GDI+ 강좌 총정리  (0) 2021.04.22
이미지 픽셀정보 직렬화 - C++ / GDI+  (0) 2021.04.15
파일 자가복제 C++ #2  (0) 2020.11.23
WINAPI C++ #2  (0) 2020.11.07
WINAPI C++ #1  (0) 2020.11.04

댓글