이 소스 코드는 rk HDRi Studio 을 만들면서 필요에 의해서 만들어진 것 입니다만, FLTK 에서 자체적으로 윈도우를 만들어 쓸 때, 아이콘을 그리고 싶은데 막상 HICON 을 이미지 원본으로는 쓸 수 없을때 Alpha 를 가진 32bit RGB 이미지로 만들어 쓰기에 좋다고 하겠습니다.
먼저 icon_to_flrgb() 함수는 다음과 같습니다.
Fl_RGB_Image* icon_to_flrgb(HICON hIcon)
{
BITMAP bm;
ICONINFO iconInfo;
GetIconInfo(hIcon, &iconInfo);
GetObject(iconInfo.hbmColor, sizeof(BITMAP),&bm);
int width = bm.bmWidth;
int height = bm.bmHeight;
int bytesPerScanLine = (width * 3 + 3) & 0xFFFFFFFC;
int size = bytesPerScanLine * height;
BITMAPINFO infoheader = {0};
infoheader.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
infoheader.bmiHeader.biWidth = width;
infoheader.bmiHeader.biHeight = height;
infoheader.bmiHeader.biPlanes = 1;
infoheader.bmiHeader.biBitCount = 24;
infoheader.bmiHeader.biCompression = BI_RGB;
infoheader.bmiHeader.biSizeImage = size;
⁄⁄ allocate Memory for Icon RGB data plus Icon mask plus ARGB buffer for the resulting image
unsigned char* pixelsIconRGB = new unsigned char[ height * width * 4 ];
if ( pixelsIconRGB == NULL )
{
return NULL;
}
unsigned char* alphaPixels = new unsigned char[ height * width * 4 ];
if ( alphaPixels == NULL )
{
delete[] pixelsIconRGB;
return NULL;
}
unsigned char* imagePixels = new unsigned char[ height * width * 4 ];
if ( imagePixels == NULL )
{
delete[] pixelsIconRGB;
delete[] alphaPixels;
return NULL;
}
HDC hDC = CreateCompatibleDC(NULL);
if ( hDC == NULL )
{
delete[] pixelsIconRGB;
delete[] alphaPixels;
return NULL;
}
HBITMAP hBmpOld = (HBITMAP)SelectObject(hDC, (HGDIOBJ)iconInfo.hbmColor);
if( GetDIBits(hDC, iconInfo.hbmColor, 0, height, (LPVOID) pixelsIconRGB, &infoheader, DIB_RGB_COLORS) == 0 )
{
DeleteDC(hDC);
delete[] pixelsIconRGB;
delete[] alphaPixels;
delete[] imagePixels;
return NULL;
}
SelectObject(hDC, hBmpOld);
⁄⁄ now get the mask
if( GetDIBits(hDC, iconInfo.hbmMask, 0,height,(LPVOID)alphaPixels, &infoheader, DIB_RGB_COLORS) == 0 )
{
DeleteDC(hDC);
delete[] pixelsIconRGB;
delete[] alphaPixels;
delete[] imagePixels;
return NULL;
}
DeleteDC(hDC);
int x=0;
int currentSrcPos=0;
int currentDestPos=0;
int linePosSrc = 0;
int linePosDest = 0;
int vsDest = height-1;
for(int y=0; y<height; y++)
{
linePosSrc = ( vsDest - y ) * ( width * 3 );
linePosDest = y * width * 4;
for(x=0; x<width; x++)
{
currentDestPos = linePosDest + ( x * 4 );
currentSrcPos = linePosSrc + ( x * 3);
imagePixels[ currentDestPos + 0 ] = pixelsIconRGB[ currentSrcPos + 2 ];
imagePixels[ currentDestPos + 1 ] = pixelsIconRGB[ currentSrcPos + 1 ];
imagePixels[ currentDestPos + 2 ] = pixelsIconRGB[ currentSrcPos + 0 ];
imagePixels[ currentDestPos + 3 ] = 0xFF - alphaPixels[ currentSrcPos ];
}
}
Fl_RGB_Image* pImage = new Fl_RGB_Image( imagePixels, width, height, 4 );
delete[] pixelsIconRGB;
delete[] alphaPixels;
return pImage;
}
그리고, 변환된 Fl_RGB_Image 는 다음 함수로 지우던지, 이와 같은 역활을 하는 코드를 만들어서 쓰면 됩니다.
void remove_fl_rgb_image( Fl_RGB_Image** img )
{
if ( img != NULL )
{
Fl_RGB_Image* srci = (Fl_RGB_Image*)*img;
if ( ( srci->array != NULL ) && ( srci->alloc_array == 0 ) )
{
delete[] srci->array;
}
delete srci;
*img = NULL;
}
}
실제 사용은 다음처럼 하시면 됩니다.
⁄⁄ Load small ICON in size 16x16.
HICON hIconWindowSmall = (HICON)LoadImage( fl_display,MAKEINTRESOURCE( IDC_ICON_A ),IMAGE_ICON,16,16,LR_SHARED );
⁄⁄ Convert HICON to Fl_RGB_Image ..
Fl_RGB_Image* convtitleiconimg = icon_to_flrgb( hIconWindowSmall );
if ( convtitleiconimg != NULL )
{
window_title_box->image( convtitleiconimg );
}
⁄⁄ .... something do .... and now .
remove_fl_rgb_image( &convtitleiconimg );
마지막 예제 처럼 remove_fl_rgb_image() 로 만들었던 이미지를 지우지 않으면 메모리에 계속 RGBA 이미지 배열이 남아 있게 되어 메모리 누수의 원인이 되므로, 반드시 사용해 주시기 바랍니다.