积累系统性知识
积聚技术精华
  首页    个人中心    撰写积文    建立课题    订立目标    整理积文    管理课题    管理目标    技能Get    代码积累 
图像编程的若干常用操作(旋转,透明等)
error997 (error997)    2014-11-20 20:26:20      目标    课题
切换到: 纯代码  
   
   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抓了。

转自 http://blog.csdn.net/y___y/article/details/1537376
(+0)技能Get

建议楼主:搜索关键字 |参考其他资源 |回复 |追问
  error997(error997):   个人中心    课题    目标    代码积累