Qt5调用QPixmap::fromWinHICON

QPixmap QPixmap::fromWinHICON ( HICON icon )  [static]

Win32 only: Returns a QPixmap  that is equivalent to the given icon.
Warning:This function is only available on Windows.
This function was introduced in Qt 4.6.

在5.2里面直接没有这个方法了,真是让人捉急.

去Qt4.7源码里翻了翻找到了 fromWinHICON的实现:


qt-everywhere-opensource-src-4.7.0\src\gui\image\qpixmap_win.cpp  line:283

其中引用到的函数 qMalloc() 在

qt-everywhere-opensource-src-4.7.0\src\corelib\global\qmalloc.cpp line:53

相关功能全部代码:


void *qMalloc(size_t size)
{
	return ::malloc(size);
}
void qFree(void *ptr)
{
	::free(ptr);
}
static QImage qt_fromWinHBITMAP(HDC hdc, HBITMAP bitmap, int w, int h)
{
	BITMAPINFO bmi;
	memset(&bmi, 0, sizeof(bmi));
	bmi.bmiHeader.biSize        = sizeof(BITMAPINFOHEADER);
	bmi.bmiHeader.biWidth       = w;
	bmi.bmiHeader.biHeight      = -h;
	bmi.bmiHeader.biPlanes      = 1;
	bmi.bmiHeader.biBitCount    = 32;
	bmi.bmiHeader.biCompression = BI_RGB;
	bmi.bmiHeader.biSizeImage   = w * h * 4;

	QImage image(w, h, QImage::Format_ARGB32_Premultiplied);
	if (image.isNull())
		return image;

	// Get bitmap bits
	uchar *data = (uchar *) qMalloc(bmi.bmiHeader.biSizeImage);

	if (GetDIBits(hdc, bitmap, 0, h, data, &bmi, DIB_RGB_COLORS)) {
		// Create image and copy data into image.
		for (int y=0; y<h; ++y) {
			void *dest = (void *) image.scanLine(y);
			void *src = data + y * image.bytesPerLine();
			memcpy(dest, src, image.bytesPerLine());
		}
	} else {
		qWarning("qt_fromWinHBITMAP(), failed to get bitmap bits");
	}
	qFree(data);

	return image;
}
QPixmap fromWinHICON(HICON icon)//qt4.7 QPixmap::fromWinHICON(hIcon)
{
	bool foundAlpha = false;
	HDC screenDevice = GetDC(0);
	HDC hdc = CreateCompatibleDC(screenDevice);
	ReleaseDC(0, screenDevice);

	ICONINFO iconinfo;
	bool result = GetIconInfo(icon, &iconinfo); //x and y Hotspot describes the icon center
	if (!result)
		qWarning("QPixmap::fromWinHICON(), failed to GetIconInfo()");

	int w = iconinfo.xHotspot * 2;
	int h = iconinfo.yHotspot * 2;

	BITMAPINFOHEADER bitmapInfo;
	bitmapInfo.biSize        = sizeof(BITMAPINFOHEADER);
	bitmapInfo.biWidth       = w;
	bitmapInfo.biHeight      = h;
	bitmapInfo.biPlanes      = 1;
	bitmapInfo.biBitCount    = 32;
	bitmapInfo.biCompression = BI_RGB;
	bitmapInfo.biSizeImage   = 0;
	bitmapInfo.biXPelsPerMeter = 0;
	bitmapInfo.biYPelsPerMeter = 0;
	bitmapInfo.biClrUsed       = 0;
	bitmapInfo.biClrImportant  = 0;
	DWORD* bits;

	HBITMAP winBitmap = CreateDIBSection(hdc, (BITMAPINFO*)&bitmapInfo, DIB_RGB_COLORS, (VOID**)&bits, NULL, 0);
	HGDIOBJ oldhdc = (HBITMAP)SelectObject(hdc, winBitmap);
	DrawIconEx( hdc, 0, 0, icon, iconinfo.xHotspot * 2, iconinfo.yHotspot * 2, 0, 0, DI_NORMAL);
	QImage image = qt_fromWinHBITMAP(hdc, winBitmap, w, h);

	for (int y = 0 ; y < h && !foundAlpha ; y++) {
		QRgb *scanLine= reinterpret_cast<QRgb *>(image.scanLine(y));
		for (int x = 0; x < w ; x++) {
			if (qAlpha(scanLine[x]) != 0) {
				foundAlpha = true;
				break;
			}
		}
	}
	if (!foundAlpha) {
		//If no alpha was found, we use the mask to set alpha values
		DrawIconEx( hdc, 0, 0, icon, w, h, 0, 0, DI_MASK);
		QImage mask = qt_fromWinHBITMAP(hdc, winBitmap, w, h);

		for (int y = 0 ; y < h ; y++){
			QRgb *scanlineImage = reinterpret_cast<QRgb *>(image.scanLine(y));
			QRgb *scanlineMask = mask.isNull() ? 0 : reinterpret_cast<QRgb *>(mask.scanLine(y));
			for (int x = 0; x < w ; x++){
				if (scanlineMask && qRed(scanlineMask[x]) != 0)
					scanlineImage[x] = 0; //mask out this pixel
				else
					scanlineImage[x] |= 0xff000000; // set the alpha channel to 255
			}
		}
	}
	//dispose resources created by iconinfo call
	DeleteObject(iconinfo.hbmMask);
	DeleteObject(iconinfo.hbmColor);

	SelectObject(hdc, oldhdc); //restore state
	DeleteObject(winBitmap);
	DeleteDC(hdc);
	return QPixmap::fromImage(image);
}

添加到 Qt5.2工程里,编译通过.

关键测试代码:


//add lib for ExtractIcon()
#include 
#pragma comment(lib,"Shell32.lib")

//使用winAPI获得dll,exe文件内所有图标资源
QString f1=ui->tx_icon->text();
HINSTANCE hInstance = (HINSTANCE)::GetModuleHandle(NULL);
int count;
count = (int)ExtractIconA(hInstance, f1.toLocal8Bit(), -1);
HICON hIcon;
qDebug()<<"totalIcon:"<<count;

QListWidget *list=ui->list_ico;
list->clear();
QPixmap img;

for(int i=0;i<count;i++){
	hIcon = ExtractIconA(hInstance, f1.toLocal8Bit(), i);

	img=fromWinHICON(hIcon);
	list->addItem(new QListWidgetItem(QIcon(img),QString::number(i)));

	DestroyIcon(hIcon);
}

最终效果:

viewIconInDll.png

 


标签: Qt

已有 4 条评论 »

  1. 好犀利的啊,一时半会还没看明白,马克一下,继续看

    1. 嘿,就是qt4源码抽出来的, 一堆win api..

      1. 好像还有其他的方法来实现,网上又找了找。
        可以提取16*16 和32*32的 图片:
        http://www.cnblogs.com/elect-fans/archive/2012/03/21/2408567.html

        1. QFileIconProvider 功能很有限,不是真的取文件内图标.
          只是取资源管理器中显示的那个图标.
          比如连形如 a.txt(文件需要存在) 都能取得文本类型的图标,你就知道是什么个意思了.

          很久没用了, 我记得是这样.

添加新评论 »

贴图表情