2

How can I load RAW 16-bit grayscale image with FreeImage?

I have unsigned char* buffer with raw data. I know its dimensions in pixels and I know it is 16bit grayscale.

I'm trying to load it with

FIBITMAP* bmp = FreeImage_ConvertFromRawBits(buffer, 1000, 1506, 2000, 16, 0, 0, 0);

and get broken RGB888 image. It is unclear what color masks I should use for grayscale as it has only one channel.

Zoe
  • 27,060
  • 21
  • 118
  • 148
rattler
  • 379
  • 2
  • 5
  • 15

3 Answers3

2

After many experiments I found partially working solution with FreeImage_ConvertFromRawBitsEx:

FIBITMAP* bmp = FreeImage_ConvertFromRawBitsEx(true, buffer, FIT_UINT16, 1000, 1506, 2000, 16, 0xFFFF, 0xFFFF, 0xFFFF);

(thanks @1201ProgramAlarm for hint with masks).

In this way, FreeImage loads the data, but in some semi-custom format. Most of conversion and saving functions (tried: JPG, PNG, BMP, TIF) fail.

As I can't load data in native 16bit format, I preferred to convert it into 8bit grayscale

unsigned short* buffer = new unsigned short[1000 * 1506];

// load data

unsigned char* buffer2 = new unsigned char[1000 * 1506];
for (int i = 0; i < 1000 * 1506; i++)
  buffer2[i] = (unsigned char)(buffer[i] / 256.f);

FIBITMAP* bmp = FreeImage_ConvertFromRawBits(buffer2, 1000, 1506, 1000, 8, 0xFF, 0xFF, 0xFF, true);

This is really not the best solution, I even don't want to mark it as right answer (will wait for something better). But after this the format will be convenient for FreeImage and it could save/convert data to whatever.

rattler
  • 379
  • 2
  • 5
  • 15
1

Concerning your issue: I have read this from their PDF documentation FreeImage1370.pdf:


FreeImage_ConvertFromRawBits

1 4 8 16 24 32


DLL_API FIBITMAP *DLL_CALLCONV FreeImage_ConvertFromRawBits(BYTE *bits, int width, int height, int pitch, unsigned bpp, unsigned red_mask, unsigned green_mask, unsigned blue_mask, BOOL topdown FI_DEFAULT(FALSE));
Converts a raw bitmap somewhere in memory to a FIBITMAP. The parameters in this function are used to describe the raw bitmap. The first parameter is a pointer to the start of the raw bits. The width and height parameter describe the size of the bitmap. The pitch defines the total width of a scanline in the source bitmap, including padding bytes that may be applied. The bpp parameter tells FreeImage what the bit depth of the bitmap is. The red_mask, green_mask and blue_mask parameters tell FreeImage the bit-layout of the color components in the bitmap. The last parameter, topdown, will store the bitmap top-left pixel first when it is TRUE or bottom-left pixel first when it is FALSE.
  • When the source bitmap uses a 32-bit padding, you can calculate the pitch using the following formula: int pitch = ((((bpp * width) + 31) / 32) * 4);

In the code you are showing:

FIBITMAP* bmp = FreeImage_ConvertFromRawBits(buffer, 1000, 1506, 2000, 16, 0, 0, 0);

You have the appropriate FIBTMAP* return type, you pass in your buffer of raw bits. From there the 2nd & 3rd parameters which are the width & height: width = 1000, height = 1506 and the 4th parameter which is the pitch: pitch = 2000 (if the bitmap is using 32bit padding refer to the last note above), the 5th parameter will be the bit depth measured in bpp you have as bpp = 16, the next 3 parameters are for your RGB color masks. Here you label them all as being 0. The last parameter is a bool flag for the orientation of the image :

  if (topdown == true ) { 
      stores top-left pixel first ) 
  else { 
      bottom left pixel is stored first 
  }

in which you omit the value.

Without more code of how you are reading in the file, parsing the header information etc. to prepare your buffer it is hard to tell where else there may be an error or an issue, but from what you provided; I think you need to check the color channel masks for grayscale images.


EDIT - I found another PDF for FreeImage from standford.edu here that refers to an older version 3.13.1 however the function declaration - definition doesn't look like it has changed any and they provide examples for b FreeImage_ConvertToRawBits & Free_Image_ConvertFromRawBits:

// this code assumes there is a bitmap loaded and
// present in a variable called ‘dib’
// convert a bitmap to a 32-bit raw buffer (top-left pixel first)
// --------------------------------------------------------------
FIBITMAP *src = FreeImage_ConvertTo32Bits(dib);
FreeImage_Unload(dib);
// Allocate a raw buffer
int width = FreeImage_GetWidth(src);
int height = FreeImage_GetHeight(src);
int scan_width = FreeImage_GetPitch(src);
BYTE *bits = (BYTE*)malloc(height * scan_width);
// convert the bitmap to raw bits (top-left pixel first)
FreeImage_ConvertToRawBits(bits, src, scan_width, 32,
FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK,
TRUE);
FreeImage_Unload(src);
// convert a 32-bit raw buffer (top-left pixel first) to a FIBITMAP
// ----------------------------------------------------------------
FIBITMAP *dst = FreeImage_ConvertFromRawBits(bits, width, height, scan_width,
32, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK, FALSE);

I think this should help you with your question about the bit masks for the color channels in a grayscale image.

Francis Cugler
  • 7,788
  • 2
  • 28
  • 59
  • I have read this PDF too and I still have no answer of what I should pass as mask. There is no loading and parsing of header. I just have a buffer and I know the kind of data. It is in form of unsigned short[]. Each value is pixel in 16bit grayscale – rattler Jan 14 '18 at 13:28
  • @rattler I edited my answer with a little more information. – Francis Cugler Jan 15 '18 at 04:10
  • See your edit. Yes, it is correct handling for *color* images. But my problem was a grayscale. – rattler Jan 15 '18 at 18:26
0

You already mentioned the FreeImage_ConvertFromRawBitsEx() function, which was added at some point between FreeImage v3.8 and v3.17, but are you calling it correctly? I was able to use this function with 16-bit grayscale data:

int nBytesPerRow = nWidth * 2;
int nBitsPerPixel = 16;
FIBITMAP* pFIB = FreeImage_ConvertFromRawBitsEx(TRUE, pImageData, FIT_UINT16, nWidth, nHeight, nBytesPerRow, nBitsPerPixel, 0, 0, 0, TRUE);

Note that nBytesPerRow and nBitsPerPixel have to be specified correctly for the 16-bit data. Also, I believe the color mask parameters are irrelevant for this data, since it is monochrome.

EDIT: I noticed that you said that saving the 16-bit data did not work correctly. That may be due to the file formats themselves. The only file format that I have found to be compatible with 16-bit grayscale data is TIFF. So, if you have 16-bit grayscale data, you can save a TIFF with FreeImage_Save() but you cannot save a BMP.

Adrian Mole
  • 49,934
  • 160
  • 51
  • 83