//-------------------------------------------------------------------
// VOImage implementation
//-------------------------------------------------------------------
// 
// Copyright ©2000 Virtual Office Systems Incorporated
// All Rights Reserved                      
//
// This code may be used in compiled form in any way you desire. This
// file may be redistributed unmodified by any means PROVIDING it is 
// not sold for profit without the authors written consent, and 
// providing that this notice and the authors name is included.
//
// This code can be compiled, modified and distributed freely, providing
// that this copyright information remains intact in the distribution.
//
// This code may be compiled in original or modified form in any private 
// or commercial application.
//
// This file is provided "as is" with no expressed or implied warranty.
// The author accepts no liability for any damage, in any form, caused
// by this code. Use it at your own risk.
//-------------------------------------------------------------------

#include "stdafx.h"

#include "VOImage.h"

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

HDC		CVOImage::g_hdc;
int		CVOImage::g_iScale = 100;
int		CVOImage::g_iMaxWidth = 10000;
int		CVOImage::g_iMaxHeight = 10000;
BOOL	CVOImage::g_bStretchBlt = FALSE;

CVOImage::CVOImage()
{
	m_hbitmap = 0;
}

CVOImage::~CVOImage()
{
	if(m_hbitmap)
		DeleteObject(m_hbitmap);
}

BOOL CVOImage::Load(HDC hdc, LPCTSTR pcszFileName)
{
	if(m_hbitmap)
		DeleteObject(m_hbitmap);

	if(!g_hdc)
		g_hdc = CreateCompatibleDC(hdc);

	HRESULT hr;
	BYTE    szBuffer[1024] = {0};
	HANDLE hFile = INVALID_HANDLE_VALUE;

	DecompressImageInfo	dii;

	hFile = CreateFile(pcszFileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL );
	if (hFile == INVALID_HANDLE_VALUE)
		return FALSE;

	// Fill in the 'DecompressImageInfo' structure
	dii.dwSize = sizeof( DecompressImageInfo );		// Size of this structure
	dii.pbBuffer = szBuffer;						// Pointer to the buffer to use for data
	dii.dwBufferMax = 1024;							// Size of the buffer
	dii.dwBufferCurrent = 0;						// The amount of data which is current in the buffer
	dii.phBM = &m_hbitmap;							// Pointer to the bitmap returned (can be NULL)
	dii.ppImageRender = NULL;						// Pointer to an IImageRender object (can be NULL)
	dii.iBitDepth = GetDeviceCaps(hdc,BITSPIXEL);	// Bit depth of the output image
	dii.lParam = ( LPARAM ) hFile;					// User parameter for callback functions
	dii.hdc = g_hdc;								// HDC to use for retrieving palettes
	dii.iScale = g_iScale;							// Scale factor (1 - 100)
	dii.iMaxWidth = g_iMaxWidth;					// Maximum width of the output image
	dii.iMaxHeight = g_iMaxHeight;					// Maxumum height of the output image
	dii.pfnGetData = GetImageData;					// Callback function to get image data
	dii.pfnImageProgress = ImageProgress;			// Callback function to notify caller of progress decoding the image
	dii.crTransparentOverride = ( UINT ) -1;		// If this color is not (UINT)-1, it will override the
													// transparent color in the image with this color. (GIF ONLY)

	// Process and decompress the image data
	hr = DecompressImageIndirect( &dii );
		
	// Clean up 
	CloseHandle( hFile );

	BITMAP	bmp;

	GetObject(m_hbitmap, sizeof(BITMAP), &bmp);

	m_dwWidth = bmp.bmWidth;
	m_dwHeight = bmp.bmHeight;

	return TRUE;
}

HBITMAP CVOImage::Copy()
{
	BITMAP	bm, bmNew;
	HBITMAP hNew;

	SelectObject(g_hdc, m_hbitmap);

	::GetObject(m_hbitmap, sizeof(BITMAP), &bm);

	HDC hdc = CreateCompatibleDC(g_hdc);
	hNew = CreateCompatibleBitmap(g_hdc, bm.bmWidth, bm.bmHeight);
	SelectObject(hdc, hNew);

	if(BitBlt(hdc, 0, 0, bm.bmWidth, bm.bmHeight, g_hdc, 0, 0, SRCCOPY))
	{
		HBITMAP hPrev = (HBITMAP) ::GetObject(hNew, sizeof(BITMAP), &bmNew);
			
		::SelectObject(hdc, hPrev);
	}

	DeleteDC(hdc);
	return hNew;
}

BOOL CVOImage::Draw(HDC hdc, int x, int y, int cx, int cy)
{
	BITMAP	bmp;
	HGDIOBJ	hOldBitmap;

	g_bStretchBlt = !(cx == -1 && cy == -1);
	hOldBitmap = SelectObject(g_hdc, m_hbitmap);
	GetObject(m_hbitmap, sizeof(BITMAP), &bmp);

	if (g_bStretchBlt)
	{
		// Stretch to fit
		StretchBlt(hdc, x , y, cx, cy, g_hdc,0,0,bmp.bmWidth,bmp.bmHeight,SRCCOPY );
	}
	else
	{
		BitBlt(hdc, x, y, bmp.bmWidth, bmp.bmHeight, g_hdc,0,0,SRCCOPY );
	}

	SelectObject(g_hdc, hOldBitmap);

	return TRUE;
}

DWORD CVOImage::GetHeight()
{
	return m_dwHeight;
}

DWORD CVOImage::GetWidth()
{
	return m_dwWidth;
}

BOOL CVOImage::SetBitmap(HDC hdc, DWORD dwResourceID, LPCTSTR pcszClass, HMODULE hModule)
{
	if(!g_hdc)
		g_hdc = CreateCompatibleDC(hdc);

	HRESULT hr;
	BYTE    szBuffer[1024] = {0}; 
	DecompressImageInfo	dii;

	CVOResource	res(hModule, dwResourceID, pcszClass);

	if(!res.IsLoaded())
		return FALSE;

	res.SetUserData(0);	// Use this for the current resource offset

	// Fill in the 'DecompressImageInfo' structure
	dii.dwSize = sizeof( DecompressImageInfo );		// Size of this structure
	dii.pbBuffer = szBuffer;						// Pointer to the buffer to use for data
	dii.dwBufferMax = 1024;							// Size of the buffer
	dii.dwBufferCurrent = 0;						// The amount of data which is current in the buffer
	dii.phBM = &m_hbitmap;							// Pointer to the bitmap returned (can be NULL)
	dii.ppImageRender = NULL;						// Pointer to an IImageRender object (can be NULL)
	dii.iBitDepth = GetDeviceCaps(hdc,BITSPIXEL);	// Bit depth of the output image
	dii.lParam = ( LPARAM ) &res;					// User parameter for callback functions
	dii.hdc = g_hdc;								// HDC to use for retrieving palettes
	dii.iScale = g_iScale;							// Scale factor (1 - 100)
	dii.iMaxWidth = g_iMaxWidth;					// Maximum width of the output image
	dii.iMaxHeight = g_iMaxHeight;					// Maxumum height of the output image
	dii.pfnGetData = GetImageResourceData;			// Callback function to get image data
	dii.pfnImageProgress = ImageProgress;			// Callback function to notify caller of progress decoding the image
	dii.crTransparentOverride = ( UINT ) -1;		// If this color is not (UINT)-1, it will override the
																								// transparent color in the image with this color. (GIF ONLY)
	// Process and decompress the image data
	hr = DecompressImageIndirect( &dii );
		
	BITMAP	bmp;

	GetObject(m_hbitmap, sizeof(BITMAP), &bmp);

	m_dwWidth = bmp.bmWidth;
	m_dwHeight = bmp.bmHeight;

	return TRUE;
}

DWORD CALLBACK CVOImage::GetImageData(LPSTR szBuffer, DWORD dwBufferMax, LPARAM lParam )
{
	DWORD dwNumberOfBytesRead;

	if ( (HANDLE)lParam == INVALID_HANDLE_VALUE )
		return 0;

	ReadFile( (HANDLE)lParam, szBuffer, dwBufferMax, &dwNumberOfBytesRead, NULL );

	// Return number of bytes read
	return dwNumberOfBytesRead;
}

DWORD CALLBACK CVOImage::GetImageResourceData(LPSTR szBuffer, DWORD dwBufferMax, LPARAM lParam)
{
	DWORD			dwNumberOfBytesToRead = dwBufferMax;
	CVOResource*	pRes = (CVOResource*) lParam;

	if(!pRes)
		return 0;

	DWORD			dwResourceOffset = pRes->GetUserData();

	if(dwResourceOffset + dwNumberOfBytesToRead > pRes->GetSize() )
		dwNumberOfBytesToRead = pRes->GetSize() - dwResourceOffset;

	memmove(szBuffer, pRes->GetData() + dwResourceOffset, dwNumberOfBytesToRead);

	pRes->SetUserData(dwResourceOffset + dwNumberOfBytesToRead);
	return dwNumberOfBytesToRead;	// return amount read
}

void CALLBACK CVOImage::ImageProgress(IImageRender *pRender, BOOL bComplete, LPARAM lParam )
{
	if( bComplete )
	{
		;// (Optional) add code here for completion processing
	}
}

BOOL CVOImage::IsLoaded()
{
	return (m_hbitmap != 0);
}

CVOResource::CVOResource(HMODULE hModule, DWORD dwResourceID, LPCTSTR pcszClass)
{
	m_dwSize = 0;
	m_hGlobal = 0;
	m_pData = 0;

	m_hrsrc = FindResource(hModule, (LPCWSTR)dwResourceID, pcszClass);

	if(m_hrsrc == 0)
		return;

	m_dwSize = SizeofResource(hModule, m_hrsrc);
	m_hGlobal = LoadResource(hModule, m_hrsrc);
	m_pData = (PBYTE) LockResource(m_hGlobal);
}

CVOResource::~CVOResource()
{
	if(m_hGlobal)
		DeleteObject(m_hGlobal);
}

BOOL CVOResource::IsLoaded()
{
	return (m_pData != NULL);
}
