سؤال

I'm using the FreeImage 3.15.4 library to analyze PNG images. I'm basically trying to build a simple data structure of consisting of a palette of all colors as well as an array version of the image per-pixel data consisting of indexes into the palette.

The thing is that FreeImage_GetBits seems to be returning a pointer to invalid data and I'm not sure why. I am able to read the width and height of the PNG file correctly, but the data pointed to by FreeImage_GetBits is just garbage data, and appears to be of an odd size. No matter how many times I run the program, it consistently dies in the same place, when iPix in the code below is equal to 131740. I get a C0000005 error accessing bits[131740] in the std::find call. The actual and reported PNG image size is 524288.

Furthermore, I've tried this code with smaller images that I myself have built and they work fine. The PNG I'm using is provided my a third party, and does not appear to be corrupt in anyway (Photoshop opens it, and DirectX can process and use it normally)

Any ideas?

Here's the data declarations:

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

And here's the code that does the color indexing:

// 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;
    }
}
هل كانت مفيدة؟

المحلول

The PNG images that were problematic were using indexed color modes and the raw pixel data was indeed being returned as 8bpp. The correct course of action was to treat this data as 8 bits per pixel, and treat each 8-bit value as an index into a palette of colors that can be retrieved using FreeImage_GetPalette. The alternative, which is the choice I ultimately made, was to call FreeImage_ConvertTo32Bits on these indexed color mode PNG images, and then pass everything through the same code path as the same 32-bit image format.

Pretty simple conversion, but here it is:

// Convert non-32 bit images
if ( FreeImage_GetBPP( hImage ) != 32 )
{
    FIBITMAP* hOldImage = hImage;
    hImage = FreeImage_ConvertTo32Bits( hOldImage );
    FreeImage_Unload( hOldImage );
}
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top