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