// GDI+ library를 사용해 bmp, png, jpg, gif 등 대부분의 이미지 형식 모두 처리 가능하다.
#include <GdiPlus.h>
#pragma comment(lib, "gdiplus")
using namespace Gdiplus;
int __stdcall GetEncoderClsid(const WCHAR *mime, CLSID *clsid)
{
UINT i, num, size;
ImageCodecInfo *info;
GetImageEncodersSize(&num, &size);
if (!size)
return -1;
if (!(info = (ImageCodecInfo*)malloc(size)))
return -1;
GetImageEncoders(num, size, info);
for (i = 0; i < num; ++i)
{
if (0 == lstrcmpiW(info[i].MimeType, mime))
{
*clsid = info[i].Clsid;
free(info);
return i; // success
}
}
free(info);
return -1;
}
#if defined(UNICODE) || defined(_UNICODE)
#define _tcsistr wcsistr
#else
#define _tcsistr stristr
#endif
char * __stdcall stristr(const char *src, const char *fnd)
{
const char *p, *q;
char a, b;
for (; ; ++src)
{
for (p = src, q = fnd; *q; ++p, ++q) // 빠른 실행 위해 *p 조건은 넣지 않는다. 안의 문자 불일치 조건으로 처리된다.
{
if (*p <= 'Z' && *p >= 'A') {a = *p + 0x20;} else {a = *p;} // 'A' 이상인 경우가 훨씬 많으므로 'Z' 이하 조건을 앞에 두는게 효율적이다.
if (*q <= 'Z' && *q >= 'A') {b = *q + 0x20;} else {b = *q;}
if (a != b)
break;
}
if (!*q)
return (char *)src;
if (!*src)
break;
}
return NULL;
}
wchar_t * __stdcall wcsistr(const wchar_t *src, const wchar_t *fnd)
{
const wchar_t *p, *q;
wchar_t a, b;
for (; ; ++src)
{
for (p = src, q = fnd; *q; ++p, ++q)
{
if (*p <= 'Z' && *p >= 'A') {a = *p + 0x20;} else {a = *p;}
if (*q <= 'Z' && *q >= 'A') {b = *q + 0x20;} else {b = *q;}
if (a != b)
break;
}
if (!*q)
return (wchar_t *)src;
if (!*src)
break;
}
return NULL;
}
int __stdcall BitmapToFile(HBITMAP hBmp, const WCHAR *path = NULL, const WCHAR *mime = NULL)
{
int i, len, ret;
BOOL bExtensionFound;
SYSTEMTIME st;
ULONG_PTR gdiplusToken;
GdiplusStartupInput gdiplusStartupInput;
CLSID clsid;
WCHAR *p, *pExt, wszPath[256], wszMime[256];
if (!path) // 경로를 전달하지 않은 경우 프로그램 디렉토리에 "Image_날짜_시간" 파일을 생성한다.
{
GetModuleFileNameW(NULL, wszPath, 255);
if (p = wcsrchr(wszPath, L'\\'))
{
if (!mime) // 이미지 형식을 지정하지 않은 경우 디폴트로 png 생성
pExt = L"png";
else if (pExt = wcsistr(mime, L"image/")) // 이미지 형식을 표현 규격에 맞춰 전달한 경우 확장자 부분만 구한다.
pExt += 6/*lstrlenW(L"image/")*/; // "image/" 문자열 부분을 건너뛴다.
else // bmp, jpeg, png 등 간단히 전달한 경우
pExt = (WCHAR *)mime;
GetLocalTime(&st);
wsprintfW(++p, L"Image_%04u-%02u-%02u_%02u.%02u.%02u.%03u.%s", st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond, st.wMilliseconds, pExt);
path = wszPath;
}
else
{
MessageBoxW(NULL, L"Invalid file path", L"BitmapToFile", MB_ICONERROR);
return 0;
}
}
if (mime) // 이미지 형식을 지정한 경우
{
if (wcsistr(mime, L"jpg")) // jpg인 경우 정식 표현 규격인 jpeg로 수정
{
mime = L"image/jpeg";
}
else if (!wcsistr(mime, L"image/")) // bmp, jpeg, png 등 간단히 전달한 경우 표현 규격에 맞춘다.
{
wsprintfW(wszMime, L"image/%s", mime);
mime = wszMime;
}
}
else // 이미지 형식을 지정하지 않은 경우 파일 확장자를 구해 표현 규격에 맞춘다.
{
bExtensionFound = FALSE;
len = lstrlenW(path);
if (len >= 3) // 파일명.확장자 형식이므로 길이가 최소 3 이상이어야 한다.
{
p = (WCHAR *)path + len - 2; // 확장자는 . 뒤에 문자열 형식이므로 논리상 -2해도 된다.
i = 32; // 반복횟수 제한. 정상적인 확장자라면 아무리 길이도 32자 이내일 것이다.
do // 논리적으로 첫 조건은 항상 참이므로 for문 대신 do while문으로 구성
{
if (*p == L'.')
{
bExtensionFound = TRUE;
++p;
if (0 == lstrcmpiW(p, L"jpg")) // jpg인 경우 정식 표현 규격인 jpeg로 수정
{
mime = L"image/jpeg";
}
else
{ wsprintfW(wszMime, L"image/%s", p); // 표현 규격
mime = wszMime;
}
break;
}
}
while (--p > path && --i); // 시작위치보다 뒤 && 지정한 확장자 길이 제한내
}
if (!bExtensionFound)
{
MessageBoxW(NULL, L"File extension not found", L"BitmapToFile", MB_ICONERROR);
return 0;
}
}
ret = 0; // 리턴값 초기화
if (Ok == GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL))
{
if (GetEncoderClsid(mime, &clsid) >= 0)
{
//Gdiplus::Bitmap gBmp(hBmp, NULL); // 스택에 지역변수로 생성. 아래 해제 부분에서 delete문을 주석처리한다.
Gdiplus::Bitmap *pBmp = Gdiplus::Bitmap::FromHBITMAP(hBmp, NULL); // new 연산자로 객체 생성
if (pBmp)
{
if (Ok == pBmp->Save(path, &clsid))
{
ret = 1;
}
else
{
MessageBoxW(NULL, L"Failed to save image file", L"BitmapToFile", MB_ICONERROR);
}
delete pBmp;
}
else
{
MessageBoxW(NULL, L"Failed to create Gdiplus::Bitmap object", L"BitmapToFile", MB_ICONERROR);
}
}
else
{
MessageBoxW(NULL, L"Failed to find the mime encoder", L"BitmapToFile", MB_ICONERROR);
}
GdiplusShutdown(gdiplusToken);
}
else
{
MessageBoxW(NULL, L"Falied to initalize GDI+ library", L"BitmapToFile", MB_ICONERROR);
}
return ret;
}
HBITMAP __stdcall FileToBitmap(const WCHAR *path)
{
HBITMAP hBmp;
ULONG_PTR gdiplusToken;
GdiplusStartupInput gdiplusStartupInput;
hBmp = NULL; // 리턴값 초기화
if (Ok == GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL))
{
Gdiplus::Bitmap *pBmp = Gdiplus::Bitmap::FromFile(path);
if (pBmp)
{
if (Ok == pBmp->GetHBITMAP(Color(0, 0, 0), &hBmp))
{
}
else
{
MessageBoxW(NULL, L"Failed to Get HBITMAP", L"FileToBitmap", MB_ICONERROR);
}
delete pBmp;
}
else
{
MessageBoxW(NULL, L"Failed to create Gdiplus::Bitmap object", L"FileToBitmap", MB_ICONERROR);
}
GdiplusShutdown(gdiplusToken);
}
else
{
MessageBoxW(NULL, L"Falied to initalize GDI+ library", L"FileToBitmap", MB_ICONERROR);
}
return hBmp;
}