MFC SetWorldTransform()旋转图片90度只有半张图

文章讲述了在编程中处理图片旋转时遇到的问题,即旋转90度的图片显示只有半张。关键点在于XFORM结构体的eDx与eDy计算方法以及BitBlt函数参数的正确使用。通过设置坐标转换参数和理解旋转中心,成功实现了图片的完整旋转。
摘要由CSDN通过智能技术生成

         今天接到一个把图片旋转90、180、270度的任务,在MSDN搜索一下,找到许多参考例程,代码也简单,很快就把代码写好了。把图片保存到硬盘,发现旋转90度的图片只有半张图!花了几个小时阅读MSDN上面的资料,终于找到了原因。这也是很多网文没有说明白的关键点。

1、XFORM结构体的eDx与eDy计算方法。

          输入坐标(x,y),转换到页面坐标(x', y')的计算方法是:

                   x' = x * eM11 + y * eM21 + eDx

                  y' = x * eM12 + y * eM22 + eDy

          旋转图片的旋转中心点就是图片的几何中心,把输入图片的中心点坐标代入(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;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值