【问题标题】:VS + Win32 + C++ + PNGVS + Win32 + C++ + PNG
【发布时间】:2016-05-09 07:28:47
【问题描述】:

我在资源编辑器中添加了一个 png 作为资源,但是如何加载和显示?我想在图片控件或所有者绘图中显示它。我不想让外部文件四处飘荡。我想我记得在某处读过你可以将文件“绑定”到可执行文件但基本上仍然像外部文件一样引用它们?

(创建一个简单的 gui 界面,带有一些背景和一些按钮状态......但只需要一个 exe,而不是 exe + button1.png + button2.png 等。我也需要透明度功能,所以没有 BMP。我也想把它全部保存在 Windows 中(没有 libpng 等...))

【问题讨论】:

  • 你是对的,有一个协议可以将资源作为文件访问。这是res protocol。从脚本语言访问资源很好。在 C++ 中工作你不需要那个。只需加载资源。
  • 您也可以使用位图获得透明度。只是不是阿尔法透明度。如果您需要 alpha 透明度,PNG 是您的最佳选择。这是你需要的吗?
  • “win32 png”的前 4 个 Google 答案都指向 Stack Overflow,因此这不是您的问题。大多数答案都是从保证 WinAPI 中的 PNG 支持开始的,事实上已经超过十年了。那么您的问题是如何加载资源?这也是样板代码。
  • @Jongware:从资源加载 PNG 绝不是样板文件。您必须使用WIC 查找、锁定、加载和提取资源。你有什么有用的贡献吗?
  • @IInspectable 是的,我想要 alpha。现在不是绝对必要,但将来会。我已经看到关于通过将 png 作为图标加载来欺骗窗口的 tut,但我似乎无法在 VS2015 中做到这一点,这似乎与文章中描述的不同。我不想要任何不必要的依赖,但可能是 GDI+。基本上我想要一个简单的、有希望的预制解决方案。请记住,它应该能够从资源文件(.rc 或 res 或其他)加载 png。

标签: c++ visual-studio winapi png


【解决方案1】:

这是我用来加载 PNG 资源以使用 Direct2D 呈现它的代码(但它并不限制您仅使用 PNG 格式或仅使用 D2D):

/**
 * Loads image from the specified resource and creates Direct2D bitmap object for that image.
 *
 * Parameters:
 * >pszResourceName
 * Image resource name.
 * >pszResourceType
 * Image resource type.
 * >pImagingFactory
 * Pointer to an instance of IWICImagingFactory object.
 * >ppBitmapSource
 * Receives loaded bitmap.
 *
 * Returns:
 * Standard HRESULT code.
 */
HRESULT directx_toolkit::loadBitmapFromResource(
    _In_z_ LPCTSTR pszResourceName,
    _In_z_ LPCTSTR pszResourceType,
    _In_ IWICImagingFactory* pImagingFactory,
    _COM_Outptr_result_maybenull_ IWICFormatConverter** ppBitmapSource) const
{
    ATLADD com_ptr<IWICFormatConverter> converter {};
    HRESULT hr = E_FAIL;
    HRSRC hResource = FindResource(ATL::_AtlBaseModule.GetResourceInstance(), pszResourceName, pszResourceType);
    if (nullptr != hResource)
    {
        HGLOBAL hData = LoadResource(ATL::_AtlBaseModule.GetResourceInstance(), hResource);
        if (nullptr != hData)
        {
            void* pData = LockResource(hData);
            DWORD nSize = SizeofResource(ATL::_AtlBaseModule.GetResourceInstance(), hResource);
            if (pData && nSize)
            {
                // Create a WIC stream to map onto the memory.
                ATLADD com_ptr<IWICStream> stream {};
                hr = pImagingFactory->CreateStream(stream.getAddressOf());
                if (SUCCEEDED(hr))
                {
                    hr = stream->InitializeFromMemory(reinterpret_cast<BYTE*> (pData), nSize);
                    if (SUCCEEDED(hr))
                    {
                        // Prepare decoder for the stream, the first image frame and conveter (to change image color
                        // format).
                        ATLADD com_ptr<IWICBitmapDecoder> decoder {};
                        hr = pImagingFactory->CreateDecoderFromStream(
                            stream.get(), nullptr, WICDecodeMetadataCacheOnLoad, decoder.getAddressOf());
                        if (SUCCEEDED(hr))
                        {
                            ATLADD com_ptr<IWICBitmapFrameDecode> frame {};
                            hr = decoder->GetFrame(0, frame.getAddressOf());
                            if (SUCCEEDED(hr))
                            {
                                hr = pImagingFactory->CreateFormatConverter(converter.getAddressOf());
                                if (SUCCEEDED(hr))
                                {
                                    hr = converter->Initialize(
                                        frame.get(),
                                        GUID_WICPixelFormat32bppPBGRA,
                                        WICBitmapDitherTypeNone,
                                        nullptr,
                                        0,
                                        WICBitmapPaletteTypeMedianCut);
                                }
                            }
                        }
                    }
                }
            }
        }
        else
        {
            hr = HRESULT_FROM_WIN32(GetLastError());
        }
    }
    else
    {
        hr = HRESULT_FROM_WIN32(GetLastError());
    }
    *ppBitmapSource = SUCCEEDED(hr) ? converter.detach() : nullptr;
    return hr;
}


/**
 * Loads image from the specified resource and creates Direct2D bitmap object for that image.
 *
 * Parameters:
 * >pszResourceName
 * Image resource name.
 * >pszResourceType
 * Image resource type.
 * >pImagingFactory
 * Pointer to an instance of IWICImagingFactory object.
 * >pDC
 * Direct2D context.
 * >ppBitmap
 * Receives loaded bitmap.
 *
 * Returns:
 * Standard HRESULT code.
 *
 * Remarks:
 * Since 'ID2D1DeviceContext::CreateBitmapFromWicBitmap' can't be called simultaneously from multiple threads, caller
 * should synchronize access to the 'pDC'.
 */
HRESULT directx_toolkit::loadBitmapFromResource(
    _In_z_ LPCTSTR pszResourceName,
    _In_z_ LPCTSTR pszResourceType,
    _In_ IWICImagingFactory* pImagingFactory,
    _In_ ID2D1DeviceContext* pDC,
    _COM_Outptr_result_maybenull_ ID2D1Bitmap1** ppBitmap) const
{
    ATLADD com_ptr<ID2D1Bitmap1> bitmap {};
    ATLADD com_ptr<IWICFormatConverter> converter {};
    HRESULT hr = loadBitmapFromResource(pszResourceName, pszResourceType, pImagingFactory, converter.getAddressOf());
    if (SUCCEEDED(hr))
    {
        hr = pDC->CreateBitmapFromWicBitmap(converter.get(), bitmap.getAddressOf());
    }
    *ppBitmap = SUCCEEDED(hr) ? bitmap.detach() : nullptr;
    return hr;
}

ATLADD com_ptrATL::CComPtr 的类似物)

毫无疑问,您可以使用 32bpp BMP 来获取具有透明蒙版的资源。

【讨论】:

  • 肯定有更简单的方法吗?虽然我喜欢使用 DirectX 的想法,但它添加了几个我现在并不真正想要的依赖项。我想我会选择 bmp。
  • @AbstractDissonance 我根本没有试图强迫你使用 DirectX :-D 我只是展示了如何使用 WIC 处理 PNG 资源。就这样。但我并没有限制你使用特定的渲染引擎。
  • @AbstractDissonance:除非您可以通过使用 CImage::Load 来依赖 ATL(和 GDI+),否则您将不得不以一种或另一种方式使用 WIC。我不明白你所说的“更简单的方式”是什么意思。这个答案并不理想,因为它混合了很多不相关的东西(例如,不需要 DirectX 命名空间,或者使用另一个未公开的自定义智能指针实现)。
猜你喜欢
  • 2010-11-26
  • 2011-12-26
  • 2010-09-26
  • 1970-01-01
  • 2023-03-15
  • 2013-06-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多