www.pudn.com > ImageSplite.rar > dibimage.cpp
/*
Module : DIBIMAGE.CPP
Purpose: Implementation for an MFC class that encapsulates DIBs
and supports a variety of image manipulation functions on it
Created: PJN / 23-07-1997
History: PJN / 23-07-1999 1. Unicode enabled the code + provision of Unicode configurations in the workspace
2. ColorsUsed function has now been implemented
Major update by Fabio Angelini. Changes include:
1. Inclusion of a C3By3MeanFilter.
2. Tidy up of how CDibImage disposes of its resources
3. Addition of a Detach method
4. Pixel access is now supported for 1, 4, 8 and 24 bit pixel formats
5. Function to convert from a HBITMAP to a DIB
6. Function to convert to a HBITMAP
7. Function to screen capture a specified area of a specified window
8. Function to convert to 24 bits.
9. Unified all the low-level API to manage DIB files into as single source code
PJN / 06-09-1999 1. Provision of a IsRunLengthEncoded function.
2. Updates to the DataFormatSupported function to prevent access violations in the
dibedit sample application
PJN / 12-09-1999 1. Added support for Jpeg loading or saving by means of the Intel Jpeg Library
PJN / 21-09-1999 1. Fixed a bug in the function WindowToDIB which is used by CDibImage::CopyFromWindow
PJN / 03-10-1999 1. Optimized memory usage when loading and saving JPEG images from file.
PJN / 25-01-2000 1. Updated code to use Intel Jpeg Library v1.1
PJN / 07-03-2000 1. Added support for True color targa (.tga) file loading and saving
2. jpeg loading and saving code thoroughly reviewed and optimized
3. The sample app now clears the histogram correctly when there are no
views visible
PJN / 20-03-2000 1. Modified some code in CDibImage which was causing the VC++ 6 compiler to bomb out
2. Removed a number of unreferenced variables detected by VC++ 6.
3. Removed a number of useless comments in tgaapi.cpp
PJN / 02-04-2000 1. Fixed an access violation in ::ReadJPegFile
2. Added a call to GlobalUnlock which was missing in CDibImage::UserDefinedFilter
Copyright (c) 1997 - 2000 by PJ Naughter.
All rights reserved.
*/
///////////////////////////////// Includes //////////////////////////////////
#include "stdafx.h"
#include "math.h"
#include "dibimage.h"
#ifndef DIBIMAGE_NO_JPEG
#include "jpegapi.h"
#endif
#include "tgaapi.h"
#include "resource.h"
///////////////////////////////// defines /////////////////////////////////////
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
//////////////////////////////// Implementation ///////////////////////////////
C3By3Filter::C3By3Filter()
{
//Default filter is a filter which will not do anything to the image
for (int i=0; i<3; i++)
for (int j=0; j<3; j++)
m_nValues[i][j] = 0;
m_nValues[1][1] = 1;
m_nDivision = 1;
m_nBias = 0;
}
COLORREF C3By3Filter::Filter(CDibImage& dibImage, LPSTR lpDibBits, int x, int y)
{
int r = 0;
int g = 0;
int b = 0;
for (int i=0; i<3; i++)
{
for (int j=0; j<3; j++)
{
COLORREF c;
if (dibImage.GetPixel(x+i-1, y+j-1, c, lpDibBits))
{
r += (m_nValues[i][j] * GetRValue(c));
g += (m_nValues[i][j] * GetGValue(c));
b += (m_nValues[i][j] * GetBValue(c));
}
}
}
ASSERT(m_nDivision);
r = min(r/m_nDivision + m_nBias, 255);
g = min(g/m_nDivision + m_nBias, 255);
b = min(b/m_nDivision + m_nBias, 255);
r = max(r, 0);
g = max(g, 0);
b = max(b, 0);
return RGB(r, g, b);
}
C3By3MedianFilter::C3By3MedianFilter()
{
}
COLORREF C3By3MedianFilter::Filter(CDibImage& dibImage, LPSTR lpDibBits, int x, int y)
{
int nPixels = 0;
for (int k=0; k<9; k++)
m_Ordered[k] = 0;
for (int i=0; i<3; i++)
{
for (int j=0; j<3; j++)
{
COLORREF c;
if (dibImage.GetPixel(x+i-1, y+j-1, c, lpDibBits))
{
m_Ordered[nPixels] = c;
nPixels++;
}
}
}
qsort(&m_Ordered, nPixels, sizeof(COLORREF), CompareFunc);
return m_Ordered[nPixels/2];
}
int C3By3MedianFilter::CompareFunc(const void *elem1, const void *elem2)
{
COLORREF c1 = *(COLORREF*)elem1;
COLORREF c2 = *(COLORREF*)elem2;
if (c1 == c2)
return 0;
else
{
BYTE r1 = GetRValue(c1);
BYTE g1 = GetGValue(c1);
BYTE b1 = GetBValue(c1);
BYTE r2 = GetRValue(c2);
BYTE g2 = GetGValue(c2);
BYTE b2 = GetBValue(c2);
if ((r1 + g1 + b1) > (r2 + g2 + b2))
return 1;
else
return -1;
}
}
C3By3MeanFilter::C3By3MeanFilter()
{
}
COLORREF C3By3MeanFilter::Filter(CDibImage& dibImage, LPSTR lpDibBits, int x, int y)
{
COLORREF r=0,g=0,b=0;
COLORREF co;
COLORREF c;
dibImage.GetPixel(x, y, co, lpDibBits);
for (int j=-1; j<2; j++)
{
for (int i=-1; i<2; i++)
{
if ( dibImage.GetPixel(x+i, y-j, c, lpDibBits) )
{
r += GetRValue(c);
g += GetGValue(c);
b += GetBValue(c);
}
}
}
return RGB(r/9, g/9, b/9 );
}
C5By5Filter::C5By5Filter()
{
//Default filter is a filter which will not do anything to the image
for (int i=0; i<5; i++)
for (int j=0; j<5; j++)
m_nValues[i][j] = 0;
m_nValues[2][2] = 1;
m_nDivision = 1;
m_nBias = 0;
}
COLORREF C5By5Filter::Filter(CDibImage& dibImage, LPSTR lpDibBits, int x, int y)
{
int r = 0;
int g = 0;
int b = 0;
for (int i=0; i<5; i++)
{
for (int j=0; j<5; j++)
{
COLORREF c;
if (dibImage.GetPixel(x+i-2, y+j-2, c, lpDibBits))
{
r += (m_nValues[i][j] * GetRValue(c));
g += (m_nValues[i][j] * GetGValue(c));
b += (m_nValues[i][j] * GetBValue(c));
}
}
}
ASSERT(m_nDivision);
r = min(r/m_nDivision + m_nBias, 255);
g = min(g/m_nDivision + m_nBias, 255);
b = min(b/m_nDivision + m_nBias, 255);
r = max(r, 0);
g = max(g, 0);
b = max(b, 0);
return RGB(r, g, b);
}
C7By7Filter::C7By7Filter()
{
//Default filter is a filter which will not do anything to the image
for (int i=0; i<7; i++)
for (int j=0; j<7; j++)
m_nValues[i][j] = 0;
m_nValues[3][3] = 1;
m_nDivision = 1;
m_nBias = 0;
}
COLORREF C7By7Filter::Filter(CDibImage& dibImage, LPSTR lpDibBits, int x, int y)
{
int r = 0;
int g = 0;
int b = 0;
for (int i=0; i<7; i++)
{
for (int j=0; j<7; j++)
{
COLORREF c;
if (dibImage.GetPixel(x+i-3, y+j-3, c, lpDibBits))
{
r += (m_nValues[i][j] * GetRValue(c));
g += (m_nValues[i][j] * GetGValue(c));
b += (m_nValues[i][j] * GetBValue(c));
}
}
}
ASSERT(m_nDivision);
r = min(r/m_nDivision + m_nBias, 255);
g = min(g/m_nDivision + m_nBias, 255);
b = min(b/m_nDivision + m_nBias, 255);
r = max(r, 0);
g = max(g, 0);
b = max(b, 0);
return RGB(r, g, b);
}
CUndoNode::CUndoNode(CDibImage* pImage, const CString& sDescription)
{
m_pImage = pImage;
m_sDescription = sDescription;
}
CUndoNode::~CUndoNode()
{
delete m_pImage;
m_pImage = NULL;
}
CDibImage::CDibImage()
{
m_hDib = NULL;
m_pWorkingArea = NULL;
m_nWidth = 0;
m_nHeight = 0;
m_nScanWidth = 0;
m_nBitsPerPixel = 0;
m_Pal = NULL;
m_nUndoSize = 4; //By default, we support 4 levels of undo, if you
//want more (at the expense of memory usage) just
//call SetUndoSize will the level you want
}
CDibImage::CDibImage(const CDibImage& ds)
{
m_hDib = NULL;
m_pWorkingArea = NULL;
m_nWidth = 0;
m_nHeight = 0;
m_nScanWidth = 0;
m_nBitsPerPixel = 0;
m_Pal = NULL;
m_nUndoSize = 4; //By default, we support 4 levels of undo, if you
//want more (at the expense of memory usage) just
//call SetUndoSize will the level you want
Attach((HDIB) CopyHandle(ds.m_hDib));
SetWorkingArea(ds.m_pWorkingArea->Clone());
}
CDibImage::~CDibImage()
{
Destroy();
//empty the redo stack
for (int i=0; iClone());
return *this;
}
BOOL CDibImage::Create(CSize size, WORD nBitCount)
{
Destroy();
BOOL bSuccess = TRUE;
CWindowDC dcScreen(NULL);
// should not already have palette
ASSERT(m_Pal == NULL);
// Select specified palette
m_Pal = ::CreateHalftonePalette(dcScreen.m_hDC);
if (m_Pal == NULL)
return FALSE;
// Fill in the BITMAPINFO Structure
BITMAPINFO bmi;
bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
bmi.bmiHeader.biWidth = size.cx;
bmi.bmiHeader.biHeight = size.cy;
bmi.bmiHeader.biPlanes = 1;
bmi.bmiHeader.biBitCount = nBitCount;
bmi.bmiHeader.biCompression = BI_RGB;
bmi.bmiHeader.biSizeImage = 0;
bmi.bmiHeader.biXPelsPerMeter = 0;
bmi.bmiHeader.biYPelsPerMeter = 0;
int nPaletteSize = ComputePaletteSize(nBitCount);
bmi.bmiHeader.biClrUsed = nPaletteSize;
bmi.bmiHeader.biClrImportant = nPaletteSize;
m_nWidth = size.cx;
m_nHeight = size.cy;
m_nBitsPerPixel = nBitCount;
m_nScanWidth = WIDTHBYTES(m_nWidth*m_nBitsPerPixel);
m_pWorkingArea = new CRectWorkingArea(Rect());
DWORD dwSize = sizeof(bmi) + m_nScanWidth*m_nHeight;
m_hDib = (HDIB) ::GlobalAlloc(GMEM_MOVEABLE | GMEM_ZEROINIT, dwSize);
if (m_hDib == NULL)
return FALSE;
LPSTR pDib = (LPSTR) ::GlobalLock((HGLOBAL) m_hDib);
memcpy(pDib, &bmi, sizeof(bmi));
::GlobalUnlock((HGLOBAL) m_hDib);
return bSuccess;
}
int CDibImage::ComputePaletteSize(DWORD nBitCount)
{
int nSize = 0;
switch (nBitCount)
{
case 1: nSize = 2; break;
case 4: nSize = 16; break;
case 8: nSize = 256; break;
case 16:
case 24:
case 32: nSize = 0; break;
default: ASSERT(FALSE); break;
}
return nSize;
}
void CDibImage::Destroy()
{
DestroyWorkingArea();
DestroyHPALLETTE();
DestroyHDIB();
}
void CDibImage::DestroyWorkingArea()
{
if (m_pWorkingArea)
{
delete m_pWorkingArea;
m_pWorkingArea = NULL;
}
}
void CDibImage::DestroyHDIB()
{
if (m_hDib)
{
GlobalFree(m_hDib);
m_hDib = NULL;
}
}
void CDibImage::DestroyHPALLETTE()
{
if ( m_Pal != NULL )
{
DeleteObject(m_Pal);
m_Pal = NULL;
}
}
BOOL CDibImage::Attach(HDIB hDib)
{
Destroy();
BOOL bSuccess = FALSE;
if (hDib)
{
m_hDib = hDib;
DWORD dwSize = GlobalSize(m_hDib);
ASSERT(dwSize);
LPSTR lpDib = (LPSTR) ::GlobalLock(m_hDib);
ASSERT(lpDib);
m_nWidth = ::DIBWidth(lpDib);
m_nHeight = ::DIBHeight(lpDib);
::GlobalUnlock((HGLOBAL) m_hDib);
m_nBitsPerPixel = GetBitsPerPixel();
m_nScanWidth = WIDTHBYTES(m_nWidth*m_nBitsPerPixel);
m_pWorkingArea = new CRectWorkingArea(Rect());
CPalette pal;
::CreateDIBPalette(m_hDib, &pal);
m_Pal = (HPALETTE) pal.Detach();
bSuccess = TRUE;
}
return bSuccess;
}
HDIB CDibImage::Detach(void)
{
DestroyWorkingArea();
DestroyHPALLETTE();
HDIB hDib = m_hDib;
m_hDib = NULL;
return hDib;
}
BOOL CDibImage::Load(LPCTSTR lpszPathName)
{
CFile f;
if (!f.Open(lpszPathName, CFile::modeRead | CFile::shareDenyWrite))
return FALSE;
//Determine what image type it is based on the filename extension
TCHAR pszExt[_MAX_EXT];
_tsplitpath(lpszPathName, NULL, NULL, NULL, pszExt);
CString sExt(pszExt);
if ((sExt.CompareNoCase(_T(".bmp")) == 0) || (sExt.CompareNoCase(_T(".dib")) == 0))
return Attach(::ReadDIBFile(f));
#ifndef DIBIMAGE_NO_JPEG
else if ((sExt.CompareNoCase(_T(".jpg")) == 0) || (sExt.CompareNoCase(_T(".jpeg")) == 0))
return Attach(::ReadJPEGFile(f));
#endif
else if (sExt.CompareNoCase(_T(".tga")) == 0)
return Attach(::ReadTGAFile(f));
else
{
TRACE(_T("Could not detemine what file type to load based on the filename extension\n"));
return FALSE;
}
}
BOOL CDibImage::Load(HINSTANCE hInst, LPCTSTR lpResourceName)
{
HRSRC hSrc = FindResource(hInst, lpResourceName, RT_BITMAP);
BOOL bSuccess = FALSE;
if (hSrc)
{
HGLOBAL hResData = LoadResource(hInst, hSrc);
if (hResData)
{
LPVOID lpResData = LockResource(hResData);
if (lpResData)
{
DWORD dwSize = SizeofResource(hInst, hSrc);
if (dwSize)
{
HGLOBAL hGlobal = GlobalAlloc(GMEM_MOVEABLE, dwSize);
if (hGlobal)
{
LPVOID lpBitmapData = GlobalLock(hGlobal);
if (lpBitmapData)
{
CopyMemory(lpBitmapData, lpResData, dwSize);
GlobalUnlock(hGlobal);
bSuccess = Attach((HDIB) hGlobal);
}
}
}
}
}
}
return bSuccess;
}
int CDibImage::GetBitsPerPixel() const
{
int nBitCount;
if (m_hDib == NULL)
nBitCount = 0;
else
{
LPSTR lpDib = (LPSTR) ::GlobalLock(m_hDib);
// Calculate the number of bits per pixel for the DIB.
if (IS_WIN30_DIB(lpDib))
{
LPBITMAPINFOHEADER pBih = (LPBITMAPINFOHEADER)lpDib;
nBitCount = pBih->biBitCount;
}
else
{
LPBITMAPCOREHEADER pbic = (LPBITMAPCOREHEADER)lpDib;
nBitCount = pbic->bcBitCount;
}
::GlobalUnlock((HGLOBAL) m_hDib);
}
return nBitCount;
}
BOOL CDibImage::IsRunLengthEncoded() const
{
BOOL bEncoded = FALSE;
if (m_hDib)
{
LPSTR lpDib = (LPSTR) ::GlobalLock(m_hDib);
// Calculate the number of bits per pixel for the DIB.
if (IS_WIN30_DIB(lpDib))
{
LPBITMAPINFOHEADER lpbih = (LPBITMAPINFOHEADER) lpDib;
bEncoded = (lpbih->biCompression == BI_RLE8) || (lpbih->biCompression == BI_RLE4);
}
::GlobalUnlock((HGLOBAL) m_hDib);
}
return bEncoded;
}
BOOL CDibImage::Draw(CDC& dc, const CRect* rcDst, const CRect* rcSrc, CPalette* pPal)
{
CRect DCRect(Rect());
if (rcDst)
DCRect = *rcDst;
CRect DibRect(Rect());
if (rcSrc)
DibRect = *rcSrc;
CPalette pal;
pal.Attach(m_Pal);
CPalette* pPalette = NULL;
if (pPal)
pPalette = pPal;
else
pPalette = &pal;
BOOL bSuccess = ::DrawDIB(dc.m_hDC, &DCRect, m_hDib, &DibRect, pPalette);
pal.Detach();
return bSuccess;
}
// Currently only support pixel access for 1, 4, 8 & 24 images.
// Also note that access to RLE images is not supported
BOOL CDibImage::DataFormatSupported(void) const
{
if (!IsRunLengthEncoded() &&
((m_nBitsPerPixel == 1) ||
(m_nBitsPerPixel == 4) ||
(m_nBitsPerPixel == 8) ||
(m_nBitsPerPixel == 24)) )
return TRUE;
else
return FALSE;
}
BOOL CDibImage::FilteringFormatSupported(void) const
{
if (m_nBitsPerPixel == 24)
return TRUE;
else
return FALSE;
}
LPBYTE CDibImage::GetPixelAddress(int x, int y, LPBYTE lpDibBits) const
{
BYTE* pData = NULL;
if (!IsRunLengthEncoded())
{
switch (m_nBitsPerPixel)
{
case 1:
{
pData = lpDibBits + ((m_nHeight - 1) - y) * m_nScanWidth + (x/8);
break;
}
case 4:
{
pData = lpDibBits + ((m_nHeight - 1) - y) * m_nScanWidth + (x/2);
break;
}
case 8:
{
pData = lpDibBits + ((m_nHeight - 1) - y) * m_nScanWidth + (x);
break;
}
case 24:
{
pData = lpDibBits + ((m_nHeight - 1) - y) * m_nScanWidth + (x*3);
break;
}
default:
{
pData = NULL;
break;
}
}
}
return pData;
}
inline BYTE GetLoNibble(BYTE Data)
{
return (BYTE) (Data & 0x0F);
}
inline BYTE GetHiNibble(BYTE Data)
{
return (BYTE) ((Data >> 4) & 0x0F);
}
inline void SetLoNibble( BYTE& DstData ,BYTE SrcData )
{
DstData = (BYTE) ((DstData & 0xF0) | (SrcData & 0x0F));
}
inline void SetHiNibble( BYTE& DstData ,BYTE SrcData )
{
DstData = (BYTE) ((DstData & 0x0F) | ((SrcData << 4) & 0xF0));
}
BOOL CDibImage::GetPixelData(int x, int y, ULONG& value, LPSTR lpDibBits) const
{
if (m_hDib == NULL)
return FALSE;
if (DataFormatSupported() == FALSE)
return FALSE;
//position is out of range
if (x >= m_nWidth || x < 0 || y >= m_nHeight || y < 0)
return FALSE;
BOOL bLocked = FALSE;
if (lpDibBits == NULL)
{
LPSTR lpDibHdr = (LPSTR) ::GlobalLock(m_hDib);
lpDibBits = ::FindDIBBits(lpDibHdr);
bLocked = TRUE;
}
BYTE* pData = GetPixelAddress(x,y,(BYTE*) lpDibBits);
switch (m_nBitsPerPixel)
{
case 1:
{
x = x % 8;
value = ( pData[0] << x ) & 0x80 ? 1 : 0;
break;
}
case 4:
{
if (x % 2)
value = GetLoNibble(pData[0]);
else
value = GetHiNibble(pData[0]);
break;
}
case 8:
{
value = pData[0];
break;
}
case 24:
{
value = RGB(pData[2], pData[1], pData[0]);
break;
}
default:
{
return FALSE;
break;
}
}
if (bLocked)
::GlobalUnlock((HGLOBAL) m_hDib);
return TRUE;
}
BOOL CDibImage::SetPixelData(int x, int y, const ULONG& value, LPSTR lpDibBits)
{
if (m_hDib == NULL)
return FALSE;
if (DataFormatSupported() == FALSE)
return FALSE;
//check the position
ASSERT(x < m_nWidth && x >= 0 && y < m_nHeight && y >= 0);
BOOL bLocked = FALSE;
if (lpDibBits == NULL)
{
LPSTR lpDibHdr = (LPSTR) ::GlobalLock(m_hDib);
lpDibBits = ::FindDIBBits(lpDibHdr);
bLocked = TRUE;
}
BYTE* pData = GetPixelAddress(x, y, (BYTE*)lpDibBits);
switch (m_nBitsPerPixel)
{
case 1:
{
x = x % 8;
if ( value )
pData[0] = (BYTE) (pData[0] | (0x80 >> x));
else
pData[0] = (BYTE) (pData[0] & ~(0x80 >> x));
break;
}
case 4:
{
if (x % 2)
SetLoNibble(pData[0], (BYTE)value);
else
SetHiNibble(pData[0], (BYTE)value);
break;
}
case 8:
{
pData[0] = (BYTE) value;
break;
}
case 24:
{
pData[0] = GetBValue(value);
pData[1] = GetGValue(value);
pData[2] = GetRValue(value);
break;
}
default:
{
return FALSE;
}
}
if (bLocked)
::GlobalUnlock((HGLOBAL) m_hDib);
return TRUE;
}
BOOL CDibImage::GetPixel(int x, int y, COLORREF& value, LPSTR lpDibBits) const
{
if (m_hDib == NULL)
return FALSE;
if (m_nBitsPerPixel != 24)
return FALSE;
//position is out of range
if (x >= m_nWidth || x < 0 || y >= m_nHeight || y < 0)
return FALSE;
BOOL bLocked = FALSE;
if (lpDibBits == NULL)
{
LPSTR lpDibHdr = (LPSTR) ::GlobalLock(m_hDib);
lpDibBits = ::FindDIBBits(lpDibHdr);
bLocked = TRUE;
}
BYTE* pData = (LPBYTE) lpDibBits + (m_nHeight - 1 - y ) * m_nScanWidth + (x * 3);
value = RGB(pData[2], pData[1], pData[0]);
if (bLocked)
::GlobalUnlock((HGLOBAL) m_hDib);
return TRUE;
}
BOOL CDibImage::SetPixel(int x, int y, const COLORREF& value, LPSTR lpDibBits)
{
if (m_hDib == NULL)
return FALSE;
if ((m_nBitsPerPixel != 24))
return FALSE;
//check the position
ASSERT(x < m_nWidth && x >= 0 && y < m_nHeight && y >= 0);
BOOL bLocked = FALSE;
if (lpDibBits == NULL)
{
LPSTR lpDibHdr = (LPSTR) ::GlobalLock(m_hDib);
lpDibBits = ::FindDIBBits(lpDibHdr);
bLocked = TRUE;
}
BOOL bSuccess = SetPixelData(x, y, value, lpDibBits);
if (bLocked)
::GlobalUnlock((HGLOBAL) m_hDib);
return bSuccess;
}
BOOL CDibImage::Save(LPCTSTR lpszPathName)
{
if (m_hDib == NULL)
return FALSE;
//Determine the file format to use based on the filename extension
TCHAR pszExt[_MAX_EXT];
_tsplitpath(lpszPathName, NULL, NULL, NULL, pszExt);
CString sExt(pszExt);
if ((sExt.CompareNoCase(_T(".bmp")) == 0) || (sExt.CompareNoCase(_T(".dib")) == 0))
{
CFile f;
if (!f.Open(lpszPathName, CFile::shareDenyWrite | CFile::modeCreate | CFile::modeWrite))
return FALSE;
else
return SaveDIBFile(m_hDib, f);
}
#ifndef DIBIMAGE_NO_JPEG
else if ((sExt.CompareNoCase(_T(".jpg")) == 0) || (sExt.CompareNoCase(_T(".jpeg")) == 0))
{
CFile f;
if (!f.Open(lpszPathName, CFile::shareDenyWrite | CFile::modeCreate | CFile::modeWrite))
return FALSE;
else
return SaveJPEGFile(m_hDib, f);
}
#endif
else if (sExt.CompareNoCase(_T(".tga")) == 0)
{
CFile f;
if (!f.Open(lpszPathName, CFile::shareDenyWrite | CFile::modeCreate | CFile::modeWrite))
return FALSE;
else
return SaveTGAFile(m_hDib, f);
}
else
{
TRACE(_T("Could not determine what file format to save as\n"));
return FALSE; //unknown file format
}
}
BOOL CDibImage::CopySelection(CDibImage& dib)
{
if (m_hDib == NULL)
return FALSE;
BOOL bSuccess = FALSE;
ASSERT(m_pWorkingArea);
CRect r = m_pWorkingArea->BoundingRectangle();
bSuccess = dib.Create(CSize(r.Width(), r.Height()), 24);
if (bSuccess)
{
LPSTR lpDibHdrSrc = (LPSTR) ::GlobalLock(m_hDib);
LPSTR lpDibBitsSrc = ::FindDIBBits(lpDibHdrSrc);
LPSTR lpDibHdrDest = (LPSTR) ::GlobalLock(dib.m_hDib);
LPSTR lpDibBitsDest = ::FindDIBBits(lpDibHdrDest);
for (int y=r.top; bSuccess && yPointInSelection(CPoint(x, y)))
{
COLORREF c;
bSuccess = GetPixel(x, y, c, lpDibBitsSrc);
bSuccess = bSuccess && dib.SetPixel(x-r.left, y-r.top, c, lpDibBitsDest);
}
}
}
GlobalUnlock((HGLOBAL) dib.m_hDib);
GlobalUnlock((HGLOBAL) m_hDib);
}
return bSuccess;
}
LPSTR CDibImage::GetDIBBits()
{
LPSTR lpDibHdrSrc = (LPSTR) ::GlobalLock(m_hDib);
return ::FindDIBBits(lpDibHdrSrc);
}
BOOL CDibImage::CopyToClipboard()
{
if (m_hDib == NULL)
return FALSE;
BOOL bSuccess = FALSE;
if (OpenClipboard(NULL))
{
if (EmptyClipboard())
{
CDibImage DibCopy;
bSuccess = CopySelection(DibCopy);
if (bSuccess)
{
HDIB hNewDib = (HDIB) CopyHandle(DibCopy.m_hDib);
bSuccess = (::SetClipboardData(CF_DIB, hNewDib) != NULL);
}
}
CloseClipboard();
}
return bSuccess;
}
BOOL CDibImage::PasteFromClipboard()
{
BOOL bSuccess = FALSE;
if (OpenClipboard(NULL))
{
HDIB hNewDib = (HDIB) CopyHandle(::GetClipboardData(CF_DIB));
CloseClipboard();
if (hNewDib != NULL)
bSuccess = Attach(hNewDib);
}
return bSuccess;
}
BOOL CDibImage::PasteAvailable()
{
return IsClipboardFormatAvailable(CF_DIB);
}
void CDibImage::SetUndoSize(int nUndoSize)
{
m_nUndoSize = nUndoSize;
if (m_nUndoSize < m_UndoStack.GetSize())
TRACE(_T("Losing some of the undo stack in CDibImage::SetUndoSize\n"));
for (int i=m_nUndoSize; i nUndoSize)
m_UndoStack.SetSize(m_nUndoSize);
if (m_RedoStack.GetSize() > nUndoSize)
m_RedoStack.SetSize(m_nUndoSize);
}
BOOL CDibImage::SaveState(UINT nID)
{
CString sDescription;
sDescription.LoadString(nID);
return SaveState(sDescription);
}
BOOL CDibImage::SaveState(const CString& sDescription)
{
//if there is no undo stack then return immediately
if (m_nUndoSize == 0)
return FALSE;
//If we have reached the limit of the undo stack
//then drop the oldest undo by moving all the items
//down in the stack
if (m_UndoStack.GetSize() == m_nUndoSize)
{
TRACE(_T("Undo stack size exceeded, discarding oldest\n"));
CUndoNode* pNode = m_UndoStack.GetAt(0);
delete pNode;
for (int i=1; i 0);
}
BOOL CDibImage::Undo()
{
BOOL bSuccess = FALSE;
int nIndex = m_UndoStack.GetUpperBound();
if (nIndex >= 0)
{
//Add the current image to the redo stack
CDibImage* pCopy = new CDibImage(*this);
CUndoNode* pNode1 = new CUndoNode(pCopy, m_sCurrentDescription);
m_RedoStack.Add(pNode1);
//Remove from the undo stack and
//reinstate the current value
CUndoNode* pNode2 = m_UndoStack.GetAt(nIndex);
operator=(*pNode2->GetImage());
pNode1->SetDescription(pNode2->GetDescription());
delete pNode2;
m_UndoStack.RemoveAt(nIndex);
bSuccess = TRUE;
}
return bSuccess;
}
BOOL CDibImage::Redo()
{
BOOL bSuccess = FALSE;
int nIndex = m_RedoStack.GetUpperBound();
if (nIndex >= 0)
{
//Add the current image to the undo stack
CDibImage* pCopy = new CDibImage(*this);
CUndoNode* pNode1 = new CUndoNode(pCopy, m_sCurrentDescription);
m_UndoStack.Add(pNode1);
//Remove from the redo stack and
//reinstate the current value
CUndoNode* pNode2 = m_RedoStack.GetAt(nIndex);
operator=(*pNode2->GetImage());
pNode1->SetDescription(pNode2->GetDescription());
delete pNode2;
m_RedoStack.RemoveAt(nIndex);
bSuccess = TRUE;
}
return bSuccess;
}
BOOL CDibImage::RedoAvailable()
{
return (m_RedoStack.GetSize() > 0);
}
CString CDibImage::UndoDescription() const
{
CString rVal;
int nIndex = m_UndoStack.GetUpperBound();
if (nIndex >= 0)
{
CUndoNode* pNode = m_UndoStack.GetAt(nIndex);
rVal = pNode->GetDescription();
}
return rVal;
}
CString CDibImage::RedoDescription() const
{
CString rVal;
int nIndex = m_RedoStack.GetUpperBound();
if (nIndex >= 0)
{
CUndoNode* pNode = m_RedoStack.GetAt(nIndex);
rVal = pNode->GetDescription();
}
return rVal;
}
CWorkingArea* CDibImage::GetWorkingArea()
{
return m_pWorkingArea;
}
void CDibImage::SetWorkingArea(CWorkingArea* pWorkingArea)
{
if (m_pWorkingArea)
{
delete m_pWorkingArea;
m_pWorkingArea = NULL;
}
m_pWorkingArea = pWorkingArea;
}
BOOL CDibImage::SetColor(COLORREF color)
{
if (m_hDib == NULL)
return FALSE;
SaveState(IDS_DI_UNDO_SETCOLOR);
ASSERT(m_pWorkingArea);
CRect r(m_pWorkingArea->BoundingRectangle());
BOOL bSuccess = TRUE;
LPSTR lpDibHdr = (LPSTR) ::GlobalLock(m_hDib);
LPSTR lpDibBits = ::FindDIBBits(lpDibHdr);
for (int y=r.top; bSuccess && yPointInSelection(CPoint(x, y)))
bSuccess = SetPixel(x, y, color, lpDibBits);
}
GlobalUnlock((HGLOBAL) m_hDib);
if (!bSuccess)
Undo();
return bSuccess;
}
BOOL CDibImage::Flip()
{
if (m_hDib == NULL)
return FALSE;
SaveState(IDS_DI_UNDO_FLIP);
ASSERT(m_pWorkingArea);
CRect r(m_pWorkingArea->BoundingRectangle());
BOOL bSuccess = TRUE;
LPSTR lpDibHdr = (LPSTR) ::GlobalLock(m_hDib);
LPSTR lpDibBits = ::FindDIBBits(lpDibHdr);
int nMiddle = r.Height()/2 + r.top;
for (int y=nMiddle; bSuccess && y>r.top; y--)
{
for (int x=r.left; bSuccess && xPointInSelection(CPoint(x, y)))
{
COLORREF c1;
int y1 = nMiddle + (nMiddle - y);
bSuccess = GetPixelData(x, y1, c1, lpDibBits);
COLORREF c2;
bSuccess = bSuccess && GetPixelData(x, y, c2, lpDibBits);
bSuccess = bSuccess && SetPixelData(x, y, c1, lpDibBits);
bSuccess = bSuccess && SetPixelData(x, y1, c2, lpDibBits);
}
}
}
GlobalUnlock((HGLOBAL) m_hDib);
if (!bSuccess)
Undo();
return bSuccess;
}
BOOL CDibImage::Mirror()
{
if (m_hDib == NULL)
return FALSE;
SaveState(IDS_DI_UNDO_MIRROR);
ASSERT(m_pWorkingArea);
CRect r(m_pWorkingArea->BoundingRectangle());
BOOL bSuccess = TRUE;
LPSTR lpDibHdr = (LPSTR) ::GlobalLock(m_hDib);
LPSTR lpDibBits = ::FindDIBBits(lpDibHdr);
int nMiddle = r.Width()/2 + r.left;
for (int x=nMiddle; bSuccess && x>r.left; x--)
{
for (int y=r.top; bSuccess && yPointInSelection(CPoint(x, y)))
{
COLORREF c1;
int x1 = nMiddle + (nMiddle - x);
bSuccess = GetPixelData(x1, y, c1, lpDibBits);
COLORREF c2;
bSuccess = bSuccess && GetPixelData(x, y, c2, lpDibBits);
bSuccess = bSuccess && SetPixelData(x, y, c1, lpDibBits);
bSuccess = bSuccess && SetPixelData(x1, y, c2, lpDibBits);
}
}
}
GlobalUnlock((HGLOBAL) m_hDib);
if (!bSuccess)
Undo();
return bSuccess;
}
BOOL CDibImage::AdjustBrightness(int Percentage)
{
if (m_hDib == NULL)
return FALSE;
if (Percentage < 0)
return FALSE;
SaveState(IDS_DI_UNDO_ADJUST_BRIGHTNESS);
ASSERT(m_pWorkingArea);
CRect r(m_pWorkingArea->BoundingRectangle());
BOOL bSuccess = TRUE;
LPSTR lpDibHdr = (LPSTR) ::GlobalLock(m_hDib);
LPSTR lpDibBits = ::FindDIBBits(lpDibHdr);
for (int y=r.top; bSuccess && yPointInSelection(CPoint(x, y)))
{
COLORREF c;
if (GetPixel(x, y, c, lpDibBits))
{
int r = min(GetRValue(c)*Percentage/100, 255);
int g = min(GetGValue(c)*Percentage/100, 255);
int b = min(GetBValue(c)*Percentage/100, 255);
r = max(r, 0);
g = max(g, 0);
b = max(b, 0);
c = RGB(r, g, b);
bSuccess = SetPixel(x, y, c, lpDibBits);
}
else
bSuccess = FALSE;
}
}
}
GlobalUnlock((HGLOBAL) m_hDib);
if (!bSuccess)
Undo();
return bSuccess;
}
BOOL CDibImage::AdjustContrast(int Percentage)
{
if (m_hDib == NULL)
return FALSE;
SaveState(IDS_DI_UNDO_CONTRAST);
ASSERT(m_pWorkingArea);
CRect r(m_pWorkingArea->BoundingRectangle());
BOOL bSuccess = TRUE;
LPSTR lpDibHdr = (LPSTR) ::GlobalLock(m_hDib);
LPSTR lpDibBits = ::FindDIBBits(lpDibHdr);
for (int y=r.top; bSuccess && yPointInSelection(CPoint(x, y)))
{
COLORREF c;
bSuccess = GetPixel(x, y, c, lpDibBits);
int r = min(128 + ((GetRValue(c) - 128)*Percentage/100), 255);
int g = min(128 + ((GetGValue(c) - 128)*Percentage/100), 255);
int b = min(128 + ((GetBValue(c) - 128)*Percentage/100), 255);
r = max(r, 0);
g = max(g, 0);
b = max(b, 0);
c = RGB(r, g, b);
bSuccess = SetPixel(x, y, c, lpDibBits);
}
}
}
GlobalUnlock((HGLOBAL) m_hDib);
if (!bSuccess)
Undo();
return bSuccess;
}
BOOL CDibImage::AdjustGammaCorrection(float Value)
{
if (m_hDib == NULL)
return FALSE;
SaveState(IDS_DI_UNDO_GAMMA);
ASSERT(m_pWorkingArea);
CRect r(m_pWorkingArea->BoundingRectangle());
BOOL bSuccess = TRUE;
double MaxRange = pow((double) 255, (double) Value) / 255;
LPSTR lpDibHdr = (LPSTR) ::GlobalLock(m_hDib);
LPSTR lpDibBits = ::FindDIBBits(lpDibHdr);
for (int y=r.top; bSuccess && yPointInSelection(CPoint(x, y)))
{
COLORREF c;
bSuccess = GetPixel(x, y, c, lpDibBits);
double dblR = pow((double) GetRValue(c), (double) Value) / MaxRange;
double dblG = pow((double) GetGValue(c), (double) Value) / MaxRange;
double dblB = pow((double) GetBValue(c), (double) Value) / MaxRange;
int r = min((int) (dblR+0.5), 255);
int g = min((int) (dblG+0.5), 255);
int b = min((int) (dblB+0.5), 255);
r = max(r, 0);
g = max(g, 0);
b = max(b, 0);
c = RGB(r, g, b);
bSuccess = SetPixel(x, y, c, lpDibBits);
}
}
}
GlobalUnlock((HGLOBAL) m_hDib);
if (!bSuccess)
Undo();
return bSuccess;
}
BOOL CDibImage::AdjustHighLight(int Percentage)
{
if (m_hDib == NULL)
return FALSE;
SaveState(IDS_DI_UNDO_HIGHLIGHT);
ASSERT(m_pWorkingArea);
CRect r(m_pWorkingArea->BoundingRectangle());
BOOL bSuccess = TRUE;
LPSTR lpDibHdr = (LPSTR) ::GlobalLock(m_hDib);
LPSTR lpDibBits = ::FindDIBBits(lpDibHdr);
for (int y=r.top; bSuccess && yPointInSelection(CPoint(x, y)))
{
COLORREF c;
bSuccess = GetPixel(x, y, c, lpDibBits);
int r = GetRValue(c);
int g = GetGValue(c);
int b = GetBValue(c);
int l = r+g+b;
if ((l > (170*3)))
{
r = min(r*Percentage/100, 255);
g = min(g*Percentage/100, 255);
b = min(b*Percentage/100, 255);
r = max(r, 0);
g = max(g, 0);
b = max(b, 0);
c = RGB(r, g, b);
bSuccess = SetPixel(x, y, c, lpDibBits);
}
}
}
}
GlobalUnlock((HGLOBAL) m_hDib);
if (!bSuccess)
Undo();
return bSuccess;
}
BOOL CDibImage::AdjustMidtone(int Percentage)
{
if (m_hDib == NULL)
return FALSE;
SaveState(IDS_DI_UNDO_MIDTONE);
ASSERT(m_pWorkingArea);
CRect r(m_pWorkingArea->BoundingRectangle());
BOOL bSuccess = TRUE;
LPSTR lpDibHdr = (LPSTR) ::GlobalLock(m_hDib);
LPSTR lpDibBits = ::FindDIBBits(lpDibHdr);
for (int y=r.top; bSuccess && yPointInSelection(CPoint(x, y)))
{
COLORREF c;
bSuccess = GetPixel(x, y, c, lpDibBits);
int r = GetRValue(c);
int g = GetGValue(c);
int b = GetBValue(c);
int l = r+g+b;
if ((l >= (85*3)) && (l <= (170*3)))
{
r = min(r*Percentage/100, 255);
g = min(g*Percentage/100, 255);
b = min(b*Percentage/100, 255);
r = max(r, 0);
g = max(g, 0);
b = max(b, 0);
c = RGB(r, g, b);
bSuccess = SetPixel(x, y, c, lpDibBits);
}
}
}
}
GlobalUnlock((HGLOBAL) m_hDib);
if (!bSuccess)
Undo();
return bSuccess;
}
BOOL CDibImage::AdjustShadow(int Percentage)
{
if (m_hDib == NULL)
return FALSE;
SaveState(IDS_DI_UNDO_SHADOW);
ASSERT(m_pWorkingArea);
CRect r(m_pWorkingArea->BoundingRectangle());
BOOL bSuccess = TRUE;
LPSTR lpDibHdr = (LPSTR) ::GlobalLock(m_hDib);
LPSTR lpDibBits = ::FindDIBBits(lpDibHdr);
for (int y=r.top; bSuccess && yPointInSelection(CPoint(x, y)))
{
COLORREF c;
bSuccess = GetPixel(x, y, c, lpDibBits);
int r = GetRValue(c);
int g = GetGValue(c);
int b = GetBValue(c);
int l = r+g+b;
if (l < (85*3))
{
r = min(r*Percentage/100, 255);
g = min(g*Percentage/100, 255);
b = min(b*Percentage/100, 255);
r = max(r, 0);
g = max(g, 0);
b = max(b, 0);
c = RGB(r, g, b);
bSuccess = SetPixel(x, y, c, lpDibBits);
}
}
}
}
GlobalUnlock((HGLOBAL) m_hDib);
if (!bSuccess)
Undo();
return bSuccess;
}
BOOL CDibImage::AdjustHue(int Percentage)
{
if (m_hDib == NULL)
return FALSE;
if (Percentage < 0)
return FALSE;
SaveState(IDS_DI_UNDO_ADJUST_HUE);
ASSERT(m_pWorkingArea);
CRect r(m_pWorkingArea->BoundingRectangle());
BOOL bSuccess = TRUE;
LPSTR lpDibHdr = (LPSTR) ::GlobalLock(m_hDib);
LPSTR lpDibBits = ::FindDIBBits(lpDibHdr);
for (int y=r.top; bSuccess && yPointInSelection(CPoint(x, y)))
{
COLORREF c;
if (GetPixel(x, y, c, lpDibBits))
{
double H;
double S;
double L;
RGBtoHSL(c, &H, &S, &L);
H = (H*Percentage/100);
bSuccess = SetPixel(x, y, HLStoRGB(H, L, S), lpDibBits);
}
else
bSuccess = FALSE;
}
}
}
GlobalUnlock((HGLOBAL) m_hDib);
if (!bSuccess)
Undo();
return bSuccess;
}
BOOL CDibImage::AdjustSaturation(int Percentage)
{
if (m_hDib == NULL)
return FALSE;
if (Percentage < 0)
return FALSE;
SaveState(IDS_DI_UNDO_ADJUST_SATURATION);
ASSERT(m_pWorkingArea);
CRect r(m_pWorkingArea->BoundingRectangle());
BOOL bSuccess = TRUE;
LPSTR lpDibHdr = (LPSTR) ::GlobalLock(m_hDib);
LPSTR lpDibBits = ::FindDIBBits(lpDibHdr);
for (int y=r.top; bSuccess && yPointInSelection(CPoint(x, y)))
{
COLORREF c;
if (GetPixel(x, y, c, lpDibBits))
{
double H;
double S;
double L;
RGBtoHSL(c, &H, &S, &L);
S = (S*Percentage/100);
bSuccess = SetPixel(x, y, HLStoRGB(H, L, S), lpDibBits);
}
else
bSuccess = FALSE;
}
}
}
GlobalUnlock((HGLOBAL) m_hDib);
if (!bSuccess)
Undo();
return bSuccess;
}
BOOL CDibImage::AdjustHSL(int PercentHue, int PercentSaturation, int PercentLuminosity)
{
if (m_hDib == NULL)
return FALSE;
if (PercentHue < 0)
return FALSE;
if (PercentSaturation < 0)
return FALSE;
if (PercentLuminosity < 0)
return FALSE;
SaveState(IDS_DI_UNDO_ADJUST_HSL);
ASSERT(m_pWorkingArea);
CRect r(m_pWorkingArea->BoundingRectangle());
BOOL bSuccess = TRUE;
LPSTR lpDibHdr = (LPSTR) ::GlobalLock(m_hDib);
LPSTR lpDibBits = ::FindDIBBits(lpDibHdr);
for (int y=r.top; bSuccess && yPointInSelection(CPoint(x, y)))
{
COLORREF c;
if (GetPixel(x, y, c, lpDibBits))
{
double H;
double S;
double L;
RGBtoHSL(c, &H, &S, &L);
S = (S*PercentSaturation/100);
H = (H*PercentHue/100);
L = (L*PercentLuminosity/100);
bSuccess = SetPixel(x, y, HLStoRGB(H, L, S), lpDibBits);
}
else
bSuccess = FALSE;
}
}
}
GlobalUnlock((HGLOBAL) m_hDib);
if (!bSuccess)
Undo();
return bSuccess;
}
WORD CDibImage::GetVersion()
{
return 0x011B; //ie v1.27
}
void CDibImage::RGBtoHSL(COLORREF rgb, double* H, double* S, double* L)
{
double delta;
double r = (double)GetRValue(rgb)/255;
double g = (double)GetGValue(rgb)/255;
double b = (double)GetBValue(rgb)/255;
double cmax = max(r,max(g,b));
double cmin = min(r,min(g,b));
*L = (cmax+cmin)/2.0;
if (cmax == cmin)
{
*S = 0;
*H = 0; // it's really undefined
}
else
{
if (*L < 0.5)
*S = (cmax-cmin)/(cmax+cmin);
else
*S = (cmax-cmin)/(2.0-cmax-cmin);
delta = cmax - cmin;
if (r==cmax)
*H = (g-b)/delta;
else if (g==cmax)
*H = 2.0 +(b-r)/delta;
else
*H = 4.0+(r-g)/delta;
*H /= 6.0;
if (*H < 0.0)
*H += 1;
}
}
double CDibImage::HuetoRGB(double m1, double m2, double h)
{
if (h < 0)
h += 1.0;
if (h > 1)
h -= 1.0;
if (6.0*h < 1)
return (m1+(m2-m1)*h*6.0);
if (2.0*h < 1)
return m2;
if (3.0*h < 2.0)
return (m1+(m2-m1)*((2.0/3.0)-h)*6.0);
return m1;
}
COLORREF CDibImage::HLStoRGB(const double& H, const double& L, const double& S)
{
double r,g,b;
double m1, m2;
if (S==0)
{
r=g=b=L;
}
else
{
if (L <= 0.5)
m2 = L*(1.0+S);
else
m2 = L+S-L*S;
m1 = 2.0*L-m2;
r = HuetoRGB(m1, m2, H+1.0/3.0);
g = HuetoRGB(m1, m2, H);
b = HuetoRGB(m1, m2, H-1.0/3.0);
}
return RGB((BYTE)(r*255),(BYTE)(g*255),(BYTE)(b*255));
}
BOOL CDibImage::AdjustRed(int Percentage)
{
if (m_hDib == NULL)
return FALSE;
if (Percentage < 0)
return FALSE;
SaveState(IDS_DI_UNDO_ADJUST_RED);
ASSERT(m_pWorkingArea);
CRect r(m_pWorkingArea->BoundingRectangle());
BOOL bSuccess = TRUE;
LPSTR lpDibHdr = (LPSTR) ::GlobalLock(m_hDib);
LPSTR lpDibBits = ::FindDIBBits(lpDibHdr);
for (int y=r.top; bSuccess && yPointInSelection(CPoint(x, y)))
{
COLORREF c;
if (GetPixel(x, y, c, lpDibBits))
{
int r = min(GetRValue(c)*Percentage/100, 255);
r = max(r, 0);
c = RGB(r, GetGValue(c), GetBValue(c));
bSuccess = SetPixel(x, y, c, lpDibBits);
}
else
bSuccess = FALSE;
}
}
}
GlobalUnlock((HGLOBAL) m_hDib);
if (!bSuccess)
Undo();
return bSuccess;
}
BOOL CDibImage::AdjustGreen(int Percentage)
{
if (m_hDib == NULL)
return FALSE;
if (Percentage < 0)
return FALSE;
SaveState(IDS_DI_UNDO_ADJUST_GREEN);
ASSERT(m_pWorkingArea);
CRect r(m_pWorkingArea->BoundingRectangle());
BOOL bSuccess = TRUE;
LPSTR lpDibHdr = (LPSTR) ::GlobalLock(m_hDib);
LPSTR lpDibBits = ::FindDIBBits(lpDibHdr);
for (int y=r.top; bSuccess && yPointInSelection(CPoint(x, y)))
{
COLORREF c;
if (GetPixel(x, y, c, lpDibBits))
{
int g = min(GetGValue(c)*Percentage/100, 255);
g = max(g, 0);
c = RGB(GetRValue(c), g, GetBValue(c));
bSuccess = SetPixel(x, y, c, lpDibBits);
}
else
bSuccess = FALSE;
}
}
}
GlobalUnlock((HGLOBAL) m_hDib);
if (!bSuccess)
Undo();
return bSuccess;
}
BOOL CDibImage::AdjustBlue(int Percentage)
{
if (m_hDib == NULL)
return FALSE;
if (Percentage < 0)
return FALSE;
SaveState(IDS_DI_UNDO_ADJUST_BLUE);
ASSERT(m_pWorkingArea);
CRect r(m_pWorkingArea->BoundingRectangle());
BOOL bSuccess = TRUE;
LPSTR lpDibHdr = (LPSTR) ::GlobalLock(m_hDib);
LPSTR lpDibBits = ::FindDIBBits(lpDibHdr);
for (int y=r.top; bSuccess && yPointInSelection(CPoint(x, y)))
{
COLORREF c;
if (GetPixel(x, y, c, lpDibBits))
{
int b = min(GetBValue(c)*Percentage/100, 255);
b = max(b, 0);
c = RGB(GetRValue(c), GetGValue(c), b);
bSuccess = SetPixel(x, y, c, lpDibBits);
}
else
bSuccess = FALSE;
}
}
}
GlobalUnlock((HGLOBAL) m_hDib);
if (!bSuccess)
Undo();
return bSuccess;
}
BOOL CDibImage::Grayscale()
{
if (m_hDib == NULL)
return FALSE;
SaveState(IDS_DI_UNDO_ADJUST_GREYSCALE);
ASSERT(m_pWorkingArea);
CRect r(m_pWorkingArea->BoundingRectangle());
BOOL bSuccess = TRUE;
LPSTR lpDibHdr = (LPSTR) ::GlobalLock(m_hDib);
LPSTR lpDibBits = ::FindDIBBits(lpDibHdr);
for (int y=r.top; bSuccess && yPointInSelection(CPoint(x, y)))
{
COLORREF c;
if (GetPixel(x, y, c, lpDibBits))
{
int val = ((GetRValue(c) + GetGValue(c) + GetBValue(c)) / 3);
bSuccess = SetPixel(x, y, RGB(val, val, val), lpDibBits);
}
else
bSuccess = FALSE;
}
}
}
GlobalUnlock((HGLOBAL) m_hDib);
if (!bSuccess)
Undo();
return bSuccess;
}
BOOL CDibImage::Negate()
{
if (m_hDib == NULL)
return FALSE;
SaveState(IDS_DI_UNDO_ADJUST_NEGATE);
ASSERT(m_pWorkingArea);
CRect r(m_pWorkingArea->BoundingRectangle());
BOOL bSuccess = TRUE;
LPSTR lpDibHdr = (LPSTR) ::GlobalLock(m_hDib);
LPSTR lpDibBits = ::FindDIBBits(lpDibHdr);
for (int y=r.top; bSuccess && yPointInSelection(CPoint(x, y)))
{
COLORREF c;
if (GetPixel(x, y, c, lpDibBits))
bSuccess = SetPixel(x, y, RGB(255 - GetRValue(c), 255 - GetGValue(c), 255 - GetBValue(c)), lpDibBits);
else
bSuccess = FALSE;
}
}
}
GlobalUnlock((HGLOBAL) m_hDib);
if (!bSuccess)
Undo();
return bSuccess;
}
BOOL CDibImage::FindEdgesFilter()
{
if (m_hDib == NULL)
return FALSE;
C3By3Filter Filter1;
Filter1.m_nValues[0][0] = -1;
Filter1.m_nValues[0][1] = 0;
Filter1.m_nValues[0][2] = 1;
Filter1.m_nValues[1][0] = -2;
Filter1.m_nValues[1][1] = 0;
Filter1.m_nValues[1][2] = 2;
Filter1.m_nValues[2][0] = -1;
Filter1.m_nValues[2][1] = 0;
Filter1.m_nValues[2][2] = 1;
C3By3Filter Filter2;
Filter2.m_nValues[0][0] = -1;
Filter2.m_nValues[0][1] = -2;
Filter2.m_nValues[0][2] = -1;
Filter2.m_nValues[1][0] = 0;
Filter2.m_nValues[1][1] = 0;
Filter2.m_nValues[1][2] = 0;
Filter2.m_nValues[2][0] = 1;
Filter2.m_nValues[2][1] = 2;
Filter2.m_nValues[2][2] = 1;
CDibImage dibCopy;
CopySelection(dibCopy);
SaveState(IDS_DI_UNDO_FILTER);
ASSERT(dibCopy.m_pWorkingArea);
CRect rectSrc(dibCopy.m_pWorkingArea->BoundingRectangle());
CRect rectDest(m_pWorkingArea->BoundingRectangle());
BOOL bSuccess = TRUE;
LPSTR lpDibHdrSrc = (LPSTR) ::GlobalLock(dibCopy.m_hDib);
LPSTR lpDibBitsSrc = ::FindDIBBits(lpDibHdrSrc);
LPSTR lpDibHdrDest = (LPSTR) ::GlobalLock(m_hDib);
LPSTR lpDibBitsDest = ::FindDIBBits(lpDibHdrDest);
for (int y=0; bSuccess && yPointInSelection(CPoint(x, y)))
{
COLORREF c1 = Filter1.Filter(dibCopy, lpDibBitsSrc, x, y);
COLORREF c2 = Filter2.Filter(dibCopy, lpDibBitsSrc, x, y);
int r = max(GetRValue(c1), GetRValue(c2));
int g = max(GetGValue(c1), GetGValue(c2));
int b = max(GetBValue(c1), GetBValue(c2));
bSuccess = SetPixel(x+rectDest.left, y+rectDest.top, RGB(r, g, b), lpDibBitsDest);
}
}
}
GlobalUnlock((HGLOBAL) m_hDib);
if (!bSuccess)
Undo();
return bSuccess;
}
BOOL CDibImage::FindVerticalEdgesFilter()
{
C3By3Filter Filter;
Filter.m_nValues[0][0] = -1;
Filter.m_nValues[0][1] = -2;
Filter.m_nValues[0][2] = -1;
Filter.m_nValues[1][0] = 0;
Filter.m_nValues[1][1] = 0;
Filter.m_nValues[1][2] = 0;
Filter.m_nValues[2][0] = 1;
Filter.m_nValues[2][1] = 2;
Filter.m_nValues[2][2] = 1;
return UserDefinedFilter(Filter);
}
BOOL CDibImage::FindHorizontalEdgesFilter()
{
C3By3Filter Filter;
Filter.m_nValues[0][0] = -1;
Filter.m_nValues[0][1] = 0;
Filter.m_nValues[0][2] = 1;
Filter.m_nValues[1][0] = -2;
Filter.m_nValues[1][1] = 0;
Filter.m_nValues[1][2] = 2;
Filter.m_nValues[2][0] = -1;
Filter.m_nValues[2][1] = 0;
Filter.m_nValues[2][2] = 1;
return UserDefinedFilter(Filter);
}
BOOL CDibImage::BlurFilter()
{
C7By7Filter Filter;
for (int i=0; i<7; i++)
for (int j=0; j<7; j++)
Filter.m_nValues[i][j] = 0;
Filter.m_nValues[3][3] = -4;
Filter.m_nValues[2][2] = 1;
Filter.m_nValues[2][3] = 4;
Filter.m_nValues[2][4] = 1;
Filter.m_nValues[3][2] = 4;
Filter.m_nValues[3][4] = 4;
Filter.m_nValues[4][2] = 1;
Filter.m_nValues[4][3] = 4;
Filter.m_nValues[4][4] = 1;
Filter.m_nDivision = 16;
return UserDefinedFilter(Filter);
}
BOOL CDibImage::AddNoiseFilter(int Percentage)
{
if (Percentage <= 0 || Percentage > 100)
return FALSE;
if (m_hDib == NULL)
return FALSE;
SaveState(IDS_DI_UNDO_ADD_NOISE);
ASSERT(m_pWorkingArea);
CRect r(m_pWorkingArea->BoundingRectangle());
BOOL bSuccess = TRUE;
LPSTR lpDibHdr = (LPSTR) ::GlobalLock(m_hDib);
LPSTR lpDibBits = ::FindDIBBits(lpDibHdr);
for (int y=r.top; bSuccess && yPointInSelection(CPoint(x, y)))
{
COLORREF c;
int r = rand()*256/RAND_MAX - 128;
int g = rand()*256/RAND_MAX - 128;
int b = rand()*256/RAND_MAX - 128;
if (GetPixel(x, y, c, lpDibBits))
bSuccess = SetPixel(x, y, RGB(GetRValue(c) + r, GetGValue(c) + g, GetBValue(c) + b), lpDibBits);
else
bSuccess = FALSE;
}
}
}
GlobalUnlock((HGLOBAL) m_hDib);
if (!bSuccess)
Undo();
return bSuccess;
}
BOOL CDibImage::MedianFilter()
{
C3By3MedianFilter Filter;
return UserDefinedFilter(Filter);
}
BOOL CDibImage::MeanFilter()
{
C3By3MeanFilter Filter;
return UserDefinedFilter(Filter);
}
BOOL CDibImage::UserDefinedFilter(CUserDefinedFilter& Filter)
{
if (m_hDib == NULL)
return FALSE;
CDibImage dibCopy;
CopySelection(dibCopy);
SaveState(IDS_DI_UNDO_FILTER);
ASSERT(dibCopy.m_pWorkingArea);
CRect rectSrc(dibCopy.m_pWorkingArea->BoundingRectangle());
CRect rectDest(m_pWorkingArea->BoundingRectangle());
BOOL bSuccess = TRUE;
LPSTR lpDibHdrSrc = (LPSTR) ::GlobalLock(dibCopy.m_hDib);
LPSTR lpDibBitsSrc = ::FindDIBBits(lpDibHdrSrc);
LPSTR lpDibHdrDest = (LPSTR) ::GlobalLock(m_hDib);
LPSTR lpDibBitsDest = ::FindDIBBits(lpDibHdrDest);
for (int y=0; bSuccess && yPointInSelection(CPoint(x, y)))
{
COLORREF c = Filter.Filter(dibCopy, lpDibBitsSrc, x, y);
bSuccess = SetPixel(x+rectDest.left, y+rectDest.top, c, lpDibBitsDest);
}
}
}
GlobalUnlock((HGLOBAL) m_hDib);
GlobalUnlock((HGLOBAL) dibCopy.m_hDib);
if (!bSuccess)
Undo();
return bSuccess;
}
int CDibImage::ColorsUsed() const
{
if (m_hDib == NULL)
return 0;
ASSERT(m_pWorkingArea);
CRect r(m_pWorkingArea->BoundingRectangle());
//Use a hash table to keep previously found colors, The
//most ideal method would be to use a sorted array with
//a binary chop but MFC does not provide one and I don't
//feel like coding up one just for the sake of this function !.
CMap colorsTable;
colorsTable.InitHashTable(r.Width() * r.Height());
//Iterate through the working area to find all its colors
BOOL bSuccess = TRUE;
int nColors = 0;
LPSTR lpDibHdr = (LPSTR) ::GlobalLock(m_hDib);
LPSTR lpDibBits = ::FindDIBBits(lpDibHdr);
for (int y=r.top; bSuccess && yPointInSelection(CPoint(x, y)))
{
COLORREF c;
if (GetPixelData(x, y, c, lpDibBits))
{
//If the color is not already in the table,
//then increment the number of colors and
//add it to the hash table
COLORREF cFound;
if (!colorsTable.Lookup(c, cFound))
{
++nColors;
colorsTable.SetAt(c, c);
}
}
}
}
}
GlobalUnlock((HGLOBAL) m_hDib);
return nColors;
}
BOOL CDibImage::SplitChannels(CDibImage& RedChannel, CDibImage& GreenChannel, CDibImage& BlueChannel)
{
if (m_hDib == NULL)
return FALSE;
if (!RedChannel.Create(Size(), 24))
return FALSE;
if (!GreenChannel.Create(Size(), 24))
return FALSE;
if (!BlueChannel.Create(Size(), 24))
return FALSE;
BOOL bSuccess = TRUE;
LPSTR lpDibHdr = (LPSTR) ::GlobalLock(m_hDib);
LPSTR lpDibBits = ::FindDIBBits(lpDibHdr);
LPSTR lpDibHdrRed = (LPSTR) ::GlobalLock(RedChannel.m_hDib);
LPSTR lpDibBitsRed = ::FindDIBBits(lpDibHdrRed);
LPSTR lpDibHdrGreen = (LPSTR) ::GlobalLock(GreenChannel.m_hDib);
LPSTR lpDibBitsGreen = ::FindDIBBits(lpDibHdrGreen);
LPSTR lpDibHdrBlue = (LPSTR) ::GlobalLock(BlueChannel.m_hDib);
LPSTR lpDibBitsBlue = ::FindDIBBits(lpDibHdrBlue);
CRect r(Rect());
for (int y=r.top; bSuccess && yBoundingRectangle());
BOOL bSuccess = TRUE;
LPSTR lpDibHdr = (LPSTR) ::GlobalLock(m_hDib);
LPSTR lpDibBits = ::FindDIBBits(lpDibHdr);
for (int y=r.top; bSuccess && yPointInSelection(CPoint(x, y)))
{
COLORREF c;
if (GetPixel(x, y, c, lpDibBits))
{
int r = GetRValue(c);
if (r < nSize)
RedChannel[r]++;
}
else
bSuccess = FALSE;
}
}
}
GlobalUnlock((HGLOBAL) m_hDib);
return bSuccess;
}
BOOL CDibImage::GetGreenHistogram(int* GreenChannel, int nSize)
{
if (m_hDib == NULL)
return FALSE;
for (int i=0; iBoundingRectangle());
BOOL bSuccess = TRUE;
LPSTR lpDibHdr = (LPSTR) ::GlobalLock(m_hDib);
LPSTR lpDibBits = ::FindDIBBits(lpDibHdr);
for (int y=r.top; bSuccess && yPointInSelection(CPoint(x, y)))
{
COLORREF c;
if (GetPixel(x, y, c, lpDibBits))
{
int g = GetGValue(c);
if (g < nSize)
GreenChannel[g]++;
}
else
bSuccess = FALSE;
}
}
}
GlobalUnlock((HGLOBAL) m_hDib);
return bSuccess;
}
BOOL CDibImage::GetBlueHistogram(int* BlueChannel, int nSize)
{
if (m_hDib == NULL)
return FALSE;
for (int i=0; iBoundingRectangle());
BOOL bSuccess = TRUE;
LPSTR lpDibHdr = (LPSTR) ::GlobalLock(m_hDib);
LPSTR lpDibBits = ::FindDIBBits(lpDibHdr);
for (int y=r.top; bSuccess && yPointInSelection(CPoint(x, y)))
{
COLORREF c;
if (GetPixel(x, y, c, lpDibBits))
{
int b = GetBValue(c);
if (b < nSize)
BlueChannel[b]++;
}
else
bSuccess = FALSE;
}
}
}
GlobalUnlock((HGLOBAL) m_hDib);
return bSuccess;
}
BOOL CDibImage::GetHistogram(int* RedChannel, int nRedSize, int* GreenChannel, int nGreenSize, int* BlueChannel, int nBlueSize)
{
if (m_hDib == NULL)
return FALSE;
for (int i=0; iBoundingRectangle());
BOOL bSuccess = TRUE;
LPSTR lpDibHdr = (LPSTR) ::GlobalLock(m_hDib);
LPSTR lpDibBits = ::FindDIBBits(lpDibHdr);
for (int y=r.top; bSuccess && yPointInSelection(CPoint(x, y)))
{
COLORREF c;
if (GetPixel(x, y, c, lpDibBits))
{
int r = GetRValue(c);
int g = GetGValue(c);
int b = GetBValue(c);
if (r < nRedSize)
RedChannel[r]++;
if (g < nGreenSize)
GreenChannel[g]++;
if (b < nBlueSize)
BlueChannel[b]++;
}
else
bSuccess = FALSE;
}
}
}
GlobalUnlock((HGLOBAL) m_hDib);
return bSuccess;
}
BOOL CDibImage::CopyFromBitmap(HBITMAP hBitmap, HPALETTE hPal)
{
HDIB hDib = BitmapToDIB(hBitmap,hPal);
if (hDib == NULL)
return FALSE;
return Attach(hDib);
}
HBITMAP CDibImage::CopyToBitmap(void)
{
return DIBToBitmap(m_hDib, m_Pal);
}
BOOL CDibImage::CopyFromMemBmpFile(HMEMBMPFILE hMemBmpFile)
{
HDIB hDib = MemBmpFileToDIB(hMemBmpFile);
if (hDib == NULL)
return FALSE;
return Attach(hDib);
}
HMEMBMPFILE CDibImage::CopyToMemBmpFile(void)
{
return DIBToMemBmpFile(m_hDib);
}
BOOL CDibImage::CopyFromWindow(CWnd *pWnd, CRect* pScreenRect)
{
HDIB hDib = WindowToDIB(pWnd, pScreenRect);
if (hDib == NULL)
return FALSE;
return Attach(hDib);
}
BOOL CDibImage::ConvertTo24Bits(void)
{
if (m_hDib == NULL)
return FALSE;
if (m_Pal == NULL)
return FALSE;
// check if it is just a 24 bits image
if (m_nBitsPerPixel == 24)
return TRUE;
LOGPALETTE* pLogPalette = CreateLogPalette(m_Pal);
if (pLogPalette == NULL)
return FALSE;
SaveState(IDS_DI_UNDO_CONVERT24BITS);
CDibImage dib;
ASSERT(m_pWorkingArea);
CRect r = m_pWorkingArea->BoundingRectangle();
BOOL bSuccess = dib.Create(CSize(r.Width(), r.Height()), 24);
if (bSuccess)
{
LPSTR lpDibHdrSrc = (LPSTR) ::GlobalLock(m_hDib);
LPSTR lpDibBitsSrc = ::FindDIBBits(lpDibHdrSrc);
LPSTR lpDibHdrDest = (LPSTR) ::GlobalLock(dib.m_hDib);
LPSTR lpDibBitsDest = ::FindDIBBits(lpDibHdrDest);
for (int x=r.left; bSuccess && xPointInSelection(CPoint(x, y)))
{
ULONG PixelData = 0;
bSuccess = GetPixelData(x, y, PixelData, lpDibBitsSrc);
PALETTEENTRY pe = pLogPalette->palPalEntry[PixelData];
COLORREF ColorData = RGB( pe.peRed, pe.peGreen, pe.peBlue );
bSuccess = bSuccess && dib.SetPixel(x-r.left, y-r.top, ColorData, lpDibBitsDest);
}
}
}
GlobalUnlock((HGLOBAL) dib.m_hDib);
GlobalUnlock((HGLOBAL) m_hDib);
if (Attach(dib.m_hDib))
dib.m_hDib = NULL;
}
if (!bSuccess)
Undo();
DestroyLogPalette( pLogPalette );
return bSuccess;
}