1676 lines
44 KiB
C++
1676 lines
44 KiB
C++
|
|
#include "stdafx.h"
|
|
#include "global.h"
|
|
#include "pbrush.h"
|
|
#include "pbrusdoc.h"
|
|
#include "pbrusfrm.h"
|
|
#include "pbrusvw.h"
|
|
#include "minifwnd.h"
|
|
#include "bmobject.h"
|
|
#include "imgsuprt.h"
|
|
#include "imgwnd.h"
|
|
#include "imgbrush.h"
|
|
#include "imgwell.h"
|
|
#include "imgtools.h"
|
|
#include "toolbox.h"
|
|
#include "imgfile.h"
|
|
#include "colorsrc.h"
|
|
#include "undo.h"
|
|
#include "props.h"
|
|
#include "ferr.h"
|
|
#include "cmpmsg.h"
|
|
#include "loadimag.h"
|
|
|
|
#ifdef _DEBUG
|
|
#undef THIS_FILE
|
|
static CHAR BASED_CODE THIS_FILE[] = __FILE__;
|
|
#endif
|
|
|
|
IMPLEMENT_DYNCREATE( CBitmapObj, CObject )
|
|
|
|
#include "memtrace.h"
|
|
|
|
/***************************************************************************/
|
|
// Map from the value in CBitmapObj::m_nColors to bits per pixel
|
|
|
|
int mpncolorsbits [] =
|
|
{
|
|
1, 4, 8, 24
|
|
};
|
|
|
|
/***************************************************************************/
|
|
|
|
CBitmapObj::CBitmapObj() : CObject(), m_dependants()
|
|
{
|
|
m_bDirty = FALSE;
|
|
m_bTempName = FALSE;
|
|
m_hThing = NULL;
|
|
m_lMemSize = 0L;
|
|
m_pImg = NULL;
|
|
m_nWidth = 0;
|
|
m_nHeight = 0;
|
|
m_nColors = 0;
|
|
m_nSaveColors = -1;
|
|
#ifdef ICO_SUPPORT
|
|
m_bSaveIcon = FALSE;
|
|
#endif
|
|
#ifdef PCX_SUPPORT
|
|
m_bPCX = FALSE;
|
|
#endif
|
|
m_bCompressed = FALSE;
|
|
m_nShrink = 0;
|
|
m_dwOffBits = 0;
|
|
}
|
|
|
|
/***************************************************************************/
|
|
|
|
CBitmapObj::~CBitmapObj()
|
|
{
|
|
ASSERT_VALID(this);
|
|
|
|
InformDependants( SN_DESTROY );
|
|
|
|
if (m_hThing != NULL)
|
|
{
|
|
Free();
|
|
}
|
|
if (m_pImg)
|
|
FreeImg(m_pImg);
|
|
}
|
|
|
|
/***************************************************************************/
|
|
|
|
void CBitmapObj::AddDependant( CBitmapObj* newDependant )
|
|
{
|
|
POSITION pos = m_dependants.Find( newDependant );
|
|
|
|
if (pos == NULL)
|
|
m_dependants.AddTail( newDependant );
|
|
}
|
|
|
|
/***************************************************************************/
|
|
|
|
void CBitmapObj::RemoveDependant( CBitmapObj* oldDependant )
|
|
{
|
|
POSITION pos = m_dependants.Find(oldDependant);
|
|
|
|
if (pos != NULL)
|
|
m_dependants.RemoveAt(pos);
|
|
}
|
|
|
|
/***************************************************************************/
|
|
|
|
void CBitmapObj::InformDependants( UINT idChange )
|
|
{
|
|
POSITION pos = m_dependants.GetHeadPosition();
|
|
|
|
while (pos != NULL)
|
|
{
|
|
CBitmapObj* pSlob = (CBitmapObj*)m_dependants.GetNext(pos);
|
|
pSlob->OnInform(this, idChange);
|
|
}
|
|
}
|
|
|
|
/***************************************************************************/
|
|
|
|
void CBitmapObj::OnInform( CBitmapObj* pChangedSlob, UINT idChange )
|
|
{
|
|
if (idChange == SN_DESTROY)
|
|
{
|
|
POSITION pos = m_dependants.Find(pChangedSlob);
|
|
|
|
if (pos != NULL)
|
|
m_dependants.RemoveAt(pos);
|
|
}
|
|
}
|
|
|
|
/***************************************************************************/
|
|
|
|
void CBitmapObj::SetDirty(BOOL bDirty)
|
|
{
|
|
m_bDirty = bDirty;
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
void CBitmapObj::Zap()
|
|
{
|
|
m_bDirty = FALSE;
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
BOOL CBitmapObj::Alloc() // m_hThing of size m_lMemSize
|
|
{
|
|
if (m_lMemSize == 0L)
|
|
return FALSE;
|
|
|
|
m_hThing = GlobalAlloc(GPTR, m_lMemSize);
|
|
|
|
if (m_hThing == NULL)
|
|
{
|
|
theApp.SetMemoryEmergency( TRUE );
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
void CBitmapObj::Free() // m_hThing and set m_lMemSize to zero
|
|
{
|
|
if (m_hThing == NULL)
|
|
{
|
|
TRACE(TEXT("Warning: called Free on a CBitmapObj with no thing!\n"));
|
|
return;
|
|
}
|
|
|
|
GlobalFree(m_hThing);
|
|
|
|
m_hThing = NULL;
|
|
m_lMemSize = 0;
|
|
}
|
|
|
|
/***************************************************************************/
|
|
|
|
CString CBitmapObj::GetDefExtension(int iStringId)
|
|
{
|
|
CString cStringExtension;
|
|
|
|
if (iStringId != 0)
|
|
{
|
|
TRY
|
|
{
|
|
cStringExtension.LoadString( iStringId );
|
|
}
|
|
CATCH(CMemoryException,e)
|
|
{
|
|
cStringExtension.Empty();
|
|
}
|
|
END_CATCH
|
|
}
|
|
else
|
|
{
|
|
cStringExtension.Empty();
|
|
}
|
|
|
|
return cStringExtension;
|
|
}
|
|
|
|
void PBGetDefDims(int &pnWidth, int &pnHeight)
|
|
{
|
|
// Setup default parameters...
|
|
// Don't use the whole screen, those bitmaps get HUGE
|
|
//
|
|
pnWidth = GetSystemMetrics( SM_CXSCREEN )/2;
|
|
pnHeight = GetSystemMetrics( SM_CYSCREEN )/2;
|
|
|
|
// Check if this is a low memory machine and use a small default bitmap
|
|
// size
|
|
if (GetSystemMetrics(SM_SLOWMACHINE) & 0x0002)
|
|
{
|
|
pnWidth = 640/2;
|
|
pnHeight = 480/2;
|
|
}
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
BOOL CBitmapObj::MakeEmpty()
|
|
{
|
|
PBGetDefDims(m_nWidth, m_nHeight);
|
|
|
|
if (theApp.m_sizeBitmap.cx
|
|
&& theApp.m_sizeBitmap.cy)
|
|
{
|
|
m_nWidth = theApp.m_sizeBitmap.cx;
|
|
m_nHeight = theApp.m_sizeBitmap.cy;
|
|
}
|
|
|
|
if (theApp.m_bEmbedded)
|
|
{
|
|
// make a nice size for embedded objects, lets try for 5 centimeters
|
|
m_nWidth = theApp.ScreenDeviceInfo.ixPelsPerDM / 2;
|
|
m_nHeight = theApp.ScreenDeviceInfo.iyPelsPerDM / 2;
|
|
}
|
|
|
|
//
|
|
// default to 256 colors if not monochrome
|
|
//
|
|
m_nColors = theApp.m_bMonoDevice? 0 : 2;
|
|
m_bDirty = TRUE;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
// Create and setup an IMG for this resource
|
|
|
|
BOOL CBitmapObj::CreateImg()
|
|
{
|
|
ASSERT(! m_pImg);
|
|
|
|
LONG cXPelsPerMeter = 0;
|
|
LONG cYPelsPerMeter = 0;
|
|
|
|
LPSTR lpbi = (LPSTR) GlobalLock(m_hThing); // NOTE: this is NULL for new resources!
|
|
|
|
if (lpbi)
|
|
{
|
|
if (IS_WIN30_DIB( lpbi ))
|
|
{
|
|
PBITMAPINFOHEADER pbmih = (PBITMAPINFOHEADER) lpbi;
|
|
m_bCompressed = pbmih->biCompression != BI_RGB;
|
|
cXPelsPerMeter = pbmih->biXPelsPerMeter;
|
|
cYPelsPerMeter = pbmih->biYPelsPerMeter;
|
|
}
|
|
|
|
m_nWidth = (int)DIBWidth ( lpbi );
|
|
m_nHeight = (int)DIBHeight( lpbi );
|
|
m_nColors = DIBNumColors( lpbi, FALSE );
|
|
|
|
if (m_nColors <= 0 || m_nColors > 256)
|
|
m_nColors = 3;
|
|
else
|
|
if (m_nColors <= 2)
|
|
m_nColors = 0;
|
|
else
|
|
if (m_nColors <= 16)
|
|
m_nColors = 1;
|
|
else
|
|
if (m_nColors <= 256)
|
|
m_nColors = 2;
|
|
}
|
|
|
|
UINT nColors = (m_nColors? 0: 1);
|
|
|
|
m_pImg = ::CreateImg( lpbi ? 0 : m_nWidth, lpbi ? 0 : m_nHeight,
|
|
nColors, nColors, cXPelsPerMeter, cYPelsPerMeter, theApp.m_bPaletted );
|
|
|
|
if (! m_pImg)
|
|
{
|
|
TRACE(TEXT("CreateImg failed\n"));
|
|
|
|
theApp.SetMemoryEmergency();
|
|
GlobalUnlock(m_hThing);
|
|
return FALSE;
|
|
}
|
|
|
|
if (g_pColors)
|
|
{
|
|
g_pColors->ResetColors ((m_nColors==1)?16:256);
|
|
}
|
|
|
|
m_pImg->cxWidth = m_nWidth;
|
|
m_pImg->cyHeight = m_nHeight;
|
|
|
|
if (! lpbi)
|
|
{
|
|
nColors = m_pImg->cPlanes * m_pImg->cBitCount;
|
|
|
|
//FEATURE - Shouldn't this be " == 0 || == 1" ??
|
|
//Half a page up negative values == TRUE color!
|
|
|
|
//This shell game with the values isn't very good...
|
|
|
|
if (nColors <= 1)
|
|
m_nColors = 0;
|
|
else
|
|
if (nColors <= 4)
|
|
m_nColors = 1;
|
|
else
|
|
if (nColors <= 8)
|
|
m_nColors = 2;
|
|
else // 24-bit image
|
|
m_nColors = 3;
|
|
}
|
|
|
|
m_pImg->m_pBitmapObj = this;
|
|
m_pImg->bDirty = m_bDirty;
|
|
|
|
if (lpbi)
|
|
{
|
|
// Load the bitmap/icon/cursor...
|
|
HBITMAP hbm = DIBToDS( lpbi, m_dwOffBits, m_pImg->hDC );
|
|
|
|
if (! hbm)
|
|
{
|
|
theApp.SetMemoryEmergency();
|
|
GlobalUnlock(m_hThing);
|
|
return FALSE;
|
|
}
|
|
|
|
m_pImg->hBitmap = hbm;
|
|
m_pImg->hBitmapOld = (HBITMAP)::SelectObject( m_pImg->hDC, hbm );
|
|
}
|
|
|
|
if ( theApp.m_bPaletted)
|
|
// If LoadImage was used && paletted
|
|
{
|
|
// Create the Palette from the dib section instead.
|
|
m_pImg->m_pPalette = PaletteFromDS(m_pImg->hDC);
|
|
}
|
|
|
|
theApp.m_pPalette = NULL;
|
|
|
|
if (m_pImg->m_pPalette && theApp.m_bPaletted)
|
|
{
|
|
m_pImg->m_hPalOld = SelectPalette( m_pImg->hDC,
|
|
(HPALETTE)m_pImg->m_pPalette->m_hObject,
|
|
FALSE );
|
|
RealizePalette( m_pImg->hDC );
|
|
|
|
theApp.m_pPalette = m_pImg->m_pPalette;
|
|
}
|
|
else
|
|
if (m_pImg->m_pPalette)
|
|
{
|
|
delete m_pImg->m_pPalette;
|
|
m_pImg->m_pPalette = NULL;
|
|
m_pImg->m_hPalOld = NULL;
|
|
}
|
|
|
|
if (g_pColors)
|
|
g_pColors->SetMono( ! m_nColors );
|
|
|
|
GlobalUnlock(m_hThing);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
BOOL CBitmapObj::Export(const TCHAR* szFileName)
|
|
{
|
|
// If the file already exists and we aren't dirty, then don't bother
|
|
// saving, just return...
|
|
CFileStatus fStat;
|
|
CString strFullName;
|
|
|
|
MkFullPath( strFullName, (const TCHAR*)szFileName );
|
|
|
|
if (CFile::GetStatus( strFullName, fStat ) && ! m_bDirty)
|
|
return TRUE;
|
|
|
|
CFile file;
|
|
|
|
CFileException e;
|
|
CFileSaver saver( szFileName );
|
|
|
|
if (! saver.CanSave())
|
|
return FALSE;
|
|
|
|
theApp.SetFileError( IDS_ERROR_EXPORT, CFileException::none, szFileName );
|
|
|
|
if (! OpenSubFile( file, saver, CFile::modeWrite
|
|
| CFile::modeCreate
|
|
| CFile::typeBinary, &e ))
|
|
{
|
|
theApp.SetFileError( IDS_ERROR_EXPORT, e.m_cause );
|
|
return FALSE;
|
|
}
|
|
|
|
BOOL bWritten = FALSE;
|
|
|
|
TRY
|
|
{
|
|
#ifdef PCX_SUPPORT
|
|
if (m_bPCX)
|
|
bWritten = WritePCX( &file );
|
|
else
|
|
#endif
|
|
bWritten = WriteResource( &file );
|
|
|
|
file.Close();
|
|
}
|
|
CATCH( CFileException, ex )
|
|
{
|
|
file.Abort();
|
|
theApp.SetFileError( IDS_ERROR_EXPORT, ex->m_cause );
|
|
return FALSE;
|
|
}
|
|
END_CATCH
|
|
|
|
if (bWritten)
|
|
bWritten = saver.Finish();
|
|
else
|
|
saver.Finish();
|
|
|
|
return bWritten;
|
|
}
|
|
|
|
typedef union _BITMAPHEADER
|
|
{
|
|
BITMAPINFOHEADER bmi;
|
|
BITMAPCOREHEADER bmc;
|
|
} BITMAPHEADER, *LPBITMAPHEADER;
|
|
|
|
inline WORD PaletteSize(LPBITMAPHEADER lpHdr) {return(PaletteSize((LPSTR)lpHdr));}
|
|
inline WORD DIBNumColors(LPBITMAPHEADER lpHdr) {return(DIBNumColors((LPSTR)lpHdr));}
|
|
inline DWORD DIBWidth(LPBITMAPHEADER lpHdr) {return(DIBWidth((LPSTR)lpHdr));}
|
|
inline DWORD DIBHeight(LPBITMAPHEADER lpHdr) {return(DIBHeight((LPSTR)lpHdr));}
|
|
|
|
/*****************************************************************************/
|
|
|
|
BOOL CBitmapObj::WriteResource( CFile* pfile, PBResType rtType )
|
|
{
|
|
BOOL bPBrushOLEHeader = (rtType == rtPBrushOLEObj);
|
|
BOOL bFileHeader = (rtType == rtFile)|| (rtType == rtPaintOLEObj) || bPBrushOLEHeader;
|
|
|
|
if (m_pImg == NULL)
|
|
{
|
|
// The image has not been loaded, so we'll just copy the
|
|
// original out to the file...
|
|
ASSERT( m_hThing );
|
|
|
|
if (! m_hThing)
|
|
return FALSE;
|
|
}
|
|
else
|
|
{
|
|
// The image has been loaded and may have been edited, so
|
|
// we'll convert it back to a dib to save...
|
|
if (! m_hThing)
|
|
SaveResource( FALSE );
|
|
|
|
if (! m_hThing)
|
|
return FALSE;
|
|
}
|
|
|
|
LPBITMAPHEADER lpDib = (LPBITMAPHEADER)GlobalLock(m_hThing);
|
|
DWORD dwLength = m_lMemSize;
|
|
DWORD dwWriteLength = dwLength;
|
|
DWORD dwHeadLength = 0;
|
|
|
|
struct _BMINFO
|
|
{
|
|
BITMAPINFOHEADER hdr;
|
|
RGBQUAD rgb[256];
|
|
} bmInfo;
|
|
|
|
LPBITMAPHEADER lpOldHdr = lpDib;
|
|
LPBITMAPHEADER lpNewHdr = lpOldHdr;
|
|
|
|
DWORD dwOldHdrLen = lpOldHdr->bmi.biSize + PaletteSize(lpOldHdr);
|
|
DWORD dwNewHdrLen = dwOldHdrLen;
|
|
|
|
if (bPBrushOLEHeader)
|
|
{
|
|
if (!IS_WIN30_DIB(lpDib))
|
|
{
|
|
LPBITMAPCOREINFO lpCoreInfo = (LPBITMAPCOREINFO)(&lpOldHdr->bmc);
|
|
memset(&bmInfo.hdr, 0, sizeof(bmInfo.hdr));
|
|
bmInfo.hdr.biSize = sizeof(bmInfo.hdr);
|
|
bmInfo.hdr.biWidth = lpCoreInfo->bmciHeader.bcWidth;
|
|
bmInfo.hdr.biHeight = lpCoreInfo->bmciHeader.bcHeight;
|
|
bmInfo.hdr.biPlanes = lpCoreInfo->bmciHeader.bcPlanes;
|
|
bmInfo.hdr.biBitCount = lpCoreInfo->bmciHeader.bcBitCount;
|
|
bmInfo.hdr.biCompression = BI_RGB;
|
|
|
|
for (int i=DIBNumColors(lpOldHdr)-1; i>=0; --i)
|
|
{
|
|
bmInfo.rgb[i].rgbBlue = lpCoreInfo->bmciColors[i].rgbtBlue;
|
|
bmInfo.rgb[i].rgbGreen = lpCoreInfo->bmciColors[i].rgbtGreen;
|
|
bmInfo.rgb[i].rgbRed = lpCoreInfo->bmciColors[i].rgbtRed;
|
|
bmInfo.rgb[i].rgbReserved = 0;
|
|
}
|
|
|
|
lpNewHdr = (LPBITMAPHEADER)(&bmInfo);
|
|
dwNewHdrLen = lpNewHdr->bmi.biSize + PaletteSize(lpNewHdr);
|
|
}
|
|
|
|
dwWriteLength += dwNewHdrLen - dwOldHdrLen;
|
|
dwLength += dwNewHdrLen - dwOldHdrLen;
|
|
|
|
if (bFileHeader)
|
|
{
|
|
#ifdef ICO_SUPPORT
|
|
if (IsSaveIcon())
|
|
{
|
|
dwHeadLength = sizeof(ICONFILEHEADER);
|
|
dwWriteLength += dwHeadLength;
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
dwHeadLength = sizeof(BITMAPFILEHEADER);
|
|
dwWriteLength += dwHeadLength;
|
|
|
|
// PBrush rounded up to 32 bytes (I don't know why)
|
|
dwWriteLength = (dwWriteLength+31) & ~31;
|
|
}
|
|
}
|
|
|
|
pfile->Write( &dwWriteLength, sizeof( dwWriteLength ));
|
|
}
|
|
|
|
if (bFileHeader)
|
|
{
|
|
// Icon support is not in application anymore, right?
|
|
#ifdef ICO_SUPPORT
|
|
if (IsSaveIcon())
|
|
{
|
|
ICONFILEHEADER hdr;
|
|
|
|
hdr.icoReserved = 0;
|
|
hdr.icoResourceType = 1;
|
|
hdr.icoResourceCount = 1;
|
|
|
|
pfile->Write( &hdr, sizeof( ICONFILEHEADER ) );
|
|
pfile->Seek( sizeof( ICONDIRENTRY ), CFile::current );
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
BITMAPFILEHEADER hdr;
|
|
|
|
hdr.bfType = ((WORD)('M' << 8) | 'B');
|
|
hdr.bfSize = dwLength + sizeof( BITMAPFILEHEADER );
|
|
hdr.bfReserved1 = 0;
|
|
hdr.bfReserved2 = 0;
|
|
hdr.bfOffBits = (DWORD)sizeof(hdr)
|
|
+ lpNewHdr->bmi.biSize
|
|
+ PaletteSize(lpNewHdr);
|
|
|
|
pfile->Write( &hdr, sizeof( hdr ));
|
|
}
|
|
}
|
|
|
|
pfile->Write(lpNewHdr, dwNewHdrLen);
|
|
|
|
BYTE* hp = ((BYTE*)lpDib) + dwOldHdrLen;
|
|
// We subtract the new header length because we have already translated
|
|
// dwLength to the new size
|
|
DWORD dwWrite = dwLength - dwNewHdrLen;
|
|
DWORD dwIconPos = pfile->GetPosition();;
|
|
|
|
while (dwWrite > 0)
|
|
{
|
|
UINT cbWrite = (UINT)min( dwWrite, 16384 );
|
|
|
|
pfile->Write( (LPVOID)hp, cbWrite );
|
|
|
|
hp += cbWrite;
|
|
dwWrite -= cbWrite;
|
|
}
|
|
|
|
dwWriteLength -= dwHeadLength;
|
|
if (dwWriteLength > dwLength)
|
|
{
|
|
// We rounded up to 32 bytes above, so this should always be < 32
|
|
ASSERT(dwWriteLength-dwLength < 32);
|
|
|
|
DWORD dwZeros[] =
|
|
{
|
|
0, 0, 0, 0, 0, 0, 0, 0,
|
|
} ;
|
|
|
|
pfile->Write( dwZeros, dwWriteLength-dwLength );
|
|
}
|
|
|
|
ASSERT( dwWrite == 0 );
|
|
|
|
// Icon support is not in application anymore, right?
|
|
#ifdef ICO_SUPPORT
|
|
if (IsSaveIcon())
|
|
{
|
|
DWORD nextPos = pfile->GetPosition();
|
|
|
|
pfile->Seek( (bFileHeader? sizeof( ICONFILEHEADER ): 0), CFile::begin );
|
|
|
|
ICONDIRENTRY dir;
|
|
|
|
dir.nWidth = (BYTE)DIBWidth ( lpDib );
|
|
dir.nHeight = (BYTE)DIBHeight ( lpDib ) / 2;
|
|
dir.nColorCount = (BYTE)DIBNumColors( lpDib );
|
|
dir.bReserved = 0;
|
|
dir.wReserved1 = 0;
|
|
dir.wReserved2 = 0;
|
|
dir.icoDIBSize = dwLength;
|
|
dir.icoDIBOffset = dwIconPos;
|
|
|
|
pfile->Write( &dir, sizeof( ICONDIRENTRY ) );
|
|
pfile->Seek( nextPos, CFile::begin );
|
|
}
|
|
else
|
|
#endif
|
|
m_bDirty = FALSE;
|
|
|
|
pfile->Flush();
|
|
|
|
GlobalUnlock(m_hThing);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
BOOL CBitmapObj::Import( LPCTSTR szFileName )
|
|
{
|
|
CFile file;
|
|
CFileException e;
|
|
|
|
theApp.SetFileError( IDS_ERROR_READLOAD, CFileException::none, szFileName );
|
|
|
|
if (! file.Open( szFileName, CFile::modeRead | CFile::typeBinary, &e ))
|
|
{
|
|
theApp.SetFileError( IDS_ERROR_READLOAD, e.m_cause );
|
|
return FALSE;
|
|
}
|
|
|
|
BOOL bGoodFile = TRUE;
|
|
|
|
|
|
TRY
|
|
{
|
|
bGoodFile = ReadResource( &file );
|
|
file.Close();
|
|
}
|
|
CATCH(CFileException, ex)
|
|
{
|
|
file.Abort();
|
|
bGoodFile = FALSE;
|
|
}
|
|
END_CATCH
|
|
|
|
if (!bGoodFile)
|
|
{
|
|
HGLOBAL hDib;
|
|
|
|
if (hDib = LoadDIBFromFile(szFileName, &theApp.m_guidFltTypeUsed))
|
|
{
|
|
bGoodFile = ReadResource(hDib);
|
|
|
|
if (bGoodFile)
|
|
{
|
|
theApp.SetFileError(0, CFileException::none);
|
|
}
|
|
else
|
|
{
|
|
theApp.SetFileError( IDS_ERROR_READLOAD, ferrNotValidBmp);
|
|
}
|
|
}
|
|
}
|
|
|
|
return bGoodFile;
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
BOOL CBitmapObj::ReadResource( CFile* pfile, PBResType rtType )
|
|
{
|
|
|
|
BOOL bPBrushOLEHeader = (rtType == rtPBrushOLEObj);
|
|
BOOL bFileHeader = (rtType == rtFile)
|
|
|| (rtType == rtPaintOLEObj)|| bPBrushOLEHeader;
|
|
|
|
DWORD dwLength = pfile->GetLength();
|
|
// special case zero length files.
|
|
if (! dwLength)
|
|
{
|
|
if (m_hThing)
|
|
Free();
|
|
|
|
m_bDirty = TRUE;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
if (bPBrushOLEHeader)
|
|
{
|
|
DWORD dwReadLen;
|
|
|
|
if (pfile->Read( &dwReadLen, sizeof( dwReadLen )) != sizeof( dwReadLen )
|
|
|| dwReadLen > dwLength)
|
|
{
|
|
theApp.SetFileError( IDS_ERROR_READLOAD, ferrNotValidBmp );
|
|
return FALSE;
|
|
}
|
|
dwLength -= sizeof(dwReadLen);
|
|
}
|
|
|
|
m_dwOffBits = 0;
|
|
|
|
if (bFileHeader)
|
|
{
|
|
BITMAPFILEHEADER hdr;
|
|
|
|
if (pfile->Read( &hdr, sizeof( hdr )) != sizeof( hdr ))
|
|
{
|
|
theApp.SetFileError( IDS_ERROR_READLOAD, ferrNotValidBmp );
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
if (hdr.bfType != ((WORD)('M' << 8) | 'B'))
|
|
{
|
|
theApp.SetFileError( IDS_ERROR_READLOAD, ferrNotValidBmp );
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
dwLength -= sizeof( hdr );
|
|
|
|
// Store the offset from the beginning of the BITMAPINFO
|
|
if (hdr.bfOffBits)
|
|
{
|
|
m_dwOffBits = hdr.bfOffBits - sizeof(hdr);
|
|
}
|
|
else
|
|
{
|
|
m_dwOffBits = 0;
|
|
}
|
|
|
|
|
|
}
|
|
|
|
if (m_hThing != NULL)
|
|
Free();
|
|
|
|
m_lMemSize = dwLength;
|
|
|
|
if (! Alloc())
|
|
return FALSE;
|
|
|
|
ASSERT( m_hThing );
|
|
|
|
PVOID lpvThing = GlobalLock(m_hThing);
|
|
|
|
BYTE* hp = (BYTE*)lpvThing;
|
|
|
|
while (dwLength > 0)
|
|
{
|
|
UINT cbRead = (UINT)min( dwLength, 16384 );
|
|
|
|
if (pfile->Read( (void FAR*)hp, cbRead ) != cbRead)
|
|
{
|
|
theApp.SetFileError( IDS_ERROR_READLOAD, ferrReadFailed );
|
|
GlobalUnlock(m_hThing);
|
|
return FALSE;
|
|
}
|
|
|
|
dwLength -= cbRead;
|
|
hp += cbRead;
|
|
}
|
|
|
|
ASSERT( dwLength == 0 );
|
|
|
|
//
|
|
// Calculate the bits offset because the BITMAPFILEHEADER had 0
|
|
//
|
|
if (!m_dwOffBits)
|
|
{
|
|
m_dwOffBits = (DWORD)(FindDIBBits ((LPSTR)lpvThing, 0) -
|
|
(LPSTR)lpvThing);
|
|
}
|
|
|
|
GlobalUnlock(m_hThing);
|
|
return TRUE;
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
BOOL CBitmapObj::ReadResource( HGLOBAL hDib )
|
|
{
|
|
LPBITMAPINFOHEADER lpbi = (LPBITMAPINFOHEADER) GlobalLock(hDib);
|
|
|
|
DWORD dwSizeImage;
|
|
|
|
if (lpbi == NULL || lpbi->biSize != sizeof(BITMAPINFOHEADER))
|
|
{
|
|
theApp.SetFileError( IDS_ERROR_READLOAD, ferrNotValidBmp );
|
|
return FALSE;
|
|
}
|
|
|
|
m_dwOffBits = lpbi->biSize + lpbi->biClrUsed * sizeof(RGBQUAD);
|
|
|
|
if (lpbi->biClrUsed == 0 && lpbi->biBitCount <= 8)
|
|
m_dwOffBits += (1 << lpbi->biBitCount) * sizeof(RGBQUAD);
|
|
|
|
if (lpbi->biSizeImage)
|
|
{
|
|
lpbi->biSizeImage = abs(lpbi->biSizeImage);
|
|
dwSizeImage = lpbi->biSizeImage;
|
|
}
|
|
else
|
|
{
|
|
dwSizeImage = abs(lpbi->biHeight) * ((lpbi->biWidth*lpbi->biBitCount+31)&~31)/8;
|
|
}
|
|
|
|
if (m_hThing != NULL)
|
|
Free();
|
|
|
|
m_lMemSize = m_dwOffBits + dwSizeImage;
|
|
|
|
m_hThing = hDib;
|
|
|
|
GlobalUnlock(hDib);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
void CBitmapObj::ReLoadImage( CPBDoc* pbDoc )
|
|
{
|
|
FreeImg( m_pImg );
|
|
CleanupImgUndo();
|
|
CleanupImgRubber();
|
|
m_pImg = NULL;
|
|
|
|
if (CreateImg())
|
|
{
|
|
POSITION pos = pbDoc->GetFirstViewPosition();
|
|
CPBView* pView = (CPBView*)pbDoc->GetNextView( pos );
|
|
|
|
if (pView)
|
|
{
|
|
pView->m_pImgWnd->SetImg( m_pImg );
|
|
pbDoc->UpdateAllViews( pView );
|
|
InvalImgRect( m_pImg, NULL );
|
|
}
|
|
}
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
void SwapBitmaps(HDC hDC1, int x1, int y1, int wid, int hgt,
|
|
HDC hDC2, int x2, int y2, CPalette* pPalette)
|
|
{
|
|
#if 0
|
|
// We would like to just XOR 3 times to swap, but sometimes the middle of the
|
|
// palette is empty, so we cannot
|
|
BitBlt(m_pImg->hDC, rect.left , rect.top,
|
|
rect.Width(), rect.Height(), hDC, 0, 0, DSx);
|
|
BitBlt(hDC, 0, 0, rect.Width(), rect.Height(), m_pImg->hDC,
|
|
rect.left, rect.top, DSx);
|
|
BitBlt(m_pImg->hDC, rect.left, rect.top, rect.Width(), rect.Height(),
|
|
hDC, 0, 0, DSx);
|
|
#else
|
|
CDC dcTemp;
|
|
|
|
CDC dc1, dc2;
|
|
dc1.Attach(hDC1);
|
|
dc2.Attach(hDC2);
|
|
|
|
|
|
|
|
BOOL bSuccess = dcTemp.CreateCompatibleDC(&dc1);
|
|
|
|
// Don't create a bitmap that is too large, or we will spend all our time
|
|
// swapping
|
|
int hgtTemp = 0x10000/wid;
|
|
hgtTemp = min(hgt, max(1, hgtTemp));
|
|
|
|
CBitmap bmTemp;
|
|
bSuccess = bSuccess && bmTemp.CreateCompatibleBitmap(&dc1, wid, hgtTemp);
|
|
bSuccess = bSuccess && dcTemp.SelectObject(&bmTemp)!=NULL;
|
|
|
|
if (!bSuccess)
|
|
{
|
|
// Make sure the DC's do not get deleted
|
|
dc1.Detach();
|
|
dc2.Detach();
|
|
return;
|
|
}
|
|
|
|
if (pPalette)
|
|
{
|
|
dcTemp.SelectPalette(pPalette, TRUE);
|
|
dcTemp.RealizePalette();
|
|
}
|
|
|
|
int yTemp;
|
|
for (yTemp=0; yTemp<hgt; yTemp+=hgtTemp)
|
|
{
|
|
hgtTemp = min(hgtTemp, hgt-yTemp);
|
|
|
|
dcTemp.BitBlt(0, 0, wid, hgtTemp, &dc1, x1, y1+yTemp, SRCCOPY);
|
|
dc1.BitBlt(x1, y1+yTemp, wid, hgtTemp, &dc2 , x2, y2+yTemp, SRCCOPY);
|
|
dc2.BitBlt(x2, y2+yTemp, wid, hgtTemp, &dcTemp, 0 , 0, SRCCOPY);
|
|
}
|
|
|
|
// Make sure the DC's do not get deleted
|
|
dc1.Detach();
|
|
dc2.Detach();
|
|
|
|
// Note that I explicitly delete the DC first, so I do not have to worry
|
|
// about selecting old objects back in
|
|
dcTemp.DeleteDC();
|
|
#endif
|
|
}
|
|
|
|
void CBitmapObj::UndoAction( CBmObjSequence* pSeq, UINT nActionID )
|
|
{
|
|
switch (nActionID)
|
|
{
|
|
default:
|
|
break;
|
|
|
|
case A_ImageChange:
|
|
|
|
if (((CImgTool::GetCurrentID() == IDMB_PICKTOOL)
|
|
|| (CImgTool::GetCurrentID() == IDMB_PICKRGNTOOL))
|
|
&& theImgBrush.m_pImg != NULL)
|
|
{
|
|
HideBrush();
|
|
InvalImgRect( theImgBrush.m_pImg, NULL ); // hide tracker
|
|
theImgBrush.m_pImg = NULL;
|
|
}
|
|
|
|
int cb;
|
|
CRect rect;
|
|
HBITMAP hImgBitmap;
|
|
|
|
pSeq->RetrieveInt( cb );
|
|
|
|
ASSERT(cb == sizeof( CRect ) + sizeof( hImgBitmap ));
|
|
|
|
pSeq->RetrieveRect( rect );
|
|
|
|
int nCursor = pSeq->m_nCursor;
|
|
|
|
pSeq->Retrieve( (BYTE*)&hImgBitmap, sizeof( hImgBitmap ) );
|
|
|
|
// Wipe out the old handles since we're reusing them in the
|
|
// new record and we don't what them deleted when this record
|
|
// is removed!
|
|
memset(&pSeq->ElementAt(nCursor), 0, sizeof( hImgBitmap ));
|
|
|
|
// Perform undo using these parameters...
|
|
|
|
SetupRubber(m_pImg);
|
|
SetUndo(m_pImg); // For redo...
|
|
HideBrush();
|
|
|
|
ASSERT(m_pImg != NULL);
|
|
|
|
HDC hDC = CreateCompatibleDC(m_pImg->hDC);
|
|
|
|
if (hDC == NULL)
|
|
{
|
|
theApp.SetGdiEmergency();
|
|
return;
|
|
}
|
|
|
|
HPALETTE hOldPalette = NULL;
|
|
HBITMAP hOldBitmap = (HBITMAP)SelectObject(hDC, hImgBitmap);
|
|
|
|
ASSERT(hOldBitmap != NULL);
|
|
|
|
if (m_pImg->m_pPalette)
|
|
{
|
|
hOldPalette = SelectPalette( hDC, (HPALETTE)m_pImg->m_pPalette->m_hObject,
|
|
FALSE ); // Background ??
|
|
RealizePalette( hDC );
|
|
}
|
|
|
|
// Three blits here swap the image and the undo bits, that
|
|
// way the undo bits are set up for a redo!
|
|
|
|
ASSERT(m_pImg->hDC != NULL);
|
|
SwapBitmaps(m_pImg->hDC, rect.left, rect.top,
|
|
rect.Width(), rect.Height(), hDC, 0, 0, m_pImg->m_pPalette);
|
|
|
|
if (hOldPalette)
|
|
SelectPalette( hDC, hOldPalette, FALSE ); // Background ??
|
|
|
|
SelectObject(hDC, hOldBitmap);
|
|
DeleteDC(hDC);
|
|
|
|
InvalImgRect (m_pImg, &rect);
|
|
CommitImgRect(m_pImg, &rect);
|
|
|
|
// Record the redo information...
|
|
|
|
theUndo.Insert((BYTE*)&hImgBitmap, sizeof (hImgBitmap));
|
|
theUndo.InsertRect(rect);
|
|
theUndo.InsertInt(sizeof (CRect) + sizeof (hImgBitmap));
|
|
theUndo.InsertInt(A_ImageChange);
|
|
theUndo.InsertPtr(m_pImg->m_pBitmapObj);
|
|
theUndo.InsertByte(CUndoBmObj::opAction);
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
void CBitmapObj::DeleteUndoAction(CBmObjSequence* pSeq, UINT nActionID)
|
|
{
|
|
switch (nActionID)
|
|
{
|
|
default:
|
|
break;
|
|
|
|
case A_ImageChange:
|
|
CRect rect;
|
|
HBITMAP hImgBitmap;
|
|
|
|
pSeq->RetrieveRect(rect);
|
|
pSeq->Retrieve((BYTE*)&hImgBitmap, sizeof (hImgBitmap));
|
|
|
|
if (hImgBitmap != NULL)
|
|
DeleteObject(hImgBitmap);
|
|
break;
|
|
}
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
BOOL CBitmapObj::FinishUndo(const CRect* pRect)
|
|
{
|
|
ASSERT( g_hUndoImgBitmap );
|
|
|
|
CRect rect;
|
|
if (pRect == NULL)
|
|
rect.SetRect(0, 0, m_pImg->cxWidth, m_pImg->cyHeight);
|
|
else
|
|
rect = *pRect;
|
|
|
|
HDC hDC1 = NULL;
|
|
HDC hDC2 = NULL;
|
|
HPALETTE hOldPalette = NULL;
|
|
HPALETTE hOldPalette2 = NULL;
|
|
HBITMAP hImgBitmap = NULL;
|
|
HBITMAP hOldBitmap1;
|
|
HBITMAP hOldBitmap2;
|
|
|
|
if (rect.left >= rect.right || rect.top >= rect.bottom)
|
|
{
|
|
// Not an error, just nothing to do...
|
|
return TRUE;
|
|
}
|
|
|
|
hImgBitmap = CreateCompatibleBitmap( m_pImg->hDC, rect.Width(), rect.Height() );
|
|
|
|
if (hImgBitmap == NULL)
|
|
goto LError;
|
|
|
|
if ((hDC1 = CreateCompatibleDC(m_pImg->hDC)) == NULL)
|
|
goto LError;
|
|
|
|
if ((hDC2 = CreateCompatibleDC(m_pImg->hDC)) == NULL)
|
|
goto LError;
|
|
|
|
if (m_pImg->m_pPalette)
|
|
{
|
|
hOldPalette = SelectPalette(hDC1, (HPALETTE)m_pImg->m_pPalette->m_hObject, FALSE );
|
|
RealizePalette( hDC1 );
|
|
|
|
hOldPalette2 = SelectPalette(hDC2, (HPALETTE)m_pImg->m_pPalette->m_hObject, FALSE );
|
|
RealizePalette( hDC2 );
|
|
}
|
|
|
|
VERIFY((hOldBitmap1 = (HBITMAP)SelectObject(hDC1, hImgBitmap)) != NULL);
|
|
VERIFY((hOldBitmap2 = (HBITMAP)SelectObject(hDC2, g_hUndoImgBitmap)) != NULL);
|
|
|
|
BitBlt(hDC1, 0, 0, rect.Width(), rect.Height(),
|
|
hDC2, rect.left , rect.top, SRCCOPY);
|
|
|
|
SelectObject(hDC1, hOldBitmap1);
|
|
SelectObject(hDC2, hOldBitmap2);
|
|
|
|
if (hOldPalette != NULL)
|
|
{
|
|
::SelectPalette(hDC1, hOldPalette, FALSE ); // Background ??
|
|
}
|
|
if (hOldPalette2 != NULL)
|
|
{
|
|
::SelectPalette(hDC2, hOldPalette2, FALSE ); // Background ??
|
|
}
|
|
|
|
DeleteDC(hDC1);
|
|
DeleteDC(hDC2);
|
|
|
|
theUndo.BeginUndo( IDS_UNDO_PAINTING );
|
|
|
|
theUndo.Insert((BYTE*)&hImgBitmap , sizeof (hImgBitmap));
|
|
theUndo.InsertRect(rect);
|
|
theUndo.InsertInt(sizeof (CRect) + sizeof (hImgBitmap));
|
|
theUndo.InsertInt(A_ImageChange);
|
|
theUndo.InsertPtr(this);
|
|
theUndo.InsertByte(CUndoBmObj::opAction);
|
|
|
|
theUndo.EndUndo();
|
|
|
|
// NOTE: At this point, we could free the undo bitmaps, but instead
|
|
// they are left around for next time...
|
|
|
|
return TRUE;
|
|
|
|
LError:
|
|
|
|
if (hImgBitmap != NULL)
|
|
DeleteObject(hImgBitmap);
|
|
|
|
if (hDC1 != NULL)
|
|
DeleteDC(hDC1);
|
|
|
|
if (hDC2 != NULL)
|
|
DeleteDC(hDC2);
|
|
|
|
// REVIEW: Since we couldn't allocate something here, there will
|
|
// be no way to undo the last operation... What should we do?
|
|
// Chances are, the system is so low on memory, a message box
|
|
// giving an option might even fail.
|
|
//
|
|
// For now, let's just beep to try to tell the user that whatever
|
|
// just happend can't be undone. Also, free the image sized bitmaps
|
|
// so the system has a little free memory.
|
|
|
|
CleanupImgUndo();
|
|
|
|
MessageBeep(0);
|
|
|
|
#ifdef _DEBUG
|
|
TRACE(TEXT("Not enough memory to undo image change!\n"));
|
|
#endif
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
BOOL CBitmapObj::SetIntProp(UINT nPropID, int val)
|
|
{
|
|
CWaitCursor waitCursor; // these all take awhile!
|
|
|
|
switch (nPropID)
|
|
{
|
|
case P_Width:
|
|
return SetSizeProp( P_Size, CSize( val, m_nHeight ) );
|
|
break;
|
|
|
|
case P_Height:
|
|
return SetSizeProp( P_Size, CSize( m_nWidth, val ) );
|
|
break;
|
|
|
|
case P_Colors:
|
|
if (CImgTool::GetCurrentID() == IDMB_PICKTOOL
|
|
|| CImgTool::GetCurrentID() == IDMB_PICKRGNTOOL)
|
|
{
|
|
CommitSelection( TRUE );
|
|
theImgBrush.m_pImg = NULL;
|
|
}
|
|
|
|
SetUndo( m_pImg );
|
|
FinishUndo( NULL );
|
|
|
|
// Perform the color-count conversion with DIBs
|
|
DWORD dwSize;
|
|
|
|
::SelectObject( m_pImg->hDC, m_pImg->hBitmapOld );
|
|
|
|
LPSTR lpDib = (LPSTR) DibFromBitmap(
|
|
m_pImg->hBitmap, BI_RGB, m_pImg->cPlanes * m_pImg->cBitCount,
|
|
m_pImg->m_pPalette, NULL, dwSize,
|
|
m_pImg->cXPelsPerMeter, m_pImg->cYPelsPerMeter );
|
|
|
|
::SelectObject( m_pImg->hDC, m_pImg->hBitmap );
|
|
|
|
if (lpDib == NULL)
|
|
{
|
|
theApp.SetGdiEmergency();
|
|
return FALSE;
|
|
}
|
|
|
|
// Make a new palette appropriate for this colors setting
|
|
CPalette* pNewPalette = NULL;
|
|
|
|
int iPlanes = (val? 1: ::GetDeviceCaps( m_pImg->hDC, PLANES ));
|
|
int iBitCnt = (val? 1: ::GetDeviceCaps( m_pImg->hDC, BITSPIXEL ));
|
|
int iColors = iPlanes * iBitCnt;
|
|
|
|
val = 3;
|
|
|
|
if (theApp.m_bPaletted)
|
|
switch (iColors)
|
|
{
|
|
case 1:
|
|
pNewPalette = GetStd2Palette();
|
|
break;
|
|
|
|
case 4:
|
|
pNewPalette = GetStd16Palette();
|
|
break;
|
|
|
|
case 8:
|
|
pNewPalette = GetStd256Palette();
|
|
break;
|
|
}
|
|
|
|
switch (iColors)
|
|
{
|
|
case 8:
|
|
val = 2;
|
|
break;
|
|
|
|
case 4:
|
|
val = 1;
|
|
break;
|
|
|
|
case 1:
|
|
val = 0;
|
|
break;
|
|
}
|
|
|
|
HBITMAP hTmpBitmap = CreateBitmap( 1, 1, iPlanes, iBitCnt, NULL );
|
|
HBITMAP hNewBitmap = CreateBitmap( m_pImg->cxWidth,
|
|
m_pImg->cyHeight,
|
|
iPlanes, iBitCnt, NULL );
|
|
if (! hTmpBitmap || ! hNewBitmap)
|
|
{
|
|
FreeDib( lpDib );
|
|
|
|
if (hTmpBitmap)
|
|
::DeleteObject( hTmpBitmap );
|
|
|
|
if (hNewBitmap)
|
|
::DeleteObject( hNewBitmap );
|
|
|
|
if (pNewPalette)
|
|
delete pNewPalette;
|
|
|
|
theApp.SetGdiEmergency();
|
|
return FALSE;
|
|
}
|
|
|
|
HPALETTE hPalOld = NULL;
|
|
|
|
::SelectObject( m_pImg->hDC, hTmpBitmap );
|
|
|
|
if (pNewPalette)
|
|
{
|
|
hPalOld = ::SelectPalette( m_pImg->hDC, (HPALETTE)pNewPalette->m_hObject, FALSE );
|
|
::RealizePalette( m_pImg->hDC );
|
|
}
|
|
|
|
int iLinesDone = SetDIBits( m_pImg->hDC, hNewBitmap, 0,
|
|
m_pImg->cyHeight,
|
|
FindDIBBits( lpDib ),
|
|
(LPBITMAPINFO)lpDib, DIB_RGB_COLORS );
|
|
FreeDib( lpDib );
|
|
|
|
if (iLinesDone != m_pImg->cyHeight)
|
|
{
|
|
::SelectObject( m_pImg->hDC, m_pImg->hBitmap );
|
|
|
|
if (hPalOld)
|
|
{
|
|
::SelectPalette( m_pImg->hDC, hPalOld, FALSE );
|
|
::RealizePalette( m_pImg->hDC );
|
|
|
|
delete pNewPalette;
|
|
}
|
|
|
|
::DeleteObject( hTmpBitmap );
|
|
::DeleteObject( hNewBitmap );
|
|
|
|
theApp.SetGdiEmergency();
|
|
|
|
return FALSE;
|
|
}
|
|
m_pImg->cPlanes = iPlanes;
|
|
m_pImg->cBitCount = iBitCnt;
|
|
|
|
m_nColors = val;
|
|
|
|
::SelectObject( m_pImg->hDC, hNewBitmap );
|
|
::DeleteObject( m_pImg->hBitmap );
|
|
|
|
m_pImg->hBitmap = hNewBitmap;
|
|
|
|
if (m_pImg->m_pPalette)
|
|
{
|
|
if (! pNewPalette)
|
|
{
|
|
::SelectPalette( m_pImg->hDC, m_pImg->m_hPalOld, FALSE );
|
|
m_pImg->m_hPalOld = NULL;
|
|
}
|
|
delete m_pImg->m_pPalette;
|
|
}
|
|
|
|
m_pImg->m_pPalette = pNewPalette;
|
|
theApp.m_pPalette = pNewPalette;
|
|
|
|
::DeleteObject( hTmpBitmap );
|
|
|
|
DirtyImg( m_pImg );
|
|
InvalImgRect( m_pImg, NULL );
|
|
|
|
// The rubber-banding bitmap is now invalid...
|
|
if (m_pImg == pRubberImg)
|
|
{
|
|
TRACE(TEXT("Clearing rubber\n"));
|
|
pRubberImg = NULL;
|
|
SetupRubber( m_pImg );
|
|
}
|
|
|
|
if (g_pColors)
|
|
g_pColors->SetMono( ! m_nColors );
|
|
|
|
InformDependants( P_Image );
|
|
break;
|
|
}
|
|
|
|
m_bDirty = TRUE;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
GPT CBitmapObj::GetIntProp(UINT nPropID, int& val)
|
|
{
|
|
switch (nPropID)
|
|
{
|
|
case P_Colors:
|
|
val = m_nColors;
|
|
return valid;
|
|
break;
|
|
|
|
case P_Image:
|
|
val = NULL;
|
|
return valid; // Must return now since this is a fake prop...
|
|
}
|
|
|
|
return invalid;
|
|
}
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
BOOL CBitmapObj::SetSizeProp(UINT nPropID, const CSize& val)
|
|
{
|
|
ASSERT(m_pImg != NULL);
|
|
|
|
if ((CImgTool::GetCurrentID() == IDMB_PICKTOOL)
|
|
|| (CImgTool::GetCurrentID() == IDMB_PICKRGNTOOL))
|
|
{
|
|
CommitSelection(TRUE);
|
|
theImgBrush.m_pImg = NULL;
|
|
}
|
|
|
|
switch (nPropID)
|
|
{
|
|
default:
|
|
ASSERT(FALSE);
|
|
|
|
case P_Size:
|
|
if (val.cx == m_pImg->cxWidth && val.cy == m_pImg->cyHeight)
|
|
return TRUE;
|
|
|
|
if (val.cx < 1 || val.cy < 1)
|
|
{
|
|
CmpMessageBox(IDS_ERROR_BITMAPSIZE, AFX_IDS_APP_TITLE,
|
|
MB_OK | MB_ICONEXCLAMATION);
|
|
return FALSE;
|
|
}
|
|
|
|
CWaitCursor waitCursor;
|
|
BOOL bStretch = FALSE;
|
|
|
|
CSize curSize;
|
|
GetImgSize(m_pImg, curSize);
|
|
|
|
bStretch = m_nShrink;
|
|
|
|
SetUndo(m_pImg);
|
|
CRect undoRect(0, 0, m_pImg->cxWidth, m_pImg->cyHeight);
|
|
|
|
if (! SetImgSize(m_pImg, (CSize)val, bStretch))
|
|
{
|
|
theApp.SetMemoryEmergency();
|
|
return FALSE;
|
|
}
|
|
|
|
FinishUndo(&undoRect);
|
|
|
|
DirtyImg(m_pImg);
|
|
|
|
pRubberImg = NULL;
|
|
SetupRubber(m_pImg);
|
|
|
|
if (theUndo.IsRecording())
|
|
{
|
|
theUndo.OnSetIntProp(this, P_Width, m_nWidth);
|
|
theUndo.OnSetIntProp(this, P_Height, m_nHeight);
|
|
}
|
|
|
|
int nOldWidth = m_nWidth;
|
|
int nOldHeight = m_nHeight;
|
|
|
|
m_nWidth = val.cx;
|
|
m_nHeight = val.cy;
|
|
|
|
if (m_nWidth != nOldWidth)
|
|
InformDependants(P_Width);
|
|
|
|
if (m_nHeight != nOldHeight)
|
|
InformDependants(P_Height);
|
|
|
|
InformDependants(P_Image);
|
|
|
|
break;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
BOOL CBitmapObj::SaveResource( BOOL bClear )
|
|
{
|
|
if (m_pImg == NULL)
|
|
return TRUE;
|
|
|
|
if (bClear)
|
|
{
|
|
if (m_hThing && ! m_pImg->bDirty && ! m_bDirty)
|
|
return TRUE; // nothing to save
|
|
|
|
m_bDirty |= m_pImg->bDirty;
|
|
|
|
if (m_pImg == theImgBrush.m_pImg)
|
|
theImgBrush.m_pImg = NULL;
|
|
|
|
if (m_pImg == pRubberImg)
|
|
pRubberImg = NULL;
|
|
|
|
HideBrush();
|
|
}
|
|
|
|
DWORD dwStyle = BI_RGB;
|
|
int iColors = m_nColors;
|
|
|
|
if (m_nSaveColors >= 0)
|
|
{
|
|
iColors = m_nSaveColors;
|
|
m_nSaveColors = -1;
|
|
}
|
|
|
|
if (m_bCompressed)
|
|
{
|
|
switch (iColors)
|
|
{
|
|
case 1:
|
|
dwStyle = BI_RLE4;
|
|
break;
|
|
|
|
case 2:
|
|
dwStyle = BI_RLE8;
|
|
break;
|
|
}
|
|
}
|
|
|
|
switch (iColors)
|
|
{
|
|
case 0:
|
|
iColors = 1;
|
|
break;
|
|
|
|
case 1:
|
|
iColors = 4;
|
|
break;
|
|
|
|
case 2:
|
|
iColors = 8;
|
|
break;
|
|
|
|
case 3:
|
|
iColors = 24;
|
|
break;
|
|
|
|
default:
|
|
iColors = 0;
|
|
break;
|
|
}
|
|
|
|
HBITMAP hBitmap = m_pImg->hBitmap;
|
|
HBITMAP hMaskBitmap = NULL;
|
|
BOOL bNewBitmap = FALSE;
|
|
HGLOBAL lpDIB;
|
|
DWORD dwSize;
|
|
|
|
// Icon support is not in application anymore, right?
|
|
#ifdef ICO_SUPPORT
|
|
if (IsSaveIcon())
|
|
{
|
|
// build a mask based on the current background color
|
|
// and make sure the bitmap is the icon size
|
|
bNewBitmap = SetupForIcon( hBitmap, hMaskBitmap );
|
|
|
|
if (iColors > 4 || iColors < 1)
|
|
iColors = 4;
|
|
}
|
|
#endif
|
|
|
|
::SelectObject( m_pImg->hDC, m_pImg->hBitmapOld );
|
|
|
|
lpDIB = DibFromBitmap(
|
|
hBitmap, dwStyle, (WORD)iColors,
|
|
theApp.m_pPalette, hMaskBitmap, dwSize,
|
|
m_pImg->cXPelsPerMeter, m_pImg->cYPelsPerMeter );
|
|
|
|
::SelectObject( m_pImg->hDC, m_pImg->hBitmap );
|
|
|
|
if (bNewBitmap)
|
|
{
|
|
::DeleteObject( hBitmap );
|
|
::DeleteObject( hMaskBitmap );
|
|
}
|
|
|
|
if (lpDIB == NULL)
|
|
{
|
|
theApp.SetMemoryEmergency();
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
if (m_hThing != NULL)
|
|
Free();
|
|
|
|
// We packed the DIB, so the offset will always be right after the palette,
|
|
// which is implied by this being 0
|
|
m_dwOffBits = 0;
|
|
m_hThing = lpDIB;
|
|
m_lMemSize = dwSize;
|
|
|
|
if (bClear)
|
|
m_pImg->bDirty = FALSE;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
// Icon support is not in application anymore, right?
|
|
BOOL CBitmapObj::SetupForIcon( HBITMAP& hBitmap, HBITMAP& hMaskBitmap )
|
|
{
|
|
CDC dcIcon;
|
|
CDC dcMask;
|
|
CBitmap bmIcon;
|
|
CBitmap bmMask;
|
|
CDC* pdcBitmap = CDC::FromHandle( m_pImg->hDC );
|
|
CSize sizeIcon( ::GetSystemMetrics( SM_CXICON ),
|
|
::GetSystemMetrics( SM_CYICON ) );
|
|
BOOL bNewBitmap = FALSE;
|
|
|
|
if (dcIcon.CreateCompatibleDC( pdcBitmap )
|
|
&& dcMask.CreateCompatibleDC( pdcBitmap )
|
|
&& bmIcon.CreateCompatibleBitmap( pdcBitmap, sizeIcon.cx, sizeIcon.cy )
|
|
&& bmMask.CreateBitmap( sizeIcon.cx, sizeIcon.cy, 1, 1, NULL ))
|
|
{
|
|
CPalette* ppalOld = NULL;
|
|
CBitmap* pbmOldIcon = dcIcon.SelectObject( &bmIcon );
|
|
CBitmap* pbmOldMask = dcMask.SelectObject( &bmMask );
|
|
|
|
if (theApp.m_pPalette)
|
|
{
|
|
ppalOld = dcIcon.SelectPalette( theApp.m_pPalette, FALSE );
|
|
dcIcon.RealizePalette();
|
|
}
|
|
dcIcon.PatBlt( 0, 0, sizeIcon.cx, sizeIcon.cy, WHITENESS );
|
|
|
|
CBrush brBackGround( crRight );
|
|
|
|
if (brBackGround.GetSafeHandle() != NULL)
|
|
{
|
|
CRect rect( 0, 0, sizeIcon.cx, sizeIcon.cy );
|
|
|
|
dcIcon.FillRect( &rect, &brBackGround );
|
|
|
|
brBackGround.DeleteObject();
|
|
}
|
|
int iWidth = min( sizeIcon.cx, m_pImg->cxWidth );
|
|
int iHeight = min( sizeIcon.cy, m_pImg->cyHeight );
|
|
|
|
dcIcon.BitBlt( 0, 0, iWidth, iHeight, pdcBitmap, 0, 0, SRCCOPY );
|
|
|
|
COLORREF oldBkColor = dcIcon.SetBkColor( crRight );
|
|
|
|
dcMask.BitBlt( 0, 0, sizeIcon.cx, sizeIcon.cy, &dcIcon, 0, 0, SRCCOPY );
|
|
|
|
COLORREF cRefFGColorOld = dcMask.SetTextColor( RGB( 0, 0, 0 ) );
|
|
COLORREF cRefBKColorOld = dcMask.SetBkColor ( RGB( 255, 255, 255 ) );
|
|
|
|
dcIcon.BitBlt( 0, 0, sizeIcon.cx, sizeIcon.cy, &dcMask, 0, 0, DSna );
|
|
|
|
dcMask.SetTextColor( cRefFGColorOld );
|
|
dcMask.SetBkColor ( cRefBKColorOld );
|
|
dcIcon.SetBkColor ( oldBkColor );
|
|
|
|
if (ppalOld != NULL)
|
|
dcIcon.SelectPalette( ppalOld, FALSE );
|
|
|
|
if (pbmOldIcon != NULL)
|
|
dcIcon.SelectObject( pbmOldIcon );
|
|
|
|
if (pbmOldMask != NULL)
|
|
dcMask.SelectObject( pbmOldMask );
|
|
|
|
hBitmap = (HBITMAP)bmIcon.Detach();
|
|
hMaskBitmap = (HBITMAP)bmMask.Detach();
|
|
bNewBitmap = TRUE;
|
|
}
|
|
|
|
if (dcIcon.GetSafeHdc() != NULL)
|
|
dcIcon.DeleteDC();
|
|
|
|
if (dcMask.GetSafeHdc() != NULL)
|
|
dcMask.DeleteDC();
|
|
|
|
if (bmIcon.GetSafeHandle() != NULL)
|
|
bmIcon.DeleteObject();
|
|
|
|
if (bmMask.GetSafeHandle() != NULL)
|
|
bmMask.DeleteObject();
|
|
|
|
return bNewBitmap;
|
|
}
|
|
|
|
/*****************************************************************************/
|