1

我正在使用FreeImage 3.15.4 库来分析 PNG 图像。我基本上是在尝试构建一个简单的数据结构,该结构由所有颜色的调色板以及包含调色板索引的图像每像素数据的数组版本组成。

问题是它FreeImage_GetBits似乎返回了一个指向无效数据的指针,我不知道为什么。我能够正确读取 PNG 文件的宽度和高度,但指向的数据FreeImage_GetBits只是垃圾数据,而且大小似乎很奇怪。无论我运行该程序多少次,它总是在同一个地方死掉,当iPix在下面的代码中等于 131740 时。在 std::find 调用中访问 bits[131740] 时出现 C0000005 错误。实际和报告的 PNG 图像大小为 524288。

此外,我已经使用我自己构建的较小图像尝试了此代码,并且它们工作正常。我正在使用的 PNG 是由我的第三方提供的,无论如何似乎都没有损坏(Photoshop 打开它,DirectX 可以正常处理和使用它)

有任何想法吗?

这是数据声明:

struct Color
{
    char b; // Blue
    char g; // Green
    char r; // Red
    char a; // Alpha value

    bool operator==( const Color& comp )
    {
        if ( a == comp.a &&
             r == comp.r &&
             g == comp.g &&
             b == comp.b )
            return TRUE;
        else
            return FALSE;
    }
};

typedef std::vector<Color> ColorPalette; // Array of colors forming a palette

这是执行颜色索引的代码:

// Read image data with FreeImage
unsigned int imageSize = FreeImage_GetWidth( hImage ) * FreeImage_GetHeight( hImage );

unsigned char* pData = new unsigned char[imageSize];

// Access bits via FreeImage
FREE_IMAGE_FORMAT fif;
FIBITMAP* hImage;
fif = FreeImage_GetFIFFromFilename( fileEntry.name.c_str() );
if( fif == FIF_UNKNOWN )
{
    return false;
}
hImage = FreeImage_Load( fif, filename );
BYTE* pPixelData = NULL;
pPixelData = FreeImage_GetBits( hImage );
if ( pPixelData == NULL )
{
    return false;
}

Color* bits = (Color*)pPixelData;
ColorPalette palette;

for ( unsigned int iPix = 0; iPix < imageSize; ++iPix )
{
    ColorPalette::iterator it;

    if( ( it = std::find( palette.begin(), palette.end(), bits[iPix] ) ) == palette.end() )
    {
        pData[iPix] = palette.size();
        palette.push_back( bits[iPix] );
    }
    else
    {
        unsigned int index = it - palette.begin();
        pData[iPix] = index;
    }
}
4

1 回答 1

1

有问题的 PNG 图像使用索引颜色模式,并且原始像素数据确实以 8bpp 的形式返回。正确的做法是将此数据视为每像素 8 位,并将每个 8 位值视为可使用FreeImage_GetPalette. 另一种方法是我最终做出的选择,即调用FreeImage_ConvertTo32Bits这些索引颜色模式 PNG 图像,然后通过与相同 32 位图像格式相同的代码路径传递所有内容。

非常简单的转换,但这里是:

// Convert non-32 bit images
if ( FreeImage_GetBPP( hImage ) != 32 )
{
    FIBITMAP* hOldImage = hImage;
    hImage = FreeImage_ConvertTo32Bits( hOldImage );
    FreeImage_Unload( hOldImage );
}
于 2013-07-29T02:14:58.007 回答