본문 바로가기

Developement/C/C++

[FLTK] HICON 에서 Fl_RGB_Image 로 변환.


 이 소스 코드는 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 이미지 배열이 남아 있게 되어 메모리 누수의 원인이 되므로, 반드시 사용해 주시기 바랍니다.