VC利用PNG图片制作异形窗口的源代码如下:
首先,在项目中添加头文件"libpng/png.h"和"zlib/zlib.h"。
然后,定义一个函数LoadPng(),用于加载PNG图片并获取图片数据和透明度信息,具体代码如下:
```c++
int LoadPng(const char* fileName, int* outWidth, int* outHeight, unsigned char** outData, std::vector<unsigned char>& outAlpha)
{
FILE* file = fopen(fileName, "rb");
if (!file) return 0;
png_byte header[8];
fread(header, 1, 8, file);
if (png_sig_cmp(header, 0, 8)) return 0;
png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
if (!png_ptr) return 0;
png_infop info_ptr = png_create_info_struct(png_ptr);
if (!info_ptr)
{
png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL);
return 0;
}
png_infop end_info = png_create_info_struct(png_ptr);
if (!end_info)
{
png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
return 0;
}
if (setjmp(png_jmpbuf(png_ptr)))
{
png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
fclose(file);
return 0;
}
png_init_io(png_ptr, file);
png_set_sig_bytes(png_ptr, 8);
png_read_info(png_ptr, info_ptr);
int width = png_get_image_width(png_ptr, info_ptr);
int height = png_get_image_height(png_ptr, info_ptr);
png_byte color_type = png_get_color_type(png_ptr, info_ptr);
png_byte bit_depth = png_get_bit_depth(png_ptr, info_ptr);
if (bit_depth == 16)
png_set_strip_16(png_ptr);
if (color_type == PNG_COLOR_TYPE_PALETTE)
png_set_palette_to_rgb(png_ptr);
if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8)
png_set_expand_gray_1_2_4_to_8(png_ptr);
if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS))
png_set_tRNS_to_alpha(png_ptr);
if (color_type == PNG_COLOR_TYPE_RGB ||
color_type == PNG_COLOR_TYPE_GRAY ||
color_type == PNG_COLOR_TYPE_PALETTE)
png_set_filler(png_ptr, 0xFF, PNG_FILLER_AFTER);
if (color_type == PNG_COLOR_TYPE_GRAY ||
color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
png_set_gray_to_rgb(png_ptr);
png_read_update_info(png_ptr, info_ptr);
png_bytep* row_pointers = new png_bytep[height];
for (int y = 0; y < height; ++y)
row_pointers[y] = new png_byte[png_get_rowbytes(png_ptr, info_ptr)];
png_read_image(png_ptr, row_pointers);
std::vector<unsigned char> alpha;
alpha.resize(width * height);
for (int y = 0; y < height; ++y)
for (int x = 0; x < width; ++x)
{
png_bytep px = &(row_pointers[y][x * 4]);
alpha[y * width + x] = px[3];
px[3] = 0xFF; //将alpha设为不透明
}
*outData = *row_pointers;
*outWidth = width;
*outHeight = height;
outAlpha = alpha;
for (int y = 0; y < height; ++y)
delete[] row_pointers[y];
delete[] row_pointers;
fclose(file);
return 1;
}
```
接下来,定义如下的异形窗口类:
```c++
class ShapedWindow
{
public:
ShapedWindow() : m_hwnd(NULL), m_hbmp(NULL), m_hit(false), m_drag(false)
{
LoadPng("shape.png", &m_width, &m_height, &m_data, m_alpha);
}
void Create(int x, int y, int width, int height)
{
m_hwnd = CreateWindowEx(NULL, TEXT("ShapedWindow"), NULL, WS_POPUP | WS_VISIBLE,
x, y, width, height, NULL, NULL, NULL, this);
}
bool HitTest(int x, int y)
{
if (m_hit || !m_hwnd) return false;
HRGN hClipRgn = CreateRectRgn(0, 0, 0, 0);
GetWindowRgn(m_hwnd, hClipRgn);
POINT pt = { x, y };
bool bHit = PtInRegion(hClipRgn, pt.x, pt.y) != 0;
DeleteObject(hClipRgn);
return bHit;
}
void Move(int x, int y)
{
SetWindowPos(m_hwnd, NULL, x, y, 0, 0, SWP_NOZORDER | SWP_NOSIZE);
}
private:
static LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
ShapedWindow* pThis = NULL;
if (uMsg == WM_CREATE)
{
LPCREATESTRUCT lpcs = reinterpret_cast<LPCREATESTRUCT>(lParam);
pThis = reinterpret_cast<ShapedWindow*>(lpcs->lpCreateParams);
SetWindowLongPtr(hwnd, GWLP_USERDATA, reinterpret_cast<ULONG_PTR>(pThis));
pThis->m_hwnd = hwnd;
}
else
{
pThis = reinterpret_cast<ShapedWindow*>(GetWindowLongPtr(hwnd, GWLP_USERDATA));
if (!pThis) return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
switch (uMsg)
{
case WM_PAINT:
{
HDC hdc;
PAINTSTRUCT ps;
hdc = BeginPaint(hwnd, &ps);
if (pThis->m_hbmp != NULL) DeleteObject(pThis->m_hbmp);
pThis->m_hbmp = CreateBitmap(pThis->m_width, pThis->m_height, 1, 32, pThis->m_data);
HDC hdcMem = CreateCompatibleDC(hdc);
SelectObject(hdcMem, pThis->m_hbmp);
BLENDFUNCTION bf = { AC_SRC_OVER, 0, 255, AC_SRC_ALPHA };
AlphaBlend(hdc, 0, 0, pThis->m_width, pThis->m_height, hdcMem, 0, 0, pThis->m_width, pThis->m_height, bf);
DeleteDC(hdcMem);
EndPaint(hwnd, &ps);
}
break;
case WM_NCHITTEST:
if (pThis->m_hit) return HTCAPTION;
break;
case WM_MOUSEMOVE:
if (pThis->m_drag)
{
int x = LOWORD(lParam);
int y = HIWORD(lParam);
pThis->Move(x - pThis->m_dragX, y - pThis->m_dragY);
}
break;
case WM_LBUTTONDOWN:
pThis->m_hit = pThis->HitTest(LOWORD(lParam), HIWORD(lParam));
if (pThis->m_hit)
{
pThis->m_drag = true;
pThis->m_dragX = LOWORD(lParam);
pThis->m_dragY = HIWORD(lParam);
}
break;
case WM_LBUTTONUP:
pThis->m_hit = false;
pThis->m_drag = false;
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
return 0;
}
private:
HWND m_hwnd;
unsigned char* m_data;
int m_width, m_height;
std::vector<unsigned char> m_alpha;
HBITMAP m_hbmp;
bool m_hit;
bool m_drag;
int m_dragX;
int m_dragY;
};
```
其中,LoadPng()函数用于加载PNG图片并获取图片数据和透明度信息,ShapedWindow类用于绘制异形窗口和响应窗口消息。
最后,在WinMain()函数中创建异形窗口,并进入消息循环,具体代码如下:
```c++
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
WNDCLASSEX wc = {};
wc.cbSize = sizeof(wc);
wc.lpfnWndProc = ShapedWindow::WindowProc;
wc.hInstance = hInstance;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.lpszClassName = TEXT("ShapedWindow");
RegisterClassEx(&wc);
ShapedWindow win;
win.Create(100, 100, 300, 300);
MSG msg = {};
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return 0;
}
```
这样,一个利用PNG图片制作的异形窗口就完成了。