C++ 我将如何使用 Win32/GDI 加载 PNG 图像(如果可能,不要使用 GDI+)?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/4567875/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-28 15:46:01  来源:igfitidea点击:

How would I load a PNG image using Win32/GDI (no GDI+ if possible)?

c++imagewinapipnggdi

提问by jnm2

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)?

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

回答by Bradley Grainger

You can use the Windows Imaging Componentto load PNG files (on Windows XP SP2 and later). See MSDN Magazinefor an introduction on how to use the API and my blog postfor a code sample that loads a PNG from an IStream and converts it to an HBITMAP.

您可以使用Windows Imaging Component加载 PNG 文件(在 Windows XP SP2 和更高版本上)。有关如何使用 API 的介绍,请参阅MSDN 杂志,请参阅我的博客文章,了解从 IStream 加载 PNG 并将其转换为 HBITMAP 的代码示例。

回答by vadim_hr

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

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

  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:

  1. 使用自定义宽度和高度(资源编辑器->图像->新图像类型)向VC项目资源添加新图标(ICO_PNG)。在此处复制您的 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;
        }
    }
}

回答by 9dan

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

您可以使用StretchDIBitsAPI 来实现,但受操作系统/驱动程序可用性的限制。

Consult MSDN documentation for details:

有关详细信息,请参阅 MSDN 文档:

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

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

http://msdn.microsoft.com/en-us/library/dd145107(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 StretchDIBitsfor PNG drawing. You'd better try WIC method or consider way to integrate GDI+ in your projects.

对于误导对这个问题感兴趣的你们,我深表歉意。让我纠正我的错误。否StretchDIBitsPNG 绘图。您最好尝试 WIC 方法或考虑将 GDI+ 集成到您的项目中的方法。

回答by HaxtraZ

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

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

  1. load png file (via libpng or stb image), pixel values saved in a variable, say buffer
  2. create HBITMAPinstance using bufferin CreateBitmap()function
  1. 加载 png 文件(通过 libpng 或 stb 图像),像素值保存在变量中,例如 buffer
  2. HBITMAP使用bufferinCreateBitmap()函数创建实例

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)

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

}

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

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