|
|
#include "precomp.h"
#pragma hdrstop
#include "strsafe.h"
CGdiPlusThumb::CGdiPlusThumb() { m_pImage = NULL; m_pImageFactory = NULL; m_szPath[0] = 0; }
CGdiPlusThumb::~CGdiPlusThumb() { if (m_pImage) m_pImage->Release();
if (m_pImageFactory) m_pImageFactory->Release(); }
STDMETHODIMP CGdiPlusThumb::GetLocation(LPWSTR pszPathBuffer, DWORD cch, DWORD * pdwPriority, const SIZE *prgSize, DWORD dwRecClrDepth, DWORD *pdwFlags) { HRESULT hr = E_UNEXPECTED;
if (m_szPath[0]) { hr = StringCchCopyW(pszPathBuffer, cch, m_szPath); if (SUCCEEDED(hr)) {
if (*pdwFlags & IEIFLAG_ASYNC) { hr = E_PENDING;
// higher than normal priority, this task is relatively fast
*pdwPriority = PRIORITY_EXTRACT_FAST; }
m_rgSize = *prgSize; m_dwRecClrDepth = dwRecClrDepth; // We only work in non-paletted modes. Some of our extractors simply always use 24bbp, should we?
if (m_dwRecClrDepth < 16) m_dwRecClrDepth = 16;
m_fOrigSize = BOOLIFY(*pdwFlags & IEIFLAG_ORIGSIZE); m_fHighQuality = BOOLIFY(*pdwFlags & IEIFLAG_QUALITY);
*pdwFlags = IEIFLAG_CACHE; } }
return hr; }
STDMETHODIMP CGdiPlusThumb::Extract(HBITMAP *phBmpThumbnail) { HRESULT hr = E_FAIL;
// Do the GDI plus stuff here
if (m_pImageFactory && m_pImage) { if (m_fHighQuality) { hr = m_pImage->Decode(SHIMGDEC_DEFAULT, 0, 0); } if (FAILED(hr)) { hr = m_pImage->Decode(SHIMGDEC_THUMBNAIL, m_rgSize.cx, m_rgSize.cy); }
if (SUCCEEDED(hr)) { // Get the image's actual size, which might be less than the requested size since we asked for a thumbnail
SIZE sizeImg; m_pImage->GetSize(&sizeImg);
// we need to fill the background with the default color if we can't resize the bitmap
// or if the image is transparent:
m_fFillBackground = !m_fOrigSize || (m_pImage->IsTransparent() == S_OK);
if (m_fOrigSize) { // if its too big, lets squish it, but try to
// maintain the same aspect ratio. This is the same
// sort of thing we do for the !m_fOrigSize case, except
// here we want to do it here because we want to return
// a correctly sized bitmap.
if (sizeImg.cx != 0 && sizeImg.cy != 0 && (sizeImg.cx > m_rgSize.cx || sizeImg.cy > m_rgSize.cy)) { if (m_rgSize.cx * sizeImg.cy > m_rgSize.cy * sizeImg.cx) { m_rgSize.cx = MulDiv(m_rgSize.cy,sizeImg.cx,sizeImg.cy); } else { m_rgSize.cy = MulDiv(m_rgSize.cx,sizeImg.cy,sizeImg.cx); } } else { // Use the size if it was small enough and they wanted original size
m_rgSize = sizeImg; } }
hr = CreateDibFromBitmapImage( phBmpThumbnail ); } }
return SUCCEEDED(hr) ? S_OK : hr; }
STDMETHODIMP CGdiPlusThumb::GetClassID(CLSID *pClassID) { *pClassID = CLSID_GdiThumbnailExtractor; return S_OK; }
STDMETHODIMP CGdiPlusThumb::IsDirty() { return E_NOTIMPL; }
STDMETHODIMP CGdiPlusThumb::Load(LPCOLESTR pszFileName, DWORD dwMode) { HRESULT hr;
hr = StringCchCopyW(m_szPath, ARRAYSIZE(m_szPath), pszFileName ); if (SUCCEEDED(hr)) { // Call ImageFactory->CreateFromFile here. If Create from file failes then
// return E_FAIL, otherwise return S_OK.
ASSERT(NULL==m_pImageFactory); HRESULT hr = CoCreateInstance(CLSID_ShellImageDataFactory, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARG(IShellImageDataFactory, &m_pImageFactory)); if (SUCCEEDED(hr)) { hr = m_pImageFactory->CreateImageFromFile(m_szPath, &m_pImage); ASSERT((SUCCEEDED(hr) && m_pImage) || (FAILED(hr) && !m_pImage)); } }
return hr; }
STDMETHODIMP CGdiPlusThumb::Save(LPCOLESTR pszFileName, BOOL fRemember) { return E_NOTIMPL; }
STDMETHODIMP CGdiPlusThumb::SaveCompleted(LPCOLESTR pszFileName) { return E_NOTIMPL; }
STDMETHODIMP CGdiPlusThumb::GetCurFile(LPOLESTR *ppszFileName) { return E_NOTIMPL; }
HRESULT CGdiPlusThumb::CreateDibFromBitmapImage(HBITMAP * pbm) { HRESULT hr = E_FAIL; BITMAPINFO bmi = {0}; void * pvBits;
bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); bmi.bmiHeader.biWidth = m_rgSize.cx; bmi.bmiHeader.biHeight = m_rgSize.cy; bmi.bmiHeader.biPlanes = 1; bmi.bmiHeader.biBitCount = (USHORT)m_dwRecClrDepth; bmi.bmiHeader.biCompression = BI_RGB; DWORD dwBPL = (((bmi.bmiHeader.biWidth * m_dwRecClrDepth) + 31) >> 3) & ~3; bmi.bmiHeader.biSizeImage = dwBPL * bmi.bmiHeader.biHeight;
HDC hdc = GetDC(NULL); HBITMAP hbmp = CreateDIBSection(hdc, &bmi, DIB_RGB_COLORS, &pvBits, NULL, 0); if (hbmp) { HDC hMemDC = CreateCompatibleDC(hdc); if (hMemDC) { HBITMAP hbmOld = (HBITMAP)SelectObject(hMemDC, hbmp); RECT rc = {0, 0, m_rgSize.cx, m_rgSize.cy};
if (m_fFillBackground) { FillRect(hMemDC, &rc, GetSysColorBrush(COLOR_WINDOW)); } // if the m_fOrigSize flag isn't set then we need to return a bitmap that is the
// requested size. In order to maintain aspect ratio that means we need to
// center the thumbnail.
if (!m_fOrigSize) { SIZE sizeImg; m_pImage->GetSize(&sizeImg);
// if its too big, lets squish it, but try to
// maintain the same aspect ratio. This is the same
// sort of thing we did for the m_fOrigSize case, except
// here we want to do it before centering.
if (sizeImg.cx != 0 && sizeImg.cy != 0 && (sizeImg.cx > m_rgSize.cx || sizeImg.cy > m_rgSize.cy)) { if (m_rgSize.cx * sizeImg.cy > m_rgSize.cy * sizeImg.cx) { sizeImg.cx = MulDiv(m_rgSize.cy,sizeImg.cx,sizeImg.cy); sizeImg.cy = m_rgSize.cy; } else { sizeImg.cy = MulDiv(m_rgSize.cx,sizeImg.cy,sizeImg.cx); sizeImg.cx = m_rgSize.cx; } }
rc.left = (m_rgSize.cx-sizeImg.cx)/2; rc.top = (m_rgSize.cy-sizeImg.cy)/2; rc.right = rc.left + sizeImg.cx; rc.bottom = rc.top + sizeImg.cy; }
hr = m_pImage->Draw(hMemDC, &rc, NULL);
SelectObject(hMemDC, hbmOld); DeleteDC(hMemDC); } } ReleaseDC(NULL, hdc);
if (SUCCEEDED(hr)) { *pbm = hbmp; } else if (hbmp) { DeleteObject(hbmp); }
return hr; }
|