如何使用 Win32/GDI 加载 PNG 图像(如果可能的话,没有 GDI+)?

发布于 2024-10-09 23:48:25 字数 86 浏览 1 评论 0原文

是否可以使用 Win32 GDI 函数将 PNG 从文件加载到 HBITMAP 中?如果没有,在不使用外部库(如 libpng)的情况下最轻的解决方案是什么?

Is it possible to load a PNG from a file into an HBITMAP using Win32 GDI functions? If not, what would be the lightest solution without using external libraries (like libpng)?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

好听的两个字的网名 2024-10-16 23:48:25

您可以使用 Windows 成像组件 加载 PNG 文件(在 Windows XP SP2 及更高版本上)。请参阅 MSDN 杂志(原文位于 网络存档 - 格式更好一点)了解如何使用 API 和 我的博客文章提供了从 IStream 加载 PNG 并将其转换为 HBITMAP 的代码示例。

You can use the Windows Imaging Component to load PNG files (on Windows XP SP2 and later). See MSDN Magazine (original in web archive - a bit better formatting) for an introduction on how to use the API and my blog post for a code sample that loads a PNG from an IStream and converts it to an HBITMAP.

心房敞 2024-10-16 23:48:25

无需使用 Windows Imaging Component、GDI+ 或 PNG 库。您可以使用图标功能。

  1. 将新图标(ICO_PNG)添加到具有自定义宽度和高度的VC项目资源中(资源编辑器->图像->新图像类型)。将您的 png 图片复制到此处,然后使用填充工具+透明色使图标透明。

  2. 将优化校准 (IDC_PNG) 添加到您的对话框(类型 = 所有者绘制)。

  3. 对话框程序代码:

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;
        }
    }
}

There is no need to use Windows Imaging Component, GDI+ or PNG library. You can use Icon functionality.

  1. Add new icon (ICO_PNG) to VC project resources with custom Width and Height (Resource Editor->Image->New Image Type). Copy Your png image here and use Fill Tool+transparent color to make icon transparent.

  2. Add Picture Control (IDC_PNG) to Your dialog (Type = Owner draw).

  3. Dialog procedure code:

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;
        }
    }
}
无戏配角 2024-10-16 23:48:25

您可以使用 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+ 集成到您的项目中。

You can do it with StretchDIBits API, but limited by OS/driver availability.

Consult MSDN documentation for details:

http://msdn.microsoft.com/en-us/library/dd145121(v=VS.85).aspx

http://msdn.microsoft.com/en-us/library/dd145107(VS.85).aspx


I sincerely apologize for misleading you guys interested in this issue.
Let me correct my mistake.
No StretchDIBits for PNG drawing.
You'd better try WIC method or consider way to integrate GDI+ in your projects.

栀子花开つ 2024-10-16 23:48:25

我们可以通过GDI显示png图像,在创建窗口时通过以下两个步骤(在窗口过程函数中的情况下WM_CREATE):

  1. 加载png文件(通过libpng或stb图像),像素值保存在变量中,说 buffer
  2. CreateBitmap() 函数中使用 buffer 创建 HBITMAP 实例

这是可运行的代码,它是纯的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'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

We can display png image via GDI, by the following two steps when creating your window(case WM_CREATE in window procedure function):

  1. load png file (via libpng or stb image), pixel values saved in a variable, say buffer
  2. create HBITMAP instance using buffer in CreateBitmap() function

Here's the runnable code, which is in pure C and main() as entry point function (libpng and zlib are from my own opencv compilation)

#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;

}

Reference: https://www.cnblogs.com/mr-wid/archive/2013/04/22/3034840.html

最单纯的乌龟 2024-10-16 23:48:25

vladimir_hr 的答案很简单。

遵循简单的步骤。

在资源头文件中声明如下:
#define IDI_PNG 1000

资源文件*.rc中有:
IDI_PNG ICON "protractor.ico"

图标文件。
使用支持自定义大小而不是标准 Windows 图标大小的图标编辑器将您的(透明)png 文件转换为图标文件,将此 png 图像保存为图标图像。

其余的只是在 DC 之间传输。

The answer by vladimir_hr is simplicity itself.

Simple steps to follow.

In the resources header file declare like:
#define IDI_PNG 1000

In the resource file *.rc have:
IDI_PNG ICON "protractor.ico"

The icon file.
Convert your (transparent) png file into an icon file by using an icon editor that support custom size instead of the standard Windows' icon sizes, save this png image as an icon image.

The rest is just blitting between DC's.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文