dib.cpp

来自「Windows 图形编程 书籍」· C++ 代码 · 共 1,118 行 · 第 1/2 页

CPP
1,118
字号
		pFileName = fi.m_TitleName;
	}

	HANDLE handle = CreateFile(pFileName, GENERIC_WRITE, FILE_SHARE_READ, 
		NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL);
	
	if ( handle == INVALID_HANDLE_VALUE )
		return FALSE;

	BITMAPFILEHEADER bmFH;

	int nHeadSize = sizeof(BITMAPINFOHEADER) + 
						sizeof(RGBQUAD) * GetDIBColorCount(pBMI->bmiHeader);

	bmFH.bfType      = 0x4D42;
	bmFH.bfSize      = nHeadSize + GetDIBPixelSize(pBMI->bmiHeader);
	bmFH.bfReserved1 = 0;
	bmFH.bfReserved2 = 0;
	bmFH.bfOffBits   = nHeadSize + sizeof(BITMAPFILEHEADER);

	DWORD dwRead = 0;
	WriteFile(handle, & bmFH, sizeof(bmFH), & dwRead, NULL);

	if ( pBits==NULL ) // packed DIB
		pBits = (BYTE *) pBMI + nHeadSize;
	
	WriteFile(handle, pBMI,  nHeadSize,						   & dwRead, NULL);
	WriteFile(handle, pBits, GetDIBPixelSize(pBMI->bmiHeader), & dwRead, NULL);

	CloseHandle(handle);

	return TRUE;
}

void SaveWindowToDIB(HWND hWnd, int nBitCount, int nCompression)
{
	HBITMAP hBmp = CaptureWindow(hWnd);

	if ( hBmp )
	{
		BITMAPINFO * pDIB = BitmapToDIB(NULL, hBmp, nBitCount, nCompression);

		if ( pDIB )
		{
			SaveDIBToFile(NULL, pDIB, NULL);
			delete [] (BYTE *) pDIB;
		}

		DeleteObject(hBmp);
	}
}

const BYTE Shift1bpp[] = { 7,     6,     5,     4,     3,     2,     1,     0     };
const BYTE Mask1bpp [] = { ~0x80, ~0x40, ~0x20, ~0x10, ~0x08, ~0x04, ~0x02, ~0x01 };

const BYTE Shift2bpp[] = { 6,     4,     2,     0     };
const BYTE Mask2bpp [] = { ~0xC0, ~0x30, ~0x0C, ~0x03 };

const BYTE Shift4bpp[] = { 4, 0 };
const BYTE Mask4bpp [] = { ~0xF0, ~0x0F };


DWORD KDIB::GetPixelIndex(int x, int y) const
{
	if ( (x<0) || (x>=m_nWidth) )
		return -1;

	if ( (y<0) || (y>=m_nHeight) )
		return -1;

	BYTE * pPixel = m_pOrigin + y * m_nDelta;

	switch ( m_nImageFormat )
	{
		case DIB_1BPP:
			return ( pPixel[x/8] >> Shift1bpp[x%8] ) & 0x01;

		case DIB_2BPP:
			return ( pPixel[x/4] >> Shift2bpp[x%4] ) & 0x03;

		case DIB_4BPP:
			return ( pPixel[x/2] >> Shift4bpp[x%4] ) & 0x0F;

		case DIB_8BPP:
			return pPixel[x];

		case DIB_16RGB555:
		case DIB_16RGB565:
			return ((WORD *)pPixel)[x];

		case DIB_24RGB888:
			pPixel += x * 3;
			return (pPixel[0]) | (pPixel[1] << 8) | (pPixel[2] << 16);
		
		case DIB_32RGB888:
		case DIB_32RGBA8888:
			return ((DWORD *)pPixel)[x];
	}

	return -1;
}

BOOL  KDIB::SetPixelIndex(int x, int y, DWORD index)
{
	if ( (x<0) || (x>=m_nWidth) )
		return FALSE;

	if ( (y<0) || (y>=m_nHeight) )
		return FALSE;

	BYTE * pPixel = m_pOrigin + y * m_nDelta;
	
	switch ( m_nImageFormat )
	{
		case DIB_1BPP:
			pPixel[x/8] = (BYTE) ( ( pPixel[x/8] & Mask1bpp[x%8] ) | ( (index & 1) << Shift1bpp[x%8] ) );
			break;

		case DIB_2BPP:
			pPixel[x/4] = (BYTE) ( ( pPixel[x/4] & Mask2bpp[x%4] ) | ( (index & 3) << Shift2bpp[x%4] ) );
			break;

		case DIB_4BPP:
			pPixel[x/2] = (BYTE) ( ( pPixel[x/2] & Mask4bpp[x%2] ) | ( (index & 15) << Shift4bpp[x%2] ) );
			break;

		case DIB_8BPP:
			pPixel[x] = (BYTE) index;
			break;

		case DIB_16RGB555:
		case DIB_16RGB565:
			((WORD *)pPixel)[x] = (WORD) index;
			break;

		case DIB_24RGB888:
			((RGBTRIPLE *)pPixel)[x] = * ((RGBTRIPLE *) & index);
			break;

		case DIB_32RGB888:
		case DIB_32RGBA8888:
			((DWORD *)pPixel)[x] = index;
			break;

		default:
			return FALSE;
	}

	return TRUE;
}


BOOL KDIB::PlgBlt(const POINT * pPoint, 
				   KDIB * pSrc, int nXSrc, int nYSrc, int nWidth, int nHeight)
{
	KReverseAffine map(pPoint);

	map.Setup(nXSrc, nYSrc, nWidth, nHeight);

	for (int dy=map.miny; dy<=map.maxy; dy++)
	for (int dx=map.minx; dx<=map.maxx; dx++)
	{
		float sx, sy;
		map.Map(dx, dy, sx, sy);

		if ( (sx>=nXSrc) && (sx<(nXSrc+nWidth))  )
		if ( (sy>=nYSrc) && (sy<(nYSrc+nHeight)) )
			SetPixelIndex(dx, dy, pSrc->GetPixelIndex( (int)sx, (int)sy));
	}

	return TRUE;
}


BOOL KDIB::PlgBltGetPixel(const POINT * pPoint, 
				   HDC hSrc, int nXSrc, int nYSrc, int nWidth, int nHeight, HDC hDst)
{
	KReverseAffine map(pPoint);

	map.Setup(nXSrc, nYSrc, nWidth, nHeight);

	for (int dy=map.miny; dy<=map.maxy; dy++)
	for (int dx=map.minx; dx<=map.maxx; dx++)
	{
		float sx, sy;
		map.Map(dx, dy, sx, sy);

		if ( (sx>=nXSrc) && (sx<(nXSrc+nWidth))  )
		if ( (sy>=nYSrc) && (sy<(nYSrc+nHeight)) )
			SetPixel(hDst, dx, dy, GetPixel(hSrc, (int)sx, (int)sy));
	}

	return TRUE;
}


BOOL KDIB::PlgBlt24(const POINT * pPoint, 
				   KDIB * pSrc, int nXSrc, int nYSrc, int nWidth, int nHeight)
{
	// factor to change FLOAT to fixed point
	const int FACTOR = 65536;

	// generate reverse transformation from destination to source
	KReverseAffine map(pPoint);

	map.Setup(nXSrc, nYSrc, nWidth, nHeight);

	// make sure within destination bitmap dimension
	if ( map.minx < 0 )         map.minx = 0;
	if ( map.maxx > m_nWidth )  map.maxx = m_nWidth;

	if ( map.miny < 0 )         map.miny = 0;
	if ( map.maxy > m_nHeight ) map.maxy = m_nHeight;

	// source rectangle in fixed point
	int sminx = nXSrc * FACTOR;
	int sminy = nYSrc * FACTOR;
	int smaxx = ( nXSrc + nWidth  ) * FACTOR;
	int smaxy = ( nYSrc + nHeight ) * FACTOR;

	// transformation matrix in fixed point
	int m11 = (int) (map.m_xm.eM11 * FACTOR);
	int m12 = (int) (map.m_xm.eM12 * FACTOR);
	int m21 = (int) (map.m_xm.eM21 * FACTOR);
	int m22 = (int) (map.m_xm.eM22 * FACTOR);
	int mdx = (int) (map.m_xm.eDx  * FACTOR);
	int mdy = (int) (map.m_xm.eDy  * FACTOR);

	BYTE * SOrigin = pSrc->m_pOrigin;
	int    SDelta  = pSrc->m_nDelta;

	// in destination bitmap, scan from first to last scanline
	for (int dy=map.miny; dy<map.maxy; dy++)
	{
/*
		// search for the first pixel on the scanline within source rectangle
		int sx = m11 * map.minx + m21 * dy + mdx;
		int sy = m12 * map.minx + m22 * dy + mdy;

		for (int dx=map.minx; dx<map.maxx; dx++, sx+=m11, sy+=m12)
			// if within source rectangle
			if ( (sx>=sminx) && (sx<smaxx) )
			if ( (sy>=sminy) && (sy<smaxy) )
				break;

		int minx = dx;

		// search for the last pixel on the scaneline within source rectangle
		sx = m11 * map.maxx + m21 * dy + mdx;
		sy = m12 * map.maxx + m22 * dy + mdy;

		for (dx=map.maxx; dx>=map.minx; dx--, sx-=m11, sy-=m12)
			// if within source rectangle
			if ( (sx>=sminx) && (sx<smaxx) )
			if ( (sy>=sminy) && (sy<smaxy) )
				break;

		int maxx = dx;
*/
		// precalculate destination pixel address for first pixel
		BYTE * pDPixel = m_pOrigin + dy * m_nDelta + map.minx * 3;

		// source pixel address for the first pixel
		int sx = m11 * map.minx + m21 * dy + mdx;
		int sy = m12 * map.minx + m22 * dy + mdy;

		// go through each pixel on the scan line
		for (int dx=map.minx; dx<map.maxx; dx++, pDPixel+=3, sx+=m11, sy+=m12)
			if ( (sx>=sminx) && (sx<smaxx) )
			if ( (sy>=sminy) && (sy<smaxy) )
			{
				// source pixel address
				BYTE * pSPixel = SOrigin + (sy/FACTOR) * SDelta;

				// copy three bytes
				* ((RGBTRIPLE *)pDPixel) = ((RGBTRIPLE *)pSPixel)[sx/FACTOR];
			}
	}

	return TRUE;
}

BOOL KDIB::Create(int width, int height, int bitcount)
{
	KBitmapInfo dibinfo;

	dibinfo.SetFormat(width, height, bitcount, BI_RGB);

	int nBitsSize = ( width * bitcount + 31 ) /32 * 4 * height;
	BYTE * pBits = new BYTE[nBitsSize];
	
	if ( pBits )
		return AttachDIB(dibinfo.CopyBMI(), pBits, 0);
	else
		return FALSE;
}

void Map(XFORM * xm, int x, int y, int & rx, int & ry)
{
	rx = (int) ( xm->eM11 * x + xm->eM21 * y + xm->eDx );
	ry = (int) ( xm->eM12 * x + xm->eM22 * y + xm->eDy );
}

BOOL Invert(XFORM & xm)
{
	FLOAT det = xm.eM11 * xm.eM22 - xm.eM21 * xm.eM12;

	if ( det==0 )
		return FALSE;

	XFORM old = xm;

	xm.eM11 =   old.eM22 / det;
	xm.eM12 = - old.eM12 / det;
	xm.eM21 = - old.eM21 / det;
	xm.eM22 =   old.eM11 / det;
	
	xm.eDx  = - ( xm.eM11 * old.eDx + xm.eM21 * old.eDy );
	xm.eDy  = - ( xm.eM12 * old.eDx + xm.eM22 * old.eDy );

	return TRUE;
}

DWORD dibtick;

HBITMAP KDIB::TransformBitmap(XFORM * xm, COLORREF crBack, int method)
{
	int x0, y0, x1, y1, x2, y2, x3, y3;

	Map(xm, 0,        0,         x0, y0);  // 0    1
	Map(xm, m_nWidth, 0,         x1, y1);  //
	Map(xm, 0,        m_nHeight, x2, y2);  // 2    3
	Map(xm, m_nWidth, m_nHeight, x3, y3);

	int xmin, xmax;
	int ymin, ymax;

	minmax(x0, x1, x2, x3, xmin, xmax);
	minmax(y0, y1, y2, y3, ymin, ymax);

	int destwidth  = xmax - xmin;
	int destheight = ymax - ymin;

	KBitmapInfo dest;
	dest.SetFormat(destwidth, destheight, m_pBMI->bmiHeader.biBitCount, m_pBMI->bmiHeader.biCompression);

	if ( m_nClrUsed )
		memcpy(dest.m_dibinfo.bmiColors, m_pRGBQUAD, sizeof(RGBQUAD) * m_nClrUsed);

	// create destination DIB section
	BYTE * pBits;
	HBITMAP hBitmap = CreateDIBSection(NULL, dest.GetBMI(), DIB_RGB_COLORS, (void **) & pBits, NULL, NULL);
	if ( hBitmap==NULL )
	{
		assert(false);
		return NULL;
	}

	// For testing GDI GetPixel speed, we need a HDC for the source bitmap
	HBITMAP hSrcBmp = NULL;
	HDC     hSrcDC  = NULL;
	HGDIOBJ hSrcOld = NULL;

	if ( method==method_gdi )
	{
		hSrcBmp = CreateDIBSection(NULL, m_pBMI, DIB_RGB_COLORS, (void **) & pBits, NULL, NULL);
		assert(hSrcBmp);

		hSrcDC  = CreateCompatibleDC(NULL);
		hSrcOld = SelectObject(hSrcDC, hSrcBmp);

		// copy pixels from DIB to source DIB section
		DrawDIB(hSrcDC, 0, 0, m_nWidth, m_nHeight, 0, 0, m_nWidth, m_nHeight, SRCCOPY);
	}

	// clear DIB section to background color
	HDC     hDstDC  = CreateCompatibleDC(NULL);
	HGDIOBJ hDstOld = SelectObject(hDstDC, hBitmap);

	HBRUSH hBrush = CreateSolidBrush(crBack);
	RECT rect = { 0, 0,  destwidth, destheight };
	FillRect(hDstDC, & rect, hBrush);
	DeleteObject(hBrush);

	KDIB destDIB;
	destDIB.AttachDIB(dest.GetBMI(), pBits, 0);

	POINT P[3] = { { x0-xmin, y0-ymin }, { x1-xmin, y1-ymin }, { x2-xmin, y2-ymin } };

	dibtick = GetTickCount();
	
	if ( (m_nBitCount<=8) && (method==method_24bpp) )
		method = method_direct;

	switch ( method )
	{
		case method_gdi:
			destDIB.PlgBltGetPixel(P, hSrcDC, 0, 0, m_nWidth, m_nHeight, hDstDC);
			break;   

		case method_direct:	
			destDIB.PlgBlt(P, this, 0, 0, m_nWidth, m_nHeight);
			break;   

		case method_24bpp:
			destDIB.PlgBlt24(P, this, 0, 0, m_nWidth, m_nHeight);
			break;
	}

	dibtick = GetTickCount() - dibtick;

	SelectObject(hDstDC, hDstOld);
	DeleteObject(hDstDC);

	if ( method==method_gdi )
	{
		SelectObject(hSrcDC, hSrcOld);

		DeleteObject(hSrcDC);
		DeleteObject(hSrcBmp);
	}

	return hBitmap;
}


// Calculate DIB pixel offset
inline int GetOffset(BITMAPINFO * pBMI, int x, int y)
{
	if ( pBMI->bmiHeader.biHeight > 0 )	// for bottom up, reflect y
		y = pBMI->bmiHeader.biHeight - 1 - y;
	
	return ( pBMI->bmiHeader.biWidth * pBMI->bmiHeader.biBitCount + 31 ) / 32 * 4 * y + 
		   ( pBMI->bmiHeader.biBitCount / 8 ) * x;
}


// Alpha Blending between two 32-bpp DIBs
BOOL AlphaBlend3232(BITMAPINFO * pBMIDst, BYTE * pBitsDst, int dx, int dy, int w, int h,
				    BITMAPINFO * pBMISrc, BYTE * pBitsSrc, int sx, int sy,
				    BLENDFUNCTION blend)
{
	int alpha = blend.SourceConstantAlpha;	// constant alpha
	int beta  = 255 - alpha;				// constant beta
	int format;

	if ( blend.AlphaFormat==0 )
		format = 0;
	else if ( alpha==255 )
		format = 1;
	else 
		format = 2;

	for (int j=0; j<h; j++)
	{
		BYTE * D = pBitsDst + GetOffset(pBMIDst, dx, j + dy);
		BYTE * S = pBitsSrc + GetOffset(pBMISrc, sx, j + sy);
		
		int i;

		switch ( format )
		{
			case 0: // constant alpha only
				for (i=0; i<w; i++)
				{
					D[0] = ( S[0] * alpha + beta * D[0] + 127 ) / 255;
					D[1] = ( S[1] * alpha + beta * D[1] + 127 ) / 255;
					D[2] = ( S[2] * alpha + beta * D[2] + 127 ) / 255;
					D[3] = ( S[3] * alpha + beta * D[3] + 127 ) / 255;
					D += 4; S += 4;
				}
				break;

			case 1: // alpha channel only
				for (i=0; i<w; i++)
				{
					beta  = 255 - S[3];
					D[0] = S[0] + ( beta * D[0] + 127 ) / 255;
					D[1] = S[1] + ( beta * D[1] + 127 ) / 255;
					D[2] = S[2] + ( beta * D[2] + 127 ) / 255;
					D[3] = S[3] + ( beta * D[3] + 127 ) / 255;
					D += 4; S += 4;
				}
				break;
			
			case 2: // both constant alpha and alpha channel
				for (i=0; i<w; i++)
				{
					beta  = 255 - ( S[3] * alpha + 127 ) / 255;
					
					D[0] = ( S[0] * alpha + beta * D[0] + 127 ) / 255;
					D[1] = ( S[1] * alpha + beta * D[1] + 127 ) / 255;
					D[2] = ( S[2] * alpha + beta * D[2] + 127 ) / 255;
					D[3] = ( S[3] * alpha + beta * D[3] + 127 ) / 255;
					D += 4; S += 4;
				}
		}
	}

	return FALSE;
}


// AlphaBlending a 32-bpp DIB to hdc
BOOL AlphaBlend(HDC hdc, int x0, int y0, const BITMAPINFO *pbmpInfo, const void * pAlphaImageData)
{
	if ( pbmpInfo->bmiHeader.biBitCount!=32 )
		return FALSE;

	if ( pbmpInfo->bmiHeader.biCompression!=BI_RGB )
		return FALSE;

	int width  = pbmpInfo->bmiHeader.biWidth;
	int height = pbmpInfo->bmiHeader.biHeight;

	BITMAPINFOHEADER bmih = { sizeof(BITMAPINFOHEADER), width, height, 1, 24 };

	VOID * pBits;

	HBITMAP hBmp = CreateDIBSection(NULL, (BITMAPINFO *) & bmih, DIB_RGB_COLORS, & pBits, NULL, NULL);

	if ( hBmp==NULL )
		return FALSE;

	HDC hMemDC = CreateCompatibleDC(hdc);
	HGDIOBJ hOld = SelectObject(hMemDC, hBmp);

	BitBlt(hMemDC, 0, 0, width, height, hdc, x0, y0, SRCCOPY); // copy destination, not working on printer

	const BYTE * psrc = (const BYTE *) pAlphaImageData;
		  BYTE * pdst = (BYTE *) pBits;

	for (int y = 0; y < abs(height); y++)
	{
		for (int x = width; x>0; x--)
		{
			BYTE alpha  = psrc[3]; //Get alpha channel byte.
			BYTE salpha = 255 - alpha;

			pdst[0] = (BYTE)(( psrc[0] * alpha + pdst[0] * salpha) / 255);
			pdst[1] = (BYTE)(( psrc[1] * alpha + pdst[1] * salpha) / 255);
			pdst[2] = (BYTE)(( psrc[2] * alpha + pdst[2] * salpha) / 255);

			pdst += 3;
			psrc += 4;
		}

		pdst += width % 3;
	}

	BOOL rslt = BitBlt(hdc, x0, y0, width, height, hMemDC, 0, 0, SRCCOPY);

	SelectObject(hMemDC, hOld);
	DeleteObject(hBmp);
	DeleteObject(hMemDC);

	return rslt;
}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?