是否可以使用Win32 GDI函数将PNG从文件加载到HBITMAP中?如果没有,不使用外部库(如libpng)的最轻量级解决方案是什么?
s8vozzvw1#
您可以使用Windows Imaging Component加载PNG文件(在Windows XP SP2及更高版本上)。请参阅MSDN Magazine(原始版本为web archive-格式稍好一些),了解如何使用API和my blog post,了解如何从IStream加载PNG并将其转换为HBITMAP的代码示例。
af7jpaap2#
不需要使用Windows Imaging Component、GDI+或PNG库。您可以使用图标功能。1.添加新图标(ICO_PNG)到VC项目资源中,并自定义宽度和高度(资源编辑器->图像->新图像类型)。复制您的png图像在这里,并使用填充工具+透明颜色,使图标透明。1.将图片控件(IDC_PNG)添加到您的对话框(类型=所有者绘制)。1.对话程序代码:
switch (msg) { ... case WM_DRAWITEM: { LPDRAWITEMSTRUCT pDIS = (LPDRAWITEMSTRUCT)lParam; if (pDIS->CtlID == IDC_PNG) { HICON hIcon = (HICON)LoadImage(GetModuleHandle(0), MAKEINTRESOURCE(ICO_LOGO), IMAGE_ICON, 0, 0, LR_LOADTRANSPARENT); DrawIconEx(pDIS->hDC, 0, 0, hIcon, 0, 0, 0, NULL, DI_NORMAL); DestroyIcon(hIcon); return TRUE; } } }
laximzn53#
您可以使用StretchDIBits API来实现,但受操作系统/驱动程序可用性的限制。有关详细信息,请参阅MSDN文档:http://msdn.microsoft.com/en-us/library/dd145121(v=VS.85).aspxhttp://msdn.microsoft.com/en-us/library/dd145107(VS.85).aspx我真诚地道歉,误导了你们对这个问题感兴趣的人。让我纠正我的错误。PNG绘图没有StretchDIBits。您最好尝试WIC方法或考虑在您的项目中集成GDI+的方法。
StretchDIBits
zfciruhq4#
我们可以通过GDI显示png图像,在创建窗口时通过以下两个步骤(窗口过程函数中的case WM_CREATE):1.加载png文件(通过libpng或stb image),像素值保存在变量中,比如buffer1.在CreateBitmap()函数中使用buffer创建HBITMAP示例下面是可运行的代码,它是纯C语言编写的,main()作为入口点函数(libpng和zlib来自我自己的opencv编译)
WM_CREATE
buffer
CreateBitmap()
HBITMAP
main()
#include <stdio.h> #include <windows.h> #include "png.h" #define CRTDBG_MAP_ALLOC #include <crtdbg.h> // **NB**: You may use OpenCV prebuilt package's self contained libpng.lib file // or, maybe, you can also compile it from source (which cost time and not necessary), see: `http://www.libpng.org` and `https://www.zlib.net` #define LIBPNG_PTH "D:/opencv_249/build/x64/vc12/staticlib/libpng.lib" #define ZLIB_PTH "D:/opencv_249/build/x64/vc12/staticlib/zlib.lib" #pragma comment(lib, LIBPNG_PTH) #pragma comment(lib, ZLIB_PTH) typedef struct MyRect { int x, y, width, height; } MyRect; char bitmap_im_pth[100]; typedef struct MyWindow { HDC dc; //HGDIOBJ image; HBITMAP hBmp; unsigned char* imdata; } MyWindow; MyWindow* my_window; enum ImageType {BMP, PNG}; long ReadPngData(const char *szPath, int *pnWidth, int *pnHeight, unsigned char **cbData) { FILE *fp = NULL; long file_size = 0, pos = 0, mPos = 0; int color_type = 0, x = 0, y = 0, block_size = 0; png_infop info_ptr; png_structp png_ptr; png_bytep *row_point = NULL; fp = fopen(szPath, "rb"); if (!fp) return -1; png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0); info_ptr = png_create_info_struct(png_ptr); png_init_io(png_ptr, fp); png_read_png(png_ptr, info_ptr, PNG_TRANSFORM_EXPAND, 0); *pnWidth = png_get_image_width(png_ptr, info_ptr); *pnHeight = png_get_image_height(png_ptr, info_ptr); color_type = png_get_color_type(png_ptr, info_ptr); file_size = (*pnWidth) * (*pnHeight) * 4; *cbData = (unsigned char *)malloc(file_size); row_point = png_get_rows(png_ptr, info_ptr); block_size = color_type == 6 ? 4 : 3; for (x = 0; x < *pnHeight; x++) for (y = 0; y < *pnWidth*block_size; y += block_size) { (*cbData)[pos++] = row_point[x][y + 2]; //B (*cbData)[pos++] = row_point[x][y + 1]; //G (*cbData)[pos++] = row_point[x][y + 0]; //R (*cbData)[pos++] = row_point[x][y + 3]; //alpha } png_destroy_read_struct(&png_ptr, &info_ptr, 0); fclose(fp); return file_size; } LRESULT __stdcall WindowProcedure(HWND window, unsigned int msg, WPARAM wp, LPARAM lp) { int im_width, im_height; int image_type = PNG; switch (msg) { case WM_CREATE: if (image_type == BMP) { my_window->hBmp = (HBITMAP)LoadImage(NULL, "lena512.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE); } else if (image_type == PNG) { ReadPngData("Lena.png", &im_width, &im_height, &my_window->imdata); my_window->hBmp = CreateBitmap(im_width, im_height, 32, 1, my_window->imdata); } if (my_window->hBmp == NULL) MessageBox(window, "Could not load image!", "Error", MB_OK | MB_ICONEXCLAMATION); break; case WM_PAINT: { BITMAP bm; PAINTSTRUCT ps; HDC hdc = BeginPaint(window, &ps); SetStretchBltMode(hdc, COLORONCOLOR); my_window->dc = CreateCompatibleDC(hdc); HBITMAP hbmOld = SelectObject(my_window->dc, my_window->hBmp); GetObject(my_window->hBmp, sizeof(bm), &bm); #if 1 BitBlt(hdc, 0, 0, bm.bmWidth, bm.bmHeight, my_window->dc, 0, 0, SRCCOPY); #else RECT rcClient; GetClientRect(window, &rcClient); int nWidth = rcClient.right - rcClient.left; int nHeight = rcClient.bottom - rcClient.top; StretchBlt(hdc, 0, 0, nWidth, nHeight, hdcMem, 0, 0, bm.bmWidth, bm.bmHeight, SRCCOPY); #endif SelectObject(my_window->dc, hbmOld); DeleteDC(my_window->dc); EndPaint(window, &ps); } break; case WM_DESTROY: printf("\ndestroying window\n"); PostQuitMessage(0); return 0L; case WM_LBUTTONDOWN: printf("\nmouse left button down at (%d, %d)\n", LOWORD(lp), HIWORD(lp)); // fall thru default: //printf("."); return DefWindowProc(window, msg, wp, lp); } } const char* szWindowClass = "myclass"; ATOM MyRegisterClass(HINSTANCE hInstance) { WNDCLASSEX wc; wc.cbSize = sizeof(WNDCLASSEX); /* Win 3.x */ wc.style = CS_DBLCLKS; wc.lpfnWndProc = WindowProcedure; wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = GetModuleHandle(0); wc.hIcon = LoadIcon(0, IDI_APPLICATION); wc.hCursor = LoadCursor(0, IDC_ARROW); wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); wc.lpszMenuName = 0; wc.lpszClassName = szWindowClass; /* Win 4.0 */ wc.hIconSm = LoadIcon(0, IDI_APPLICATION); return RegisterClassEx(&wc); } BOOL InitInstance(HINSTANCE hInstance, int nCmdShow) { MyRect rect; rect.x = 300; rect.y = 300; rect.width = 640; rect.height = 480; DWORD defStyle = WS_VISIBLE | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_SYSMENU; HWND hwnd = CreateWindowEx(0, szWindowClass, "title", defStyle, rect.x, rect.y, rect.width, rect.height, 0, 0, hInstance, 0); if (!hwnd) { return FALSE; } ShowWindow(hwnd, nCmdShow); UpdateWindow(hwnd); return TRUE; } void create_my_window(MyWindow** _my_window) { MyWindow* my_window = (MyWindow*)malloc(sizeof(MyWindow)); my_window->dc = NULL; my_window->imdata = NULL; my_window->hBmp = NULL; *_my_window = my_window; // write back } void destroy_my_window(MyWindow* my_window) { if (my_window) { if (my_window->imdata) free(my_window->imdata); free(my_window); } } int main() { printf("hello world!\n"); HINSTANCE hInstance = GetModuleHandle(0); int nCmdShow = SW_SHOWDEFAULT; MyRegisterClass(hInstance); create_my_window(&my_window); if (!InitInstance(hInstance, nCmdShow)) { return FALSE; } MSG msg; while (GetMessage(&msg, 0, 0, 0)) { DispatchMessage(&msg); } destroy_my_window(my_window); return 0; }
参考:https://www.cnblogs.com/mr-wid/archive/2013/04/22/3034840.html
gcuhipw95#
弗拉基米尔_hr的答案是简单本身。简单的步骤遵循。在resources头文件中声明如下:#define IDI_PNG 1000在资源文件 *.rc中有:IDI_PNG ICON“protractor.ico”图标文件。使用支持自定义大小而不是标准Windows图标大小的图标编辑器将您的(透明)png文件转换为图标文件,将此png图像保存为图标图像。剩下的就是DC之间的传输了。
5条答案
按热度按时间s8vozzvw1#
您可以使用Windows Imaging Component加载PNG文件(在Windows XP SP2及更高版本上)。请参阅MSDN Magazine(原始版本为web archive-格式稍好一些),了解如何使用API和my blog post,了解如何从IStream加载PNG并将其转换为HBITMAP的代码示例。
af7jpaap2#
不需要使用Windows Imaging Component、GDI+或PNG库。您可以使用图标功能。
1.添加新图标(ICO_PNG)到VC项目资源中,并自定义宽度和高度(资源编辑器->图像->新图像类型)。复制您的png图像在这里,并使用填充工具+透明颜色,使图标透明。
1.将图片控件(IDC_PNG)添加到您的对话框(类型=所有者绘制)。
1.对话程序代码:
laximzn53#
您可以使用
StretchDIBits
API来实现,但受操作系统/驱动程序可用性的限制。有关详细信息,请参阅MSDN文档:
http://msdn.microsoft.com/en-us/library/dd145121(v=VS.85).aspx
http://msdn.microsoft.com/en-us/library/dd145107(VS.85).aspx
我真诚地道歉,误导了你们对这个问题感兴趣的人。让我纠正我的错误。PNG绘图没有
StretchDIBits
。您最好尝试WIC方法或考虑在您的项目中集成GDI+的方法。zfciruhq4#
我们可以通过GDI显示png图像,在创建窗口时通过以下两个步骤(窗口过程函数中的case
WM_CREATE
):1.加载png文件(通过libpng或stb image),像素值保存在变量中,比如
buffer
1.在
CreateBitmap()
函数中使用buffer
创建HBITMAP
示例下面是可运行的代码,它是纯C语言编写的,
main()
作为入口点函数(libpng和zlib来自我自己的opencv编译)参考:https://www.cnblogs.com/mr-wid/archive/2013/04/22/3034840.html
gcuhipw95#
弗拉基米尔_hr的答案是简单本身。
简单的步骤遵循。
在resources头文件中声明如下:#define IDI_PNG 1000
在资源文件 *.rc中有:IDI_PNG ICON“protractor.ico”
图标文件。使用支持自定义大小而不是标准Windows图标大小的图标编辑器将您的(透明)png文件转换为图标文件,将此png图像保存为图标图像。
剩下的就是DC之间的传输了。