windows-nt/Source/XPSP1/NT/printscan/ui/cimage/cimage.cpp

1617 lines
31 KiB
C++
Raw Normal View History

2020-09-26 03:20:57 -05:00
// CIMAGE.CPP
// Implementation of CDIBImage and its kin
#include <windows.h>
#include <objbase.h>
#include <shlobj.h>
#include "wiadebug.h"
#include "cunknown.h"
#include <initguid.h>
#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<PBYTE>(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<LPVOID *>(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<PVOID*>(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<BITMAPINFO *>(GlobalLock (m_hDIB));
if (!pDIB)
{
hr = E_OUTOFMEMORY;
goto exit_gracefully;// (TEXT("GlobalLock failed in GetInfo"));
}
uSize = static_cast<LONG>(Util::GetBmiSize (pDIB));
*ppbmi = reinterpret_cast<BITMAPINFO*>(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<DWORD>(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<HBITMAP>(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<LPTSTR>(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<PBITMAPINFOHEADER>(GlobalLock (m_hDIB));
pBits = reinterpret_cast<PBYTE>(pDIB) + Util::GetBmiSize(reinterpret_cast<PBITMAPINFO>(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<PBITMAPFILEHEADER>(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<LPOLESTR>(m_szDefaultExt);
}
else
{
szCur = m_szFile;
}
hr = CoGetMalloc (1,&pMalloc);
if (FAILED(hr))
{
goto exit_gracefully;// (hr, TEXT("CoGetMalloc in GetCurFile"));
}
*ppszFileName = reinterpret_cast<LPOLESTR>(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<LPVOID*>(&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<LPVOID *>(&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;
}