Hey! I’m working on a project where I’m creating an image and then sending it to a remote server for persistence and some other things (not real important but I can elaborate if necessary).
Using Cinder-ASIO and Cinder-Protocol I’ve been able to create a multipart/form-data HTTP request and POST it to the server. Currently I’m just passing some text fields as I’ve been testing, but now I’m ready to include the image file in the request. In any HTTP file upload examples I’ve found (not Cinder related), users are not necessarily generating the image in the same context as they are uploading it, so they all explain how you open the file from the filesystem first, then use that data in the HTTP request.
I could use writeImage() to save the image first, then open it for the purposes of including it in the HTTP request, but I’m wondering if there is a way to get at the data as it would be written to an image file, without actually doing the writing. I’ve looked into the ImageTarget class briefly and it seems like it might help, but can’t quite figure this one out.
If the download is in the form of a ci::ImageSourceRef, then cinder’s Image I/O will load the image directly with it needing to be saved to a file. Remote URLS already work with something like
loadImage( loadUrl( ... ) )
but of course this uses cinder’s built in HTTP support which isn’t near as powerful as Cinder-ASIO. I’m sure the latter could be made to work in the same manner.
Hey, thanks for the response. I might be misunderstanding your response, or I might have done a poor job explaining what I’m trying to accomplish. Basically, my Cinder app is doing some drawing to an FBO based on some user input parameters. I need to upload this resulting texture/image to a web service. The web service is not a Cinder app, it accepts a standard HTTP multipart/form-data request. When building the HTTP request, I need to pass the raw file data as well as the content-type parameter (for me that’s image/png).
I couldn’t find any Cinder specific examples doing this, so I looked for some more general ‘C++ multipart/form-data file upload’. All the examples I could find describe how to read the file you want to upload from the filesystem, and use the data in the HTTP request. I can only assume this is because these examples didn’t involve actually generating the image in the same application.
So - I really have no need to save the image to the filesystem in my Cinder application, I only need the raw PNG file data to include in the HTTP request. I’ve been looking through the Cinder source to see how writeImage() works. If I understand it correctly, there must be a step immediately before writing the file to disk where it formats the ImageSource data into a proper image file format. If I could somehow grab that data without writing it to disk, I could skip that step.
For now, I’m just using writeImage() to save the FBO’s color texture as a PNG, then using loadString() to get the image data when I’m building up the HTTP request.
Hopefully that makes sense/more sense. If you totally understood this already in your previous response, then I think I’m missing something. Let me know if I can clarify any further!
Try using writeImage with an in-memory DataTargetRef. The function takes a polymorphic target type, which allows you to substitute an in-memory buffer rather than a filesystem resource, as follows:
auto output_stream = OStreamMem::create();
Surface surf(100, 100, false);
auto target = DataTargetStream::createRef(output_stream);
writeImage(target, surf, ImageTarget::Options(), "png");
After writing the image to an in-memory buffer with png encoding, you will need to get the data out of that buffer.
The following will probably work:
// construct a stream from output buffer (hoping that tell gives us the right number of bytes)
std::string str((char*)output_stream->getBuffer(), output_stream->tell());
This assumes that the mOffset member of the stream correctly tells us how far into the output buffer we have written. The output stream doesn’t provide a size() method to tell us how much data it contains, but based on reading through the source of OStreamMem, it looks like writing to the stream will advance the mOffset member to the end of the stream’s buffer. As tell() returns the value of mOffset, it should behave the way we want it to provided we don’t seek* in the buffer.
As a suggestion to Andrew/others, I think it would be worth adding a getSize() method to OStreamMem, since writing to a buffer that you can’t reliably find the end of doesn’t seem very useful (seekAbsolute(-1) won’t behave as documented). tell() both isn’t intended to find the end and also is fragile in the event you seek to another position in the buffer.