CImage隐式将灰度PNG图像转换为32bpp ARGB

时间:2015-08-04 19:38:40

标签: mfc gdi+

我使用ATL:CImage类来解码png图像。 但是加载后图像会转换为RGBA(每像素4个字节)图像。

ATL:CImage img;
img.Load((LPCTSTR)("test.png")); // 8bit grayscale

成功加载后,m_nBPP成员为32(也称为4字节),m_bHasAlphaChannel为真。但它们应该是8而且是假的。

由于隐式转换,我们需要手动将RGBA转换回8BPP。我正在处理超过400张图片。所以这是应用程序的主要减速。

在Visual Studio论坛上,我读到这是GDI +中的一个问题,因为它隐式将所有灰度PNG图像转换为32bpp ARGB

有解决方法吗?

1 个答案:

答案 0 :(得分:0)

如果您想要控制,请使用Windows Imaging Component。您需要创建Decoder并检索您感兴趣的image frame(s)PNG Format Overview概述了PNG支持。

以下示例代码打开灰度PNG图像,并显示有关媒体的信息:

#include <windows.h>
#include <wincodec.h>
#pragma comment(lib, "Windowscodecs.lib")
#include <iostream>

int main() {
    ::CoInitialize( NULL );

创建工厂COM服务器:

    IWICImagingFactory* pFactory = NULL;
    HRESULT hr = ::CoCreateInstance( CLSID_WICImagingFactory,
                                     NULL,
                                     CLSCTX_INPROC_SERVER,
                                     IID_IWICImagingFactory,
                                     (void**)&pFactory );

根据图像源创建解码器:

    IWICBitmapDecoder* pDecoder = NULL;
    if ( SUCCEEDED( hr ) ) {
        hr = pFactory->CreateDecoderFromFilename( L"test.png",
                                                  NULL,
                                                  GENERIC_READ,
                                                  WICDecodeMetadataCacheOnDemand,
                                                  &pDecoder );
    }

虽然PNG文件始终包含单个图像,但有一些图像格式允许在单个文件中存储多个图像。通常,您将不得不查询帧计数并迭代所有帧,一个接一个地解码:

    UINT frameCount = 0;
    if ( SUCCEEDED( hr ) ) {
        hr = pDecoder->GetFrameCount( &frameCount );
    }

    if ( SUCCEEDED( hr ) ) {
        std::wcout << L"Framecount: " << frameCount << std::endl;

        for ( UINT frameIndex = 0; frameIndex < frameCount; ++frameIndex ) {
            std::wcout << std::endl << L"Frame " << frameIndex << L":" << std::endl;
            IWICBitmapFrameDecode* pFrame = NULL;
            hr = pDecoder->GetFrame( frameIndex, &pFrame );

转储图片尺寸以供说明之用:

            if ( SUCCEEDED( hr ) ) {
                UINT width = 0, height = 0;
                hr = pFrame->GetSize( &width, &height );
                if ( SUCCEEDED( hr ) ) {
                    std::wcout << L"  width: " << width <<
                                  L", height: " << height << std::endl;
                }
            }

要验证图像数据是否未被更改,请转储bpp和通道计数信息:

            if ( SUCCEEDED( hr ) ) {
                WICPixelFormatGUID pixelFormat = { 0 };
                pFrame->GetPixelFormat( &pixelFormat );
                if ( SUCCEEDED( hr ) ) {
                    // Translate pixelformat to bpp
                    IWICComponentInfo* pComponentInfo = NULL;
                    hr = pFactory->CreateComponentInfo( pixelFormat, &pComponentInfo );
                    IWICPixelFormatInfo* pPixelFormatInfo = NULL;
                    if ( SUCCEEDED( hr ) ) {
                        hr = pComponentInfo->QueryInterface( &pPixelFormatInfo );
                    }

                    UINT bpp = 0;
                    if ( SUCCEEDED( hr ) ) {
                        hr = pPixelFormatInfo->GetBitsPerPixel( &bpp );
                    }
                    if ( SUCCEEDED( hr ) ) {
                        std::wcout << L"  bpp: " << bpp << std::endl;
                    }

                    UINT channelCount = 0;
                    if ( SUCCEEDED( hr ) ) {
                        hr = pPixelFormatInfo->GetChannelCount( &channelCount );
                    }
                    if ( SUCCEEDED( hr ) ) {
                        std::wcout << L"  Channel Count: " << channelCount << std::endl;
                    }

                    // Cleanup
                    if ( pPixelFormatInfo != NULL ) { pPixelFormatInfo->Release(); }
                    if ( pComponentInfo != NULL ) { pComponentInfo->Release(); }
                }
            }

剩下的就是资源清理:

            // Cleanup
            if ( pFrame != NULL ) { pFrame->Release(); }
        }
    }

    // Cleanup
    if ( pDecoder != NULL ) { pDecoder->Release(); }
    if ( pFactory != NULL ) { pFactory->Release(); }

    return 0;
}

针对此图片运行此代码

8bpp grayscale image

产生以下输出:

Framecount: 1

Frame 0:
  width: 50, height: 50
  bpp: 8
  Channel Count: 1