FreeImage_SaveToMemory to char array

Hello,

Does anyone knows a trick to save from FreeImage_SaveToMemory to a unsigned char array?

I want to compress an image from the vidgraber to jpg and send it over tcp and then draw on the other end.

thnx
Tasos

ofMemoryImage and the webscraper code. i think it does what you want, give it a try.

related post: http://forum.openframeworks.cc/t/problem-with-ofmemoryimage-and-threaded-web-scraper/1081/1

Hi, I tried to do the same thing, did anyone get it to work? I’m a c++ novice so here is what I tried to put together. I want to send a jpeg image stream to flash, I got it to work using the raw pixeldata but flash it too slow to handle all the data so I wanna send compressed frames now. would be happy if someone could point me in the right direction. thanks!

  
  
void compressImageStream(unsigned char * pixelData) {                  
        // open a memory stream, create a destination stream  
        // totalBytes=VIDEO_WIDTH*VIDEO_HEIGHT*VIDEO_BIT_DEPTH  
  
        FIMEMORY *srcStream = FreeImage_OpenMemory(pixelData, totalBytes);  
        FIMEMORY *destStream = FreeImage_OpenMemory();  
          
        // get the file type FREE_IMAGE_FORMAT   
        FREE_IMAGE_FORMAT imageFormat = FreeImage_GetFileTypeFromMemory(srcStream, 0);  
          
        // load image from the memory handle   
        FIBITMAP *srcImageData = FreeImage_LoadFromMemory(imageFormat, srcStream, 0);  
          
        // encode and save the image to the memory   
        FreeImage_SaveToMemory(FIF_JPEG, srcImageData, destStream, 0);  
           
        // copy destinationStream into a local unsigned char pixels  
	memcpy(pixels, pixelData, totalBytes);  
}   
  

Hello,
Perhaps this help; I have been working last year on a project involving sending images over Ethernet, and it is very useful to be able to compress them (as JPG) before sending. This is possible on openFrameworks (using ofImage) only when saving them on the disk, but it is not possible to compress on memory. It should be easy to implement a method to do that on the ofImage class.

For the time being, I am doing something bad (modifying the base class). Indeed, in order to use FreeImage_SaveToMemory, we need to get a pointer to a FIBITMAP object corresponding to the ofImage. This method exist:

FIBITMAP * getBmpFromPixels(ofPixels &pix);

but is PRIVATE, so I had to modify the base class… this is bad, I know. It would be much better to have something like a public:

unsigned char * compressedPixels;

in the ofImage class (or ofPixels), and when calling image.getPixels(…) we could ask for the compressed array as parameter. For instance,
=image.getPixels(30, &finalsize) could mean get the 30% compress image array (of course, the array size is unknown, so we need to get the final size of the byte array).

Because of the “private” character of getBmpFromPixels, I needed to add a method to the ofImage class, and I thought that this may be useful for some people to try streaming frame-by-frame compressed video, so here is how it works:

  1. In ofImage.h, one need to add a new public method:

FIBITMAP * getBmp(void); // get an image of format FIBITMAP from the ofImage
void putBmpIntoPixels(FIBITMAP * bmp);

These are very simple, and implemented on ofImage.cpp like this:

FIBITMAP * ofImage::getBmp() {
return(getBmpFromPixels(myPixels));

}

void ofImage::putBmpIntoPixels(FIBITMAP * bmp) {
putBmpIntoPixels(bmp, myPixels);

}

  1. Then, in myApp.cpp (for instance), the compression on memory is done as following. Assuming colorImage is an object of class ofImage, and cp_ratio is an integer from 0 to 100 (the compression ratio):

ofImage colorImage.loadImage(“image.jpg”);

int cp_ratio =50; // means 50% compression

And assuming the compressed image is stored in an auxiliary array (allocated statically here for simplicity):

unsigned char compressedPixels[640*480*3+3];

Note: this assumes that the maximum size of the image after compression is RGB/VGA, but we could do dynamic allocation of course. The 3 additional bytes are for storing a header corresponding to the length of the stream - remember the goal is to send the image over TCP/IP and we need to uncompress it on the other side, but since compression won’t give always the same size, we need this “header”.

A more clear way can be to send the size of the compressed image as a string (using the function ofxTCPClient::send(string message)), but this will imply a more complex handshake protocol (first send the string, then the image to be read).

Then the following code compresses the colorImage on memory, and copies the compressed data on the auxbuff array (to be sent using TCP/IP):

uint32_t size_in_bytes; // the size of the image in bytes

unsigned char* compressedImageBytes; // the buffer where the compressed data will be stored.

// (a) get the FIBITMAP image from the ofImage (using the new public method):
//
FIBITMAP *dib=colorImage.getBmp();
if (dib) // bitmap successfully created
{
// (b) open a memory stream to compress the image onto mem_buffer:
//
FIMEMORY *hmem = FreeImage_OpenMemory();
// © encode and save the image to the memory (on dib FIBITMAP image):
//
if (!FreeImage_SaveToMemory(FIF_JPEG, dib, hmem, cp_ratio))
cout << “Error compressing image into memory” << endl;
/*

NOTE: at this point, hmem contains the entire data in memory stored in fif format. the
amount of space used by the memory is equal to file_size:
long file_size = FreeImage_TellMemory(hmem);
but can also be retrieved by FreeImage_AcquireMemory that retrieves both the
length of the buffer, and the buffer memory address.
*/

size_in_bytes = 0;
// Save compressed data on mem_buffer
// note: FreeImage_AquireMemory allocates space for aux_mem_buffer):
//
BYTE *mem_buffer = NULL;
if (!FreeImage_AcquireMemory(hmem, &mem_buffer, &size_in_bytes))
cout << “Error aquiring compressed image from memory” << endl;

/*
Now, before closing the memory stream, copy the content of mem_buffer
to an auxiliary buffer (note: in case you want to reconstruct the image, you may
need to send the length of the array too, so I am adding it as the first three bytes
on the array - not elegant, but it’s just an example):
*/

compressedImageBytes[0]=(size_in_bytes>>16)&0x000000FF; //MSB of the three bytes
compressedImageBytes[1]=(size_in_bytes>>8)&0x000000FF; // middle byte
compressedImageBytes[2]=(size_in_bytes)&0x000000FF; // LSB

// Then, copy the bulk of the image (the “payload”):
//
memcpy(&(compressedPixels[3]),aux_mem_buffer, size_in_bytes);

// Finally, close the FIBITMAP object, or we will get a memory leak:
FreeImage_Unload(dib);

// Close the memory stream (otherwise we may get a memory leak).
FreeImage_CloseMemory(hmem);
}

That’s it. Now, the image can be send using an ofxTCPServer object (in a threaded object):


ofxTCPServer server;

And when sending to client clientID:

TCP.sendRawBytes(clientID,(char*)compressedPixels, 3+size_in_bytes);

NOTE: it may be better to send the image in “chunks” (as explained by rocknrolldk in http://forum.openframeworks.cc/t/video-streaming-between-two-installations/3505/0). However, we need to take care of the fact that the array does not have a constant lenght, and we cannot do as he does (sending the image row by row). Instead, we could define a chunck length (arbitrarily, to be calibrated to optimize the flow), but for the time being the non-optimal method seems to work.
On the other side, we first wait until we receive three bytes (the length of the following payload):

// (a) Read the “header”, consisting on the first three bytes for the size of the compressed image:
//
int rrec=tcpClient.TCPClient.ReceiveAll((char*)auxbuff, 3);

if (rrec==3) {
// convert to a single integer (most significant byte first):
compressedSize=(int)((unsigned char)auxbuff[0]*65536+ \
(unsigned char)auxbuff[1]*256+ \
(unsigned char)auxbuff[2]);

}

// Then read the rest of the image:
rrec=tcpClient.TCPClient.ReceiveAll((char*)auxbuff, compressedSize);

// (b) Then, uncompress the image if we received everything:
if (rrec==compressedSize) { // otherwise discard

// Attach the binary data to a memory stream
FIMEMORY *hmem = FreeImage_OpenMemory((BYTE*)auxbuff, compressedSize);
// get the file type
FREE_IMAGE_FORMAT fif = FreeImage_GetFileTypeFromMemory(hmem, 0);

// rem: normally, fif should be FIF_JPEG
// load an FIBITMAP image from the memory stream, directly onto the buffer of the
// current image:
//
FIBITMAP *dib = FreeImage_LoadFromMemory(fif, hmem, 0);
if (dib) { // bitmap successfully created
//Set the pixels of the ofImage from this FIBITMAP image:
colorImg.putBmpIntoPixels(dib);
FreeImage_Unload(dib);
}

// close the memory stream (otherwise we may get a memory leak).
FreeImage_CloseMemory(hmem);

// Finally, update the pixels of the ofImage object:
colorImg.update();
}

I will post some example code of this client/server example if someone is interested.

hey alvaro

we wanted to implement this for 007 the method is there but not implemented yet:

void ofSaveImage(ofPixels & pix, ofBuffer & buffer, ofImageQualityType qualityLevel = OF_IMAGE_QUALITY_BEST);

will use your code, thanks!

btw, to send images over the network i usually use ofxHttpUtils + ofxHttpServer and send the data in a POST request which takes care of all the problems with dividing the data in chunks…

here it is:

https://github.com/openframeworks/openFrameworks/commit/30d5bc95e0ba064a4231c8dcff1d17c140ba76d5

only works with 8 and 16bit images, no float by now

thanks

btw, to send images over the network i usually use ofxHttpUtils + ofxHttpServer and send the data in
a POST request which takes care of all the problems with dividing the data in chunks…

excellent! I’ve been looking for that for a while. thanks, I will try it and compare with sending the raw data (is there an overhead for the POST request method?)

there should be a little but compared to the size of the whole image is unnoticeable

Hi Arturo,

I just try to compile example that is inside ofxHttpServer in your github and not compile in osx 10.6 with Xcode 3.26 for me. I attached image of the error. Do you have any about where come this error? For me looks like linkage problem.

Thanks