GDI实现图片旋转,博主在网上找了好多资料,都不太如意。
并且在尝试中发现,如果先用SetViewportOrgEx将HDC上的坐标原点移动到图片中心;再在HDC上的获取每个点,用三角函数进行变换,算得新坐标进行点绘制。理论可行,但是因为double与int转换的关系,会丢失精度,旋转后图像会很模糊。
附:三角函数公式
逆时针:
x1=xcos(β)-ysin(β);
y1=ycos(β)+xsin(β);
顺时针:
x1=xcos(β)+ysin(β);
y1=ycos(β)-xsin(β);
笔者兜兜转转找了很多资料,发现有大神利用函数PlgBlt实现图片的旋转,但是用的是VB。根据理解,本人进行了修改,并译成了C++。代码如下,重点在于Rotate函数,并附上使用方法:
using namespace std;
extern "C"
{
#include <windows.h>
#include <tchar.h>
#include "resource.h"
}
#define ID_TIMER 1
/*
逆时针
x1=xcos(β)-ysin(β);
y1=ycos(β)+xsin(β);
顺时针
x1=xcos(β)+ysin(β);
y1=ycos(β)-xsin(β);
*/
LRESULT CALLBACK WndProc(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam);
void Rotate(HDC hdcDest,int xPos,int yPos,int angle,HDC hdcSrc,int xSrc,int ySrc,int srcWidth,int srcHeight);
HWND hwnd;
HINSTANCE hInst;
int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int nShowCmd)
{
TCHAR szAppName[]=TEXT("first win");
MSG msg;
WNDCLASS wndclass;
hInst=hInstance;
wndclass.style=CS_HREDRAW | CS_VREDRAW;
wndclass.lpfnWndProc=WndProc;
wndclass.cbClsExtra=0;
wndclass.cbWndExtra=0;
wndclass.hInstance=hInstance;
wndclass.hIcon=LoadIcon(NULL,IDI_APPLICATION);
wndclass.hCursor=LoadCursor(NULL,IDC_ARROW);
wndclass.hbrBackground=(HBRUSH)GetStockObject(WHITE_BRUSH);
wndclass.lpszMenuName=NULL;
wndclass.lpszClassName=szAppName;
if(!RegisterClass(&wndclass))
{
MessageBox(NULL,TEXT("error"),szAppName,MB_ICONERROR);
return 0;
}
hwnd=CreateWindow(szAppName,
TEXT("hello"),
WS_OVERLAPPEDWINDOW^WS_MAXIMIZEBOX^WS_THICKFRAME,
20, //CW_USEDEFAULT
50,
600, //CW_USEDEFAULT,
400, //CW_USEDEFAULT,
NULL,
NULL,
hInstance,
NULL);
ShowWindow(hwnd,nShowCmd);
UpdateWindow(hwnd);
while(GetMessage(&msg,NULL,0,0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
HDC hdc;
PAINTSTRUCT ps;
HDC dcWin,dcBmp1,dcBmp2;
HBITMAP hBmp1,hBmp2;
POINT pt;
RECT rect;
int angle=0;
void Rotate(HDC hdcDest,int xPos,int yPos,int angle,HDC hdcSrc,int xSrc,int ySrc,int srcWidth,int srcHeight,COLORREF col)
{
POINT pt[3];
POINT defPt[3];
double notPI=3.14/180;
double thetS,thetC;
int ret;
pt[0].x=-srcWidth * 0.5;
pt[0].y=-srcHeight * 0.5;
pt[1].x = pt[0].x + srcWidth;
pt[1].y = pt[0].y;
pt[2].x = pt[0].x;
pt[2].y = pt[0].y + srcHeight;
thetS = sin(angle * notPI);
thetC = cos(angle * notPI);
defPt[0].x = (pt[0].x * thetC - pt[0].y * thetS) + xPos;
defPt[0].y = (pt[0].x * thetS + pt[0].y * thetC) + yPos;
defPt[1].x = (pt[1].x * thetC - pt[1].y * thetS) + xPos;
defPt[1].y = (pt[1].x * thetS + pt[1].y * thetC) + yPos;
defPt[2].x = (pt[2].x * thetC - pt[2].y * thetS) + xPos;
defPt[2].y = (pt[2].x * thetS + pt[2].y * thetC) + yPos;
HBRUSH hBrush=CreateSolidBrush(col);
RECT rect;
rect.left=rect.top=0;
rect.right=rect.left+srcWidth;
rect.bottom=rect.top+srcHeight;
FillRect(hdcDest,&rect,hBrush);
DeleteObject(hBrush);
PlgBlt(hdcDest, &defPt[0], hdcSrc, xSrc, ySrc, srcWidth, srcHeight, 0, 0, 0);
}
LRESULT CALLBACK WndProc(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam)
{
switch(message)
{
case WM_CREATE:
dcWin=GetDC(hwnd);
dcBmp1=CreateCompatibleDC(dcWin);
dcBmp2=CreateCompatibleDC(dcWin);
hBmp1=LoadBitmap(hInst,MAKEINTRESOURCE(IDB_BITMAP1));
hBmp2=CreateCompatibleBitmap(dcWin,98,98);
SelectObject(dcBmp1,hBmp1);
SelectObject(dcBmp2,hBmp2);
//将dcBmp1以(49,49)为坐标中心旋转angle角度后后画到dcBmp2中
Rotate(dcBmp2,49,49,angle,dcBmp1,0,0,98,98,0xffffff);
SetTimer(hwnd,ID_TIMER,500,NULL);
break;
case WM_PAINT:
hdc=BeginPaint(hwnd,&ps);
SetBkMode(hdc,TRANSPARENT);
BitBlt(hdc,0,0,98,98,dcBmp1,0,0,SRCCOPY);
BitBlt(hdc,100,0,98,98,dcBmp2,0,0,SRCCOPY);
EndPaint(hwnd,&ps);
break;
case WM_TIMER:
if(wParam==ID_TIMER)
{
angle=(angle+15)%360;
Rotate(dcBmp2,49,49,angle,dcBmp1,0,0,98,98,0xffffff);
InvalidateRect(hwnd,NULL,true);
UpdateWindow(hwnd);
}
break;
case WM_DESTROY:
ReleaseDC(hwnd,dcWin);
DeleteDC(dcBmp1);
DeleteDC(dcBmp2);
DeleteObject(hBmp1);
DeleteObject(hBmp2);
KillTimer(hwnd,ID_TIMER);
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hwnd,message,wParam,lParam);
}
知识兔