www.pudn.com > ImageCheck.rar > CaiImage.cpp


// CaiImage.cpp: implementation of the CCaiImage class. 
// 
////////////////////////////////////////////////////////////////////// 
 
#include "stdafx.h" 
#include "ImageCheck.h" 
#include "CaiImage.h" 
#include "stdlib.h" 
 
#ifdef _DEBUG 
#undef THIS_FILE 
static char THIS_FILE[]=__FILE__; 
#define new DEBUG_NEW 
#endif 
 
////////////////////////////////////////////////////////////////////// 
// Construction/Destruction 
////////////////////////////////////////////////////////////////////// 
 
CCaiImage::CCaiImage() 
{ 
	m_nImgType = 0; 
	pDib = NULL; 
	m_dwEffWidth = 0; 
	m_rtImgShow.SetRectEmpty(); 
	m_bIsPrepare = FALSE; 
	memset(&head,0,sizeof(head)); 
	m_bAutoFit = TRUE; 
	m_dwSize = 0; 
} 
 
CCaiImage::~CCaiImage() 
{ 
	Destroy(); 
} 
 
 
BOOL CCaiImage::LoadBMP(CString strFilePath) 
{ 
	if (strFilePath.IsEmpty()) 
	{ 
		return FALSE; 
	} 
 
	CFile imgFile; 
	if (!imgFile.Open(strFilePath,CFile::modeRead|CFile::typeBinary)) 
	{ 
		return FALSE; 
	} 
 
	BITMAPFILEHEADER   bf; 
	if (imgFile.Read(&bf,min(14,sizeof(bf)))==0) 
	{ 
		//Not a BMP file 
		return FALSE; 
	} 
 
    if (bf.bfType != BFT_BITMAP) 
	{ 
		return FALSE; 
    } 
 
	BITMAPINFOHEADER bmpHeader; 
	if (!DibReadBitmapInfo(&imgFile,&bmpHeader)) 
	{ 
		return FALSE; 
	} 
 
	DWORD dwCompression=bmpHeader.biCompression; 
	DWORD dwBitCount=bmpHeader.biBitCount; //preserve for BI_BITFIELDS compression  
	BOOL bIsOldBmp = bmpHeader.biSize == sizeof(BITMAPCOREHEADER); 
	BOOL bTopDownDib = bmpHeader.biHeight<0; // check if it's a top-down bitmap 
	if (bTopDownDib)  
	{ 
		bmpHeader.biHeight=-bmpHeader.biHeight; 
	} 
 
	if (!CreateImg(bmpHeader.biWidth,bmpHeader.biHeight,bmpHeader.biBitCount)) 
	{ 
		return FALSE; 
	} 
 
	head.biXPelsPerMeter = bmpHeader.biXPelsPerMeter; 
	head.biYPelsPerMeter = bmpHeader.biYPelsPerMeter; 
	 
 
    RGBQUAD *pRgb = GetPalette(); 
    if (pRgb) 
	{ 
        if (bIsOldBmp) 
		{ 
             // convert a old color table (3 byte entries) to a new 
             // color table (4 byte entries) 
            imgFile.Read((void*)pRgb,DibNumColors(&bmpHeader) * sizeof(RGBTRIPLE)); 
 
            for (int i=DibNumColors(&head)-1; i>=0; i--) 
			{ 
                pRgb[i].rgbRed      = ((RGBTRIPLE *)pRgb)[i].rgbtRed; 
                pRgb[i].rgbBlue     = ((RGBTRIPLE *)pRgb)[i].rgbtBlue; 
                pRgb[i].rgbGreen    = ((RGBTRIPLE *)pRgb)[i].rgbtGreen; 
                pRgb[i].rgbReserved = (BYTE)0; 
            } 
        }  
		else 
		{ 
            imgFile.Read((void*)pRgb,DibNumColors(&bmpHeader) * sizeof(RGBQUAD)); 
			//force rgbReserved=0, to avoid problems with some WinXp bitmaps 
			for (unsigned int i=0; i> 1) & 1 )== 1) 
										imgFile.Read(&second_byte, sizeof(BYTE));												 
									break; 
							}; 
							break; 
						default : 
						{ 
							BYTE *sline = GetBits(scanline); 
							imgFile.Read(&second_byte, sizeof(BYTE)); 
							for (unsigned i = 0; i < status_byte; i++) 
							{ 
								if (low_nibble) 
								{ 
									if ((DWORD)(sline+bits) < (DWORD)(GetBits()+head.biSizeImage)) 
									{ 
										*(sline + bits) |= (second_byte & 0x0F); 
									} 
									bits++; 
								} 
								else  
								{ 
									if ((DWORD)(sline+bits) < (DWORD)(GetBits()+head.biSizeImage)) 
									{ 
										*(sline + bits) = (BYTE)(second_byte & 0xF0); 
									} 
								}				 
								low_nibble = !low_nibble; 
							} 
						} 
						break; 
					}; 
				} 
				break; 
			} 
			case BI_RLE8 : 
			{ 
				BYTE status_byte = 0; 
				BYTE second_byte = 0; 
				int scanline = 0; 
				int bits = 0; 
 
				for (BOOL bContinue = TRUE; bContinue; ) 
				{ 
					imgFile.Read(&status_byte, sizeof(BYTE)); 
					switch (status_byte) { 
						case RLE_COMMAND : 
							imgFile.Read(&status_byte, sizeof(BYTE)); 
							switch (status_byte) { 
								case RLE_ENDOFLINE : 
									bits = 0; 
									scanline++; 
									break; 
								case RLE_ENDOFBITMAP : 
									bContinue=FALSE; 
									break; 
								case RLE_DELTA : 
								{ 
									// read the delta values 
									BYTE delta_x; 
									BYTE delta_y; 
									imgFile.Read(&delta_x, sizeof(BYTE)); 
									imgFile.Read(&delta_y, sizeof(BYTE)); 
									// apply them 
									bits     += delta_x; 
									scanline += delta_y; 
									break; 
								} 
								default : 
									imgFile.Read((void *)(GetBits(scanline) + bits), sizeof(BYTE) * status_byte); 
									// align run length to even number of bytes  
									if ((status_byte & 1) == 1) 
										imgFile.Read(&second_byte, sizeof(BYTE));												 
									bits += status_byte;													 
									break;								 
							}; 
							break; 
						default : 
							BYTE *sline = GetBits(scanline); 
							imgFile.Read(&second_byte, sizeof(BYTE)); 
							for (unsigned i = 0; i < status_byte; i++) 
							{ 
								if ((DWORD)bitsRead(pdib,sizeof(BITMAPINFOHEADER))==0) 
	{ 
		return FALSE; 
	} 
 
    BITMAPCOREHEADER   bc; 
    switch (pdib->biSize) // what type of bitmap info is this? 
    { 
        case sizeof(BITMAPINFOHEADER): 
            break; 
 
		case 64: //sizeof(OS2_BMP_HEADER): 
            fh->Seek((long)(64 - sizeof(BITMAPINFOHEADER)),SEEK_CUR); 
			break; 
 
        case sizeof(BITMAPCOREHEADER): 
            bc = *(BITMAPCOREHEADER*)pdib; 
            pdib->biSize               = bc.bcSize; 
            pdib->biWidth              = (DWORD)bc.bcWidth; 
            pdib->biHeight             = (DWORD)bc.bcHeight; 
            pdib->biPlanes             =  bc.bcPlanes; 
            pdib->biBitCount           =  bc.bcBitCount; 
            pdib->biCompression        = BI_RGB; 
            pdib->biSizeImage          = 0; 
            pdib->biXPelsPerMeter      = 0; 
            pdib->biYPelsPerMeter      = 0; 
            pdib->biClrUsed            = 0; 
            pdib->biClrImportant       = 0; 
 
			fh->Seek((long)(sizeof(BITMAPCOREHEADER)-sizeof(BITMAPINFOHEADER)), SEEK_CUR); 
 
            break; 
        default: 
			//give a last chance 
			 if (pdib->biSize>(sizeof(BITMAPINFOHEADER))&& 
				(pdib->biSizeImage==(unsigned long)(pdib->biHeight*((((pdib->biBitCount*pdib->biWidth)+31)/32)*4)))&& 
				(pdib->biPlanes==1)&&(pdib->biCompression==BI_RGB)&&(pdib->biClrUsed==0)) 
			 { 
	             fh->Seek((long)(pdib->biSize - sizeof(BITMAPINFOHEADER)),SEEK_CUR); 
				 break; 
			 } 
			return false; 
    } 
 
    FixBitmapInfo(pdib); 
 
    return true;	 
} 
 
BOOL CCaiImage::Destroy() 
{ 
	m_bIsPrepare = FALSE; 
	if (pDib) 
	{ 
		delete [] pDib; 
		pDib=NULL; 
	} 
	return TRUE;	 
} 
 
void* CCaiImage::CreateImg(DWORD dwWidth, DWORD dwHeight, DWORD wBpp) 
{ 
	if (!Destroy()) 
	{ 
		return NULL; 
	} 
	if ((dwWidth == 0) || (dwHeight == 0)) 
	{ 
		return NULL; 
	} 
	 
    // Make sure bits per pixel is valid 
    if		(wBpp <= 1)	wBpp = 1; 
    else if (wBpp <= 4)	wBpp = 4; 
    else if (wBpp <= 8)	wBpp = 8; 
    else				wBpp = 24; 
 
 
	// set the correct bpp value 
    switch (wBpp){ 
        case 1: 
            head.biClrUsed = 2;	break; 
        case 4: 
            head.biClrUsed = 16; break; 
        case 8: 
            head.biClrUsed = 256; break; 
        default: 
            head.biClrUsed = 0; 
    } 
 
	if (((dwWidth*dwHeight*wBpp)>>8) > 256000000) 
	{ 
		return NULL; 
	} 
	m_dwEffWidth = ((((wBpp * dwWidth) + 31) / 32) * 4); 
    // initialize BITMAPINFOHEADER 
	head.biSize = sizeof(BITMAPINFOHEADER); // 
    head.biWidth = dwWidth;		// fill in width from parameter 
    head.biHeight = dwHeight;	// fill in height from parameter 
    head.biPlanes = 1;			// must be 1 
    head.biBitCount = (WORD)wBpp;		// from parameter 
    head.biCompression = BI_RGB;     
    head.biSizeImage = m_dwEffWidth * dwHeight; 
    head.biClrImportant = 0; 
	 
	DWORD dwSize = 0; 
	dwSize = head.biSize + head.biSizeImage + GetPaletteSize(); 
	m_dwSize = dwSize; 
	//pDib = malloc(dwSize); // alloc memory block to store our bitmap 
	pDib = new BYTE[dwSize]; 
    if (!pDib) 
	{ 
		return NULL; 
	} 
	//clear the palette 
	RGBQUAD* pal=GetPalette(); 
	if (pal) 
	{ 
		memset(pal,0,GetPaletteSize()); 
	} 
	 
    // use our bitmap info structure to fill in first part of 
    // our DIB with the BITMAPINFOHEADER 
    BITMAPINFOHEADER*  lpbi; 
	lpbi = (BITMAPINFOHEADER*)(pDib); 
    *lpbi = head; 
 
	m_rtImgShow = CRect(0,0,head.biWidth,head.biHeight); 
	m_bIsPrepare = TRUE; 
	return pDib; 
} 
 
bool CCaiImage::CreateFromArray(BYTE *pArray, DWORD dwWidth, DWORD dwHeight, DWORD dwBitsperpixel, DWORD dwBytesperline, bool bFlipImage) 
{ 
	if (pArray==NULL) return false; 
	if (!((dwBitsperpixel==1)||(dwBitsperpixel==4)||(dwBitsperpixel==8)|| 
		(dwBitsperpixel==24)||(dwBitsperpixel==32))) return false; 
 
	if (!CreateImg(dwWidth,dwHeight,dwBitsperpixel)) return false; 
 
	BYTE *dst,*src; 
 
	for (DWORD y = 0; y>i)&0x01) ns[0]++; 
				if ((greenmask>>i)&0x01) ns[1]++; 
				if ((bluemask>>i)&0x01) ns[2]++; 
			} 
			ns[1]+=ns[0]; ns[2]+=ns[1];	ns[0]=8-ns[0]; ns[1]-=8; ns[2]-=8; 
			// dword aligned width for 16 bit image 
			long effwidth2=(((head.biWidth + 1) / 2) * 4); 
			WORD w; 
			long y2,y3,x2,x3; 
			BYTE *p=GetBits(); 
			// scan the buffer in reverse direction to avoid reallocations 
			for (long y=head.biHeight-1; y>=0; y--) 
			{ 
				y2=effwidth2*y; 
				y3=m_dwEffWidth*y; 
				for (long x=head.biWidth-1; x>=0; x--) 
				{ 
					x2 = 2*x+y2; 
					x3 = 3*x+y3; 
					w = (WORD)(src[x2]+256*src[1+x2]); 
					p[  x3]=(BYTE)((w & bluemask)<>ns[1]); 
					p[2+x3]=(BYTE)((w & redmask)>>ns[2]); 
				} 
			} 
			break; 
		} 
		case 32: 
		{ 
			// dword aligned width for 32 bit image 
			long effwidth4 = head.biWidth * 4; 
			long y4,y3,x4,x3; 
			BYTE *p=GetBits(); 
			// scan the buffer in reverse direction to avoid reallocations 
			for (long y=head.biHeight-1; y>=0; y--) 
			{ 
				y4=effwidth4*y; 
				y3=m_dwEffWidth*y; 
				for (long x=head.biWidth-1; x>=0; x--) 
				{ 
					x4 = 4*x+y4; 
					x3 = 3*x+y3; 
					p[  x3]=src[  x4]; 
					p[1+x3]=src[1+x4]; 
					p[2+x3]=src[2+x4]; 
				} 
			} 
		} 
	} 
	return; 
} 
 
BYTE* CCaiImage::GetBits(DWORD row) 
{ 
	if (pDib) 
	{ 
		if (row) 
		{ 
			if (row<(DWORD)head.biHeight) 
			{ 
				return ((BYTE*)pDib + *(DWORD*)pDib + GetPaletteSize() + (m_dwEffWidth * row)); 
			} 
			else 
			{ 
				return NULL; 
			} 
		} 
		else 
		{ 
			return ((BYTE*)pDib + *(DWORD*)pDib + GetPaletteSize()); 
		} 
	} 
	return NULL; 
} 
 
 
 
void CCaiImage::Flip() 
{ 
	if (!pDib)  
	{ 
		return; 
	} 
 
	BYTE *iSrc,*iDst,*iTmp; 
 
	iTmp = new BYTE[m_dwEffWidth]; 
	iSrc=GetBits() + (head.biHeight-1)*m_dwEffWidth; 
	iDst=GetBits(); 
    for(long y=0; y < head.biHeight/2; y++) 
	{ 
		memcpy(iTmp,iDst,m_dwEffWidth); 
		memcpy(iDst,iSrc,m_dwEffWidth); 
		memcpy(iSrc,iTmp,m_dwEffWidth); 
		iSrc-=m_dwEffWidth; 
		iDst+=m_dwEffWidth; 
	} 
	delete []iTmp; 
} 
 
BOOL CCaiImage::GetPixel(LONG nx, LONG ny, RGBQUAD &rgbQuad) 
{ 
	if (!m_bIsPrepare) 
	{ 
		return FALSE; 
	} 
	if ((nx<0)||(ny<0)||(nx>=head.biWidth)||(ny>=head.biHeight)) 
	{ 
		return FALSE; 
	} 
 
	ny = head.biHeight - ny; 
	 
	RGBQUAD rgb={0,0,0,0}; 
 
	if (head.biClrUsed) 
	{ 
		rgb = GetPaletteColor(GetPixelIndex(nx,ny)); 
	} 
	else 
	{ 
		BYTE* iDst  = GetBits(ny); 
		if(iDst) 
		{ 
			iDst += nx*3; 
			rgb.rgbBlue = *iDst++; 
			rgb.rgbGreen= *iDst++; 
			rgb.rgbRed  = *iDst; 
		} 
		else 
		{ 
			return FALSE; 
		} 
	} 
 
	rgbQuad = rgb; 
	return TRUE; 
} 
 
BYTE CCaiImage::GetPixelIndex(long x, long y) 
{ 
	if (!m_bIsPrepare) 
	{ 
		return 0; 
	} 
 
	if ((pDib==NULL)||(head.biClrUsed==0)) return 0; 
 
	if ((x<0)||(y<0)||(x>=head.biWidth)||(y>=head.biHeight)) 
	{ 
		return 0; 
	} 
	if (head.biBitCount==8) 
	{ 
		return GetBits()[y*m_dwEffWidth + x]; 
	} else 
	{ 
		BYTE pos; 
		BYTE iDst= GetBits()[y*m_dwEffWidth + (x*head.biBitCount >> 3)]; 
		if (head.biBitCount==4) 
		{ 
			pos = (BYTE)(4*(1-x%2)); 
			iDst &= (0x0F<> pos); 
		} 
		else if (head.biBitCount==1) 
		{ 
			pos = (BYTE)(7-x%8); 
			iDst &= (0x01<> pos); 
		} 
	} 
	return 0; 
} 
 
RGBQUAD CCaiImage::GetPaletteColor(BYTE idx) 
{ 
	RGBQUAD rgb = {0,0,0,0}; 
	if ((pDib)&&(head.biClrUsed)) 
	{ 
		BYTE* iDst = (BYTE*)(pDib) + sizeof(BITMAPINFOHEADER); 
		if (idx=head.biWidth)||(ny>=head.biHeight)) 
		return FALSE; 
	ny = head.biHeight - ny; 
	if (head.biClrUsed) 
		SetPixelIndex(nx,ny,GetNearestIndex(rgbQuad)); 
	else 
	{ 
		BYTE* iDst = GetBits(ny); 
		if (iDst) 
		{ 
			iDst += nx*3; 
			*iDst++ = rgbQuad.rgbBlue; 
			*iDst++ = rgbQuad.rgbGreen; 
			*iDst   = rgbQuad.rgbRed; 
		} 
	} 
	return TRUE; 
} 
 
BYTE CCaiImage::GetNearestIndex(RGBQUAD c) 
{ 
	if ((pDib==NULL)||(head.biClrUsed==0)) return 0; 
 
	BYTE* iDst = (BYTE*)(pDib) + sizeof(BITMAPINFOHEADER); 
	long distance=200000; 
	int i,j = 0; 
	long k,l; 
	int m = (int)(head.biClrImportant==0 ? head.biClrUsed : head.biClrImportant); 
	for(i=0,l=0;i=head.biWidth)||(y>=head.biHeight)) return ; 
 
	if (head.biBitCount==8) 
	{ 
		GetBits()[y*m_dwEffWidth + x]=i; 
		return; 
	}  
	else  
	{ 
		BYTE pos; 
		BYTE* iDst= GetBits() + y*m_dwEffWidth + (x*head.biBitCount >> 3); 
		if (head.biBitCount==4) 
		{ 
			pos = (BYTE)(4*(1-x%2)); 
			*iDst &= ~(0x0F<GetWidth(),pImage->GetHeight(),pImage->GetBitCount())) 
	{ 
		return FALSE; 
	} 
	memcpy(pDib,pImage->pDib,pImage->GetSize()); 
	return TRUE; 
} 
 
int CCaiImage::GetBitCount() 
{ 
	return head.biBitCount; 
} 
 
DWORD CCaiImage::GetSize() 
{ 
	return m_dwSize; 
} 
 
void CCaiImage::DrawImg(HDC hdc, CRect rect) 
{ 
	if (pDib) 
	{ 
		CRect rtPreview = rect; 
		if (m_bAutoFit) 
		{ 
			LONG nWidth; 
			LONG nHeight; 
 
			DOUBLE dbRatioPic = (DOUBLE)GetWidth() / (DOUBLE)GetHeight(); 
			DOUBLE dbRatioWin = (DOUBLE)rect.Width() / (DOUBLE)rect.Height(); 
			if (dbRatioWin>dbRatioPic) 
			{ 
				nHeight = rect.Height(); 
				nWidth = (long)(nHeight * dbRatioPic); 
			} 
			else 
			{ 
				nWidth = rect.Width(); 
				nHeight = (long)(nWidth / dbRatioPic); 
			} 
 
			rtPreview.left = (rect.Width()-nWidth)/2 ; 
			rtPreview.top = (rect.Height() - nHeight)/2; 
			rtPreview.right = rtPreview.left + nWidth; 
			rtPreview.bottom = rtPreview.top + nHeight;			 
		} 
		SetStretchBltMode(hdc,COLORONCOLOR);	 
		StretchDIBits(hdc, rtPreview.left , rtPreview.top,rtPreview.Width(), 
					rtPreview.Height(), 0, 0, head.biWidth, head.biHeight, 
					GetBits(),(BITMAPINFO*)pDib,DIB_RGB_COLORS,SRCCOPY);		 
	} 
} 
 
bool CCaiImage::Median(long Ksize) 
{ 
	if (!pDib) return false; 
 
	long k2 = Ksize/2; 
	long kmax= Ksize-k2; 
	long i,j,k; 
 
	RGBQUAD* kernel = (RGBQUAD*)malloc(Ksize*Ksize*sizeof(RGBQUAD)); 
 
	CCaiImage tmp; 
	if (!tmp.CopyImg(this)) 
	{ 
		return FALSE; 
	} 
 
	long xmin,xmax,ymin,ymax; 
	xmin = ymin = 0; 
	xmax = head.biWidth; ymax=head.biHeight; 
 
	for(long y=ymin; yrgbRed,c1->rgbGreen,c1->rgbBlue); 
	int g2 = (int)RGB2GRAY(c2->rgbRed,c2->rgbGreen,c2->rgbBlue); 
	 
	return (g1-g2); 
}