// Image.cpp : Implementation of cImage #include "stdafx.h" #include "Inject.h" #include "Image.h" #include "Manager.h" ///////////////////////////////////////////////////////////////////////////// // cImage cImage::~cImage() { cManager::_p->removeImage( this ); } void cImage::loadFile() { // ::MessageBox( NULL, _T( "cImage::loadFile" ), _T( "Inject.dll" ), MB_OK ); HANDLE hBitmap = ::CreateFile( m_szFilename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL ); if( hBitmap == INVALID_HANDLE_VALUE ) { int nError = ::GetLastError(); return; } BITMAPFILEHEADER bfh; DWORD dwRead; ::ReadFile( hBitmap, &bfh, sizeof( BITMAPFILEHEADER ), &dwRead, NULL ); BITMAPINFOHEADER bih; ::ReadFile( hBitmap, &bih, sizeof( BITMAPINFOHEADER ), &dwRead, NULL ); RGBQUAD pal[ 256 ]; ::memset( pal, 0, sizeof( RGBQUAD[ 256 ] ) ); // Figure out the number of colors used int nEntries = 1 << ( bih.biBitCount ); if( bih.biClrUsed != 0 ) nEntries = bih.biClrUsed; ::ReadFile( hBitmap, pal, sizeof( RGBQUAD ) * nEntries, &dwRead, NULL ); SIZE szImage = { bih.biWidth, bih.biHeight }; cManager::_p->CreateCanvas( &szImage, &m_pImage ); CComPtr< IDirectDrawSurface4 > pSurface; m_pImage->GetSurface( IID_IDirectDrawSurface4, reinterpret_cast< void ** >( &pSurface ) ); DDSURFACEDESC2 desc; desc.dwSize = sizeof( DDSURFACEDESC2 ); pSurface->Lock( NULL, &desc, DDLOCK_WAIT | DDLOCK_SURFACEMEMORYPTR | DDLOCK_WRITEONLY, NULL ); WORD wDownMixed[ 256 ]; RGBQUAD *pSrc = pal; for( WORD *pDest = wDownMixed; pDest != wDownMixed + ( nEntries - 1 ); ++ pDest, ++ pSrc ) { m_pImage->DownMixRGB(pSrc->rgbRed, pSrc->rgbGreen, pSrc->rgbBlue, pDest); } *pDest = 0x07FF; // Mekle: Added the (bih.biWidth % 4) sections below, as BMP rows MUST end on a 32bit boundry BYTE *pbSurf = reinterpret_cast< BYTE * >( desc.lpSurface ) + ( desc.dwHeight - 1 ) * desc.lPitch; BYTE *pbRow = new BYTE[ bih.biWidth + (bih.biWidth % 4) ]; for( int nRow = 0; nRow < bih.biHeight; ++ nRow ) { ::ReadFile( hBitmap, pbRow, bih.biWidth + (bih.biWidth % 4), &dwRead, NULL ); WORD *pwDest = reinterpret_cast< WORD * >( pbSurf ); for( BYTE *pbSrc = pbRow; pbSrc != pbRow + bih.biWidth; ++ pbSrc, ++ pwDest ) // Lookup the color in the downmixed palette *pwDest = wDownMixed[ *pbSrc ]; pbSurf -= desc.lPitch; } delete[] pbRow; pSurface->Unlock( NULL ); ::CloseHandle( hBitmap ); } void cImage::loadResource() { } void cImage::loadPortal() { // ::MessageBox( NULL, _T( "cImage::loadPortal" ), _T( "Inject.dll" ), MB_OK ); struct cColorImage { DWORD m_dwID, m_dwX, m_dwY; }; try { cDatFile::cFile icon = cManager::_p->m_portal.getFile( m_dwID ); cColorImage header; icon.read( reinterpret_cast< BYTE * >( &header ), sizeof( cColorImage ) ); SIZE szImage = { header.m_dwX, header.m_dwY }; cManager::_p->CreateCanvas( &szImage, &m_pImage ); CComPtr< IDirectDrawSurface4 > pSurface; m_pImage->GetSurface( IID_IDirectDrawSurface4, reinterpret_cast< void ** >( &pSurface ) ); DDSURFACEDESC2 desc; desc.dwSize = sizeof( DDSURFACEDESC2 ); pSurface->Lock( NULL, &desc, DDLOCK_WAIT | DDLOCK_SURFACEMEMORYPTR | DDLOCK_WRITEONLY, NULL ); BYTE *pSrcLine = new BYTE[ 3 * header.m_dwX ], *pEndLine = pSrcLine + 3 * header.m_dwX; for( int i = 0; i < header.m_dwY; ++ i ) { // Read in a line icon.read( pSrcLine, 3 * header.m_dwX ); WORD *pwDest = reinterpret_cast< WORD * >( reinterpret_cast< BYTE * >( desc.lpSurface ) + desc.lPitch * i ); for( BYTE *pbSrc = pSrcLine; pbSrc != pEndLine; pbSrc += 3, ++ pwDest ) { // Check for black (transparent) if( pbSrc[ 0 ] == 0 && pbSrc[ 1 ] == 0 && pbSrc[ 2 ] == 0 ) *pwDest = 0x07FF; else { // Downmix the pixel value m_pImage->DownMixRGB(pbSrc[0], pbSrc[1], pbSrc[2], pwDest); } } } delete[] pSrcLine; pSurface->Unlock( NULL ); } catch( ... ) { // Failure, file not found } } bool cImage::testImage() { bool bReload = false; if( m_pImage.p == NULL ) bReload = true; else { VARIANT_BOOL bLost; m_pImage->get_WasLost( &bLost ); if( bLost ) { m_pImage.Release(); bReload = true; } } if( bReload ) { // Reload the image switch( m_source ) { case eFile: loadFile(); break; case eResource: loadResource(); break; case ePortal: loadPortal(); break; } } return ( m_pImage.p != NULL ); } STDMETHODIMP cImage::PatBlt(ICanvas *pDest, LPRECT prcDest, LPPOINT ptOrigin) { // ::MessageBox( NULL, _T( "cImage::PatBlt" ), _T( "Inject.dll" ), MB_OK ); if( !testImage() ) return E_FAIL; SIZE sz; m_pImage->get_Size( &sz ); POINT ptAdjOrigin = { ptOrigin->x % sz.cx, ptOrigin->y % sz.cy }; if( ptAdjOrigin.x > 0 ) ptAdjOrigin.x -= sz.cx; if( ptAdjOrigin.y > 0 ) ptAdjOrigin.y -= sz.cy; RECT rcPlacement; RECT rcSrc; POINT ptSrcOrigin; // Scan down for( int y = prcDest->top + ptAdjOrigin.y; y < prcDest->bottom; y += sz.cy ) { rcPlacement.top = y; rcPlacement.bottom = y + sz.cy; if( rcPlacement.top < prcDest->top ) rcPlacement.top = prcDest->top; if( rcPlacement.bottom > prcDest->bottom ) rcPlacement.bottom = prcDest->bottom; ptSrcOrigin.y = ( rcPlacement.top - prcDest->top - ptAdjOrigin.y ) % sz.cy; rcSrc.top = ptSrcOrigin.y; rcSrc.bottom = rcSrc.top + ( rcPlacement.bottom - rcPlacement.top ); // Scan across for( int x = prcDest->left + ptAdjOrigin.x; x < prcDest->right; x += sz.cx ) { rcPlacement.left = x; rcPlacement.right = x + sz.cx; if( rcPlacement.left < prcDest->left ) rcPlacement.left = prcDest->left; if( rcPlacement.right > prcDest->right ) rcPlacement.right = prcDest->right; ptSrcOrigin.x = ( rcPlacement.left - prcDest->left - ptAdjOrigin.x ) % sz.cx; rcSrc.left = ptSrcOrigin.x; rcSrc.right = rcSrc.left + ( rcPlacement.right - rcPlacement.left ); POINT pt = { rcPlacement.left, rcPlacement.top }; pDest->Blt( &rcSrc, m_pImage, &pt ); } } _ASSERTMEM( _CrtCheckMemory( ) ); return S_OK; } STDMETHODIMP cImage::StretchBlt(ICanvas *pDest, LPPOINT pptDest, long nWidth, long nStartStretch, long nEndStretch) { if( !testImage() ) return E_FAIL; // Ok, the image is getting placed in three sections, fixed beginning and end // and variable length middle sections (delimited by nStartStretch and nEndStretch) // First we place the fixed beginning and end lengths SIZE sz; m_pImage->get_Size( &sz ); RECT rcSrcHead = { 0, 0, nStartStretch, sz.cy }, rcSrcTail = { nEndStretch, 0, sz.cx, sz.cy }, rcSrcMiddle = { nStartStretch, 0, nEndStretch, sz.cy }; int nTailPlacement = pptDest->x + nWidth - ( sz.cx - nEndStretch ); POINT ptHead = { pptDest->x, pptDest->y }, ptTail = { nTailPlacement, pptDest->y }, ptStretch = { 0, pptDest->y }; // Do the first Blts pDest->Blt( &rcSrcHead, m_pImage, &ptHead ); pDest->Blt( &rcSrcTail, m_pImage, &ptTail ); // Now do the middle sections for( ptStretch.x = pptDest->x + nStartStretch; ptStretch.x < nTailPlacement; ptStretch.x += ( nEndStretch - nStartStretch ) ) { if( ( nTailPlacement - ptStretch.x ) < ( rcSrcMiddle.right - rcSrcMiddle.left ) ) rcSrcMiddle.right = rcSrcMiddle.left + ( nTailPlacement - ptStretch.x ); pDest->Blt( &rcSrcMiddle, m_pImage, &ptStretch ); } return S_OK; } STDMETHODIMP cImage::Blt(LPRECT rcSrc, ICanvas *pDest, LPPOINT pptDest) { if( !testImage() ) return E_FAIL; SIZE sz; m_pImage->get_Size( &sz ); RECT rcImage = { 0, 0, sz.cx, sz.cy }; pDest->Blt( &rcImage, m_pImage, pptDest ); return S_OK; } STDMETHODIMP cImage::get_Size(SIZE *pVal) { if( !testImage() ) return E_FAIL; m_pImage->get_Size( pVal ); return S_OK; } STDMETHODIMP cImage::StretchBltArea(LPRECT prcSrc, ICanvas *pDest, LPRECT prcDest) { if( !testImage() ) return E_FAIL; SIZE sizeImage; get_Size( &sizeImage ); if( prcSrc->right > sizeImage.cx ) prcSrc->right = sizeImage.cx ; if( prcSrc->bottom > sizeImage.cy ) prcSrc->bottom = sizeImage.cy; if( prcSrc->left < 0 ) prcSrc->left = 0; if( prcSrc->top < 0 ) prcSrc->top = 0; if( prcSrc->left >= prcSrc->right ) prcSrc->left = prcSrc->right - 1; if( prcSrc->top >= prcSrc->bottom ) prcSrc->top = prcSrc->bottom - 1; pDest->StretchBlt( prcSrc, m_pImage, prcDest ); return S_OK; }