位圖的旋轉

1基本算法
假使 旋轉中心 cx ,cy ;旋轉角度a; x,y處的象素旋轉後的位置 nx,ny
nx=x+cosa*(x-cx)-sina*(y-cy)
ny=y+sina*(x-cx)+cosa*(y-cy)
2文本的旋轉
http://www.codeguru.com/bitmap/RotateByShear.shtml
http://www.codeguru.com/bitmap/rotate_bitmap.shtml
http://www.ittide.com/document/article/graphic/12.html

對256位圖旋轉
/*************************************************************************
*
* 函數名稱:
*   RotateDIB()
*
* 參數:
*   LPSTR lpDIB - 指向源DIB的指針
*   int iRotateAngle - 旋轉的角度(0-360度)
*
* 返回值:
*   HGLOBAL            - 旋轉成功返回新DIB句柄,否則返回NULL。
*
* 說明:
*   該函數用來以圖像中心爲中心旋轉DIB圖像,返回新生成DIB的句柄。
* 調用該函數會自動擴大圖像以顯示所有的象素。函數中採用最鄰近插
* 值算法進行插值。
*
************************************************************************/

HGLOBAL WINAPI RotateDIB(LPSTR lpDIB, int iRotateAngle)
{

// 源圖像的寬度和高度
//float irotateangle=iRotateAngle*3.1415926/180
LONG lWidth;
LONG lHeight;

// 旋轉後圖像的寬度和高度
LONG lNewWidth;
LONG lNewHeight;

// 圖像每行的字節數
LONG lLineBytes;

// 旋轉後圖像的寬度(lNewWidth',必須是4的倍數)
LONG lNewLineBytes;

// 指向源圖像的指針
LPSTR lpDIBBits;

// 指向源象素的指針
LPSTR lpSrc;

// 旋轉後新DIB句柄
HDIB hDIB;

// 指向旋轉圖像對應象素的指針
LPSTR lpDst;

// 指向旋轉圖像的指針
LPSTR lpNewDIB;
LPSTR lpNewDIBBits;

// 指向BITMAPINFO結構的指針(Win3.0)
LPBITMAPINFOHEADER lpbmi;

// 指向BITMAPCOREINFO結構的指針
LPBITMAPCOREHEADER lpbmc;

// 循環變量(象素在新DIB中的座標)
LONG i;
LONG j;

// 象素在源DIB中的座標
LONG i0;
LONG j0;

// 旋轉角度(弧度)
float fRotateAngle;

// 旋轉角度的正弦和餘弦
float fSina, fCosa;

// 源圖四個角的座標(以圖像中心爲座標系原點)
float fSrcX1,fSrcY1,fSrcX2,fSrcY2,fSrcX3,fSrcY3,fSrcX4,fSrcY4;

// 旋轉後四個角的座標(以圖像中心爲座標系原點)
float fDstX1,fDstY1,fDstX2,fDstY2,fDstX3,fDstY3,fDstX4,fDstY4;

// 兩個中間常量
float f1,f2;

// 找到源DIB圖像象素起始位置
lpDIBBits = ::FindDIBBits(lpDIB);

// 獲取圖像的"寬度"(4的倍數)
lWidth = ::DIBWidth(lpDIB);

// 計算圖像每行的字節數
lLineBytes = WIDTHBYTES(lWidth *8);

// 獲取圖像的高度
lHeight = ::DIBHeight(lpDIB);

// 將旋轉角度從度轉換到弧度
fRotateAngle = (float) RADIAN(iRotateAngle);

// 計算旋轉角度的正弦(double)fRotateAngle
fSina = (float) sin(fRotateAngle);

// 計算旋轉角度的餘弦(double)fRotateAngle
fCosa = (float) cos(fRotateAngle);

// 計算原圖的四個角的座標(以圖像中心爲座標系原點)
fSrcX1 = (float) (- (lWidth  - 1) / 2);
fSrcY1 = (float) (  (lHeight - 1) / 2);
fSrcX2 = (float) (  (lWidth  - 1) / 2);
fSrcY2 = (float) (  (lHeight - 1) / 2);
fSrcX3 = (float) (- (lWidth  - 1) / 2);
fSrcY3 = (float) (- (lHeight - 1) / 2);
fSrcX4 = (float) (  (lWidth  - 1) / 2);
fSrcY4 = (float) (- (lHeight - 1) / 2);

// 計算新圖四個角的座標(以圖像中心爲座標系原點)
fDstX1 =  fCosa * fSrcX1 + fSina * fSrcY1;
fDstY1 = -fSina * fSrcX1 + fCosa * fSrcY1;
fDstX2 =  fCosa * fSrcX2 + fSina * fSrcY2;
fDstY2 = -fSina * fSrcX2 + fCosa * fSrcY2;
fDstX3 =  fCosa * fSrcX3 + fSina * fSrcY3;
fDstY3 = -fSina * fSrcX3 + fCosa * fSrcY3;
fDstX4 =  fCosa * fSrcX4 + fSina * fSrcY4;
fDstY4 = -fSina * fSrcX4 + fCosa * fSrcY4;

// 計算旋轉後的圖像實際寬度
lNewWidth  = (LONG) ( max( fabs(fDstX4 - fDstX1), fabs(fDstX3 - fDstX2) ) + 0.5);

// 計算新圖像每行的字節數
lNewLineBytes = WIDTHBYTES(lNewWidth * 8);

// 計算旋轉後的圖像高度
lNewHeight = (LONG) ( max( fabs(fDstY4 - fDstY1), fabs(fDstY3 - fDstY2) )  + 0.5);

// 兩個常數,這樣不用以後每次都計算了
f1 = (float) (-0.5 * (lNewWidth - 1) * fCosa - 0.5 * (lNewHeight - 1) * fSina
+ 0.5 * (lWidth  - 1));
f2 = (float) ( 0.5 * (lNewWidth - 1) * fSina - 0.5 * (lNewHeight - 1) * fCosa
+ 0.5 * (lHeight - 1));

// 分配內存,以保存新DIB
hDIB = (HDIB) ::GlobalAlloc(GHND, lNewLineBytes * lNewHeight + *(LPDWORD)lpDIB + ::PaletteSize(lpDIB));

// 判斷是否內存分配失敗
if (hDIB == NULL)
{
// 分配內存失敗
return NULL;
}

// 鎖定內存
lpNewDIB =  (char * )::GlobalLock((HGLOBAL) hDIB);

// 複製DIB信息頭和調色板
memcpy(lpNewDIB, lpDIB, *(LPDWORD)lpDIB + ::PaletteSize(lpDIB));

// 找到新DIB象素起始位置
lpNewDIBBits = ::FindDIBBits(lpNewDIB);

// 獲取指針
lpbmi = (LPBITMAPINFOHEADER)lpNewDIB;
lpbmc = (LPBITMAPCOREHEADER)lpNewDIB;

// 更新DIB中圖像的高度和寬度
if (IS_WIN30_DIB(lpNewDIB))
{
// 對於Windows 3.0 DIB
lpbmi->biWidth = lNewWidth;
lpbmi->biHeight = lNewHeight;
}
else
{
// 對於其它格式的DIB
lpbmc->bcWidth = (unsigned short) lNewWidth;
lpbmc->bcHeight = (unsigned short) lNewHeight;
}

// 針對圖像每行進行操作
for(i = 0; i < lNewHeight; i++)
{
// 針對圖像每列進行操作
for(j = 0; j < lNewWidth; j++)
{
// 指向新DIB第i行,第j個象素的指針
// 注意此處寬度和高度是新DIB的寬度和高度
lpDst = (char *)lpNewDIBBits + lNewLineBytes * (lNewHeight - 1 - i) + j;

// 計算該象素在源DIB中的座標
i0 = (LONG) (-((float) j) * fSina + ((float) i) * fCosa + f2 + 0.5);
j0 = (LONG) ( ((float) j) * fCosa + ((float) i) * fSina + f1 + 0.5);

// 判斷是否在源圖範圍內
if( (j0 >= 0) && (j0 < lWidth) && (i0 >= 0) && (i0 < lHeight))
{
// 指向源DIB第i0行,第j0個象素的指針
lpSrc = (char *)lpDIBBits + lLineBytes * (lHeight - 1 - i0) + j0;

// 複製象素
*lpDst = *lpSrc;
}
else
{
// 對於源圖中沒有的象素,直接賦值爲255
* ((unsigned char*)lpDst) = 255;
}

}

}

// 返回
return hDIB;
}

進一步優化,當前顯示模式

16:  
  555   bits   :0rrrrrgggggbbbbb  
  565   bits   :   rrrrrggggggbbbbb  
  24:  
      rrrrrrrrggggggggbbbbbbbb  
  32:  
      aaaaaaaarrrrrrrrggggggggbbbbbbbb  

 判斷顯示模式GetDeviceCaps(*m_pDC,BITSPIXEL)來

 用dc->GetCurrentBitmap()->GetBitmapBits 取得數據.
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章