您的位置:首页 > 编程语言

图像编程的若干常用操作(旋转,透明等)

2007-03-22 12:21 465 查看

void DrawTransparentBitmap(HDC hdc, HBITMAP hBitmap, short xStart,


short yStart, COLORREF cTransparentColor)




...{


BITMAP bm;


COLORREF cColor;


HBITMAP bmAndBack, bmAndObject, bmAndMem, bmSave;


HBITMAP bmBackOld, bmObjectOld, bmMemOld, bmSaveOld;


HDC hdcMem, hdcBack, hdcObject, hdcTemp, hdcSave;


POINT ptSize;


hdcTemp = CreateCompatibleDC(hdc);


SelectObject(hdcTemp, hBitmap); // Select the bitmap


GetObject(hBitmap, sizeof(BITMAP), (LPSTR)&bm);


ptSize.x = bm.bmWidth; // Get width of bitmap


ptSize.y = bm.bmHeight; // Get height of bitmap


DPtoLP(hdcTemp, &ptSize, 1); // Convert from device


// to logical points


// Create some DCs to hold temporary data.


hdcBack = CreateCompatibleDC(hdc);


hdcObject = CreateCompatibleDC(hdc);


hdcMem = CreateCompatibleDC(hdc);


hdcSave = CreateCompatibleDC(hdc);


// Create a bitmap for each DC. DCs are required for a number of


// GDI functions.


// Monochrome DC


bmAndBack = CreateBitmap(ptSize.x, ptSize.y, 1, 1, NULL);


// Monochrome DC


bmAndObject = CreateBitmap(ptSize.x, ptSize.y, 1, 1, NULL);


bmAndMem = CreateCompatibleBitmap(hdc, ptSize.x, ptSize.y);


bmSave = CreateCompatibleBitmap(hdc, ptSize.x, ptSize.y);


// Each DC must select a bitmap object to store pixel data.


bmBackOld = (HBITMAP)::SelectObject(hdcBack, bmAndBack);


bmObjectOld = (HBITMAP)::SelectObject(hdcObject, bmAndObject);


bmMemOld = (HBITMAP)::SelectObject(hdcMem, bmAndMem);


bmSaveOld = (HBITMAP)::SelectObject(hdcSave, bmSave);


// Set proper mapping mode.


SetMapMode(hdcTemp, GetMapMode(hdc));


// Save the bitmap sent here, because it will be overwritten.


BitBlt(hdcSave, 0, 0, ptSize.x, ptSize.y, hdcTemp, 0, 0, SRCCOPY);


// Set the background color of the source DC to the color.


// contained in the parts of the bitmap that should be transparent


cColor = SetBkColor(hdcTemp, cTransparentColor);


// Create the object mask for the bitmap by performing a BitBlt


// from the source bitmap to a monochrome bitmap.


BitBlt(hdcObject, 0, 0, ptSize.x, ptSize.y, hdcTemp, 0, 0,


SRCCOPY);


// Set the background color of the source DC back to the original


// color.


SetBkColor(hdcTemp, cColor);


// Create the inverse of the object mask.


BitBlt(hdcBack, 0, 0, ptSize.x, ptSize.y, hdcObject, 0, 0,


NOTSRCCOPY);


// Copy the background of the main DC to the destination.


BitBlt(hdcMem, 0, 0, ptSize.x, ptSize.y, hdc, xStart, yStart,


SRCCOPY);


// Mask out the places where the bitmap will be placed.


BitBlt(hdcMem, 0, 0, ptSize.x, ptSize.y, hdcObject, 0, 0, SRCAND);


// Mask out the transparent colored pixels on the bitmap.


BitBlt(hdcTemp, 0, 0, ptSize.x, ptSize.y, hdcBack, 0, 0, SRCAND);


// XOR the bitmap with the background on the destination DC.


BitBlt(hdcMem, 0, 0, ptSize.x, ptSize.y, hdcTemp, 0, 0, SRCPAINT);


// Copy the destination to the screen.


BitBlt(hdc, xStart, yStart, ptSize.x, ptSize.y, hdcMem, 0, 0,


SRCCOPY);


// Place the original bitmap back into the bitmap sent here.


BitBlt(hdcTemp, 0, 0, ptSize.x, ptSize.y, hdcSave, 0, 0, SRCCOPY);


// Delete the memory bitmaps.


DeleteObject(SelectObject(hdcBack, bmBackOld));


DeleteObject(SelectObject(hdcObject, bmObjectOld));


DeleteObject(SelectObject(hdcMem, bmMemOld));


DeleteObject(SelectObject(hdcSave, bmSaveOld));


// Delete the memory DCs.


DeleteDC(hdcMem);


DeleteDC(hdcBack);


DeleteDC(hdcObject);


DeleteDC(hdcSave);


DeleteDC(hdcTemp);


}



1.位图的旋转
如果你的应用程序仅工作在Windows NT下,那么你可以通过API函数旋转你的位图。
你或者使用world transformation和BitBlt()或者使用PlgBlt()旋转位图。一个
使用第一种方法的函数显示在下面。

如果你的目标是多平台的,那么你的任务变得非常困难。你只能通过旋转源位图中
每个象素或者直接操作DIB字节得到旋转位图。第一种方法通过每个点的处理是非
常慢的,第二种方法是很复杂的,但它有足够快的速度。注:下面的所有函数旋转
后产生新的位图,如果你需要直接绘制位图,请自已修改函数。 其中函数1仅工作
在NT环境下,它是最简单也是最快的,可惜它不支持Windows95。

所有的函数所接受的角度单位是弧度,如果是角度单位是度请用下面的公式转换。

radian = (2*pi *degree)/360

旋转步骤:

创建一对与设备兼容的显示设备。一个用于源位图,一个用于旋转后的目标位图。

预计算正弦和余弦函数值,这样可以避免重复计算。

用下面的公式计算旋转图像后的矩形
newx = x.cos(angle) + y.sin(angle)
newy = y.cos(angle) - x.sin(angle)

旋转后的位图将不能占用整个新位图,我们将用背景色填充它。

点阵转换公式
newx = x * eM11 + y * eM21 + eDx
newy = x * eM12 + y * eM22 + eDy
其中eM11和eM22是角度的余弦值,eM21是角度的正弦,eM12是eM21的负值。 eDx & eDy
目的是旋转后的位图在新的位图不被剪切。

函数一:适用于NT


// GetRotatedBitmapNT - Create a new bitmap with rotated image


// Returns - Returns new bitmap with rotated image


// hBitmap - Bitmap to rotate


// radians - Angle of rotation in radians


// clrBack - Color of pixels in the resulting bitmap that do


// not get covered by source pixels


HBITMAP GetRotatedBitmapNT( HBITMAP hBitmap, float radians, COLORREF clrBack )




...{


// Create a memory DC compatible with the display


CDC sourceDC, destDC;


sourceDC.CreateCompatibleDC( NULL );


destDC.CreateCompatibleDC( NULL );


// Get logical coordinates


BITMAP bm;


GetObject( hBitmap, sizeof( bm ), &bm );


float cosine = (float)cos(radians);


float sine = (float)sin(radians);


// Compute dimensions of the resulting bitmap


// First get the coordinates of the 3 corners other than origin


int x1 = (int)(bm.bmHeight * sine);


int y1 = (int)(bm.bmHeight * cosine);


int x2 = (int)(bm.bmWidth * cosine + bm.bmHeight * sine);


int y2 = (int)(bm.bmHeight * cosine - bm.bmWidth * sine);


int x3 = (int)(bm.bmWidth * cosine);


int y3 = (int)(-bm.bmWidth * sine);


int minx = min(0,min(x1, min(x2,x3)));


int miny = min(0,min(y1, min(y2,y3)));


int maxx = max(0,max(x1, max(x2,x3)));


int maxy = max(0,max(y1, max(y2,y3)));


int w = maxx - minx;


int h = maxy - miny;


// Create a bitmap to hold the result


HBITMAP hbmResult = ::CreateCompatibleBitmap(CClientDC(NULL), w, h);


HBITMAP hbmOldSource = (HBITMAP)::SelectObject( sourceDC.m_hDC, hBitmap );


HBITMAP hbmOldDest = (HBITMAP)::SelectObject( destDC.m_hDC, hbmResult );


// Draw the background color before we change mapping mode


HBRUSH hbrBack = CreateSolidBrush( clrBack );


HBRUSH hbrOld = (HBRUSH)::SelectObject( destDC.m_hDC, hbrBack );


destDC.PatBlt( 0, 0, w, h, PATCOPY );


::DeleteObject( ::SelectObject( destDC.m_hDC, hbrOld ) );


// We will use world transform to rotate the bitmap


SetGraphicsMode(destDC.m_hDC, GM_ADVANCED);


XFORM xform;


xform.eM11 = cosine;


xform.eM12 = -sine;


xform.eM21 = sine;


xform.eM22 = cosine;


xform.eDx = (float)-minx;


xform.eDy = (float)-miny;


SetWorldTransform( destDC.m_hDC, &xform );


// Now do the actual rotating - a pixel at a time


destDC.BitBlt(0,0,bm.bmWidth, bm.bmHeight, &sourceDC, 0, 0, SRCCOPY );


// Restore DCs


SelectObject( sourceDC.m_hDC, hbmOldSource );


SelectObject( destDC.m_hDC, hbmOldDest );


return hbmResult;


}







函数二: GetRotatedBitmap()使用 GetPixel & SetPixel


// GetRotatedBitmap - Create a new bitmap with rotated image


// Returns - Returns new bitmap with rotated image


// hBitmap - Bitmap to rotate


// radians - Angle of rotation in radians


// clrBack - Color of pixels in the resulting bitmap that do


// not get covered by source pixels


// Note - If the bitmap uses colors not in the system palette


// then the result is unexpected. You can fix this by


// adding an argument for the logical palette.


HBITMAP GetRotatedBitmap( HBITMAP hBitmap, float radians, COLORREF clrBack )




...{


// Create a memory DC compatible with the display


CDC sourceDC, destDC;


sourceDC.CreateCompatibleDC( NULL );


destDC.CreateCompatibleDC( NULL );


// Get logical coordinates


BITMAP bm;


GetObject( hBitmap, sizeof( bm ), &bm );


float cosine = (float)cos(radians);


float sine = (float)sin(radians);


// Compute dimensions of the resulting bitmap


// First get the coordinates of the 3 corners other than origin


int x1 = (int)(-bm.bmHeight * sine);


int y1 = (int)(bm.bmHeight * cosine);


int x2 = (int)(bm.bmWidth * cosine - bm.bmHeight * sine);


int y2 = (int)(bm.bmHeight * cosine + bm.bmWidth * sine);


int x3 = (int)(bm.bmWidth * cosine);


int y3 = (int)(bm.bmWidth * sine);


int minx = min(0,min(x1, min(x2,x3)));


int miny = min(0,min(y1, min(y2,y3)));


int maxx = max(x1, max(x2,x3));


int maxy = max(y1, max(y2,y3));


int w = maxx - minx;


int h = maxy - miny;


// Create a bitmap to hold the result


HBITMAP hbmResult =CreateCompatibleBitmap(CClientDC(NULL), w, h);


HBITMAP hbmOldSource = (HBITMAP)SelectObject( sourceDC.m_hDC, hBitmap );


HBITMAP hbmOldDest = (HBITMAP)SelectObject( destDC.m_hDC, hbmResult );


// Draw the background color before we change mapping mode


HBRUSH hbrBack = CreateSolidBrush( clrBack );


HBRUSH hbrOld = (HBRUSH)SelectObject( destDC.m_hDC, hbrBack );


destDC.PatBlt( 0, 0, w, h, PATCOPY );


DeleteObject(SelectObject( destDC.m_hDC, hbrOld ) );


// Set mapping mode so that +ve y axis is upwords


sourceDC.SetMapMode(MM_ISOTROPIC);


sourceDC.SetWindowExt(1,1);


sourceDC.SetViewportExt(1,-1);


sourceDC.SetViewportOrg(0, bm.bmHeight-1);


destDC.SetMapMode(MM_ISOTROPIC);


destDC.SetWindowExt(1,1);


destDC.SetViewportExt(1,-1);


destDC.SetWindowOrg(minx, maxy);


// Now do the actual rotating - a pixel at a time


// Computing the destination point for each source point


// will leave a few pixels that do not get covered


// So we use a reverse transform - e.i. compute the source point


// for each destination point


for( int y = miny; y < maxy; y++ )




...{


for( int x = minx; x < maxx; x++ )




...{


int sourcex = (int)(x*cosine + y*sine);


int sourcey = (int)(y*cosine - x*sine);


if( sourcex >= 0 && sourcex < bm.bmWidth && sourcey >= 0 && sourcey < bm.bmHeight )


destDC.SetPixel(x,y,sourceDC.GetPixel(sourcex,sourcey));


}


}


// Restore DCs


SelectObject( sourceDC.m_hDC, hbmOldSource );


SelectObject( destDC.m_hDC, hbmOldDest );


return hbmResult;


}







函数三: GetRotatedBitmap()使用DIB


// GetRotatedBitmap - Create a new bitmap with rotated image


// Returns - Returns new bitmap with rotated image


// hDIB - Device-independent bitmap to rotate


// radians - Angle of rotation in radians


// clrBack - Color of pixels in the resulting bitmap that do


// not get covered by source pixels


HANDLE GetRotatedBitmap( HANDLE hDIB, float radians, COLORREF clrBack)




...{


// Get source bitmap info


BITMAPINFO &bmInfo = *(LPBITMAPINFO)hDIB ;


int bpp = bmInfo.bmiHeader.biBitCount; // Bits per pixel


int nColors = bmInfo.bmiHeader.biClrUsed ? bmInfo.bmiHeader.biClrUsed:1 << bpp;


int nWidth = bmInfo.bmiHeader.biWidth;


int nHeight = bmInfo.bmiHeader.biHeight;


int nRowBytes = ((((nWidth * bpp) + 31) & ~31) / 8);


// Make sure height is positive and biCompression is BI_RGB or BI_BITFIELDS


DWORD &compression = bmInfo.bmiHeader.biCompression;


if( nHeight < 0 || (compression!=BI_RGB &&compression!=BI_BITFIELDS))


return NULL;


LPVOID lpDIBBits;


if( bmInfo.bmiHeader.biBitCount > 8 )


lpDIBBits = (LPVOID)((LPDWORD)(bmInfo.bmiColors +bmInfo.bmiHeader.biClrUsed) +((compression == BI_BITFIELDS) ? 3 : 0));


else


lpDIBBits = (LPVOID)(bmInfo.bmiColors + nColors);


// Compute the cosine and sine only once


float cosine = (float)cos(radians);


float sine = (float)sin(radians);


// Compute dimensions of the resulting bitmap


// First get the coordinates of the 3 corners other than origin


int x1 = (int)(-nHeight * sine);


int y1 = (int)(nHeight * cosine);


int x2 = (int)(nWidth * cosine - nHeight * sine);


int y2 = (int)(nHeight * cosine + nWidth * sine);


int x3 = (int)(nWidth * cosine);


int y3 = (int)(nWidth * sine);


int minx = min(0,min(x1, min(x2,x3)));


int miny = min(0,min(y1, min(y2,y3)));


int maxx = max(x1, max(x2,x3));


int maxy = max(y1, max(y2,y3));


int w = maxx - minx;


int h = maxy - miny;


// Create a DIB to hold the result


int nResultRowBytes = ((((w * bpp) + 31) & ~31) / 8);


long len = nResultRowBytes * h;


int nHeaderSize = ((LPBYTE)lpDIBBits-(LPBYTE)hDIB) ;


HANDLE hDIBResult = GlobalAlloc(GMEM_FIXED,len+nHeaderSize);


// Initialize the header information


memcpy( (void*)hDIBResult, (void*)hDIB, nHeaderSize);


BITMAPINFO &bmInfoResult = *(LPBITMAPINFO)hDIBResult ;


bmInfoResult.bmiHeader.biWidth = w;


bmInfoResult.bmiHeader.biHeight = h;


bmInfoResult.bmiHeader.biSizeImage = len;


LPVOID lpDIBBitsResult = (LPVOID)((LPBYTE)hDIBResult + nHeaderSize);


// Get the back color value (index)


ZeroMemory( lpDIBBitsResult, len );


DWORD dwBackColor;


switch(bpp)




...{


case 1: //Monochrome


if( clrBack == RGB(255,255,255) )


memset( lpDIBBitsResult, 0xff, len );


break;


case 4:


case 8: //Search the color table


int i;


for(i = 0; i < nColors; i++ )




...{


if( bmInfo.bmiColors[i].rgbBlue == GetBValue(clrBack)


&& bmInfo.bmiColors[i].rgbGreen == GetGValue(clrBack)


&& bmInfo.bmiColors[i].rgbRed == GetRValue(clrBack) )




...{


if(bpp==4) i = i | i<<4;


memset( lpDIBBitsResult, i, len );


break;


}


}


// If not match found the color remains black


break;


case 16:


// Windows95 supports 5 bits each for all colors or 5 bits for red


& blue


// and 6 bits for green - Check the color mask for RGB555 or RGB565


if( *((DWORD*)bmInfo.bmiColors) == 0x7c00 )




...{


// Bitmap is RGB555


dwBackColor = ((GetRValue(clrBack)>>3) << 10) +


((GetRValue(clrBack)>>3) << 5) +


(GetBValue(clrBack)>>3) ;


}


else




...{


// Bitmap is RGB565


dwBackColor = ((GetRValue(clrBack)>>3) << 11) +


((GetRValue(clrBack)>>2) << 5) +


(GetBValue(clrBack)>>3) ;


}


break;


case 24:


case 32:


dwBackColor = (((DWORD)GetRValue(clrBack)) << 16) |


(((DWORD)GetGValue(clrBack)) << 8) |


(((DWORD)GetBValue(clrBack)));


break;


}


// Now do the actual rotating - a pixel at a time


// Computing the destination point for each source point


// will leave a few pixels that do not get covered


// So we use a reverse transform - e.i. compute the source point


// for each destination point


for( int y = 0; y < h; y++ )




...{


for( int x = 0; x < w; x++ )




...{


int sourcex = (int)((x+minx)*cosine + (y+miny)*sine);


int sourcey = (int)((y+miny)*cosine - (x+minx)*sine);


if( sourcex >= 0 && sourcex < nWidth && sourcey >= 0 && sourcey < nHeight )




...{


// Set the destination pixel


switch(bpp)




...{


BYTE mask;


case 1: //Monochrome


mask = *((LPBYTE)lpDIBBits + nRowBytes*sourcey +


sourcex/8) & (0x80 >> sourcex%8);


//Adjust mask for destination bitmap


mask = mask ? (0x80 >> x%8) : 0;


*((LPBYTE)lpDIBBitsResult + nResultRowBytes*(y) +


(x/8)) &= ~(0x80 >> x%8);


*((LPBYTE)lpDIBBitsResult + nResultRowBytes*(y) +


(x/8)) |= mask;


break;


case 4:


mask = *((LPBYTE)lpDIBBits + nRowBytes*sourcey +


sourcex/2) & ((sourcex&1) ? 0x0f : 0xf0);


//Adjust mask for destination bitmap


if( (sourcex&1) != (x&1) )


mask = (mask&0xf0) ? (mask>>4) : (mask<<4);


*((LPBYTE)lpDIBBitsResult + nResultRowBytes*(y) +


(x/2)) &= ~((x&1) ? 0x0f : 0xf0);


*((LPBYTE)lpDIBBitsResult + nResultRowBytes*(y) +


(x/2)) |= mask;


break;


case 8:


BYTE pixel ;


pixel = *((LPBYTE)lpDIBBits + nRowBytes*sourcey +


sourcex);


*((LPBYTE)lpDIBBitsResult + nResultRowBytes*(y) +


(x)) = pixel;


break;


case 16:


DWORD dwPixel;


dwPixel = *((LPWORD)((LPBYTE)lpDIBBits +nRowBytes*sourcey + sourcex*2));


*((LPWORD)((LPBYTE)lpDIBBitsResult +nResultRowBytes*y + x*2)) = (WORD)dwPixel;


break;


case 24:


dwPixel = *((LPDWORD)((LPBYTE)lpDIBBits +nRowBytes*sourcey + sourcex*3)) & 0xffffff;


*((LPDWORD)((LPBYTE)lpDIBBitsResult +nResultRowBytes*y + x*3)) |= dwPixel;


break;


case 32:


dwPixel = *((LPDWORD)((LPBYTE)lpDIBBits +nRowBytes*sourcey + sourcex*4));


*((LPDWORD)((LPBYTE)lpDIBBitsResult +nResultRowBytes*y + x*4)) = dwPixel;


}


}


else




...{


// Draw the background "color."tppabs="http://www.codeguru.com/bitmap/color." Thebackground color


// has already been drawn for 8 bits per pixel and less


switch(bpp)




...{


case 16:


*((LPWORD)((LPBYTE)lpDIBBitsResult +nResultRowBytes*y + x*2))=(WORD)dwBackColor;


break;


case 24:


*((LPDWORD)((LPBYTE)lpDIBBitsResult+nResultRowBytes*y + x*3))|=dwBackColor;


break;


case 32:


*((LPDWORD)((LPBYTE)lpDIBBitsResult+nResultRowBytes*y + x*4)) = dwBackColor;


break;


}


}


}


}


return hDIBResult;


}



2.透明背景的位图
函数一:
下面的DrawTransparentBmp函数是一个完整的正确显示透明位图的函数,其各参数说明如下:
HDC hdc:目标HDC,即将要绘制位图的HDC
HBITMAP hbmp:位图的句柄,此位图可以是2位、4位、8位、16位、24位位图。
RECT &rect:将要绘制的区域
COLORREF colorTrans:透明色

函数清单如下:


BOOL DrawTransparentBmp(HDC hdc, HBITMAP hbmp, RECT &rect, COLORREF colorTrans)




...{


HDC dcImage, dcTrans, dcImage24;


HBITMAP holdbmp24, hbmp24;


HBITMAP holdbmp;


HBITMAP hbmpTrans, holdbmpTrans;


// 创建内存DC


dcImage = CreateCompatibleDC(hdc);


dcTrans = CreateCompatibleDC(hdc);


dcImage24 = CreateCompatibleDC(hdc);


if (dcImage == NULL || dcTrans == NULL || dcImage24 == NULL)// Error: can't create compatible dc


return FALSE;


// 获得图像属性


BITMAP bmp;


GetObject(hbmp, sizeof(bmp), &bmp);


// 选择图片到dcImage中


holdbmp = (HBITMAP)SelectObject(dcImage, hbmp);


// 创建24色位图,这样才能正确地显示带透明色的位图


LPBITMAPINFO lpBmpInfo;


lpBmpInfo = (BITMAPINFO*) new BYTE[sizeof(BITMAPINFOHEADER)];


lpBmpInfo->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);


lpBmpInfo->bmiHeader.biPlanes = 1;


lpBmpInfo->bmiHeader.biBitCount = nBitCount;


lpBmpInfo->bmiHeader.biCompression = BI_RGB;


lpBmpInfo->bmiHeader.biSizeImage = 0;


lpBmpInfo->bmiHeader.biClrUsed = 0;


lpBmpInfo->bmiHeader.biWidth = bmp.bmWidth;


lpBmpInfo->bmiHeader.biHeight = bmp.bmHeight;


HDC dc = CreateCompatibleDC(NULL);


// 创建新图片


LPVOID lpBits;


hbmp24 =::CreateDIBSection(dc,lpBmpInfo,DIB_RGB_COLORS,


&lpBits,NULL,0);


DeleteDC(dc);


delete lpBmpInfo;


if (hbmp24 == NULL)// Error


return FALSE;


holdbmp24 = (HBITMAP)SelectObject(dcImage24, hbmp24);


// 将原图片绘制到24色位图中


BitBlt(dcImage24, 0, 0, bmp.bmWidth, bmp.bmHeight, dcImage, 0, 0, SRCCOPY);


// 创建Mask位图


hbmpTrans = CreateBitmap(bmp.bmWidth, bmp.bmHeight, 1, 1, NULL);


if (hbmpTrans == NULL)// Error


return FALSE;


// 选择mask位图到dcTrans中


holdbmpTrans = (HBITMAP)SelectObject(dcTrans, hbmpTrans);


// 创建掩码图像(基于指定的颜色)


COLORREF oldbkcolor = SetBkColor(dcImage24, colorTrans);


BitBlt(dcTrans, 0, 0, bmp.bmWidth, bmp.bmHeight, dcImage24, 0, 0, SRCCOPY);


SetBkColor(dcImage24, RGB(0,0,0));


COLORREF oldtextcolor = SetTextColor(dcImage24, RGB(255,255,255));


BitBlt(dcImage24, 0, 0, bmp.bmWidth, bmp.bmHeight, dcTrans, 0, 0, SRCAND);


// 去除指定的颜色


COLORREF crOldBack, crOldText;


crOldBack = SetBkColor(hdc, RGB(255,255,255));


crOldText = SetTextColor(hdc, RGB(0,0,0));


// 显示透明位图


StretchBlt(hdc, rect.left, rect.top, rect.right - rect.left,rect.bottom - rect.top,


dcTrans, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCAND);


StretchBlt(hdc, rect.left, rect.top, rect.right - rect.left,rect.bottom - rect.top,


dcImage24, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCPAINT);


// 恢复设置及释放资源


SelectObject(dcImage, holdbmp);


SelectObject(dcImage24, holdbmp24);


SelectObject(dcTrans, holdbmpTrans);


DeleteObject(hbmp24);


DeleteObject(hbmpTrans);


SetBkColor(hdc, crOldBack);


SetTextColor(hdc, crOldText);


SetBkColor(dcImage24, oldbkcolor);


SetTextColor(dcImage24, oldtextcolor);


DeleteDC(dcImage);


DeleteDC(dcImage24);


DeleteDC(dcTrans);


return TRUE;


}

函数二:
该函数摘自MSDN.


void DrawTransparentBitmap(HDC hdc, HBITMAP hBitmap, short xStart,


short yStart, COLORREF cTransparentColor)




...{


BITMAP bm;


COLORREF cColor;


HBITMAP bmAndBack, bmAndObject, bmAndMem, bmSave;


HBITMAP bmBackOld, bmObjectOld, bmMemOld, bmSaveOld;


HDC hdcMem, hdcBack, hdcObject, hdcTemp, hdcSave;


POINT ptSize;


hdcTemp = CreateCompatibleDC(hdc);


SelectObject(hdcTemp, hBitmap); // Select the bitmap


GetObject(hBitmap, sizeof(BITMAP), (LPSTR)&bm);


ptSize.x = bm.bmWidth; // Get width of bitmap


ptSize.y = bm.bmHeight; // Get height of bitmap


DPtoLP(hdcTemp, &ptSize, 1); // Convert from device


// to logical points


// Create some DCs to hold temporary data.


hdcBack = CreateCompatibleDC(hdc);


hdcObject = CreateCompatibleDC(hdc);


hdcMem = CreateCompatibleDC(hdc);


hdcSave = CreateCompatibleDC(hdc);


// Create a bitmap for each DC. DCs are required for a number of


// GDI functions.


// Monochrome DC


bmAndBack = CreateBitmap(ptSize.x, ptSize.y, 1, 1, NULL);


// Monochrome DC


bmAndObject = CreateBitmap(ptSize.x, ptSize.y, 1, 1, NULL);


bmAndMem = CreateCompatibleBitmap(hdc, ptSize.x, ptSize.y);


bmSave = CreateCompatibleBitmap(hdc, ptSize.x, ptSize.y);


// Each DC must select a bitmap object to store pixel data.


bmBackOld = (HBITMAP)::SelectObject(hdcBack, bmAndBack);


bmObjectOld = (HBITMAP)::SelectObject(hdcObject, bmAndObject);


bmMemOld = (HBITMAP)::SelectObject(hdcMem, bmAndMem);


bmSaveOld = (HBITMAP)::SelectObject(hdcSave, bmSave);


// Set proper mapping mode.


SetMapMode(hdcTemp, GetMapMode(hdc));


// Save the bitmap sent here, because it will be overwritten.


BitBlt(hdcSave, 0, 0, ptSize.x, ptSize.y, hdcTemp, 0, 0, SRCCOPY);


// Set the background color of the source DC to the color.


// contained in the parts of the bitmap that should be transparent


cColor = SetBkColor(hdcTemp, cTransparentColor);


// Create the object mask for the bitmap by performing a BitBlt


// from the source bitmap to a monochrome bitmap.


BitBlt(hdcObject, 0, 0, ptSize.x, ptSize.y, hdcTemp, 0, 0,


SRCCOPY);


// Set the background color of the source DC back to the original


// color.


SetBkColor(hdcTemp, cColor);


// Create the inverse of the object mask.


BitBlt(hdcBack, 0, 0, ptSize.x, ptSize.y, hdcObject, 0, 0,


NOTSRCCOPY);


// Copy the background of the main DC to the destination.


BitBlt(hdcMem, 0, 0, ptSize.x, ptSize.y, hdc, xStart, yStart,


SRCCOPY);


// Mask out the places where the bitmap will be placed.


BitBlt(hdcMem, 0, 0, ptSize.x, ptSize.y, hdcObject, 0, 0, SRCAND);


// Mask out the transparent colored pixels on the bitmap.


BitBlt(hdcTemp, 0, 0, ptSize.x, ptSize.y, hdcBack, 0, 0, SRCAND);


// XOR the bitmap with the background on the destination DC.


BitBlt(hdcMem, 0, 0, ptSize.x, ptSize.y, hdcTemp, 0, 0, SRCPAINT);


// Copy the destination to the screen.


BitBlt(hdc, xStart, yStart, ptSize.x, ptSize.y, hdcMem, 0, 0,


SRCCOPY);


// Place the original bitmap back into the bitmap sent here.


BitBlt(hdcTemp, 0, 0, ptSize.x, ptSize.y, hdcSave, 0, 0, SRCCOPY);


// Delete the memory bitmaps.


DeleteObject(SelectObject(hdcBack, bmBackOld));


DeleteObject(SelectObject(hdcObject, bmObjectOld));


DeleteObject(SelectObject(hdcMem, bmMemOld));


DeleteObject(SelectObject(hdcSave, bmSaveOld));


// Delete the memory DCs.


DeleteDC(hdcMem);


DeleteDC(hdcBack);


DeleteDC(hdcObject);


DeleteDC(hdcSave);


DeleteDC(hdcTemp);


}



3.位图的保存
Storing an Image
Many applications store images permanently as files. For example, drawing applications store pictures, spreadsheet applications store charts, CAD applications store drawings, and so on.

If you are writing an application that stores a bitmap image in a file, you should use the bitmap file format described in Bitmap Storage. To store a bitmap in this format, you must use a BITMAPINFOHEADER, a BITMAPV4HEADER, or a BITMAPV5HEADER structure and an array of RGBQUAD structures, as well as an array of palette indexes.

The following example code defines a function that uses a BITMAPINFO structure and allocates memory for and initializes members within a BITMAPINFOHEADER structure. Note that the BITMAPINFO structure cannot be used with either a BITMAPV4HEADER or a BITMAPV5HEADER structure.

PBITMAPINFO CreateBitmapInfoStruct(HWND hwnd, HBITMAP hBmp)
{
BITMAP bmp;
PBITMAPINFO pbmi;
WORD cClrBits;

// Retrieve the bitmap color format, width, and height.
if (!GetObject(hBmp, sizeof(BITMAP), (LPSTR)&bmp))
errhandler("GetObject", hwnd);

// Convert the color format to a count of bits.
cClrBits = (WORD)(bmp.bmPlanes * bmp.bmBitsPixel);
if (cClrBits == 1)
cClrBits = 1;
else if (cClrBits <= 4)
cClrBits = 4;
else if (cClrBits <= 8)
cClrBits = 8;
else if (cClrBits <= 16)
cClrBits = 16;
else if (cClrBits <= 24)
cClrBits = 24;
else cClrBits = 32;

// Allocate memory for the BITMAPINFO structure. (This structure
// contains a BITMAPINFOHEADER structure and an array of RGBQUAD
// data structures.)

if (cClrBits != 24)
pbmi = (PBITMAPINFO) LocalAlloc(LPTR,
sizeof(BITMAPINFOHEADER) +
sizeof(RGBQUAD) * (1<< cClrBits));

// There is no RGBQUAD array for the 24-bit-per-pixel format.

else
pbmi = (PBITMAPINFO) LocalAlloc(LPTR,
sizeof(BITMAPINFOHEADER));

// Initialize the fields in the BITMAPINFO structure.

pbmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
pbmi->bmiHeader.biWidth = bmp.bmWidth;
pbmi->bmiHeader.biHeight = bmp.bmHeight;
pbmi->bmiHeader.biPlanes = bmp.bmPlanes;
pbmi->bmiHeader.biBitCount = bmp.bmBitsPixel;
if (cClrBits < 24)
pbmi->bmiHeader.biClrUsed = (1<<cClrBits);

// If the bitmap is not compressed, set the BI_RGB flag.
pbmi->bmiHeader.biCompression = BI_RGB;

// Compute the number of bytes in the array of color
// indices and store the result in biSizeImage.
// For Windows NT, the width must be DWORD aligned unless
// the bitmap is RLE compressed. This example shows this.
// For Windows 95/98/Me, the width must be WORD aligned unless the
// bitmap is RLE compressed.
pbmi->bmiHeader.biSizeImage = ((pbmi->bmiHeader.biWidth * cClrBits +31) & ~31) /8
* pbmi->bmiHeader.biHeight;
// Set biClrImportant to 0, indicating that all of the
// device colors are important.
pbmi->bmiHeader.biClrImportant = 0;
return pbmi;
}
The following example code defines a function that initializes the remaining structures, retrieves the array of palette indices, opens the file, copies the data, and closes the file.

void CreateBMPFile(HWND hwnd, LPTSTR pszFile, PBITMAPINFO pbi,
HBITMAP hBMP, HDC hDC)
{
HANDLE hf; // file handle
BITMAPFILEHEADER hdr; // bitmap file-header
PBITMAPINFOHEADER pbih; // bitmap info-header
LPBYTE lpBits; // memory pointer
DWORD dwTotal; // total count of bytes
DWORD cb; // incremental count of bytes
BYTE *hp; // byte pointer
DWORD dwTmp;

pbih = (PBITMAPINFOHEADER) pbi;
lpBits = (LPBYTE) GlobalAlloc(GMEM_FIXED, pbih->biSizeImage);

if (!lpBits)
errhandler("GlobalAlloc", hwnd);

// Retrieve the color table (RGBQUAD array) and the bits
// (array of palette indices) from the DIB.
if (!GetDIBits(hDC, hBMP, 0, (WORD) pbih->biHeight, lpBits, pbi,
DIB_RGB_COLORS))
{
errhandler("GetDIBits", hwnd);
}

// Create the .BMP file.
hf = CreateFile(pszFile,
GENERIC_READ | GENERIC_WRITE,
(DWORD) 0,
NULL,
CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
(HANDLE) NULL);
if (hf == INVALID_HANDLE_VALUE)
errhandler("CreateFile", hwnd);
hdr.bfType = 0x4d42; // 0x42 = "B" 0x4d = "M"
// Compute the size of the entire file.
hdr.bfSize = (DWORD) (sizeof(BITMAPFILEHEADER) +
pbih->biSize + pbih->biClrUsed
* sizeof(RGBQUAD) + pbih->biSizeImage);
hdr.bfReserved1 = 0;
hdr.bfReserved2 = 0;

// Compute the offset to the array of color indices.
hdr.bfOffBits = (DWORD) sizeof(BITMAPFILEHEADER) +
pbih->biSize + pbih->biClrUsed
* sizeof (RGBQUAD);

// Copy the BITMAPFILEHEADER into the .BMP file.
if (!WriteFile(hf, (LPVOID) &hdr, sizeof(BITMAPFILEHEADER),
(LPDWORD) &dwTmp, NULL))
{
errhandler("WriteFile", hwnd);
}

// Copy the BITMAPINFOHEADER and RGBQUAD array into the file.
if (!WriteFile(hf, (LPVOID) pbih, sizeof(BITMAPINFOHEADER)
+ pbih->biClrUsed * sizeof (RGBQUAD),
(LPDWORD) &dwTmp, ( NULL))
errhandler("WriteFile", hwnd);

// Copy the array of color indices into the .BMP file.
dwTotal = cb = pbih->biSizeImage;
hp = lpBits;
if (!WriteFile(hf, (LPSTR) hp, (int) cb, (LPDWORD) &dwTmp,NULL))
errhandler("WriteFile", hwnd);

// Close the .BMP file.
if (!CloseHandle(hf))
errhandler("CloseHandle", hwnd);

// Free memory.
GlobalFree((HGLOBAL)lpBits);
}

(2)

BOOL SaveDCBmp(HDC hDC, HBITMAP hBitmap, LPCTSTR lpFileName)
{
//当前分辨率下每象素所占字节数
int iBits;
//位图中每象素所占字节数
WORD wBitCount;
//定义调色板大小, 位图中像素字节大小 ,位图文件大小 , 写入文件字节数
DWORD dwPaletteSize=0, dwBmBitsSize=0, dwDIBSize=0, dwWritten=0;
//位图属性结构
BITMAP Bitmap;
//位图文件头结构
BITMAPFILEHEADER bmfHdr;
//位图信息头结构
BITMAPINFOHEADER bi;
//指向位图信息头结构
LPBITMAPINFOHEADER lpbi;
//定义文件,分配内存句柄,调色板句柄
HANDLE fh, hDib, hPal,hOldPal=NULL;

//计算位图文件每个像素所占字节数
iBits = GetDeviceCaps(hDC, BITSPIXEL) * GetDeviceCaps(hDC, PLANES);

if (iBits <= 1) wBitCount = 1;
else if (iBits <= 4) wBitCount = 4;
else if (iBits <= 8) wBitCount = 8;
else wBitCount = 24;

//wBitCount = 4;

GetObject(hBitmap, sizeof(Bitmap), (LPSTR)&Bitmap);
bi.biSize = sizeof(BITMAPINFOHEADER);
bi.biWidth = Bitmap.bmWidth;
bi.biHeight = Bitmap.bmHeight;
bi.biPlanes = 1;
bi.biBitCount = wBitCount;
bi.biCompression = BI_RGB;
bi.biSizeImage = 0;
bi.biXPelsPerMeter = 0;
bi.biYPelsPerMeter = 0;
bi.biClrImportant = 0;
bi.biClrUsed = 0;

dwBmBitsSize = ((Bitmap.bmWidth * wBitCount + 31) / 32) * 4 * Bitmap.bmHeight;

//为位图内容分配内存
hDib = GlobalAlloc(GHND,dwBmBitsSize + dwPaletteSize + sizeof(BITMAPINFOHEADER));
lpbi = (LPBITMAPINFOHEADER)GlobalLock(hDib);
*lpbi = bi;

// 处理调色板
hPal = GetStockObject(DEFAULT_PALETTE);
if (hPal)
{
hOldPal = ::SelectPalette(hDC, (HPALETTE)hPal, FALSE);
}

// 获取该调色板下新的像素值
GetDIBits(hDC, hBitmap, 0, (UINT) Bitmap.bmHeight, (LPSTR)lpbi + sizeof(BITMAPINFOHEADER)
+dwPaletteSize, (BITMAPINFO *)lpbi, DIB_RGB_COLORS);

//恢复调色板
if (hOldPal)
{
::SelectPalette(hDC, (HPALETTE)hOldPal, TRUE);
RealizePalette(hDC);
}

//创建位图文件
fh = CreateFile(lpFileName, GENERIC_WRITE,0, NULL, CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, NULL);

if (fh == INVALID_HANDLE_VALUE) return FALSE;

// 设置位图文件头
bmfHdr.bfType = 0x4D42; // "BM"
dwDIBSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + dwPaletteSize + dwBmBitsSize;
bmfHdr.bfSize = dwDIBSize;
bmfHdr.bfReserved1 = 0;
bmfHdr.bfReserved2 = 0;
bmfHdr.bfOffBits = (DWORD)sizeof(BITMAPFILEHEADER) + (DWORD)sizeof(BITMAPINFOHEADER) + dwPaletteSize;
// 写入位图文件头
WriteFile(fh, (LPSTR)&bmfHdr, sizeof(BITMAPFILEHEADER), &dwWritten, NULL);
// 写入位图文件其余内容
WriteFile(fh, (LPSTR)lpbi, dwDIBSize, &dwWritten, NULL);
//清除
GlobalUnlock(hDib);
GlobalFree(hDib);
CloseHandle(fh);

return TRUE;
}

4.画渐变背景
BOOL GradientFill(
HDC hdc,
CONST PTRIVERTEX pVertex,
DWORD dwNumVertex,
CONST PVOID pMesh,
DWORD dwNumMesh,
DWORD dwMode
);

5.GDI+实现双缓冲
void CMyView::ShowImage(CDC *pDC, Image *pImage)
{
int w = pImage->GetWidth();
int h = pImage->GetHeight();

// 内存中创建临时Bitmap
Bitmap *pBMP = new Bitmap(w,h);
Graphics *g = Graphics::FromImage(pBMP);
Point destPoints[3] =
{
Point(0, 0), Point(w, 0), Point(x, h)
};
g->DrawImage(pImage,&destPoints[0],3);

Graphics graphics(pDC->m_hDC);
graphics.DrawImage(pBMP, destPoints, 3);
delete pBMP;
}

void CMyView::OnDraw(CDC *pDC)
{
Image *pImage = GetDocument()->m_pImage; // m_pImage 在文档类中
ShowImage(pDC, pImage);
}

6.窗口被遮挡得情况下截图
PrintWindow函数
PrintWindow函数的执行体在你的进程,而WM_PRINT的执行体在对方进程内。
PrintWindow是被winspool.drv隐式导出的,所以你用Depends是看不到,只有在lib里面能记录到。
另外:PrintWindow 必须在XP以上版本进行所以2K下是不能使用该函数的。要么你就只能注入到目的进程然后再目的进程内用WM_PRINT抓了。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: