【问题标题】:create transparent image from png, winapi从png,winapi创建透明图像
【发布时间】:2013-03-26 18:36:08
【问题描述】:

我创建了一个简单的表单在winapi中测试:我在这里上传:http://pastebin.com/7dNjE1Tb

我想放一个简单的png文件到我的hwnd,比如这张图:http://www.ledavi-network.com/includes/images/bg_shadow_png.png

我知道我应该使用这个:http://msdn.microsoft.com/en-us/library/windows/desktop/dd145141(v=vs.85).aspx,但我是 winapi 的新手,我没有找到任何示例如何使用这个 TransparentBlt 函数。

有人可以帮我创建一个非常简单的例子吗?

编辑: 但我想做什么? 我想创建一个带有阴影的特殊背景的按钮。因此,如果有人知道更简单的方法,我会忘记使用 TransparentBlt。那么还有其他解决方案吗?

【问题讨论】:

  • 如果您使用 GDI+ Image 代替,您几乎肯定会更轻松地显示 PNG。
  • 也许,我更新了我的问题,请阅读

标签: c++ winapi png transparency


【解决方案1】:

在这里,这将完成这项工作。您需要确保为 AlphaBlend 链接了 gdiplus 和 msimg32 库(TransparentBlt 假定图像中的 single rgb 颜色将被视为透明。即,使用 TransparentBlt 时它只是 1 位透明度- 完全不透明或完全透明。)

您(大概)希望使用 AlphaBlend 来完成这项工作。

注意 - 我没有费心将 WM_ERASEBKGND 添加到 WndProc 函数。因此,每次重新绘制图像时,它都会直接绘制在已经存在的顶部(尝试调整窗口大小)。只需在erasebkg 中做一个FillRect,就可以了。

编辑:代码更新为使用带有 NULL hbitmap 的 displayImage 来做背景。

来吧:

#define WIN32_LEAN_AND_MEAN
#define WINVER 0x0600       // needed for alphablend function..

#include <windows.h>
#include <gdiplus.h>

const char g_szClassName[] = "myWindowClass";


// BMP, GIF, JPEG, PNG, TIFF, Exif, WMF, and EMF
// requires GDIPlus
HBITMAP mLoadImg(WCHAR *szFilename)
{
   HBITMAP result=NULL;

   Gdiplus::Bitmap* bitmap = new Gdiplus::Bitmap(szFilename,false);
   bitmap->GetHBITMAP(NULL, &result);
   delete bitmap;
   return result;
}

//void CStaticImg::displayImage(HBITMAP mBmp, HWND mHwnd)
void displayImage(HBITMAP mBmp, HWND mHwnd)
{
    RECT myRect;
    BITMAP bm;
    HDC screenDC, memDC;
    HBITMAP oldBmp;
    BLENDFUNCTION bf;

    GetObject(mBmp, sizeof(bm), &bm);

    bf.BlendOp = AC_SRC_OVER;
    bf.BlendFlags = 0;
    bf.SourceConstantAlpha = 0xff;

    bf.AlphaFormat = AC_SRC_ALPHA;

    screenDC = GetDC(mHwnd);
    GetClientRect(mHwnd, &myRect);

    if (mBmp == NULL)
        FillRect(screenDC, &myRect, WHITE_BRUSH);

    else
    {
        memDC = CreateCompatibleDC(screenDC);
        oldBmp = (HBITMAP)SelectObject(memDC, mBmp);
        AlphaBlend (screenDC, 0, 0, myRect.right,myRect.bottom, memDC, 0, 0, bm.bmWidth,bm.bmHeight, bf);
        SelectObject(memDC, oldBmp);
        DeleteDC(memDC);
        ReleaseDC(mHwnd, screenDC);
    }
}



// Step 4: the Window Procedure
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    static HBITMAP myImage;
    switch(msg)
    {
        case WM_CLOSE:
            DestroyWindow(hwnd);
        break;

        case WM_ERASEBKGND:
            displayImage(NULL, hwnd);
        break;

        case WM_CREATE:
            myImage = mLoadImg(L"bg_shadow_png.png");
        break;

        case WM_PAINT:
            //displayImage(HBITMAP mBmp, HWND mHwnd);
            displayImage(myImage, hwnd);
            ValidateRect(hwnd, NULL);
            break;

        case WM_DESTROY:
            PostQuitMessage(0);
        break;
        default:
            return DefWindowProc(hwnd, msg, wParam, lParam);
    }
    return 0;
}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
    LPSTR lpCmdLine, int nCmdShow)
{
    WNDCLASSEX wc;
    HWND hwnd;
    MSG Msg;

    static Gdiplus::GdiplusStartupInput gdiplusStartupInput;
    static ULONG_PTR gdiplusToken;
    // so we can load all the image formats that windows supports natively - (I'm using a transparent PNG on the main dialog)
    GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);


    //Step 1: Registering the Window Class
    wc.cbSize        = sizeof(WNDCLASSEX);
    wc.style         = 0;
    wc.lpfnWndProc   = WndProc;
    wc.cbClsExtra    = 0;
    wc.cbWndExtra    = 0;
    wc.hInstance     = hInstance;
    wc.hIcon         = LoadIcon(NULL, IDI_APPLICATION);
    wc.hCursor       = LoadCursor(NULL, IDC_ARROW);
    wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
    wc.lpszMenuName  = NULL;
    wc.lpszClassName = g_szClassName;
    wc.hIconSm       = LoadIcon(NULL, IDI_APPLICATION);

    if(!RegisterClassEx(&wc))
    {
        MessageBox(NULL, "Window Registration Failed!", "Error!",
            MB_ICONEXCLAMATION | MB_OK);
        return 0;
    }

    // Step 2: Creating the Window
    hwnd = CreateWindowEx(
        WS_EX_CLIENTEDGE,
        g_szClassName,
        "The title of my window",
        WS_OVERLAPPEDWINDOW,
        CW_USEDEFAULT, CW_USEDEFAULT, 240, 120,
        NULL, NULL, hInstance, NULL);

    if(hwnd == NULL)
    {
        MessageBox(NULL, "Window Creation Failed!", "Error!",
            MB_ICONEXCLAMATION | MB_OK);
        return 0;
    }

    ShowWindow(hwnd, nCmdShow);
    UpdateWindow(hwnd);

    // Step 3: The Message Loop
    while(GetMessage(&Msg, NULL, 0, 0) > 0)
    {
        TranslateMessage(&Msg);
        DispatchMessage(&Msg);
    }

    Gdiplus::GdiplusShutdown(gdiplusToken);
    return Msg.wParam;
}

【讨论】:

  • 谢谢,但我收到两个警告:warning: passing NULL to non-pointer argument 1 of 'Gdiplus::Color::Color(Gdiplus::ARGB)' [-Wconversion-null] warning: deprecated conversion from string constant to 'WCHAR* {aka wchar_t*}' [-Wwrite-strings]
  • 如果我改变背景还有一个问题,例如:wc.hbrBackground = (HBRUSH) GetStockObject(BLACK_BRUSH);什么都没有发生,图片没有出现
  • 好的,我解决了 wc.hbrBackground 问题,但警告仍然存在
  • 好吧,除了警告之外还有一个问题,当我调整窗口大小时,图像消失了。为什么?
  • 不客气。总是很高兴分享有趣的学习内容。 :) 是的,我也收到了这两个警告。您可以通过将第一个将 NULL 更改为 0 来对它们进行核对,第二个可以通过将 (wchar_t*) 放在大写 L 之前来中性化。第三,当我按照您的建议在第 114 行更改背景时,输出不变。您可能希望处理 WM_ERASEBKG。我不记得了,我已经有一段时间没有用 GDI/GDI+ 做过任何事情了。无论如何,希望这足以让您深入了解文档并找到自己的方式。 :)
猜你喜欢
  • 2012-06-16
  • 2011-11-29
  • 2011-08-31
  • 2023-04-01
  • 1970-01-01
  • 2011-10-19
  • 2018-10-09
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多