GDI实现图片旋转,博主在网上找了好多资料,都不太如意。

并且在尝试中发现,如果先用SetViewportOrgEx将HDC上的坐标原点移动到图片中心;再在HDC上的获取每个点,用三角函数进行变换,算得新坐标进行点绘制。理论可行,但是因为double与int转换的关系,会丢失精度,旋转后图像会很模糊。

附:三角函数公式

逆时针:
x1=xcos(β)-ysin(β);
y1=ycos(β)+xsin(β);

顺时针:
x1=xcos(β)+ysin(β);
y1=ycos(β)-xsin(β);

笔者兜兜转转找了很多资料,发现有大神利用函数PlgBlt实现图片的旋转,但是用的是VB。根据理解,本人进行了修改,并译成了C++。代码如下,重点在于Rotate函数,并附上使用方法:

#include <cmath>
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=;
wndclass.cbWndExtra=;
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 ;
} hwnd=CreateWindow(szAppName,
TEXT("hello"),
WS_OVERLAPPEDWINDOW^WS_MAXIMIZEBOX^WS_THICKFRAME,
, //CW_USEDEFAULT
,
, //CW_USEDEFAULT,
, //CW_USEDEFAULT,
NULL,
NULL,
hInstance,
NULL); ShowWindow(hwnd,nShowCmd);
UpdateWindow(hwnd); while(GetMessage(&msg,NULL,,))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
} return msg.wParam;
} HDC hdc;
PAINTSTRUCT ps; HDC dcWin,dcBmp1,dcBmp2;
HBITMAP hBmp1,hBmp2; POINT pt;
RECT rect; int angle=; void Rotate(HDC hdcDest,int xPos,int yPos,int angle,HDC hdcSrc,int xSrc,int ySrc,int srcWidth,int srcHeight,COLORREF col)
{
POINT pt[];
POINT defPt[];
double notPI=3.14/; double thetS,thetC;
int ret; pt[].x=-srcWidth * 0.5;
pt[].y=-srcHeight * 0.5; pt[].x = pt[].x + srcWidth;
pt[].y = pt[].y; pt[].x = pt[].x;
pt[].y = pt[].y + srcHeight; thetS = sin(angle * notPI);
thetC = cos(angle * notPI);
defPt[].x = (pt[].x * thetC - pt[].y * thetS) + xPos;
defPt[].y = (pt[].x * thetS + pt[].y * thetC) + yPos; defPt[].x = (pt[].x * thetC - pt[].y * thetS) + xPos;
defPt[].y = (pt[].x * thetS + pt[].y * thetC) + yPos; defPt[].x = (pt[].x * thetC - pt[].y * thetS) + xPos;
defPt[].y = (pt[].x * thetS + pt[].y * thetC) + yPos; HBRUSH hBrush=CreateSolidBrush(col);
RECT rect;
rect.left=rect.top=;
rect.right=rect.left+srcWidth;
rect.bottom=rect.top+srcHeight;
FillRect(hdcDest,&rect,hBrush);
DeleteObject(hBrush); PlgBlt(hdcDest, &defPt[], hdcSrc, xSrc, ySrc, srcWidth, srcHeight, , , );
} 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,,); SelectObject(dcBmp1,hBmp1);
SelectObject(dcBmp2,hBmp2); //将dcBmp1以(49,49)为坐标中心旋转angle角度后后画到dcBmp2中
Rotate(dcBmp2,,,angle,dcBmp1,,,,,0xffffff); SetTimer(hwnd,ID_TIMER,,NULL); break;
case WM_PAINT:
hdc=BeginPaint(hwnd,&ps);
SetBkMode(hdc,TRANSPARENT); BitBlt(hdc,,,,,dcBmp1,,,SRCCOPY);
BitBlt(hdc,,,,,dcBmp2,,,SRCCOPY); EndPaint(hwnd,&ps);
break;
case WM_TIMER:
if(wParam==ID_TIMER)
{
angle=(angle+)%;
Rotate(dcBmp2,,,angle,dcBmp1,,,,,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();
return ; } return DefWindowProc(hwnd,message,wParam,lParam);
}

windows api(GDI)实现图片旋转的更多相关文章

  1. Windows API 函数列表 附帮助手册

    所有Windows API函数列表,为了方便查询,也为了大家查找,所以整理一下贡献出来了. 帮助手册:700多个Windows API的函数手册 免费下载 API之网络函数 API之消息函数 API之 ...

  2. Windows API Finishing

    input { font-size: 14px; height: 26px } td { border-style: none; border-color: inherit; border-width ...

  3. Windows API函数大全(完整)

    Windows API函数大全,从事软件开发的朋友可以参考下 1. API之网络函数 WNetAddConnection 创建同一个网络资源的永久性连接 WNetAddConnection2 创建同一 ...

  4. [windows菜鸟]Windows API函数大全(完整)

    Windows API函数大全,从事软件开发的朋友可以参考下 1. API之网络函数 WNetAddConnection 创建同一个网络资源的永久性连接 WNetAddConnection2 创建同一 ...

  5. WINDOWS API 大全(一)

    1. API之网络函数 WNetAddConnection 创建同一个网络资源的永久性连接 WNetAddConnection2 创建同一个网络资源的连接 WNetAddConnection3 创建同 ...

  6. 在VBA中使用Windows API

    VBA是一种强大的编程语言,可用于自定义Microsoft Office解决方案.通过使用VBA处理一个或多个Office应用程序对象模型,可以容易地修改Office应用程序的功能或者能够使两个或多个 ...

  7. 学习之路三十九:新手学习 - Windows API

    来到了新公司,一开始就要做个程序去获取另外一个程序里的数据,哇,挑战性很大. 经过两周的学习,终于搞定,主要还是对Windows API有了更多的了解. 文中所有的消息常量,API,结构体都整理出来了 ...

  8. windows API 开发飞机订票系统 图形化界面 (二)

    首先,用到的数据结构的定义.以及全局变量和函数的声明如下: // Flight.c : 定义应用程序的入口点. // #include "stdafx.h" //订单 typede ...

  9. C#中调用Windows API的要点 .

    介绍 API(Application Programming Interface),我想大家不会陌生,它是我们Windows编程的常客,虽然基于.Net平台的C#有了强大的类库,但是,我们还是不能否认 ...

随机推荐

  1. robotframework+python3+selenium之创建第一个项目---第三集

    1.新建一个project 选择Directory,则是文件夹 2.选择文件,创建new suite    test_1 3.创建test case   baidu_test 4.此时界面如图: 5. ...

  2. java创建一个空白zip

    String zipath = localpath+zipname+".zip"; public static void createNewzip(String zipath) t ...

  3. 30 System类

    System类代表系统,系统级的很多属性和控制方法都放置在该类的内部.该类位于java.lang包.由于该类的构造方法是private的,所以无法创建该类的对象,也就是无法实例化该类.其内部的成员变量 ...

  4. python 模拟按键模拟键盘按键按下放开

    python模拟按键 pip install pypiwin32安装库 import win32conimport win32apiimport time 导入 打个比方模拟A win32api.ke ...

  5. leetcode-52-N皇后②

    题目描述: 方法一:回溯 class Solution: def totalNQueens(self, n: int) -> int: def backtrack(i,tmp,col,z_dia ...

  6. unity 打包Apk生成签名证书keystore

    进行Android项目开发中想要将androidapp导出为apk的时候需要选择一个数字证书,即keystore文件(android.keystore),它用来对我们的APP进行签名,是导出APP的一 ...

  7. Dart编程数字Number

    Dart数字可以分为: int - 任意大小的整数. int 数据类型用于表示整数. double -64位(双精度)浮点数,由IEEE 754标准规定. 在 double 数据类型用于表示小数 in ...

  8. java script 数组去重两种方法

    第一种方法: var arr=[1,1,2,3,4,4,4,5,6,6,6,6];    var arrb=Array();    for(var i=0;i<arr.length;i++)   ...

  9. zjoi 2008 树的统计——树链剖分

    比较基础的一道树链剖分的题 大概还是得说说思路 树链剖分是将树剖成很多条链,比较常见的剖法是按儿子的size来剖分,剖分完后对于这课树的询问用线段树维护——比如求路径和的话——随着他们各自的链向上走, ...

  10. NX二次开发-UFUN获得边的类型UF_MODL_ask_edge_type

    1 NX11+VS2013 2 3 #include <uf.h> 4 #include <uf_ui.h> 5 #include <uf_modl.h> 6 #i ...