(我写了这个答案,并认为 OP 出于某种原因想要 Gdiplus ...常规 GDI 几乎是一样的,尽管在这种情况下实际上有一个 CreatRoundRectRgn(...))
您可以使用带有 Region 的 SetClip 成员函数设置 Gdiplus::Graphics 对象的剪辑区域。您可以从Path 创建一个Region,但在Gdi+ 中显然没有开箱即用的方法来创建圆角矩形形状的路径,因此您必须手动完成。 StackOverflow 上有一个关于 doing this in C# 的答案,另一个将其移植到 C++/Win32 here。
代码如下:
#include <windows.h>
#include <objidl.h>
#include <gdiplus.h>
namespace gdi = Gdiplus;
#pragma comment (lib,"Gdiplus.lib")
void GetRoundRectPath(gdi::GraphicsPath* pPath, gdi::Rect r, int dia)
{
// diameter can't exceed width or height
if (dia > r.Width) dia = r.Width;
if (dia > r.Height) dia = r.Height;
// define a corner
gdi::Rect Corner(r.X, r.Y, dia, dia);
// begin path
pPath->Reset();
// top left
pPath->AddArc(Corner, 180, 90);
// tweak needed for radius of 10 (dia of 20)
if (dia == 20)
{
Corner.Width += 1;
Corner.Height += 1;
r.Width -= 1; r.Height -= 1;
}
// top right
Corner.X += (r.Width - dia - 1);
pPath->AddArc(Corner, 270, 90);
// bottom right
Corner.Y += (r.Height - dia - 1);
pPath->AddArc(Corner, 0, 90);
// bottom left
Corner.X -= (r.Width - dia - 1);
pPath->AddArc(Corner, 90, 90);
// end path
pPath->CloseFigure();
}
VOID OnPaint(HDC hdc, gdi::Image* img)
{
gdi::Graphics g(hdc);
gdi::GraphicsPath path;
GetRoundRectPath(&path, { 10,10,512,512 }, 50);
gdi::Region rgn(&path);
g.SetClip(&rgn);
g.DrawImage(img, 10, 10);
}
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
INT WINAPI WinMain(HINSTANCE hInstance, HINSTANCE, PSTR, INT iCmdShow)
{
HWND hWnd;
MSG msg;
WNDCLASS wndClass;
gdi::GdiplusStartupInput gdiplusStartupInput;
ULONG_PTR gdiplusToken;
// Initialize GDI+.
gdi::GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);
{
// nest everything in a scope so that the image doesnt
// get destroyed after Gdiplus has been shut down.
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 = TEXT("cliptorrect");
RegisterClass(&wndClass);
gdi::Image img(TEXT("C:\\test\\lenna.png"));
hWnd = CreateWindow(
TEXT("cliptorrect"),
TEXT("clip to round rect"),
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
548,
572,
NULL,
NULL,
hInstance,
&img
);
ShowWindow(hWnd, iCmdShow);
UpdateWindow(hWnd);
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
gdi::GdiplusShutdown(gdiplusToken);
return msg.wParam;
} // WinMain
LRESULT CALLBACK WndProc(HWND hWnd, UINT message,
WPARAM wParam, LPARAM lParam)
{
HDC hdc;
PAINTSTRUCT ps;
switch (message)
{
case WM_CREATE: {
CREATESTRUCT* cs = reinterpret_cast<CREATESTRUCT*>(lParam);
SetWindowLongPtr(hWnd, GWLP_USERDATA, reinterpret_cast<LONG>(cs->lpCreateParams));
} return 0;
case WM_PAINT:
hdc = BeginPaint(hWnd, &ps);
OnPaint(hdc, reinterpret_cast<gdi::Image*>(GetWindowLongPtr(hWnd, GWLP_USERDATA)));
EndPaint(hWnd, &ps);
return 0;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
}
上面的输出看起来像
不过,我不确定 GDi+ 中是否有办法获得抗锯齿效果。