1

I'm trying to save the output of my rendering to file. I'm already using FreeImage as a dependency so I'd like to continue using it. I'm using glReadPixels to read the RGB values from the buffer. These values were entered into the buffer as GLubytes, so I figure I need to read them as such. However, when I run the following code snippet, the FreeImage_ConvertFromRawBits call seg faults and I don't understand why. I've consulted the docs, and it seems that I'm doing everything correctly. Has anyone else run into this issue?

GLubyte pixels[3*_winWidth*_winHeight];
glReadPixels(0, 0, _winWidth, _winHeight, GL_RGB, GL_UNSIGNED_BYTE, pixels);
FIBITMAP *bitmap = FreeImage_ConvertFromRawBits(pixels, _winWidth,
    _winHeight, 3 *_winWidth, 24, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK,
    FI_RGBA_BLUE_MASK, false);
marcman
  • 3,233
  • 4
  • 36
  • 71

2 Answers2

2

I saw this question a bit after you posted it. If I recall correctly, I think you said your snippet was simplified in contrast to what you're actually using.

Thus the best guess then is that you aren't allocating enough memory for pixels.

Here is a more complete example for taking a screenshot and saving it with FreeImage.

BYTE *pixels = (BYTE*)malloc(width * height * 3);

glReadPixels(0, 0, width, height, GL_BGR, GL_UNSIGNED_BYTE, pixels);

FIBITMAP *image = FreeImage_ConvertFromRawBits(pixels, width, height, 3 * width, 24, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK, FALSE);

if (FreeImage_Save(FIF_BMP, image, "screenshot.bmp", 0))
    printf("Successfully saved!\n");
else
    printf("Failed saving!\n");

FreeImage_Unload(image);

free(pixels);

Here you can see that OpenGL as well as the photo viewer are showing the same.

Lastly I remembered something about the color mask being redundant. I looked a bit around and found this thread from 2005.

At the moment, color mask are only used for 16-bit RGB images, that's why your code produces two identical images.

FreeImage Thread, 2005

It's of course an old thread, so take it with a grain of salt. I wasn't however able to find any newer mentions of it. Changing the masks for FreeImage_ConvertFromRawBits() had no effect when I tested it.

Community
  • 1
  • 1
vallentin
  • 23,478
  • 6
  • 59
  • 81
0

In addition to

the color mask being redundant

in the accepted answer, there may be situations where you have to revert pixels and swap red and blue channels. Unfortunately, FreeImage_ConvertToRawBits() and its counterpart FreeImage_ConvertFromRawBits() can swap channels using masks only in 16bpp bitmaps. But you can do it manually, here is the code loading the PNG file without that function. In your case you can first revert raw pixels, then load them into FIBITMAP via FreeImage_ConvertFromRawBits():

BOOL bTopdown = TRUE; // Set to FALSE if straight pixels

FIBITMAP* hOriginal = FreeImage_Load(FIF_PNG, "awesomeface.png"); // Load file
FIBITMAP* hAdjusted = FreeImage_ConvertTo32Bits(hOriginal); // All to RGBA32
if (bTopdown) FreeImage_FlipVertical(hAdjusted);
FreeImage_Unload(original); // Cleanup

GLFWimage image; // Set GLFWimage
image.width = FreeImage_GetWidth(hAdjusted);
image.height = FreeImage_GetHeight(hAdjusted);
image.pixels = FreeImage_GetBits(hAdjusted);
if (bTopdown)
{
    UINT* pUintPixels = (UINT*)pPixels; // Swap blue and red channels
    for (int i = 0; i < iWidth * iHeight - 1; i++)
    {
        UINT uRGBA = pUintPixels[i];
        pUintPixels[i] = (uRGBA & (FI_RGBA_ALPHA_MASK | FI_RGBA_GREEN_MASK)) |
        ((uRGBA & FI_RGBA_RED_MASK) >> 16) | ((uRGBA & FI_RGBA_BLUE_MASK) << 16);
    }
}

// Use GLFWimage

FreeImage_Unload(adjusted); // Cleanup