// CIMAGE.CPP // Implementation of CDIBImage and its kin #include #include #include #include "wiadebug.h" #include "cunknown.h" #include #include "util.h" #define DEFINE_GUIDS #include "cimage.h" STDMETHODIMP CDIBImage::QueryInterface ( REFIID riid, LPVOID* ppvObject ) { HRESULT hr; INTERFACES iface[] = { &IID_IBitmapImage, (IBitmapImage *) this, &IID_IPersistFile, (IPersistFile *) this, &IID_IDIBProperties, (IDIBProperties *) this, &IID_IImageProperties, (IImageProperties *) this, }; // // Next, try the normal cases... // hr = HandleQueryInterface(riid, ppvObject, iface, ARRAYSIZE(iface)); return hr; } STDMETHODIMP_(ULONG) CDIBImage::AddRef() { return CUnknown::HandleAddRef(); } STDMETHODIMP_(ULONG) CDIBImage::Release() { return CUnknown::HandleRelease(); } CDIBImage::CDIBImage() : m_hDIB(NULL), m_hBitmap(NULL), m_bDirty(FALSE), m_szFile(NULL), m_szDefaultExt (L"*.bmp") { } CDIBImage::~CDIBImage() { if (m_hDIB) { GlobalFree (m_hDIB); } if (m_hBitmap) { DeleteObject (m_hBitmap); } if (m_szFile) { delete [] m_szFile; } } /*++ Name: CDIBImage::InternalCreate Description: Given a global memory DIB or an HBITMAP, init the object. Both a DIB and an HBITMAP are stored for quick access at the expense of increased memory use. Arguments: hDIB - global handle to a DIB hBmp - handle to a dibsection or compatible bitmap Return Value: S_OK on success, error code otherwise Notes: --*/ HRESULT CDIBImage::InternalCreate (HANDLE hDIB, HBITMAP hBmp) { WIA_PUSHFUNCTION (TEXT("CDIBImage::InternalCreate")); HDC hdc = NULL; PBYTE pDIB = NULL; HRESULT hr = S_OK; if (!hDIB && !hBmp) { hr = E_INVALIDARG; goto exit_gracefully;// (hr, TEXT("NULL handles to InternalCreate")); } hdc = GetDC (NULL); if (m_hDIB) { GlobalFree (m_hDIB); } if (m_hBitmap) { DeleteObject (m_hBitmap); } if (hDIB) { m_hDIB = hDIB; } else { m_hDIB = Util::BitmapToDIB (hdc, hBmp); if (!m_hDIB) { hr = E_FAIL; goto exit_gracefully; } } if (hBmp) { m_hBitmap = hBmp; } else { pDIB = reinterpret_cast(GlobalLock(m_hDIB)); m_hBitmap = Util::DIBBufferToBMP (hdc, pDIB, FALSE); if (!m_hBitmap) { hr = E_FAIL; goto exit_gracefully; } } exit_gracefully: if (hdc) { ReleaseDC (NULL, hdc); } if (pDIB) { GlobalUnlock (m_hDIB); } return hr; } /*++ Name: CDIBImage::CreateFromDataObject Description: Given an IDataObject pointer, retrieve an IBitmapImage interface for the data. Arguments: pdo - IDataObject interface Return Value: S_OK on success Notes: the pdo is not released by this function TODO: Add support for CF_BITMAP and other TYMED values --*/ STDMETHODIMP CDIBImage::CreateFromDataObject ( IDataObject *pdo ) { FORMATETC fmt; STGMEDIUM stg; HRESULT hr = E_FAIL; WIA_PUSHFUNCTION(TEXT("CDIBImage::CreateFromDataObject")); if (!pdo) { goto exit_gracefully;// (hr, TEXT("NULL IDataObject passed to CreateFromDataObject")); } // Try with CF_DIB and TYMED_HGLOBAL only memset (&stg, 0, sizeof(stg)); fmt.cfFormat = CF_DIB; fmt.ptd = NULL; fmt.dwAspect = DVASPECT_CONTENT; fmt.lindex = -1; fmt.tymed = TYMED_HGLOBAL; if (SUCCEEDED(hr=pdo->GetData(&fmt, &stg))) { hr = InternalCreate (stg.hGlobal, NULL); if (stg.pUnkForRelease) { stg.pUnkForRelease->Release(); } else { GlobalFree (stg.hGlobal); } } exit_gracefully: return hr; } /*++ Name: CDIBImage::CreateFromBitmap Description: Given an HBITMAP, init the object Arguments: hBitmap - dibsection or compatible bitmap Return Value: S_OK on success Notes: --*/ STDMETHODIMP CDIBImage::CreateFromBitmap ( HBITMAP hBitmap ) { return InternalCreate (NULL, hBitmap); } /*++ Name: CDIBImage::CreateFromDIB Description: Given a global memory DIB, init the object Arguments: hDIB - global DIB handle Return Value: S_OK on success Notes: --*/ STDMETHODIMP CDIBImage::CreateFromDIB ( HANDLE hDIB ) { return InternalCreate (hDIB, NULL); } /*++ Name: CDIBImage::Blt Description: Draw the image to the given DC Arguments: hdcDest- target DC prect - rectangle to fill in the DC xSrc - x coord to start in the image ySrc - y coord to start in the image dwRop - GDI ROP code Return Value: S_OK on success, E_FAIL if BitBlt fails Notes: --*/ STDMETHODIMP CDIBImage::Blt ( HDC hdcDest, LPRECT prect, INT xSrc, INT ySrc, DWORD dwRop ) { WIA_PUSHFUNCTION(TEXT("CDIBImage::Blt")); HDC hdc = CreateCompatibleDC (hdcDest); HGDIOBJ hOld; BITMAP bm; HRESULT hr = S_OK; ZeroMemory (&bm, sizeof(bm)); GetObject (m_hBitmap, sizeof(bm), &bm); if (hdc) { hOld = SelectObject (hdc, m_hBitmap); if (!::BitBlt (hdcDest, prect->left, prect->top, prect->right-prect->left, prect->bottom-prect->top, hdc, xSrc, ySrc, dwRop )) { hr = E_FAIL; } SelectObject (hdc, hOld); DeleteDC (hdc); } else { hr = E_OUTOFMEMORY; } return hr; } /*++ Name: CDIBImage::Stretch Description: StretchBlt wrapper for the image Arguments: hdcDest - destination DC prcSrc - rectangle of the image to blt prcDest - rectangle of the DC to fill dwRop - GDI ROP code Return Value: S_OK on success, E_FAIL if StretchBlt fails Notes: --*/ STDMETHODIMP CDIBImage::Stretch ( HDC hdcDest, LPRECT prcSrc, LPRECT prcDest, DWORD dwRop ) { WIA_PUSHFUNCTION(TEXT("CDIBImage::Stretch")); HRESULT hr = S_OK; if (!prcSrc || !prcDest) { hr = E_INVALIDARG; } else { HDC hdc = CreateCompatibleDC (hdcDest); HGDIOBJ hOld = NULL; if (hdc) { hOld = SelectObject (hdc, m_hBitmap); if (!::StretchBlt (hdcDest, prcDest->left, prcDest->top, prcDest->right-prcDest->left, prcDest->bottom-prcDest->top, hdc, prcSrc->left, prcSrc->top, prcSrc->right-prcSrc->left, prcSrc->bottom-prcDest->top, dwRop )) { hr = E_FAIL; } SelectObject (hdc, hOld); DeleteDC (hdc); } else { hr = E_OUTOFMEMORY; } } return hr; } /*++ Name: CDIBImage::GetProperties Description: Retrieve an IImageProperties interface for the image Arguments: ppip - IImageProperties pointer to fill in Return Value: S_OK on success Notes: --*/ STDMETHODIMP CDIBImage::GetProperties ( IImageProperties **ppip ) { if (!ppip) { return E_INVALIDARG; } return QueryInterface (IID_IImageProperties, reinterpret_cast(ppip)); } /*++ Name: CDIBImage::ConvertToDIB Description: Allocate a global DIB and fill it with the current image Arguments: phDIB - handle pointer to fill in Return Value: S_OK on success Notes: --*/ STDMETHODIMP CDIBImage::ConvertToDIB ( HANDLE *phDIB ) { HANDLE hDIB; SIZE_T size; HRESULT hr = S_OK; PVOID pdib = NULL; PVOID pcopy = NULL; WIA_PUSHFUNCTION(TEXT("CDIBImage::ConvertToDIB")); if (!phDIB) { hr = E_INVALIDARG; goto exit_gracefully;// (hr, TEXT("NULL phDIB to ConvertToDIB")); } *phDIB = NULL; size = GlobalSize (m_hDIB); pdib = GlobalLock (m_hDIB); if (!pdib) { hr = E_OUTOFMEMORY; goto exit_gracefully;// (hr, TEXT("GlobalLock failed in ConvertToDIB")); } hDIB = GlobalAlloc (GHND, size); if (!hDIB) { hr = E_OUTOFMEMORY; goto exit_gracefully;// (hr, TEXT("GlobalAlloc failed in ConvertToDIB")); } pcopy = GlobalLock (hDIB); if (!pcopy) { GlobalFree (hDIB); hr = E_OUTOFMEMORY; goto exit_gracefully;// (hr, TEXT("GlobalLock failed in ConvertToDIB")); } memcpy (pcopy, pdib, size); exit_gracefully: if (phDIB && hDIB && pcopy) { GlobalUnlock (hDIB); *phDIB = hDIB; } if (pdib) { GlobalUnlock (m_hDIB); } return hr; } /*++ Name: CDIBImage::CopyToClipboard Description: Put the image contents delimited by prect on the clipboard Arguments: prect - part of the image to copy Return Value: S_OK on success Notes: --*/ STDMETHODIMP CDIBImage::CopyToClipboard ( LPRECT prect ) { WIA_PUSHFUNCTION(TEXT("CDIBImage::CopyToClipboard")); HRESULT hr = S_OK; OpenClipboard (NULL); EmptyClipboard(); if (!prect) { //default to CF_DIB for whole image hr = SetClipboardData (CF_DIB, m_hDIB) ? S_OK:E_FAIL; } else { // Create an HBITMAP for the selected region HBITMAP hbmp = CropBitmap (m_hBitmap, prect); if (!hbmp) { hr = E_OUTOFMEMORY; goto exit_gracefully;// (hr, TEXT("CropBitmap failed in CopyToClipboard")); } hr = SetClipboardData (CF_BITMAP, hbmp) ? S_OK : E_FAIL; DeleteObject (hbmp); } exit_gracefully: CloseClipboard (); return hr; } /*++ Name: CDIBImage::Rotate Description: Rotate the image around its center Arguments: nDegrees - amount to rotate Return Value: S_OK on success Notes: Currently only 90,180,270 degrees are supported --*/ STDMETHODIMP CDIBImage::Rotate ( INT nDegrees ) { WIA_PUSHFUNCTION (TEXT("CDIBImage::Rotate")); HRESULT hr = S_OK; HBITMAP hNew; hNew = RotateBitmap (m_hBitmap, nDegrees); if (!hNew) { hr = E_FAIL; goto exit_gracefully;// (hr, TEXT("RotateBitmap failed in Rotate")); } else { m_bDirty = TRUE; InternalCreate (NULL, hNew); } exit_gracefully: return hr; } STDMETHODIMP CDIBImage::Crop (RECT *prcCrop, IBitmapImage **ppImage ) { HBITMAP hBitmap; HRESULT hr = S_OK; CDIBImage *pObj; *ppImage = NULL; hBitmap = CropBitmap (m_hBitmap, prcCrop); if (hBitmap) { pObj = new CDIBImage (); if (pObj) { (pObj)->QueryInterface (IID_IBitmapImage, reinterpret_cast(ppImage)); (*ppImage)->CreateFromBitmap (hBitmap); pObj->Release(); } DeleteObject (hBitmap); } else { hr = HRESULT_FROM_WIN32(GetLastError()); } return hr; } ////////////////////////////////IImageProperties methods /*++ Name: CDIBImage::GetSize Description: Returns the dimensions of the image Arguments: pSize - pointer to SIZE structure to fill Return Value: S_OK on success Notes: --*/ STDMETHODIMP CDIBImage::GetSize ( SIZE *pSize ) { WIA_PUSHFUNCTION (TEXT("CDIBImage::GetSize")); BITMAP bm; if (!pSize) { return E_INVALIDARG; } ZeroMemory (&bm, sizeof(bm)); GetObject (m_hBitmap, sizeof (bm), &bm); pSize->cx = bm.bmWidth; pSize->cy = bm.bmHeight; return S_OK; } /*++ Name: CDIBImage::GetDepth Description: Return the bits per pixel of the image Arguments: pwBPP - pointer to value to fill in Return Value: S_OK on success Notes: --*/ STDMETHODIMP CDIBImage::GetDepth ( WORD *pwBPP ) { WIA_PUSHFUNCTION (TEXT("CDIBImage::GetDepth")); BITMAP bm; if (!pwBPP) { return E_INVALIDARG; } if (GetObject (m_hBitmap, sizeof (bm), &bm) >= sizeof(bm)) { *pwBPP = bm.bmBitsPixel; return S_OK; } return E_FAIL; } STDMETHODIMP CDIBImage::SetDepth ( WORD wBPP ) { return E_NOTIMPL; } STDMETHODIMP CDIBImage::GetAlpha ( BYTE *pAlpha ) { return E_NOTIMPL; } STDMETHODIMP CDIBImage::SetAlpha ( BYTE Alpha ) { return E_NOTIMPL; } STDMETHODIMP CDIBImage::GetAspectRatio( SIZE *pAspect ) { return E_NOTIMPL; } STDMETHODIMP CDIBImage::SetAspectRatio( SIZE *pAspect ) { return E_NOTIMPL; } //IDIBProperties methods /*++ Name: CDIBImage::GetInfo Description: Construct a BITMAPINFO structure for the current image Arguments: ppbmi - pointer to BITMAPINFO pointer to allocate Return Value: S_OK on success Notes: --*/ STDMETHODIMP CDIBImage::GetInfo( BITMAPINFO **ppbmi ) { WIA_PUSHFUNCTION(TEXT("CDIBImage::GetInfo")); IMalloc *pMalloc = NULL; ULONG uSize; HRESULT hr = S_OK; BITMAPINFO *pDIB = NULL; hr = CoGetMalloc (1, &pMalloc); if (FAILED(hr)) { goto exit_gracefully;// (hr, TEXT("SHGetMalloc in GetInfo")); } pDIB = reinterpret_cast(GlobalLock (m_hDIB)); if (!pDIB) { hr = E_OUTOFMEMORY; goto exit_gracefully;// (TEXT("GlobalLock failed in GetInfo")); } uSize = static_cast(Util::GetBmiSize (pDIB)); *ppbmi = reinterpret_cast(pMalloc->Alloc (uSize)); if (!*ppbmi) { hr = E_OUTOFMEMORY; goto exit_gracefully;// (hr, TEXT("IMalloc::Alloc")); } memcpy (*ppbmi, pDIB, uSize); exit_gracefully: if (pMalloc) { pMalloc->Release(); } if (pDIB) { GlobalUnlock (m_hDIB); } return hr; } STDMETHODIMP CDIBImage::GetDIBSize( DWORD *pdwSize ) { if (!pdwSize) { return E_POINTER; } *pdwSize = static_cast(GlobalSize(m_hDIB)); return S_OK; } ////////////////////////////////// IPersistFile methods STDMETHODIMP CDIBImage::IsDirty( void ) { return m_bDirty? S_OK:S_FALSE; } /*++ Name: CDIBImage::Load Description: Init the image from an image file Arguments: pszFileName - path to the image file dwMode - storage mode to open with, currently ignored Return Value: S_OK on success Notes: --*/ STDMETHODIMP CDIBImage::Load( LPCOLESTR pszFileName, DWORD dwMode ) { HRESULT hr = S_OK; LPTSTR szDibFile = NULL; HBITMAP hBitmap; WIA_PUSHFUNCTION (TEXT("CDIBImage::Load")); if (!pszFileName || !*pszFileName) { hr = E_INVALIDARG; goto exit_gracefully;// (hr, TEXT("NULL filename to Load")); } if (m_szFile) { delete [] m_szFile; } m_szFile = new WCHAR[lstrlenW(pszFileName)+1]; if (!m_szFile) { hr = E_OUTOFMEMORY; goto exit_gracefully; } wcscpy (m_szFile, pszFileName); #ifdef UNICODE szDibFile = m_szFile; #else INT len; len = WideCharToMultiByte (CP_ACP, 0, m_szFile, -1, szDibFile, 0, NULL, NULL); szDibFile = new CHAR[len+1]; if (!szDibFile) { hr = E_OUTOFMEMORY; goto exit_gracefully;// (hr, TEXT("Unable to allocate file name in Load")); } WideCharToMultiByte (CP_ACP, 0, m_szFile, -1, szDibFile, len, NULL, NULL); #endif // UNICODE hBitmap = reinterpret_cast(LoadImage(NULL, szDibFile, IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION|LR_LOADFROMFILE)); hr = CreateFromBitmap (hBitmap); m_bDirty = FALSE; exit_gracefully: #ifndef UNICODE if (szDibFile) { delete [] szDibFile; } #endif //ndef UNICODE return hr; } STDMETHODIMP CDIBImage::GetClassID ( CLSID *pClassID ) { memcpy (pClassID, &CLSID_WIAImage, sizeof(CLSID)); return S_OK; } /*++ Name: CDIBImage::Save Description: Save the current image to file Arguments: pszFileName - file to save to. If NULL, use the current file name fRemember - whether to keep pszFileName as the new file name Return Value: S_OK on success Notes: --*/ STDMETHODIMP CDIBImage::Save ( LPCOLESTR pszFileName, BOOL fRemember ) { HANDLE hFile; HRESULT hr = S_OK; LPTSTR pszDibFile = NULL; PBYTE pDibFile = NULL; PBITMAPINFOHEADER pDIB = NULL; PBYTE pBits; DWORD dw; WIA_PUSHFUNCTION(TEXT("CDIBImage::Save")); if (!*pszFileName) { hr = E_INVALIDARG; goto exit_gracefully;// (hr, TEXT("Empty filename to Save")); } if (fRemember && pszFileName) { if (m_szFile) { delete [] m_szFile; } m_szFile = new WCHAR[lstrlenW(pszFileName)+1]; if (!m_szFile) { hr = E_OUTOFMEMORY; goto exit_gracefully; } lstrcpyW (m_szFile, pszFileName); } #ifdef UNICODE pszDibFile = const_cast(pszFileName); #else INT len; len = WideCharToMultiByte (CP_ACP, 0, pszFileName, -1, NULL, 0, NULL, NULL); pszDibFile = new CHAR[len+1]; if (!pszDibFile) { hr = E_OUTOFMEMORY; goto exit_gracefully;// (hr, TEXT("Unable to allocate file name in Load")); } WideCharToMultiByte (CP_ACP, 0, pszFileName, -1, pszDibFile, len, NULL, NULL); #endif // UNICODE pDIB = reinterpret_cast(GlobalLock (m_hDIB)); pBits = reinterpret_cast(pDIB) + Util::GetBmiSize(reinterpret_cast(pDIB)); pDibFile = Util::AllocDibFileFromBits (pBits, pDIB->biWidth, pDIB->biHeight, pDIB->biBitCount); if (!pDibFile) { hr = E_OUTOFMEMORY; goto exit_gracefully;// (hr, TEXT("AllocDibFileFromBits in Save")); } hFile = CreateFile (pszDibFile, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (INVALID_HANDLE_VALUE == hFile) { hr = E_FAIL; goto exit_gracefully;// (hr, TEXT("CreateFile in Save")); } WriteFile (hFile, pDibFile, reinterpret_cast(pDibFile)->bfSize, &dw, NULL); CloseHandle (hFile); exit_gracefully: if (pDIB) { GlobalUnlock (m_hDIB); } if (pDibFile) { LocalFree (pDibFile); } #ifndef UNICODE if (pszDibFile) { delete [] pszDibFile; } #endif //ndef UNICODE return hr; } STDMETHODIMP CDIBImage::SaveCompleted ( LPCOLESTR pszFileName ) { return E_NOTIMPL; } /*++ Name: CDIBImage::GetCurFile Description: Return the current file name of the image, or the preferred "file mask" for this kind of file. In this case the preferred mask is "*.bmp" Arguments: ppszFileName - pointer to string to fill in Return Value: S_OK on success Notes: --*/ STDMETHODIMP CDIBImage::GetCurFile ( LPOLESTR *ppszFileName ) { HRESULT hr = S_OK; LPOLESTR szCur; IMalloc *pMalloc = NULL; WIA_PUSHFUNCTION(TEXT("CDIBImage::GetCurFile")); if (!ppszFileName) { hr = E_INVALIDARG; goto exit_gracefully;// (hr, TEXT("NULL out pointer to GetCurFile")); } if (!m_szFile) { szCur = const_cast(m_szDefaultExt); } else { szCur = m_szFile; } hr = CoGetMalloc (1,&pMalloc); if (FAILED(hr)) { goto exit_gracefully;// (hr, TEXT("CoGetMalloc in GetCurFile")); } *ppszFileName = reinterpret_cast(pMalloc->Alloc((lstrlenW(szCur)+1)*sizeof(OLECHAR))); if (*ppszFileName) { lstrcpyW (*ppszFileName, szCur); } else { hr = E_OUTOFMEMORY; } exit_gracefully: if (pMalloc) { pMalloc->Release(); } return hr; } // IDataObject methods STDMETHODIMP CDIBImage::GetData ( FORMATETC *pformatetcIn, STGMEDIUM *pmedium ) { return E_NOTIMPL; } STDMETHODIMP CDIBImage::GetDataHere ( FORMATETC *pformatetc, STGMEDIUM *pmedium ) { return E_NOTIMPL; } STDMETHODIMP CDIBImage::QueryGetData ( FORMATETC *pformatetc ) { return E_NOTIMPL; } STDMETHODIMP CDIBImage::GetCanonicalFormatEtc ( FORMATETC *pformatectIn, FORMATETC *pformatetcOut ) { return E_NOTIMPL; } STDMETHODIMP CDIBImage::SetData ( FORMATETC *pformatetc, STGMEDIUM *pmedium, BOOL fRelease ) { return E_NOTIMPL; } STDMETHODIMP CDIBImage::EnumFormatEtc ( DWORD dwDirection, IEnumFORMATETC **ppenumFormatEtc ) { return E_NOTIMPL; } STDMETHODIMP CDIBImage::DAdvise ( FORMATETC *pformatetc, DWORD advf, IAdviseSink *pAdvSink, DWORD *pdwConnection ) { return E_NOTIMPL; } STDMETHODIMP CDIBImage::DUnadvise ( DWORD dwConnection ) { return E_NOTIMPL; } STDMETHODIMP CDIBImage::EnumDAdvise ( IEnumSTATDATA **ppenumAdvise ) { return E_NOTIMPL; } /////////////////////////////////////////////////////////////////////////////// // Helper APIs /*++ Name: MakeNewDIBImage Description: Create an IBitmapImage interface for a CDIBImage object given an IDataObject Arguments: pdo - IDataObject pointer pbiOut - IBitmapImage pointer to fill in pfe - type of data to use Return Value: S_OK on success Notes: --*/ HRESULT MakeNewDIBImage (IDataObject *pdo, IBitmapImage **pbiOut, FORMATETC *pfe) { WIA_PUSHFUNCTION (TEXT("MakeNewDIBImage")); CDIBImage *pDibImage = NULL; IBitmapImage *pbi = NULL; IPersistFile *ppf; STGMEDIUM stg; FORMATETC fmt; HRESULT hr = S_OK; *pbiOut = NULL; pDibImage = new CDIBImage (); if (!pDibImage) { hr = E_OUTOFMEMORY; goto exit_gracefully; } if (FAILED(hr = pDibImage->QueryInterface (IID_IBitmapImage, reinterpret_cast(&pbi) ))) { goto exit_gracefully;// (hr, TEXT("QueryInterface for IBitmapImage")); } if (pfe) { if (FAILED(hr = pdo->GetData (pfe, &stg))) { goto exit_gracefully;// (hr, TEXT("GetData in MakeNewDIBImage")); } switch (pfe->tymed) { case TYMED_HGLOBAL: hr = pbi->CreateFromDIB (stg.hGlobal); break; case TYMED_GDI: hr = pbi->CreateFromBitmap (stg.hBitmap); break; case TYMED_FILE: hr = pbi->QueryInterface (IID_IPersistFile, reinterpret_cast(&ppf) ); if (SUCCEEDED(hr)) { hr = ppf->Load (stg.lpszFileName, STGM_READ); ppf->Release(); } else { hr = DV_E_TYMED; } break; default: hr= DV_E_TYMED; break; } } else { // try HGLOBAL fmt.cfFormat = CF_DIB; fmt.tymed = TYMED_HGLOBAL; fmt.lindex = -1; fmt.dwAspect = DVASPECT_CONTENT; fmt.ptd = NULL; hr = MakeNewDIBImage (pdo, &pbi, &fmt); } exit_gracefully: if (pDibImage) { pDibImage->Release (); } if (SUCCEEDED(hr)) { *pbiOut = pbi; } else if (pbi) { pbi->Release(); } return hr; } /*++ Name: GetImageFromDataObject Description: Retrieve an IBitmapImage interface for an IDataObject Arguments: pdo - IDataObject pointer pbi - IBitmapImage pointer to fill in Return Value: S_OK on success Notes: In the future, private formats in the IDataObject may allow this function to return interfaces for other formats than DIB --*/ HRESULT GetImageFromDataObject (IN IDataObject *pdo, OUT IBitmapImage **pbi) { WIA_PUSHFUNCTION(TEXT("GetImageFromDataObject")); IEnumFORMATETC *pEnum; FORMATETC fe; ULONG ul; BOOL bMatch = FALSE; HRESULT hr = S_OK; if (SUCCEEDED(pdo->EnumFormatEtc (DATADIR_GET, &pEnum))) { while (S_OK == pEnum->Next (1, &fe,&ul)) { switch (fe.cfFormat) { case CF_DIB: case CF_BITMAP: if (SUCCEEDED(hr= MakeNewDIBImage (pdo, pbi, &fe))) { bMatch = TRUE; } break; default: break; } } if (!bMatch) { hr = E_FAIL; } pEnum->Release(); } else { // just try DIBImage hr = MakeNewDIBImage (pdo, pbi, NULL); } return hr; } #define MAKEPOINT(p,i,j) {(p).x = i;(p).y = j;} HBITMAP RotateBitmap (HBITMAP hbm, UINT uAngle) { HDC hMemDCsrc = NULL; HDC hMemDCdst = NULL; HDC hdc = NULL; HBITMAP hNewBm = NULL; BITMAP bm; LONG cx, cy; POINT pts[3]; if (!hbm) return NULL; ZeroMemory (&bm, sizeof(bm)); GetObject (hbm, sizeof(BITMAP), (LPSTR)&bm); switch (uAngle) { case 0: case 360: cx = bm.bmWidth; cy = bm.bmHeight; MAKEPOINT (pts[0], 0, 0) MAKEPOINT (pts[1], bm.bmWidth, 0) MAKEPOINT (pts[2], 0, bm.bmHeight) break; case 90: cx = bm.bmHeight; cy = bm.bmWidth; MAKEPOINT(pts[0],bm.bmHeight,0) MAKEPOINT(pts[1],bm.bmHeight,bm.bmWidth) MAKEPOINT(pts[2],0,0) break; case 180: cx = bm.bmWidth; cy = bm.bmHeight; MAKEPOINT(pts[0],bm.bmWidth, bm.bmHeight) MAKEPOINT(pts[1],0,bm.bmHeight) MAKEPOINT(pts[2],bm.bmWidth,0) break; case 270: case -90: cx = bm.bmHeight; cy = bm.bmWidth; MAKEPOINT(pts[0],0, bm.bmWidth) MAKEPOINT(pts[1],0,0) MAKEPOINT(pts[2],bm.bmHeight, bm.bmWidth) break; default: return NULL; WIA_TRACE((TEXT("RotateBitmap called with unsupported angle %d\n"), uAngle)); break; } hdc = GetDC (NULL); if (hdc) { hMemDCsrc = CreateCompatibleDC (hdc); hMemDCdst = CreateCompatibleDC (hdc); } if (hdc && hMemDCsrc && hMemDCdst) { hNewBm = CreateBitmap(cx, cy, bm.bmPlanes, bm.bmBitsPixel, NULL); if (hNewBm) { SelectObject (hMemDCsrc, hbm); SelectObject (hMemDCdst, hNewBm); PlgBlt ( hMemDCdst, pts, hMemDCsrc, 0, 0, bm.bmWidth, bm.bmHeight, NULL, 0,0); } } if (hdc) ReleaseDC (NULL,hdc); if (hMemDCsrc) DeleteDC (hMemDCsrc); if (hMemDCdst) DeleteDC (hMemDCdst); return hNewBm; } HBITMAP CropBitmap ( HBITMAP hbm, PRECT prc) { HDC hMemDCsrc = NULL; HDC hMemDCdst = NULL; HDC hdc; HBITMAP hNewBm = NULL; BITMAP bm; INT dx,dy; if (!hbm) return NULL; hdc = GetDC (NULL); if (hdc) { hMemDCsrc = CreateCompatibleDC (hdc); hMemDCdst = CreateCompatibleDC (hdc); } if (hdc && hMemDCsrc && hMemDCdst) { ZeroMemory (&bm, sizeof(bm)); GetObject (hbm, sizeof(BITMAP), (LPSTR)&bm); dx = prc->right - prc->left; dy = prc->bottom - prc->top; /*hNewBm = +++CreateBitmap - Not Recommended(use CreateDIBitmap)+++ (dx, dy, bm.bmPlanes, bm.bmBitsPixel, NULL);*/ hNewBm = CreateBitmap(dx, dy, bm.bmPlanes, bm.bmBitsPixel, NULL); if (hNewBm) { SelectObject (hMemDCsrc, hbm); SelectObject (hMemDCdst, hNewBm); BitBlt (hMemDCdst, 0, 0, dx, dy, hMemDCsrc, prc->left, prc->top, SRCCOPY); } } if (hdc) ReleaseDC (NULL,hdc); if (hMemDCsrc) DeleteDC (hMemDCsrc); if (hMemDCdst) DeleteDC (hMemDCdst); return hNewBm; }