1. 程式人生 > 其它 >Windows下C++三種方法獲取檔案縮圖並儲存為圖片

Windows下C++三種方法獲取檔案縮圖並儲存為圖片

技術標籤:Windows程式設計

1. 簡介

在Windows資料夾中,不需要開啟檔案,即可以通過大圖示、平鋪等方面檢視到不同檔案的縮圖。
![在這裡插入圖片描述](https://img-blog.csdnimg.cn/20201222204635330.png

2. 方法一

縮圖資訊資料夾的,在資料夾中顯示。所以Windows提供了資料夾相關元件來獲取縮圖資訊。因為IShellFolder元件的方法只能用寬字元,所以介面需要使用寬字元符。此方法相容XP系統及之後的作業系統。

HBITMAP GetThumbnail(const std::wstring& _strFilePath)
{
	std::wstring strDir;
	std::wstring strFileName;
	int nPos =
_strFilePath.find_last_of(L"\\"); strDir = _strFilePath.substr(0,nPos); strFileName = _strFilePath.substr(nPos+1); CComPtr<IShellFolder> pDesktop = NULL; HRESULT hr = SHGetDesktopFolder(&pDesktop); if(FAILED(hr)) return NULL; LPITEMIDLIST pidl = NULL; hr = pDesktop->
ParseDisplayName(NULL, NULL, (LPWSTR)strDir.c_str(), NULL, &pidl, NULL); if(FAILED(hr)) return NULL; CComPtr<IShellFolder> pSub = NULL; hr = pDesktop->BindToObject(pidl, NULL, IID_IShellFolder, (void**)&pSub); if(FAILED(hr)) return NULL; hr = pSub->ParseDisplayName(NULL
, NULL, (LPWSTR)strFileName.c_str(), NULL, &pidl, NULL); if(FAILED(hr)) return NULL; CComPtr<IExtractImage> pIExtract = NULL; hr = pSub ->GetUIObjectOf(NULL, 1, (LPCITEMIDLIST *)&pidl, IID_IExtractImage, NULL, (void**)& pIExtract); if(FAILED(hr)) return NULL; SIZE size = {64, 128}; // 請求獲取的圖片大小 DWORD dwFlags = IEIFLAG_ORIGSIZE | IEIFLAG_QUALITY; OLECHAR pathBuffer[MAX_PATH] = {0}; // 24為顏色深度,縮圖一般是24位顏色 hr = pIExtract->GetLocation(pathBuffer, MAX_PATH, NULL, &size, 24, &dwFlags); if(FAILED(hr)) return NULL; // Get the image HBITMAP hThumbnail = NULL; hr = pIExtract ->Extract(&hThumbnail); if(FAILED(hr)) return NULL; return hThumbnail; }

3. 方法二

隨著Windows的升級,Windows針對縮圖,還提供了專元件介面,更加方便。但是隻支援Win7及之後的系統。


HBITMAP GetThumbnailEx(WCHAR* path)
{
	HRESULT hr = CoInitialize(nullptr);

	// Get the thumbnail
	IShellItem* item = nullptr;
	hr = SHCreateItemFromParsingName(path, nullptr, IID_PPV_ARGS(&item));

	IThumbnailCache* cache = nullptr;
	hr = CoCreateInstance(
		CLSID_LocalThumbnailCache,
		nullptr,
		CLSCTX_INPROC,
		IID_PPV_ARGS(&cache));

	ISharedBitmap* shared_bitmap;
	hr = cache->GetThumbnail(
		item,
		48*64,
		WTS_EXTRACT,
		&shared_bitmap,
		nullptr,
		nullptr);

	// Retrieve thumbnail HBITMAP
	HBITMAP hbitmap = NULL;
	hr = shared_bitmap->GetSharedBitmap(&hbitmap);
	CoUninitialize();

	return hbitmap;
}

3. 方法三

有時自定義的文件,也想讓系統顯示相應的縮圖,怎麼辦呢?Windows提供了COM元件介面,只需要實際相應的介面處理自己定義的檔案,然後完成相應文件縮圖的定義即可。
更多詳細資訊參考官方資料:C++ Windows Shell thumbnail handler

4. 其他

4.1. 儲存圖片


BOOL SaveBitmapToFile(HBITMAP hBitmap, const CString& szfilename)
{          
	//計算點陣圖檔案每個畫素所佔位元組數              
	HDC hDC  = CreateDC("DISPLAY", NULL, NULL, NULL);  
	int iBits  = GetDeviceCaps(hDC,   BITSPIXEL)*GetDeviceCaps(hDC,   PLANES);             
	DeleteDC(hDC);       
	//點陣圖中每象素所佔位元組數
	WORD wBitCount = 0;
	if(iBits <=  1)                                                   
		wBitCount = 1;             
	else  if(iBits <=  4)                               
		wBitCount  = 4;             
	else if(iBits <=  8)                               
		wBitCount  = 8;             
	else                                                                                                                               
		wBitCount  = 24;

	BITMAP Bitmap = {};
	GetObject(hBitmap,   sizeof(Bitmap),   (LPSTR)&Bitmap);      
	BITMAPINFOHEADER bi = {};
	bi.biSize= sizeof(BITMAPINFOHEADER);      
	bi.biWidth = Bitmap.bmWidth;         
	bi.biHeight =  Bitmap.bmHeight;         
	bi.biPlanes =  1;         
	bi.biBitCount = wBitCount;         
	bi.biCompression= BI_RGB;                

	DWORD dwBmBitsSize  = 16*((Bitmap.bmWidth *wBitCount+31) / 32)*4* Bitmap.bmHeight;         

	//為點陣圖內容分配記憶體              
	DWORD dwPaletteSize = 0;
	HANDLE hDib  = GlobalAlloc(GHND,dwBmBitsSize+dwPaletteSize+sizeof(BITMAPINFOHEADER));             
	LPBITMAPINFOHEADER lpbi  = (LPBITMAPINFOHEADER)GlobalLock(hDib);             
	*lpbi  = bi;             

	// 處理調色盤
	HANDLE hOldPal = NULL; 
	HANDLE hPal = GetStockObject(DEFAULT_PALETTE);             
	if (hPal)             
	{             
		hDC  = ::GetDC(NULL);             
		hOldPal = ::SelectPalette(hDC,(HPALETTE)hPal, FALSE);             
		RealizePalette(hDC);             
	}         

	//點陣圖檔案大小寫入檔案位元組數              
	DWORD dwDIBSize=0;
	DWORD dwWritten=0;      

	// 獲取該調色盤下新的畫素值              
	GetDIBits(hDC,hBitmap, 0,(UINT)Bitmap.bmHeight,  
		(LPSTR)lpbi+ sizeof(BITMAPINFOHEADER)+dwPaletteSize,   
		(BITMAPINFO *)lpbi, DIB_RGB_COLORS);             

	//恢復調色盤                  
	if (hOldPal)             
	{             
		::SelectPalette(hDC,   (HPALETTE)hOldPal,   TRUE);             
		RealizePalette(hDC);             
		::ReleaseDC(NULL,   hDC);             
	}             

	//建立點陣圖檔案                  
	HANDLE fh  = CreateFile(szfilename,   GENERIC_WRITE,0,   NULL,   CREATE_ALWAYS,           
		FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN,   NULL);             

	if (fh == INVALID_HANDLE_VALUE)         
		return FALSE;            

	// 設定點陣圖檔案頭              
	BITMAPFILEHEADER bmfHdr = {};
	bmfHdr.bfType = 0x4D42;     //"BM"              
	dwDIBSize  = sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER)+dwPaletteSize+dwBmBitsSize;                 
	bmfHdr.bfSize = dwDIBSize;                       
	bmfHdr.bfOffBits = (DWORD)sizeof(BITMAPFILEHEADER)+(DWORD)sizeof(BITMAPINFOHEADER)+dwPaletteSize;    

	// 寫入點陣圖檔案頭              
	WriteFile(fh, (LPSTR)&bmfHdr, sizeof(BITMAPFILEHEADER), &dwWritten, NULL);             
	// 寫入點陣圖檔案其餘內容              
	WriteFile(fh, (LPSTR)lpbi, dwDIBSize, &dwWritten, NULL);             
	// 清除                  
	GlobalUnlock(hDib);             
	GlobalFree(hDib);             
	CloseHandle(fh);             

	return TRUE;         
}

4.2. 程式碼

程式碼