c++ - 使用 C++ 在 Windows Mobile 6.x 中处理透明 PNG

标签 c++ windows-mobile png gdi+ transparent

我一直在尝试添加资源并在我的 Windows Mobile 6.x 应用程序中使用一些半透明的 PNG 文件。经过几天的环顾四周并尝试不同的方法后,我决定动态加载和使用 gdiplus.dll 并使用平面 API。一切正常,除了函数 GdipCreateHBITMAPFromBitmap 返回 NotImplemented (6)。知道如何解决这个问题吗?我在此处附加了 3 个文件。

GdiPlusDynamic.cpp:

#include "GdiPlusDynamic.h"
#include "GdiPlusDynamicTools.h"

#include <string>

TAutoStream::TAutoStream(HGLOBAL m_hBuffer)
{
    pStream = NULL;
    switch(::CreateStreamOnHGlobal(m_hBuffer, TRUE, &pStream))
    {
    case E_NOINTERFACE:
        throw std::wstring(L"The specified interface is not supported");
        break;
    case E_OUTOFMEMORY:
        throw std::wstring(L"Not enough memory");
        break;
    default:
        break;
    }
}

TAutoStream::~TAutoStream(void)
{
    if(NULL != pStream)
        pStream->Release();
}

IStream* TAutoStream::get(void)
{
    return pStream;
}

AutoGlobal::AutoGlobal(UINT uFlags, SIZE_T dwBytes) : len(0)
{
    m_hBuffer  = ::GlobalAlloc(uFlags, dwBytes);
    if(IsOk())
    {
        memset(m_hBuffer, 0, dwBytes);
        len = dwBytes;
    }
}

AutoGlobal::~AutoGlobal(void)
{
    if(IsOk())
        ::GlobalFree(m_hBuffer);
}

bool AutoGlobal::IsOk(void)
{
    return (NULL != m_hBuffer);
}
HGLOBAL AutoGlobal::get(void)
{
    return m_hBuffer;
}

TAutoLockedBuff::TAutoLockedBuff(UINT uFlags, SIZE_T dwBytes) : AutoGlobal(uFlags, dwBytes)
{
    pBuffer = NULL;
    if(AutoGlobal::IsOk())
        pBuffer = GlobalLock(m_hBuffer);
}
TAutoLockedBuff::~TAutoLockedBuff(void)
{
    if(IsOk())
        GlobalUnlock(m_hBuffer);
}
bool TAutoLockedBuff::IsOk(void)
{
    return (AutoGlobal::IsOk() && (NULL != pBuffer));
}
void TAutoLockedBuff::CopyFrom(const void* pSrcData, SIZE_T srcLen)
{
    if(IsOk())
        CopyMemory(pBuffer, pSrcData, min(srcLen, len));
}

TDynamicGdiPlus::TDynamicGdiPlus(void) : everythigOK(false)
{
    GdiplusStartupInput dpStartupInfo;

    token                           = 0;
    pGdiplusStartup                 = NULL;
    pGdiplusShutdown                = NULL;
    pGdipCreateBitmapFromStream     = NULL;
    pGdipCreateHBITMAPFromBitmap    = NULL;
    pGdipFree                       = NULL;

    hGdiPlus = ::LoadLibrary(L"gdiplus.dll");
    if(NULL == hGdiPlus)
        throw std::wstring(L"Unable to load 'gdiplus.dll'");

    pGdiplusStartup = (TGdiplusStartup)GetProcAddress(hGdiPlus, L"GdiplusStartup");
    if(NULL == pGdiplusStartup)
        throw std::wstring(L"Unable to get the address of 'GdiplusStartup'");

    pGdiplusShutdown = (TGdiplusShutdown)GetProcAddress(hGdiPlus, L"GdiplusShutdown");
    if(NULL == pGdiplusShutdown)
        throw std::wstring(L"Unable to get the address of 'GdiplusShutdown'");

    pGdipCreateBitmapFromStream = (TGdipCreateBitmapFromStream)GetProcAddress(hGdiPlus, L"GdipCreateBitmapFromStreamICM");
    if(NULL == pGdipCreateBitmapFromStream)
        throw std::wstring(L"Unable to get the address of 'GdipCreateBitmapFromStreamICM'");

    pGdipCreateHBITMAPFromBitmap = (TGdipCreateHBITMAPFromBitmap)GetProcAddress(hGdiPlus, L"GdipCreateHBITMAPFromBitmap");
    if(NULL == pGdipCreateHBITMAPFromBitmap)
        throw std::wstring(L"Unable to get the address of 'GdipCreateHBITMAPFromBitmap'");

    pGdipFree = (TGdipFree)GetProcAddress(hGdiPlus, L"GdipFree");
    if(NULL == pGdipFree)
        throw std::wstring(L"Unable to get the address of 'GdipFree'");

    if(Status::Ok != pGdiplusStartup(&token, &dpStartupInfo, NULL))
        throw std::wstring(L"Unable to start 'GDI Plus'");
    else
        everythigOK = true;
}

TDynamicGdiPlus::~TDynamicGdiPlus(void)
{
    if((0 != token) && (NULL != pGdiplusShutdown))
        pGdiplusShutdown(token);
    if(NULL != hGdiPlus)
        FreeLibrary(hGdiPlus);
}

HBITMAP TDynamicGdiPlus::LoadImageFromResource(HINSTANCE hInst, LPCTSTR lpName, LPCTSTR lpType)
{
    HBITMAP retVal = NULL;

    if(everythigOK)
    {
        HRSRC hResource = ::FindResource(hInst, lpName, lpType);
        if (NULL != hResource)
        {
            DWORD imageSize = ::SizeofResource(hInst, hResource);
            if (0 < imageSize)
            {
                const void* pResourceData = ::LockResource(::LoadResource(hInst, hResource));
                if (NULL != pResourceData)
                {
                    TAutoLockedBuff m_Buffer(GMEM_MOVEABLE, imageSize + 1);
                    void* pBmp;

                    m_Buffer.CopyFrom(pResourceData, imageSize);
                    TAutoStream m_Stream(m_Buffer.get());

                    pGdipCreateBitmapFromStream(m_Stream.get(), &pBmp);
                    if (NULL != pBmp)
                    {
                        pGdipCreateHBITMAPFromBitmap(pBmp, &retVal, 0x00FFFFFF); // this returns NotImplemented
                        pGdipFree(pBmp);
                        if(NULL == retVal)
                            throw std::wstring(L"Unable to extract HBITMAP from Gdiplus::Bitmap");
                    }
                    else
                        throw std::wstring(L"Unable to extract Gdiplus::Bitmap from stream");
                }
                else
                    throw std::wstring(L"Unable to lock resource");
            }
            else
                throw std::wstring(L"Size of resource is 0");
        }
        else
            throw std::wstring(L"Unable to find resource");
    }
    return retVal;
}

GdiPlusDynamic.h

#pragma once

typedef enum  {
  Ok                          = 0,
  GenericError                = 1,
  InvalidParameter            = 2,
  OutOfMemory                 = 3,
  ObjectBusy                  = 4,
  InsufficientBuffer          = 5,
  NotImplemented              = 6,
  Win32Error                  = 7,
  WrongState                  = 8,
  Aborted                     = 9,
  FileNotFound                = 10,
  ValueOverflow               = 11,
  AccessDenied                = 12,
  UnknownImageFormat          = 13,
  FontFamilyNotFound          = 14,
  FontStyleNotFound           = 15,
  NotTrueTypeFont             = 16,
  UnsupportedGdiplusVersion   = 17,
  GdiplusNotInitialized       = 18,
  PropertyNotFound            = 19,
  PropertyNotSupported        = 20,
  ProfileNotFound             = 21 
} Status;

enum DebugEventLevel
{
    DebugEventLevelFatal,
    DebugEventLevelWarning
};

// Callback function that GDI+ can call, on debug builds, for assertions
// and warnings.

typedef VOID (WINAPI *DebugEventProc)(DebugEventLevel level, CHAR *message);

// Notification functions which the user must call appropriately if
// "SuppressBackgroundThread" (below) is set.

typedef Status (WINAPI *NotificationHookProc)(OUT ULONG_PTR *token);
typedef VOID (WINAPI *NotificationUnhookProc)(ULONG_PTR token);

struct GdiplusStartupInput
{
    UINT32 GdiplusVersion;             // Must be 1  (or 2 for the Ex version)
    DebugEventProc DebugEventCallback; // Ignored on free builds
    BOOL SuppressBackgroundThread;     // FALSE unless you're prepared to call 
                                       // the hook/unhook functions properly
    BOOL SuppressExternalCodecs;       // FALSE unless you want GDI+ only to use
                                       // its internal image codecs.

    GdiplusStartupInput(
        DebugEventProc debugEventCallback = NULL,
        BOOL suppressBackgroundThread = FALSE,
        BOOL suppressExternalCodecs = FALSE)
    {
        GdiplusVersion = 1;
        DebugEventCallback = debugEventCallback;
        SuppressBackgroundThread = suppressBackgroundThread;
        SuppressExternalCodecs = suppressExternalCodecs;
    }
};

struct GdiplusStartupOutput
{
    // The following 2 fields are NULL if SuppressBackgroundThread is FALSE.
    // Otherwise, they are functions which must be called appropriately to
    // replace the background thread.
    //
    // These should be called on the application's main message loop - i.e.
    // a message loop which is active for the lifetime of GDI+.
    // "NotificationHook" should be called before starting the loop,
    // and "NotificationUnhook" should be called after the loop ends.

    NotificationHookProc NotificationHook;
    NotificationUnhookProc NotificationUnhook;
};

typedef Status (WINAPI *TGdiplusStartup)(ULONG_PTR* token, const GdiplusStartupInput *input, GdiplusStartupOutput *output);
typedef void (WINAPI *TGdiplusShutdown)(ULONG_PTR token);
typedef Status (WINAPI *TGdipCreateBitmapFromStream)(IStream* stream, void **bitmap);
typedef Status (WINAPI *TGdipCreateHBITMAPFromBitmap)(void* bitmap, HBITMAP* hbmReturn, DWORD background);
typedef void (WINAPI *TGdipFree)(void* ptr);

class TDynamicGdiPlus
{
private:
    bool everythigOK;
protected:
    HMODULE                         hGdiPlus;
    TGdiplusStartup                 pGdiplusStartup;
    TGdiplusShutdown                pGdiplusShutdown;
    TGdipCreateBitmapFromStream     pGdipCreateBitmapFromStream;
    TGdipCreateHBITMAPFromBitmap    pGdipCreateHBITMAPFromBitmap;
    TGdipFree                       pGdipFree;
    ULONG_PTR                       token;
public:
    TDynamicGdiPlus(void);
    virtual ~TDynamicGdiPlus(void);
    HBITMAP LoadImageFromResource(HINSTANCE hInst, LPCTSTR lpName, LPCTSTR lpType);
};

和 GdiPlusDynamicTools.h

#pragma once

class TAutoStream
{
protected:
    IStream* pStream;
public:
    TAutoStream(HGLOBAL m_hBuffer);
    virtual ~TAutoStream(void);
    IStream* get(void);
};

class AutoGlobal
{
protected:
    HGLOBAL m_hBuffer;
    SIZE_T len;
public:
    AutoGlobal(UINT uFlags, SIZE_T dwBytes);
    virtual ~AutoGlobal(void);
    bool IsOk(void);
    HGLOBAL get(void);
};

class TAutoLockedBuff : public AutoGlobal
{
protected:
    void* pBuffer;
public:
    TAutoLockedBuff(UINT uFlags, SIZE_T dwBytes);
    virtual ~TAutoLockedBuff(void);
    bool IsOk(void);
    void CopyFrom(const void* pSrcData, SIZE_T srcLen);
};

最佳答案

您可以使用 IImagingFactory服务代替 GDI+ 此服务可以渲染带有 alpha channel 的 png、bmp。

我们将此服务用于 Windows Mobile 6.x 下的实际项目

此代码模型:

CComPtr<IImagingFactory> spImageFactory;
spImageFactory.CoCreateInstance(__uuidof(ImagingFactory);

HRSRC hRes = FindResource(hInstance, MAKEINTRESOURCE(resID), _T("PNG"));
DWORD imageSize = SizeOfResource(hInstance, hRes);
HGLOBAL hGlobal = LoadResource(hInstance, hRes);

CComPtr<IImage> spImage;
spImageFactory->CreateImageFromBuffer(LockResource(hGlobal, imageSize), BufferDisposalFlagNone, &spImage);

ImageInfo info = {0};
spImage->GetImageInfo(&info);

CRect rect(x, y, x+info.Width, y+info.Height);
spImage->Draw(hDc, &rect, NULL);

关于c++ - 使用 C++ 在 Windows Mobile 6.x 中处理透明 PNG,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5422383/

相关文章:

javascript - Windows 10 应用程序 - 从应用程序内启动其他应用程序或 native Windows 应用程序

ios - 查明 PNG 是 8 位还是 24 位以及 alpha

c# - 如何在 Windows Mobile 6.5 上终止进程

c++ - 就地构建 std::function 目标

c++ - 多生产者/消费者绩效

c++ - OpenGL 如何使用多重采样 2d 纹理将深度缓冲区附加到帧缓冲区

c# - 如何 : Taking photos in windows mobile without CameraCaptureDialog?

html - css3 border-image的透明png问题

html - 减少 html5 中大图像的加载时间

C++:编译器提示构造函数中的变量初始化