Windows下C++三種方法獲取檔案縮圖並儲存為圖片
阿新 • • 發佈:2020-12-23
技術標籤:Windows程式設計
1. 簡介
在Windows資料夾中,不需要開啟檔案,即可以通過大圖示、平鋪等方面檢視到不同檔案的縮圖。
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;
}