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