今天接到一个把图片旋转90、180、270度的任务,在MSDN搜索一下,找到许多参考例程,代码也简单,很快就把代码写好了。把图片保存到硬盘,发现旋转90度的图片只有半张图!花了几个小时阅读MSDN上面的资料,终于找到了原因。这也是很多网文没有说明白的关键点。
1、XFORM结构体的eDx与eDy计算方法。
输入坐标(x,y),转换到页面坐标(x', y')的计算方法是:
旋转图片的旋转中心点就是图片的几何中心,把输入图片的中心点坐标代入(x, y),输出图片的中心点代入(x', y'),可以得到:
eDx = x_out - x_in * eM11 - y_in * eM21
eDy = y_out - x_in * eM12 - y_in * eM22
2、BitBlt()函数的参数填写要小心!BitBlt()函数先遍历读取输入DC的数据,接着把数据进行坐标变换,写入目标DC,这意味着参数cx, cy填写的是输出图片旋转前的宽高,并非旋转后的图片宽高!!旋转后的图片宽高就是创建输出图片的宽高。
BOOL BitBlt(
[in] HDC hdc,
[in] int x,
[in] int y,
[in] int cx, // 注意:此处宽高用于遍历输入图片
[in] int cy, //
[in] HDC hdcSrc,
[in] int x1,
[in] int y1,
[in] DWORD rop
);
// 设置坐标转换参数
void SetRotate(HDC hDC,int angle, CPoint srcCenter,CPoint newCenter)
{
XFORM xform;
float fangle = (float)(360.0 - angle) * 3.1415926 / 180.0;
float sinVal = sin(fangle);
float cosVal = cos(fangle);
xform.eM11 = cosVal;
xform.eM12 = sinVal;
xform.eM21 = -sinVal;
xform.eM22 = cosVal;
xform.eDx = newCenter.x - srcCenter.x * cosVal + srcCenter.y * sinVal;
xform.eDy = newCenter.y - srcCenter.x * sinVal - srcCenter.y * cosVal;
SetWorldTransform(hDC, &xform);
}
旋转图片函数
HBITMAP GetRotateHbmp(HBITMAP srcHbmp, int angle)
{
HDC hdc = NULL;
HDC srcDC, dstDC;
BITMAP bm;
GetObject(srcHbmp, sizeof(bm), &bm);
int w_bitblt = bm.bmWidth;
int h_bitblt = bm.bmHeight;
int w_dst = w_bitblt;
int h_dst = h_bitblt;
switch (angle){
case 90:
case 270:
w_dst = h_bitblt;
h_dst = w_bitblt;
break;
}
BITMAPINFO bi;
memset(&bi, 0, sizeof(bi));
bi.bmiHeader.biSize = sizeof(BITMAPINFO);
bi.bmiHeader.biWidth = w_dst;
bi.bmiHeader.biHeight = h_dst;
bi.bmiHeader.biPlanes = 1;
bi.bmiHeader.biBitCount = 32; // rgba
hdc = ::GetDC(NULL);
void* pData = NULL;
HBITMAP dstHbmp = CreateDIBSection(hdc, &bi, DIB_RGB_COLORS, (void**)&pData, NULL, 0);
if (dstHbmp == NULL || pData == NULL) {
MPRINTF("GetScreenBmp() CreateDIBSection fail[errNO:%d]\n", GetLastError());
if (dstHbmp) {
DeleteObject(dstHbmp);
dstHbmp = NULL;
}
goto _exit__;
}
srcDC = CreateCompatibleDC(hdc);
dstDC = CreateCompatibleDC(hdc);
HGDIOBJ oldSrcHbmp = SelectObject(srcDC,srcHbmp);
HGDIOBJ oldDstHbmp = SelectObject(dstDC,dstHbmp);
SetGraphicsMode(dstDC, GM_ADVANCED);
SetRotate(dstDC, angle, CPoint(w_bitblt/2, h_bitblt/2),CPoint(w_dst / 2, h_dst / 2));
GetObject(srcHbmp, sizeof(bm), &bm);
BitBlt(dstDC,0, 0, w_bitblt, h_bitblt, srcDC, 0, 0, SRCCOPY);
ModifyWorldTransform(dstDC, NULL, MWT_IDENTITY);
SelectObject(srcDC,oldSrcHbmp);
SelectObject(dstDC,oldDstHbmp);
DeleteDC(srcDC);
DeleteDC(srcDC);
_exit__:
if (hdc) {
::ReleaseDC(NULL, hdc);
}
return dstHbmp;
}