现在的位置: 首页 > 综合 > 正文

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

2013年08月10日 ⁄ 综合 ⁄ 共 9574字 ⁄ 字号 评论关闭

 

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, 11, NULL);
    
// Monochrome DC
    bmAndObject = CreateBitmap(ptSize.x, ptSize.y, 11, 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, 00, ptSize.x, ptSize.y, hdcTemp, 00, 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, 00, ptSize.x, ptSize.y, hdcTemp, 00,
    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, 00, ptSize.x, ptSize.y, hdcObject, 00,
    NOTSRCCOPY);
    
// Copy the background of the main DC to the destination.
    BitBlt(hdcMem, 00, ptSize.x, ptSize.y, hdc, xStart, yStart,
    SRCCOPY);
    
// Mask out the places where the bitmap will be placed.
    BitBlt(hdcMem, 00, ptSize.x, ptSize.y, hdcObject, 00, SRCAND);
    
// Mask out the transparent colored pixels on the bitmap.
    BitBlt(hdcTemp, 00, ptSize.x, ptSize.y, hdcBack, 00, SRCAND);
    
// XOR the bitmap with the background on the destination DC.
    BitBlt(hdcMem, 00, ptSize.x, ptSize.y, hdcTemp, 00, SRCPAINT);
    
// Copy the destination to the screen.
    BitBlt(hdc, xStart, yStart, ptSize.x, ptSize.y, hdcMem, 00,
    SRCCOPY);
    
// Place the original bitmap back into the bitmap sent here.
    BitBlt(hdcTemp, 00, ptSize.x, ptSize.y, hdcSave, 00, 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( 
00, 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, 00, 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( 
00, 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
    forint y = miny; y < maxy; y++ )
    
{
        
forint 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));
        }

抱歉!评论已关闭.