www.pudn.com > 基于TWAIN接口程序.zip > DIB.cpp


#include "stdafx.h" 
#include "math.h" 
#include "DIB.h" 
 
#define BIG_DISTANCE 10000000L 
 
#define DIST(r1,g1,b1,r2,g2,b2) \ 
	    (long) (3L*(long)((r1)-(r2))*(long)((r1)-(r2)) + \ 
		    4L*(long)((g1)-(g2))*(long)((g1)-(g2)) + \ 
		    2L*(long)((b1)-(b2))*(long)((b1)-(b2))) 
 
 
static unsigned char masktable[] = { 0x80,0x40,0x20,0x10,0x08,0x04,0x02,0x01 }; 
 
 
 
CDIB::CDIB(HANDLE hDib,int nBits) 
{ 
	m_pVoid = NULL; 
	m_pLinePtr = NULL; 
	m_bUseGamma=FALSE; 
	width=height=0; 
	if(hDib) 
	{ 
		CreateFromHandle(hDib,nBits); 
	} 
} 
 
CDIB::~CDIB() 
{ 
	DestroyDIB(); 
} 
 
void CDIB::DestroyDIB() 
{ 
	if(m_pVoid) free(m_pVoid); 
	m_pVoid = NULL; 
	if(m_pLinePtr) free(m_pLinePtr); 
	m_pLinePtr = NULL; 
} 
 
 
BOOL CDIB::Create(int width,int height,int bits) 
{ 
	/* 
		Free existing image 
	*/ 
	DestroyDIB(); 
//	ASSERT(bits == 24 || bits == 8); 
 
BITMAPINFOHEADER bmInfo; 
	 
	memset(&bmInfo,0,sizeof(BITMAPINFOHEADER)); 
	bmInfo.biSize = sizeof(BITMAPINFOHEADER); 
	bmInfo.biWidth = width; 
	bmInfo.biHeight = height; 
	bmInfo.biPlanes = 1; 
	bmInfo.biBitCount = bits; 
	bmInfo.biCompression = BI_RGB; 
	return Create(bmInfo); 
} 
 
BOOL CDIB::Create(BITMAPINFOHEADER& bmInfo) 
{ 
	bytes = (bmInfo.biBitCount*bmInfo.biWidth)>>3; 
	height = bmInfo.biHeight; 
	width = bmInfo.biWidth; 
//	bmInfo.biHeight *= -1; 
	while(bytes%4) bytes++; 
 
	int size; 
	size = sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD)*GetPaletteSize(bmInfo) + bytes*height; 
	m_pVoid = (void *)malloc(size); 
	if(!m_pVoid) return FALSE; 
 
	m_pInfo = (PBITMAPINFO )m_pVoid; 
	memcpy((void *)&m_pInfo->bmiHeader,(void *)&bmInfo,sizeof(BITMAPINFOHEADER)); 
	m_pRGB = (RGBQUAD *)((unsigned char *)m_pVoid + sizeof(BITMAPINFOHEADER)) ; 
	m_pBits = (unsigned char *)(m_pVoid) + sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD)*GetPaletteSize(); 
 
int i; 
BYTE **ptr; 
	m_pLinePtr = (BYTE **)malloc(sizeof(BYTE *)*height); 
	if(!m_pLinePtr) return FALSE; 
	for(i=0,ptr=m_pLinePtr; i < height; i++,ptr++) 
	{ 
		//*ptr = (int)(m_pBits)+(i*bytes); 
		//*ptr = (int)GetLinePtr(i); 
		*ptr = m_pBits + (height-i-1)*bytes; 
	} 
	m_nFlags = 0; 
	return TRUE; 
} 
 
void CDIB::SetPalette(unsigned char *palette) 
{ 
int i,size; 
RGBQUAD *rgb; 
	if(!palette) return; 
	size = GetPaletteSize(); 
	for(i=0,rgb = m_pRGB; i < size; i++,rgb++,palette+=3) 
	{ 
		if(m_bUseGamma) 
		{ 
			rgb->rgbRed = Gamma[palette[0]]; 
			rgb->rgbGreen = Gamma[palette[1]]; 
			rgb->rgbBlue = Gamma[palette[2]]; 
		} 
		else 
		{ 
			rgb->rgbRed = palette[0]; 
			rgb->rgbGreen = palette[1]; 
			rgb->rgbBlue = palette[2]; 
		} 
		rgb->rgbReserved = (BYTE)0; 
	} 
} 
 
void CDIB::SetPalette(RGBQUAD *pRGB) 
{ 
int size; 
	if(!pRGB) return; 
	size = GetPaletteSize(); 
	memcpy(m_pRGB,pRGB,size*sizeof(RGBQUAD)); 
} 
 
 
int CDIB::GetPaletteSize() 
{ 
	return GetPaletteSize(m_pInfo->bmiHeader); 
} 
 
 
int CDIB::GetPaletteSize(BITMAPINFOHEADER& bmInfo) 
{ 
	switch(bmInfo.biBitCount) 
	{ 
	case 1: 
			return 2; 
	case 4: 
			return 16; 
	case 8: 
			return 256; 
	default: 
			return 0; 
	} 
} 
 
 
void CDIB::SetPixel(int x,int y,COLORREF color) 
{ 
unsigned char *ptr; 
	ASSERT(x >= 0 && y >=0); 
	ASSERT(x < width && y < height); 
 
//	ptr = m_pBits + (y*bytes) + x * 3; 
	ptr = (unsigned char *)m_pLinePtr[y]; 
	ptr += x*3; 
	*ptr++ = (unsigned char)GetBValue(color); 
	*ptr++ = (unsigned char)GetGValue(color); 
	*ptr++ = (unsigned char)GetRValue(color); 
} 
 
void CDIB::SetPixel8(int x,int y,unsigned char color) 
{ 
unsigned char *ptr,*aptr; 
	ASSERT(x >= 0 && y >=0); 
	ASSERT(x < width && y < height); 
 
//	ptr = m_pBits + (y*bytes) + x ; 
//	ptr = (unsigned char *)m_pLinePtr[y] ; 
	ptr = GetLinePtr(y); 
	aptr = ptr; 
	ptr += x; 
	*ptr = color; 
} 
 
 
COLORREF CDIB::GetPixel(int x,int y) 
{ 
unsigned char *ptr; 
COLORREF color; 
	if(x < 0 || y < 0)  return 0; 
	if(x >= width || y >= height) return 0; 
 
//	ptr = m_pBits + (y*bytes) + x * 3; 
	ptr = GetLinePtr(y); 
	ptr += (x*3); 
	color = RGB(*(ptr+2),*(ptr+1),*ptr); 
	return color; 
} 
 
CBitmap *CDIB::GetTempBitmap(CDC& dc) 
{ 
HBITMAP hBitmap; 
CBitmap *temp; 
	ASSERT(m_pVoid != NULL); 
	hBitmap = CreateDIBitmap(dc.m_hDC, 
				(PBITMAPINFOHEADER)m_pInfo, 
				CBM_INIT, 
				(const void *)m_pBits, 
				m_pInfo, 
				DIB_RGB_COLORS); 
 
	if(hBitmap == NULL) return NULL; 
	temp = CBitmap::FromHandle(hBitmap); 
	return temp; 
} 
 
CBitmap *CDIB::GetBitmap(CDC& dc) 
{ 
HBITMAP hBitmap; 
CBitmap *temp; 
	ASSERT(m_pVoid != NULL); 
	hBitmap = CreateDIBitmap(dc.m_hDC, 
				(PBITMAPINFOHEADER)m_pInfo, 
				CBM_INIT, 
				(const void *)m_pBits, 
				m_pInfo, 
				DIB_RGB_COLORS); 
 
	if(hBitmap == NULL) return NULL; 
	temp = CBitmap::FromHandle(hBitmap); 
	if(temp) 
	{ 
		BITMAP bmp; 
		LPVOID lpVoid; 
		temp->GetBitmap(&bmp); 
		lpVoid = malloc(bmp.bmWidthBytes*bmp.bmHeight); 
		if(!lpVoid) return NULL; 
		temp->GetBitmapBits(bmp.bmWidthBytes*bmp.bmHeight,lpVoid); 
		CBitmap *newBmp = new CBitmap; 
		newBmp->CreateBitmapIndirect(&bmp); 
		newBmp->SetBitmapBits(bmp.bmWidthBytes*bmp.bmHeight,lpVoid); 
		free(lpVoid); 
		return newBmp; 
	} 
	else return NULL; 
 
} 
 
void CDIB::CopyLine(int source,int dest) 
{ 
unsigned char *src,*dst; 
	ASSERT(source <= height && source >= 0); 
	ASSERT(dest <= height && dest >= 0); 
	if(source == dest) return; 
	src = GetLinePtr(source); 
	dst = GetLinePtr(dest); 
	memcpy(dst,src,bytes); 
} 
 
void CDIB::InitDIB(COLORREF color) 
{ 
int i,j; 
unsigned char *ptr; 
	 
	if(m_pInfo->bmiHeader.biBitCount == 24) 
	{ 
		unsigned char col[3]; 
		col[0]=GetBValue(color); 
		col[1]=GetGValue(color); 
		col[2]=GetRValue(color); 
		for(i=0,ptr = m_pBits; i < height; i++) 
		{ 
			ptr = m_pBits + i*bytes; 
			for(j=0; j < width ; j++,ptr+=3) 
			{ 
				memcpy(ptr,col,3); 
			} 
		} 
	} 
	else 
	{ 
		for(i=0,ptr = m_pBits; i < height; i++,ptr+=bytes) 
		{ 
			memset(ptr,(BYTE)color,bytes); 
		} 
	} 
} 
 
 
void CDIB::BitBlt(HDC hDest,int nXDest,int nYDest,int nWidth,int nHeight,int xSrc,int ySrc) 
{ 
	SetDIBitsToDevice(hDest,nXDest,nYDest,nWidth,nHeight,xSrc,Height()-ySrc-nHeight,0,Height(),m_pBits,m_pInfo,DIB_RGB_COLORS); 
} 
 
void CDIB::StretchBlt(HDC hDest,int nXDest,int nYDest,int nDWidth,int nDHeight,int xSrc,int ySrc,int  nSWidth,int nSHeight) 
{ 
	int err; 
	err = StretchDIBits(hDest,nXDest,nYDest,nDWidth,nDHeight,xSrc,ySrc,nSWidth,nSHeight,m_pBits,(CONST BITMAPINFO * )&m_pInfo->bmiHeader,DIB_RGB_COLORS,SRCCOPY); 
} 
 
void CDIB::ExpandBlt(int nXDest,int nYDest,int xRatio,int yRatio,CDIB& dibSrc,int xSrc,int ySrc,int  nSWidth,int nSHeight) 
{ 
	SetPalette(dibSrc.m_pRGB); 
 
	nSWidth = xSrc+nSWidth > dibSrc.width ? dibSrc.width-xSrc : nSWidth; 
	nSHeight = ySrc+nSHeight > dibSrc.height? dibSrc.height-ySrc : nSHeight; 
 
	Expand(nXDest,nYDest,xRatio,yRatio,dibSrc,xSrc,ySrc,nSWidth,nSHeight); 
} 
 
void CDIB::Expand(int nXDest,int nYDest,int xRatio,int yRatio,CDIB& dibSrc,int xSrc,int ySrc,int  nSWidth,int nSHeight) 
{ 
int xNum,yNum,xErr,yErr;	 
int nDWidth,nDHeight; 
	 
	nDWidth = nSWidth*xRatio; 
	nDHeight = nSHeight*yRatio; 
 
	nDWidth = nXDest+nDWidth > width ? width-nXDest : nDWidth ;  
	nDHeight = nYDest+nDHeight > height ? height-nYDest : nDHeight; 
 
	xNum = nDWidth/xRatio; 
	yNum = nDHeight/yRatio; 
	xErr = nDWidth%xRatio; 
	yErr = nDHeight%yRatio; 
 
unsigned char *buffer,*srcPtr,*destPtr,*ptr; 
int i,j,k; 
	 
	buffer = (unsigned char *)malloc(nDWidth+20); 
	if(!buffer) return; 
 
	for(i=0; i < yNum; i++,ySrc++) 
	{ 
		srcPtr = dibSrc.GetLinePtr(ySrc) + xSrc; 
		ptr = buffer; 
		for(j=0; j < xNum; j++,ptr+=xRatio) 
		{ 
			memset(ptr,*(srcPtr+j),xRatio); 
			k=*(srcPtr+j); 
		} 
		memset(ptr,(unsigned char)k,xErr); 
		for(j=0; j < yRatio ; j++,nYDest++) 
		{ 
			destPtr = GetLinePtr(nYDest) + nXDest; 
			memcpy(destPtr,buffer,nDWidth);		 
		} 
	} 
	for(j=0; j < yErr; j++,nYDest++) 
	{ 
		destPtr = GetLinePtr(nYDest) + nXDest; 
		memcpy(destPtr,buffer,nDWidth);		 
	} 
	free(buffer); 
} 
 
void CDIB::StretchBlt(int nXDest,int nYDest,int nDWidth,int nDHeight,CDIB& dibSrc,int xSrc,int ySrc,int  nSWidth,int nSHeight) 
{ 
	SetPalette(dibSrc.m_pRGB); 
	nDWidth = nXDest+nDWidth > width ? width-nXDest : nDWidth ;  
	nDHeight = nYDest+nDHeight > height ? height-nYDest : nDHeight; 
 
	nSWidth = xSrc+nSWidth > dibSrc.width ? dibSrc.width-xSrc : nSWidth; 
	nSHeight = ySrc+nSHeight > dibSrc.height? dibSrc.height-ySrc : nSHeight; 
 
int xDiv,yDiv; 
int xMod,yMod; 
 
	xDiv = nDWidth/nSWidth; 
	xMod = nDWidth%nSWidth; 
 
	yDiv = nDHeight/nSHeight; 
	yMod = nDHeight%nSHeight; 
 
	if(!xMod && !yMod && xDiv > 0 && yDiv > 0) 
	{ 
		ExpandBlt(nXDest,nYDest,xDiv,yDiv,dibSrc,xSrc,ySrc,nSWidth,nSHeight); 
		return; 
	} 
 
unsigned char *tempPtr,*srcPix,*destPix,*q; 
	tempPtr = (unsigned char *)malloc(nDWidth+20); 
int i,j,k,l,x,y,m; 
int xErr,yErr; 
	for(i=yErr=m=0; i < nSHeight; i++) 
	{ 
		srcPix = dibSrc.GetLinePtr(i+ySrc) + xSrc; 
		q = tempPtr; 
		for(j=l=xErr=0; j < nSWidth; j++,srcPix++) 
		{ 
			k = xDiv; 
			xErr += xMod; 
			if(xErr >= nSWidth) 
			{ 
				k++; 
				xErr%=nSWidth; 
			} 
			x=0; 
			while(l < nDWidth &&  x < k) 
			{ 
				*q++ = *srcPix; 
				l++; 
				x++; 
			} 
		} 
		while(l < nDWidth) 
		{ 
			*q++=*srcPix; 
			l++; 
		} 
		k= yDiv; 
		yErr += yMod; 
		if(yErr >= nSHeight) 
		{ 
			k++; 
			yErr%=nSHeight; 
		} 
		y=0; 
		while(m < nDHeight && y < k) 
		{ 
			destPix = GetLinePtr(m+nYDest) + nXDest; 
			memcpy(destPix,tempPtr,nDWidth); 
			m++; 
			y++; 
		} 
	} 
	while(m < nDHeight ) 
	{ 
		destPix = GetLinePtr(m+nYDest) + nXDest; 
		memcpy(destPix,tempPtr,nDWidth); 
		m++; 
	} 
	free(tempPtr); 
} 
 
void CDIB::BitBlt(int nXDest,int nYDest,int nWidth,int nHeight,CDIB& dibSrc,int nSrcX,int nSrcY,BYTE *colors) 
{ 
	SetPalette(dibSrc.m_pRGB); 
	if(nXDest < 0) 
	{ 
		nSrcX -= nXDest; 
		nWidth += nXDest; 
		nXDest=0; 
	} 
	if(nYDest < 0) 
	{ 
		nSrcY -= nYDest; 
		nHeight += nYDest; 
		nYDest=0; 
	} 
	if(nSrcX < 0) 
	{ 
		nXDest -= nSrcX; 
		nWidth += nSrcX; 
		nSrcX=0; 
	} 
	if(nSrcY < 0) 
	{ 
		nYDest -= nSrcY; 
		nHeight += nSrcY; 
		nSrcY=0; 
	} 
	nWidth = nXDest+nWidth > width ? width-nXDest : nWidth ;  
	nHeight = nYDest+nHeight > height ? height-nYDest : nHeight; 
 
	nWidth = nSrcX+nWidth > dibSrc.width ? dibSrc.width-nSrcX : nWidth; 
	nHeight = nSrcY+nHeight > dibSrc.height? dibSrc.height-nSrcY : nHeight; 
 
	nWidth = __max(0,nWidth); 
	nHeight = __max(0,nHeight); 
int i,k,l,j; 
unsigned char *srcPtr,*destPtr; 
	if(!colors) 
	{ 
		for(i=0,k=nSrcY,l=nYDest; i < nHeight; i++,k++,l++) 
		{ 
			if(k < 0 || l < 0) 
			{ 
				continue; 
			} 
			else 
			{ 
				srcPtr = dibSrc.GetLinePtr(k); 
				destPtr = GetLinePtr(l); 
				memcpy(destPtr+nXDest,srcPtr+nSrcX,nWidth); 
			} 
		} 
	} 
	else 
	{ 
		for(i=0,k=nSrcY,l=nYDest; i < nHeight; i++,k++,l++) 
		{ 
			if(k < 0 || l < 0) 
			{ 
				continue; 
			} 
			else 
			{ 
				srcPtr = dibSrc.GetLinePtr(k)+nXDest; 
				destPtr = GetLinePtr(l)+nSrcX; 
				for(j=0; j < nWidth; j++,srcPtr++,destPtr++) 
				{ 
					if(colors[*srcPtr]) *destPtr=*srcPtr; 
				} 
			} 
		} 
	} 
} 
 
unsigned char *CDIB::GetLinePtr(int line) 
{ 
/*unsigned char *ptr; 
	ptr = m_pBits + (height-line-1)*bytes; 
	return ptr;*/ 
	return m_pLinePtr[line]; 
} 
	 
BOOL CDIB::CopyDIB(CDIB& dib) 
{ 
	if(Create(dib.m_pInfo->bmiHeader)) 
	{ 
		SetPalette(dib.m_pRGB); 
		memcpy(m_pBits,dib.m_pBits,height*bytes); 
		return TRUE; 
	} 
	return FALSE; 
} 
 
void CDIB::ReplaceColor(unsigned char oldColor,unsigned char newColor) 
{ 
int i,j; 
unsigned char *ptr;	 
	for(i=0; i < height; i++) 
	{ 
		ptr = GetLinePtr(i); 
		for(j=0; j < width; j++) 
		{ 
			if(ptr[j] == oldColor) ptr[j] = newColor; 
		} 
	} 
} 
 
 
CDIB& CDIB::operator=(CDIB& dib) 
{ 
	CopyDIB(dib); 
	return *this; 
} 
 
HANDLE CDIB::GetDIBits(int nStartX,int nStartY,int nCx,int nCy) 
{ 
	if(nStartX == -1) 
	{ 
		nStartX = nStartY=0; 
		nCx = width; 
		nCy = height; 
		CDIB dib; 
		dib.Create(nCx,nCy,8); 
		dib.BitBlt(0,0,nCx,nCy,*this,0,0); 
		dib.SetPalette(m_pRGB); 
		return dib.DIBHandle(); 
	} 
	return DIBHandle(); 
} 
 
DWORD CDIB::GetDIBSize() 
{ 
	return sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD)*GetPaletteSize() + bytes*height; 
} 
 
HANDLE CDIB::DIBHandle() 
{ 
int nSize; 
HANDLE hMem; 
	nSize = sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD)*GetPaletteSize() + bytes*height; 
	hMem = GlobalAlloc(GMEM_DDESHARE | GMEM_MOVEABLE,nSize); 
	if(hMem  == NULL) return NULL; 
UCHAR *lpVoid,*pBits; 
LPBITMAPINFOHEADER pHead; 
RGBQUAD *pRgb; 
	lpVoid = (UCHAR *)GlobalLock(hMem); 
	pHead = (LPBITMAPINFOHEADER )lpVoid; 
	memcpy(pHead,&m_pInfo->bmiHeader,sizeof(BITMAPINFOHEADER)); 
	pRgb = (RGBQUAD *)(lpVoid + sizeof(BITMAPINFOHEADER) ); 
	memcpy(pRgb,m_pRGB,sizeof(RGBQUAD)*GetPaletteSize()); 
	pBits = lpVoid + sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD)*GetPaletteSize(); 
	memcpy(pBits,m_pBits,height*bytes); 
	GlobalUnlock(lpVoid); 
	return hMem; 
} 
 
BOOL CDIB::CreateFromHandle(HANDLE hMem,int bits) 
{ 
	DestroyDIB(); 
UCHAR *lpVoid,*pBits; 
LPBITMAPINFOHEADER pHead; 
RGBQUAD *pRgb; 
	lpVoid = (UCHAR *)GlobalLock(hMem); 
	pHead = (LPBITMAPINFOHEADER )lpVoid; 
	width = pHead->biWidth; 
	height = pHead->biHeight; 
	m_nBits = pHead->biBitCount; 
	if(pHead->biCompression != BI_RGB)  
	{ 
		GlobalUnlock(lpVoid); 
		return FALSE; 
	} 
	if(pHead->biBitCount >= 15) 
	{ 
		if(pHead->biBitCount != 24)  
		{ 
			GlobalUnlock(lpVoid); 
			return FALSE; 
		} 
	} 
	if(!Create(*pHead)) 
	{ 
		GlobalUnlock(lpVoid); 
		return FALSE; 
	} 
	pRgb = (RGBQUAD *)(lpVoid + sizeof(BITMAPINFOHEADER) ); 
	memcpy(m_pRGB,pRgb,sizeof(RGBQUAD)*GetPaletteSize()); 
	pBits = lpVoid + sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD)*GetPaletteSize(); 
	memcpy(m_pBits,pBits,height*bytes); 
	GlobalUnlock(lpVoid); 
	return TRUE; 
} 
 
void CDIB::UseGamma(float fg,BOOL bUse) 
{ 
	m_bUseGamma = bUse; 
	m_fOldGamma = m_fGamma; 
	m_fGamma = fg; 
	CreateGammaCurve(); 
} 
 
 
void CDIB::CreateGammaCurve() 
{ 
int i; 
	for(i=0;i<256;++i) 
	{ 
	    Gamma[i]=(int)(255 * pow((double)i/255,m_fGamma) + (double)0.5); 
	} 
} 
 
 
 
void CDIB::GetPixel(UINT x,UINT y,int& pixel) 
{ 
	ASSERT(x < (UINT)Width()); 
	ASSERT(y < (UINT)Height()); 
	if(x >= (UINT)Width()) return; 
	if(y >= (UINT)Height()) return; 
	pixel=(GetLinePtr(y))[x]; 
} 
 
BOOL CDIB::Make8Bit(CDIB& dib) 
{ 
int nBits;	 
	ASSERT(Width() == dib.Width()); 
	ASSERT(Height() == dib.Height()); 
	nBits = dib.GetBitCount(); 
	switch(nBits) 
	{ 
	case 1: 
		return SwitchFromOne(dib); 
		break; 
	case 4: 
		return SwitchFromFour(dib); 
		break; 
	case 8: 
		return SwitchPalette(dib); 
		break; 
	case 24: 
		return SwitchFrom24(dib); 
		break; 
	default: 
		return FALSE; 
	} 
	return FALSE; 
} 
 
/* 
BOOL CDIB::SwitchFrom24(CDIB& dib) 
{ 
int i,j,w,h; 
unsigned char *sPtr,*dPtr; 
	w = Width(); 
	h = Height(); 
	memset(CachePtr,0,sizeof(CachePtr)); 
	for(i=0; i < h; i++) 
	{ 
		dPtr = GetLinePtr(i); 
		sPtr = dib.GetLinePtr(i); 
		for(j=0 ; j < w; j++,dPtr++,sPtr+=3) 
		{ 
			*dPtr = ClosestColor((RGBQUAD *)sPtr); 
		} 
	} 
	return TRUE; 
} 
*/ 
 
 
BOOL CDIB::SwitchFromOne(CDIB& dib) 
{ 
int i,n,j,w,h; 
unsigned char *sPtr,*dPtr; 
unsigned char cols[2]; 
	w = Width(); 
	h = Height(); 
	memset(CachePtr,0,sizeof(CachePtr)); 
	cols[0]=ClosestColor(dib.m_pRGB); 
	cols[1]=ClosestColor(dib.m_pRGB+1); 
	for(i=0; i < h; i++) 
	{ 
		dPtr = GetLinePtr(i); 
		sPtr = dib.GetLinePtr(i); 
		for(j=0 ; j < w; j++,dPtr++) 
		{ 
			if(!(sPtr[j>>3] & masktable[j&7])) *dPtr = cols[0]; 
			else *dPtr = cols[1]; 
		} 
	} 
	return TRUE; 
} 
 
BOOL CDIB::SwitchFromFour(CDIB& dib) 
{ 
int i,n,j,w,h; 
unsigned char *sPtr,*dPtr; 
unsigned char cols[16]; 
	w = Width(); 
	h = Height(); 
	memset(CachePtr,0,sizeof(CachePtr)); 
	for(i=0; i < 16; i++) 
	{ 
		cols[i]=ClosestColor(dib.m_pRGB+i); 
	} 
	for(i=0; i < h; i++) 
	{ 
		dPtr = GetLinePtr(i); 
		sPtr = dib.GetLinePtr(i); 
		for(j=0 ; j < w; j++,dPtr++) 
		{ 
			if(!(j&1)) n = (*sPtr & 0xf0)>>4; 
			else  
			{ 
				n = *sPtr & 0x0f; 
				sPtr++; 
			} 
			*dPtr = cols[n]; 
		} 
	} 
	return TRUE; 
} 
 
BOOL CDIB::SwitchPalette(CDIB& dib) 
{ 
int i,j,w,h; 
unsigned char *sPtr,*dPtr; 
unsigned char cols[256]; 
	w = Width(); 
	h = Height(); 
	memset(CachePtr,0,sizeof(CachePtr)); 
	for(i=0; i < 256; i++) 
	{ 
		cols[i]=ClosestColor(dib.m_pRGB+i); 
	} 
	for(i=0; i < h; i++) 
	{ 
		dPtr = GetLinePtr(i); 
		sPtr = dib.GetLinePtr(i); 
		for(j=0 ; j < w; j++,sPtr++,dPtr++) 
		{ 
			*dPtr = cols[*sPtr]; 
		} 
	} 
	return TRUE; 
} 
 
 
int CDIB::ClosestColor(RGBQUAD *pRgb) 
{ 
unsigned int dist=BIG_DISTANCE,i,d,c; 
RGBQUAD *pQuad=m_pRGB; 
int pSize=GetPaletteSize(); 
	for(i=0; i < pSize;i++) 
	{ 
		if(CachePtr[i]) 
		{ 
			if(!memcmp((void *)&CacheQuad[i],(void *)pRgb,3))  
			{ 
				return i; 
			} 
		} 
	} 
	for(i=0; i < pSize; i++,pQuad++) 
	{ 
		d = Distance(*pRgb,*pQuad); 
		if(!d)  
		{ 
			CacheQuad[i]=*pRgb; 
			CachePtr[i]=1; 
			return i; 
		}		 
		if(dist > d)  
		{ 
			c = i; 
			dist = d; 
		} 
	} 
	CacheQuad[c]=*pRgb; 
	CachePtr[c]=1; 
	return c; 
} 
 
unsigned int CDIB::Distance(RGBQUAD& rgb1,RGBQUAD& rgb2) 
{ 
unsigned int d; 
	d =  3*(unsigned)((rgb1.rgbRed)-(rgb2.rgbRed))*(unsigned)((rgb1.rgbRed)-(rgb2.rgbRed)); 
	d += 4*(unsigned)((rgb1.rgbGreen)-(rgb2.rgbGreen))*(unsigned)((rgb1.rgbGreen)-(rgb2.rgbGreen)) ; 
	d += 2*(unsigned)((rgb1.rgbBlue)-(rgb2.rgbBlue))*(unsigned)((rgb1.rgbBlue)-(rgb2.rgbBlue)); 
	return d; 
} 
 
BOOL CDIB::OpenDIB(CString& csFileName) 
{ 
CFile file; 
	if(!file.Open(csFileName,CFile::modeRead | CFile::typeBinary)) 
	{ 
		return FALSE; 
	} 
	file.Close(); 
	if(OpenBMP(csFileName)) return TRUE; 
	return FALSE; 
} 
 
 
 
BOOL CDIB::SaveDIB(CString& csFileName,BitmapType type) 
{ 
CFile file; 
	if(!file.Open(csFileName,CFile::modeCreate | CFile::typeBinary)) 
	{ 
		return FALSE; 
	} 
	file.Close(); 
	switch(type) 
	{ 
	case BMP: 
			return SaveBMP(csFileName); 
	default: 
			return FALSE; 
	} 
	return FALSE; 
} 
 
BOOL CDIB::SaveBMP(CString& csFileName) 
{ 
BITMAPFILEHEADER bFile; 
CFile file; 
	if(!file.Open(csFileName,CFile::modeWrite | CFile::typeBinary)) 
	{ 
		return FALSE; 
	} 
	::ZeroMemory(&bFile,sizeof(bFile)); 
	memcpy((void *)&bFile.bfType,"BM",2); 
	bFile.bfSize = GetDIBSize() + sizeof(bFile); 
	bFile.bfOffBits = sizeof(BITMAPINFOHEADER) + GetPaletteSize()*sizeof(RGBQUAD) + sizeof(BITMAPFILEHEADER); 
	file.Write(&bFile,sizeof(bFile)); 
	file.Write(m_pVoid,GetDIBSize()); 
	file.Close(); 
	return TRUE; 
 
} 
 
BOOL CDIB::OpenBMP(CString& csFileName) 
{ 
BITMAPFILEHEADER bFile; 
BITMAPINFOHEADER head; 
CFile file; 
	if(!file.Open(csFileName,CFile::modeRead | CFile::typeBinary)) 
	{ 
		return FALSE; 
	} 
	file.Read(&bFile,sizeof(bFile)); 
	if(memcmp((void *)&bFile.bfType,"BM",2)) 
	{ 
		file.Close(); 
		return FALSE; 
	} 
	file.Read(&head,sizeof(head)); 
	if(!Create(head)) 
	{ 
		file.Close(); 
		return FALSE; 
	} 
	file.Read(m_pRGB,sizeof(RGBQUAD)*GetPaletteSize()); 
	file.Seek(bFile.bfOffBits,CFile::begin); 
	file.Read(m_pBits,height*bytes); 
	file.Close(); 
	return TRUE; 
 
} 
 
 
int CDIB::CountColors() 
{ 
	ASSERT(GetBitCount()==8); 
BYTE colors[256],*ptr; 
int nNum=0,i,j,w,d; 
	w = Width(); 
	d = Height(); 
	memset(colors,0,256); 
	for(i=0; i < d; i++) 
	{ 
		ptr = GetLinePtr(i); 
		for(j=0; j < w; j++,ptr++) 
		{ 
			if(!colors[*ptr]) 
			{ 
				colors[*ptr]=1; 
				nNum++; 
			} 
		} 
	} 
	return nNum; 
} 
 
int CDIB::EnumColors(BYTE *array) 
{ 
	ASSERT(GetBitCount()==8); 
BYTE *ptr; 
int nNum=0,i,j,w,d; 
	w = Width(); 
	d = Height(); 
	memset(array,0,256); 
	for(i=0; i < d; i++) 
	{ 
		ptr = GetLinePtr(i); 
		for(j=0; j < w; j++,ptr++) 
		{ 
			if(!array[*ptr]) 
			{ 
				array[*ptr]=1; 
				nNum++; 
			} 
		} 
	} 
	return nNum; 
} 
 
COLORREF CDIB::PaletteColor(int nIndex) 
{ 
	ASSERT(nIndex < 256); 
RGBQUAD *pRGB= m_pRGB+nIndex; 
	return RGB(pRGB->rgbRed,pRGB->rgbGreen,pRGB->rgbBlue); 
} 
 
BOOL CDIB::SwitchFrom24(CDIB& dib) 
{ 
int i,j,w,h,c; 
unsigned char *sPtr,*dPtr; 
BYTE *index_ptr=NULL; 
RGBQUAD rgb; 
	w = Width(); 
	h = Height(); 
	index_ptr = (BYTE *)malloc(0x7FFF+1); 
	if(!index_ptr) return FALSE; 
	memset(CachePtr,0,sizeof(CachePtr)); 
	for(i=0; i <= 0x7FFF; i++) 
	{ 
		rgb.rgbRed = (((i & 0x7C00)>>10) << 3) | 0x07; 
		rgb.rgbGreen = (((i & 0x3e0)>>5) << 3) | 0x07; 
		rgb.rgbBlue = ((i & 0x1F)<<3) | 0x07; 
		index_ptr[i] = ClosestColor(&rgb); 
	} 
	for(i=0; i < h; i++) 
	{ 
		dPtr = GetLinePtr(i); 
		sPtr = dib.GetLinePtr(i); 
		for(j=0 ; j < w; j++,dPtr++,sPtr+=3) 
		{ 
			c = (*sPtr >> 3) | ((*(sPtr+1) >> 3) << 5) | ((*(sPtr+2) >> 3) << 10); 
			*dPtr = index_ptr[c]; 
		} 
	} 
	free(index_ptr); 
	return TRUE; 
}