#include "stdafx.h"
#include "dib.h"
#include "mythreadfunction.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

IMPLEMENT_SERIAL(CDIBitmap,CObject,0)

CDIBitmap::CDIBitmap()
{
	m_pBMI = NULL;
	m_pBits = NULL;
	m_p2Bits = NULL;
	isTwoBuffer = false;
	bmBitsSize = 0;

	copyStatus = 0;
	hWnd = NULL;
}

CDIBitmap::~CDIBitmap()
{
	if(m_pBMI != NULL)
	{
		free(m_pBMI);
		m_pBMI = NULL;
	}
	if(m_pBits != NULL)
	{
		free(m_pBits);
		m_pBits = NULL;
	}
	if(m_p2Bits != NULL)
	{
		free(m_p2Bits);
		m_p2Bits = NULL;
	}
}

void CDIBitmap::SetTwoBuffer(bool isTwoBuffer)
{
	CDIBitmap::isTwoBuffer = isTwoBuffer;
}

void CDIBitmap::Buf2ToBuf1()
{
	if(isTwoBuffer)
		memcpy(m_pBits,m_p2Bits,bmBitsSize);
}
void CDIBitmap::Buf1ToBuf2()
{
	if(m_p2Bits != NULL)
		free(m_p2Bits);
	m_p2Bits = (BYTE*)malloc(bmBitsSize);
	memcpy(m_p2Bits,m_pBits,bmBitsSize);
}

int CDIBitmap::GetBMWidth()
{
	return width;
}

int CDIBitmap::GetBMHeight()
{
	return height;
}

BOOL CDIBitmap::LoadDIB(CString fileName)
{
	CFile file(fileName,CFile::modeRead);

	if(m_pBMI != NULL)
		free(m_pBMI);
	if(m_pBits != NULL)
		free(m_pBits);

	//第一步
	BITMAPFILEHEADER bmfHeader;
	file.Read(&bmfHeader,sizeof(bmfHeader));
	ASSERT(bmfHeader.bfType == 0x4D42);  //BM
	//第二步
	BITMAPINFOHEADER bmiHeader;
	file.Read(&bmiHeader,sizeof(bmiHeader));
	int bmiSize = sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD);
	m_pBMI = (BITMAPINFO*)malloc(bmiSize);
	memcpy(m_pBMI,&bmiHeader,sizeof(BITMAPINFOHEADER));
	int colorTableSize =  GetNumClrEntries() * sizeof(RGBQUAD);
	//移动指针m_pBMI,向后移动sizeof(BITMAPINFOHEADER)位
	file.Read( (BYTE*)m_pBMI + sizeof(BITMAPINFOHEADER),colorTableSize );
	//第三步
	bmBitsSize = bmfHeader.bfSize - bmfHeader.bfOffBits;
	m_pBits = (BYTE*)malloc(bmBitsSize);
	file.Seek(bmfHeader.bfOffBits,CFile::begin);
	file.ReadHuge(m_pBits,bmBitsSize);

	//初始化变量
	//bmBitsSize = bmfHeader.bfSize - bmfHeader.bfOffBits;
	width = m_pBMI->bmiHeader.biWidth;
	height = m_pBMI->bmiHeader.biHeight;
	remainBytes = 4 - ((3*width) % 4);
	if(remainBytes == 4)
		remainBytes = 0;
	widthBytes = 3*width + remainBytes;
	if(isTwoBuffer)
	{
		if(m_p2Bits != NULL)
			free(m_p2Bits);
		m_p2Bits = (BYTE*)malloc(bmBitsSize);
		memcpy(m_p2Bits,m_pBits,bmBitsSize);
	}
	file.Close();
	return true;
}

void CDIBitmap::Serialize(CArchive &ar)
{
	//暂无//防止意外写入
	ASSERT(true);
}

void CDIBitmap::DrawBitmap(CDC *pDC, int x, int y)
{
	if(m_pBMI == NULL)
		return;
	::SetDIBitsToDevice(pDC->GetSafeHdc(),
		x,y,
		width,height,0,0,
		0,height,
		m_pBits,m_pBMI,
		DIB_RGB_COLORS);
}

void CDIBitmap::DrawBitmap(CDC *pDC, int destX, int destY,int srcX,int srcY,int srcCx,int srcCy)
{
	if(m_pBMI == NULL)
		return;
	//destX=>left destY=>top
	//srcX=>left srcY=>top srcCx=>width srcCy=>height
	int w,h,yy;
	if((srcX + srcCx) >= width)
		w = width - srcX;
	else
		w = srcCx;
	if((srcY + srcCy) >= height)
	{
		h = height - srcY;
		yy = 0;
	}
	else
	{
		h = srcCy;
		yy = height - (srcY + srcCy);
	}
	if((w <= 0) || (h <= 0))
		return;
	::SetDIBitsToDevice(pDC->GetSafeHdc(),
		destX,destY,
		w,h,srcX,yy,
		0,height,
		m_pBits,m_pBMI,
		DIB_RGB_COLORS);
}

void CDIBitmap::StretchBitmap(CDC *pDC, int x, int y, int cx, int cy)
{
	::StretchDIBits(pDC->GetSafeHdc(),
		x,y,cx,cy,
		0,0,width,height,
		m_pBits,m_pBMI,DIB_RGB_COLORS,
		SRCCOPY);
}

int CDIBitmap::GetNumClrEntries()
{
	if(m_pBMI->bmiHeader.biClrUsed != 0)
		return m_pBMI->bmiHeader.biClrUsed;
	else
		switch (m_pBMI->bmiHeader.biBitCount)
		{
			case 1:
				return 2;
			case 4:
				return 16;
			case 8:
				return 256;
			default:
				return 0;
		}
}


RGBQUAD* CDIBitmap::GetBMColorTabPtr()
{
	//位图颜色表 位于 位图信息头 后面
	return (LPRGBQUAD)( ((BYTE*)(m_pBMI)) + sizeof(BITMAPINFOHEADER) );
}

void CDIBitmap::BltBmpToBuf(int x, int y,CDIBitmap *pSrcDIB,COLORREF crTrsp)
{
	int srcWidth = pSrcDIB->width;
	int srcHeight = pSrcDIB->height;
	BYTE *pSrc = pSrcDIB->GetBMBitsPtr();
	if(pSrc == NULL)
		return;
	BYTE *pDest = m_pBits;
//top
	if(y < 0) 
	{
		srcHeight += y;
		if(srcHeight <= 0)
			srcHeight = 0;
		y = 0;
	}
//right
	int srcRXOff = 0;
	if(x > (width - srcWidth))
	{
		srcRXOff = x - (width - srcWidth);
		srcWidth -= srcRXOff;
	}
//left
	int srcLXOff = 0;
	if(x < 0)
	{
		srcLXOff = -x;
		x = 0;
	}
//bottom
	int srcYOff = 0;
	if(y > height - srcHeight)
	{
		srcYOff = y - (height - srcHeight);
		pDest += 3*x;
	}
	else
		pDest += 3*x  + widthBytes * (height - y - srcHeight);
	pSrc += 3*srcLXOff + pSrcDIB->widthBytes * srcYOff;

	int i,j;
	int srcRemainBytes = pSrcDIB->remainBytes + 3*srcLXOff + 3*srcRXOff;
	int destRemainBytes = widthBytes - (3*(srcWidth - srcLXOff));

	if(crTrsp == -1)
	{
		for(i=srcYOff;i<srcHeight;i++)
		{
			for(j=srcLXOff;j<srcWidth;j++)
			{
				*(pDest++)=*(pSrc++);
				*(pDest++)=*(pSrc++);
				*(pDest++)=*(pSrc++);
			}
			pSrc += srcRemainBytes;
			pDest += destRemainBytes;
		}
	}
	else
		for(i=srcYOff;i<srcHeight;i++)
		{
			for(j=srcLXOff;j<srcWidth;j++)
			{
				if(RGB(*pSrc,*(pSrc+1),*(pSrc+2)) != crTrsp)
//颜色容差				if((*pSrc<254) && (*(pSrc+1)<254)&& (*(pSrc+2)<254))
				{
					*(pDest++)=*(pSrc++);
					*(pDest++)=*(pSrc++);
					*(pDest++)=*(pSrc++);
				}
				else
				{
					pDest+=3;
					pSrc+=3;
				}
			}
			pSrc += srcRemainBytes;
			pDest += destRemainBytes;
		}
}

void CDIBitmap::CopyScreen(CDC *pDC,int x0,int y0,CString fileName)
{
	CDIBitmap::pDC = pDC;
	CDIBitmap::x0 = x0;
	CDIBitmap::y0 = y0;

	LoadDIB(fileName); //读取bmp文件,截取的屏幕大小以此bmp文件决定

	if(m_pBits != NULL)
		free(m_pBits);
	if(m_p2Bits != NULL)
		free(m_p2Bits);

	copyStatus = 0; //正常复制屏幕，非0时中断屏幕复制
	pMyThread = AfxBeginThread(MyThreadFunction,this,THREAD_PRIORITY_NORMAL);
	//返回1表示屏幕复制完成，返回2表示复制过程中断
}

bool CDIBitmap::FastCopyScreen(CDC *pDC,int x,int y,int cx,int cy)
{
	CBitmap bm;
	int Width=cx;
	int Height=cy;
	bm.CreateCompatibleBitmap(pDC,Width,Height);
	//与pDC兼容的CBtimap

	CDC tdc;
	tdc.CreateCompatibleDC(pDC);
	CBitmap *pOld=tdc.SelectObject(&bm);
	tdc.BitBlt(0,0,Width,Height,pDC,x,y,SRCCOPY);
	//将屏幕区域的图像传送到bm中
	tdc.SelectObject(pOld);

	BITMAP btm;
	bm.GetBitmap(&btm);
	//得到bm的信息
	DWORD size=btm.bmWidthBytes*btm.bmHeight;
	LPSTR lpData=(LPSTR)malloc(sizeof(BYTE)*size);
/////////////////////////////////////////////
	BITMAPINFOHEADER bih;
	bih.biBitCount=btm.bmBitsPixel;
	bih.biClrImportant=0;
	bih.biClrUsed=0;
	bih.biCompression=0;
	bih.biHeight=btm.bmHeight;
	bih.biPlanes=1;
	bih.biSize=sizeof(BITMAPINFOHEADER);
	bih.biSizeImage=size;
	bih.biWidth=btm.bmWidth;
	bih.biXPelsPerMeter=0;
	bih.biYPelsPerMeter=0;
///////////////////////////////////
//	lpData = (LPSTR)btm.bmBits;//0x00000000
	GetDIBits(*pDC,bm,0,bih.biHeight,lpData,(BITMAPINFO*)&bih,DIB_RGB_COLORS);
	//将bm中的bits复制到lpData
	//	bm.GetBitmapBits(size,lpData);
	//此函数在处理5-5-5模式的16位色下会出现颜色混乱 ???
///////////////////////////////////

	//初始化变量
	if(m_pBits != NULL)//能不能只分配一次内存？
	{
		free(m_pBits);
		m_pBits = NULL;
	}

	width = btm.bmWidth;
	height = btm.bmHeight;
	remainBytes = 4 - ((3*width) % 4);
	if(remainBytes == 4)
		remainBytes = 0;
	widthBytes = 3*width + remainBytes;
	
	m_pBMI = new BITMAPINFO;
	if(bih.biBitCount == 32)
	{
		bih.biBitCount = 24;
		bih.biSizeImage=widthBytes*height;
		bmBitsSize = bih.biSizeImage;
		BYTE *pBits = (BYTE *)malloc(sizeof(BYTE)*bmBitsSize);
		//能不能只分配一次内存？
		m_pBits = pBits;
		BYTE *tpData = (BYTE *)lpData;
		for(int i=0;i<height;i++)
		{
			for(int j=0;j<width;j++)
			{
				*(pBits++) = *(tpData++);
				*(pBits++) = *(tpData++);
				*(pBits++) = *(tpData++);
				tpData++;
			}
			pBits += remainBytes;
		}
		free(lpData);
	}
	else if(bih.biBitCount == 24)
	{
		bmBitsSize = size;
		m_pBits = (BYTE *)lpData;
	}
	else
	{
		::MessageBox(hWnd,"显示器分辨率应为\n800*600*24或\n800*600*32以上","",MB_OK);
		return false;
	}

	m_pBMI->bmiHeader = bih;

	if(isTwoBuffer)
	{
		if(m_p2Bits == NULL)
			m_p2Bits = (BYTE*)malloc(bmBitsSize);
		else
		{
		}
		memcpy(m_p2Bits,m_pBits,bmBitsSize);
	}
	return true;
}

void CDIBitmap::ChangeColor(COLORREF s, COLORREF d)
{
	BYTE *pBits = m_pBits;
	int sR,sG,sB;
	int dR,dG,dB;
	sR = GetRValue(s);
	sG = GetGValue(s);
	sB = GetBValue(s);
	dR = GetRValue(d);
	dG = GetGValue(d);
	dB = GetBValue(d);
	for(int i=0;i<height;i++)
	{
		for(int j=0;j<width;j++)
		{
//			if(RGB(*(pBits++),*(pBits++),*(pBits++)) == s) //这样不行，*(pBits++)中的值会被改变，而且RGB的顺序也不对。
//			#define RGB(r,g,b) ((COLORREF)(((BYTE)(r)|((WORD)((BYTE)(g))<<8))|(((DWORD)(BYTE)(b))<<16)))
			if(*(pBits++) == sB)//注意RGB的顺序，这样效率很高。
			{
				if(*(pBits++) == sG)
				{
					if(*(pBits++) == sR)
					{
						*(--pBits) = dR;
						*(--pBits) = dG;
						*(--pBits) = dB;
						pBits += 3;
					}
				}
				else
					pBits++;
			}
			else
				pBits +=2;
		}
		pBits += remainBytes;
	}
	if(isTwoBuffer)
	{
		memcpy(m_p2Bits,m_pBits,bmBitsSize);
	}
}

CDIBitmap* CDIBitmap::CopyDIB(int x, int y, int w, int h)
{
	CDIBitmap *bmp = new CDIBitmap;

	//初始化变量
	bmp->width = w;
	bmp->height = h;
	bmp->remainBytes = 4 - ((3*w) % 4);
	if(bmp->remainBytes == 4)
		bmp->remainBytes = 0;
	bmp->widthBytes = 3*w + bmp->remainBytes;
	bmp->bmBitsSize = bmp->widthBytes * bmp->height;

	BITMAPINFOHEADER *pBIH = new BITMAPINFOHEADER;
	pBIH->biBitCount=m_pBMI->bmiHeader.biBitCount;
	pBIH->biClrImportant=0;
	pBIH->biClrUsed=0;
	pBIH->biCompression=0;
	pBIH->biHeight=h;
	pBIH->biWidth=w;
	pBIH->biSizeImage=bmp->bmBitsSize;
	pBIH->biSize=sizeof(BITMAPINFOHEADER);
	pBIH->biPlanes=1;
	pBIH->biXPelsPerMeter=0;
	pBIH->biYPelsPerMeter=0;

	bmp->m_pBMI = new BITMAPINFO;
	bmp->m_pBMI->bmiHeader = *pBIH;

	bmp->m_pBits = (BYTE *)malloc(sizeof(BYTE)*bmp->bmBitsSize);
//////////////////////////////////////////////////////
	int srcWidth = w;
	int srcHeight = h;
	//注意：使用的是BltBmpToBuf()的代码
	BYTE *pSrc = bmp->m_pBits;//
	BYTE *pDest = m_pBits;//
//top
	if(y < 0) 
	{
		srcHeight += y;
		if(srcHeight <= 0)
			srcHeight = 0;
		y = 0;
	}
//right
	int srcRXOff = 0;
	if(x > (width - srcWidth))
	{
		srcRXOff = x - (width - srcWidth);
		srcWidth -= srcRXOff;
	}
//left
	int srcLXOff = 0;
	if(x < 0)
	{
		srcLXOff = -x;
		x = 0;
	}
//bottom
	int srcYOff = 0;
	if(y > height - srcHeight)
	{
		srcYOff = y - (height - srcHeight);
		pDest += 3*x;
	}
	else
		pDest += 3*x  + widthBytes * (height - y - srcHeight);
	pSrc += 3*srcLXOff + bmp->widthBytes * srcYOff;

	int i,j;
	int srcRemainBytes = bmp->remainBytes + 3*srcLXOff + 3*srcRXOff;
	int destRemainBytes = widthBytes - (3*(srcWidth - srcLXOff));

	for(i=srcYOff;i<srcHeight;i++)
	{
		for(j=srcLXOff;j<srcWidth;j++)
		{
			*(pSrc++)=*(pDest++);//这里做一下改动
			*(pSrc++)=*(pDest++);
			*(pSrc++)=*(pDest++);
		}
		pSrc += srcRemainBytes;
		pDest += destRemainBytes;
	}
/////////////////////////////////////////////////
	delete pBIH;
	return bmp;
}

void CDIBitmap::ChangeColor(COLORREF s, COLORREF d, int range)
{
	BYTE *pBits = m_pBits;
	int s1R,s1G,s1B;
	int s2R,s2G,s2B;
	int dR,dG,dB;
	s1R = GetRValue(s)-range;
	s1G = GetGValue(s)-range;
	s1B = GetBValue(s)-range;
	s2R = GetRValue(s)+range;
	s2G = GetGValue(s)+range;
	s2B = GetBValue(s)+range;
	dR = GetRValue(d);
	dG = GetGValue(d);
	dB = GetBValue(d);
	for(int i=0;i<height;i++)
	{
		for(int j=0;j<width;j++)
		{
//			if(RGB(*(pBits++),*(pBits++),*(pBits++)) == s) //这样不行，*(pBits++)中的值会被改变，而且RGB的顺序也不对。
//			#define RGB(r,g,b) ((COLORREF)(((BYTE)(r)|((WORD)((BYTE)(g))<<8))|(((DWORD)(BYTE)(b))<<16)))
			if((*(pBits) >= s1B) && (*(pBits++) <= s2B))//注意RGB的顺序，这样效率很高。
			{
				if((*(pBits) >= s1G) && (*(pBits++) <= s2G))
				{
					if((*(pBits) >= s1R) && (*(pBits++) <= s2R))
					{
						*(--pBits) = dR;
						*(--pBits) = dG;
						*(--pBits) = dB;
						pBits += 3;
					}
				}
				else
					pBits++;
			}
			else
				pBits +=2;
		}
		pBits += remainBytes;
	}
	if(isTwoBuffer)
	{
		memcpy(m_p2Bits,m_pBits,bmBitsSize);
	}
}
