DuiLib改底层支持Icon图片显示

之前的那边文章通过自定义控件让icon图标直接绘制在控件上,这种方法虽然能显示icon图标,但如果想调整图标的大小和样式都要自己去改控件的代码不用使用DuiLib内部的一些属性(例如:padding, inset等),而且想要显示的icon的话必须使用控件,这样太不方便了。后来想过去改stb_image.c的底层解析代码,但我对icon的数据结构不是很了解,后来发现,DuiLib其实是通过stb_image这个图片解析引擎将其他(png, jpg...)都转换成统一的比特位数据结构,然后构造出一个bitmap,然后再绘制在屏幕上,也就是说DuiLib最后绘制的都是bmp格式的图片,这样,我们对于icon这种window风格的图标文件不需要去解析了,直接转换成bitmap就行了,这在vc下也很好实现。

现在UIRender.cpp 中 TImageInfo* CRenderEngine::LoadImage(STRINGorID bitmap, LPCTSTR type, DWORD mask) 前加个C风格的转换函数,C++成员函数也行。

HBITMAP ConvertIconToBitmap(HICON hIcon, int* x, int* y) 
{ 
	ICONINFO csII;
	if (!::GetIconInfo(hIcon, &csII))
		return NULL;
	DWORD dwWidth = csII.xHotspot * 2;
	DWORD dwHeight = csII.yHotspot * 2;
	*x = dwWidth;
	*y = dwHeight;
	HDC hDc = ::GetDC(NULL);
	HDC hMemDc = ::CreateCompatibleDC(hDc);
	HBITMAP hBitMap = ::CreateCompatibleBitmap(hDc, dwWidth , dwHeight);
	if (!hBitMap) return NULL;
	::SelectObject(hMemDc,hBitMap);
	::DrawIconEx(hMemDc, 0, 0, hIcon, dwWidth, dwHeight, 0, NULL, DI_NORMAL);
	::DeleteDC(hMemDc);
	::ReleaseDC(NULL, hDc);
	::DestroyIcon(hIcon);
	return hBitMap;
}
这个函数的作用是将HICON句柄转成HBITMAP句柄

然后在改下 CRenderEngine::LoadImage( ) 函数:

TImageInfo* CRenderEngine::LoadImage(STRINGorID bitmap, LPCTSTR type, DWORD mask)
{
	DuiLib::CDuiString str (bitmap.m_lpstr);
	if (0 == _tcscmp(_T(".ico"), str.Right(4)))
	{
		TCHAR szDrive[_MAX_DRIVE] = {0};
		TCHAR szDir[_MAX_DIR] = {0};
		TCHAR szFname[_MAX_FNAME] = {0};
		TCHAR szExt[_MAX_EXT] = {0};

		_tsplitpath_s(bitmap.m_lpstr, szDrive, szDir, szFname, szExt);
		if (_tcscmp(szExt, _T(".ico")) == 0)
		{
			CDuiString sFile;
			if (_tcscmp(szDrive, _T("")) == 0)
				sFile = CPaintManagerUI::GetResourcePath();
			sFile += bitmap.m_lpstr;
			HICON hIcon = (HICON)::LoadImage(NULL, sFile.GetData(), IMAGE_ICON, 0, 0, LR_LOADFROMFILE | LR_DEFAULTSIZE);
			if (NULL != hIcon)
			{
				TImageInfo* data = new TImageInfo;
				data->hBitmap = ConvertIconToBitmap(hIcon, &(data->nX), &(data->nY));
				data->alphaChannel = true;
				data->dwMask = mask;
				return data;
			}
		}
	}

    LPBYTE pData = NULL;
    DWORD dwSize = 0;

	do 
	{
		if( type == NULL ) {
			CDuiString sFile = CPaintManagerUI::GetResourcePath();
			if( CPaintManagerUI::GetResourceZip().IsEmpty() ) {
				sFile += bitmap.m_lpstr;
				HANDLE hFile = ::CreateFile(sFile.GetData(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, \
					FILE_ATTRIBUTE_NORMAL, NULL);
				if( hFile == INVALID_HANDLE_VALUE ) break;
				dwSize = ::GetFileSize(hFile, NULL);
				if( dwSize == 0 ) break;

				DWORD dwRead = 0;
				pData = new BYTE[ dwSize ];
				::ReadFile( hFile, pData, dwSize, &dwRead, NULL );
				::CloseHandle( hFile );

				if( dwRead != dwSize ) {
					delete[] pData;
					pData = NULL;
					break;
				}
			}
			else {
				sFile += CPaintManagerUI::GetResourceZip();
				HZIP hz = NULL;
				if( CPaintManagerUI::IsCachedResourceZip() ) hz = (HZIP)CPaintManagerUI::GetResourceZipHandle();
				else hz = OpenZip((void*)sFile.GetData(), 0, 2);
				if( hz == NULL ) break;
				ZIPENTRY ze; 
				int i; 
				if( FindZipItem(hz, bitmap.m_lpstr, true, &i, &ze) != 0 ) break;
				dwSize = ze.unc_size;
				if( dwSize == 0 ) break;
				pData = new BYTE[ dwSize ];
				int res = UnzipItem(hz, i, pData, dwSize, 3);
				if( res != 0x00000000 && res != 0x00000600) {
					delete[] pData;
					pData = NULL;
					if( !CPaintManagerUI::IsCachedResourceZip() ) CloseZip(hz);
					break;
				}
				if( !CPaintManagerUI::IsCachedResourceZip() ) CloseZip(hz);
			}
		}
		else {
			HRSRC hResource = ::FindResource(CPaintManagerUI::GetResourceDll(), bitmap.m_lpstr, type);
			if( hResource == NULL ) break;
			HGLOBAL hGlobal = ::LoadResource(CPaintManagerUI::GetResourceDll(), hResource);
			if( hGlobal == NULL ) {
				FreeResource(hResource);
				break;
			}

			dwSize = ::SizeofResource(CPaintManagerUI::GetResourceDll(), hResource);
			if( dwSize == 0 ) break;
			pData = new BYTE[ dwSize ];
			::CopyMemory(pData, (LPBYTE)::LockResource(hGlobal), dwSize);
			::FreeResource(hResource);
		}
	} while (0);

	while (!pData)
	{
		//读不到图片, 则直接去读取bitmap.m_lpstr指向的路径
		HANDLE hFile = ::CreateFile(bitmap.m_lpstr, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, \
			FILE_ATTRIBUTE_NORMAL, NULL);
		if( hFile == INVALID_HANDLE_VALUE ) break;
		dwSize = ::GetFileSize(hFile, NULL);
		if( dwSize == 0 ) break;

		DWORD dwRead = 0;
		pData = new BYTE[ dwSize ];
		::ReadFile( hFile, pData, dwSize, &dwRead, NULL );
		::CloseHandle( hFile );

		if( dwRead != dwSize ) {
			delete[] pData;
			pData = NULL;
		}
		break;
	}
	if (!pData)
	{
		//::MessageBox(0, _T("读取图片数据失败!"), _T("抓BUG"), MB_OK);
		return NULL;
	}

    LPBYTE pImage = NULL;
    int x,y,n;
    pImage = stbi_load_from_memory(pData, dwSize, &x, &y, &n, 4);
    delete[] pData;
	if( !pImage ) {
		//::MessageBox(0, _T("解析图片失败"), _T("抓BUG"), MB_OK);
		return NULL;
	}

    BITMAPINFO bmi;
    ::ZeroMemory(&bmi, sizeof(BITMAPINFO));
    bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
    bmi.bmiHeader.biWidth = x;
    bmi.bmiHeader.biHeight = -y;
    bmi.bmiHeader.biPlanes = 1;
    bmi.bmiHeader.biBitCount = 32;
    bmi.bmiHeader.biCompression = BI_RGB;
    bmi.bmiHeader.biSizeImage = x * y * 4;

    bool bAlphaChannel = false;
    LPBYTE pDest = NULL;
    HBITMAP hBitmap = ::CreateDIBSection(NULL, &bmi, DIB_RGB_COLORS, (void**)&pDest, NULL, 0);
	if( !hBitmap ) {
		//::MessageBox(0, _T("CreateDIBSection失败"), _T("抓BUG"), MB_OK);
		return NULL;
	}

    for( int i = 0; i < x * y; i++ ) 
    {
        pDest[i*4 + 3] = pImage[i*4 + 3];
        if( pDest[i*4 + 3] < 255 )
        {
            pDest[i*4] = (BYTE)(DWORD(pImage[i*4 + 2])*pImage[i*4 + 3]/255);
            pDest[i*4 + 1] = (BYTE)(DWORD(pImage[i*4 + 1])*pImage[i*4 + 3]/255);
            pDest[i*4 + 2] = (BYTE)(DWORD(pImage[i*4])*pImage[i*4 + 3]/255); 
            bAlphaChannel = true;
        }
        else
        {
            pDest[i*4] = pImage[i*4 + 2];
            pDest[i*4 + 1] = pImage[i*4 + 1];
            pDest[i*4 + 2] = pImage[i*4]; 
        }

        if( *(DWORD*)(&pDest[i*4]) == mask ) {
            pDest[i*4] = (BYTE)0;
            pDest[i*4 + 1] = (BYTE)0;
            pDest[i*4 + 2] = (BYTE)0; 
            pDest[i*4 + 3] = (BYTE)0;
            bAlphaChannel = true;
        }
    }

    stbi_image_free(pImage);

    TImageInfo* data = new TImageInfo;
    data->hBitmap = hBitmap;
    data->nX = x;
    data->nY = y;
    data->alphaChannel = bAlphaChannel;
    return data;
}

这样就可以了,改了底层,DuiLib就直接可以像其他图片格式一样使用.ico文件了。:)



你可能感兴趣的:(DuiLib)