Можно ли загрузить PNG из файла в HBITMAP с помощью функций Win32 GDI? Если нет, то что было бы самым легким решением без использования внешних библиотек (например, libpng)?
Как загрузить PNG-образ с помощью Win32/GDI (если нет GDI +)?
Ответ 1
Вы можете использовать компонент Windows Imaging для загрузки файлов PNG (в Windows XP с пакетом обновления 2 (SP2) и более поздних версий). См. Журнал MSDN для ознакомления с тем, как использовать API и мой пост в блоге для образца кода, который загружает PNG из IStream и преобразует его в HBITMAP.
Ответ 2
Нет необходимости использовать компонент Windows Imaging Component, GDI + или PNG. Вы можете использовать функцию Icon.
-
Добавить новый значок (ICO_PNG) в ресурсы проекта VC с пользовательской шириной и высотой (Редактор ресурсов → Изображение → Тип нового изображения). Скопируйте здесь изображение png и используйте прозрачный цвет Fill Tool +, чтобы сделать значок прозрачным.
-
Добавьте в свой диалог управление изображением (IDC_PNG) (Type = Owner draw).
-
Код процедуры диалога:
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;
}
}
}
Ответ 3
Вы можете сделать это с помощью API StretchDIBits
, но ограничены наличием ОС/драйверов.
Подробнее см. документацию MSDN:
http://msdn.microsoft.com/en-us/library/dd145121(v=VS.85).aspx
http://msdn.microsoft.com/en-us/library/dd145107(VS.85).aspx
Я искренне извиняюсь за то, что вы обманываете вас, ребята, интересующиеся этой проблемой.
Позвольте мне исправить мою ошибку.
Нет StretchDIBits
для рисования PNG.
Вам лучше попробовать WIC-метод или рассмотреть возможность интеграции GDI + в ваши проекты.
Ответ 4
Мы можем отобразить изображение png через GDI, выполнив два следующих шага при создании вашего окна (случай WM_CREATE
в функции оконной процедуры):
- загрузить png файл (через libpng или stb image), значения пикселей сохраняются в переменной, скажем,
buffer
- создать экземпляр
HBITMAP
, используяbuffer
в функцииCreateBitmap()
Здесь исполняемый код на чистом C и main()
в качестве функции точки входа (libpng и zlib взяты из моей собственной компиляции opencv)
#include <stdio.h>
#include <windows.h>
#include "png.h"
#define CRTDBG_MAP_ALLOC
#include <crtdbg.h>
// **NB**: You may use OpenCV prebuilt package 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
Ответ 5
Вам не нужна внешняя библиотека для отображения PNG в Win32
Существует множество методов, таких как OleLoadPicture() (KB218972), IImgCtx, IShellImageDataFactory, IWICImagingFactory и т.д.
Ответ 6
Не думайте, что GDI поддерживает png, посмотрели ли вы на libpng