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; 
}