www.pudn.com > dibimage.zip > 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. 
                       
 
 
 
Copyright (c) 1997 - 1999 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 "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 
  { 
    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; 
  } 
 
  BYTE* pData = GetPixelAddress(x, y, (BYTE*)lpDibBits); 
  BOOL bSuccess = SetPixelData(x, y, value, lpDibBits); 
 
  if (bLocked) 
    ::GlobalUnlock((HGLOBAL) m_hDib); 
 
  return TRUE; 
} 
 
 
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 
  { 
    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 0x0110;  //ie v1.10      
    
  /* Revision History 
  1.0  18/11/1997:  Initial Public Release 
  1.01 10/11/1998:  See help file for changes 
  1.1  24/07/1999:  See help file for changes 
  */ 
} 
 
 
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); 
 
  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; 
}