libjpeg can read JPEG data from a FILE* or a buffer. My data is coming from a std::istream. I could read the entire std::istream into a buffer to use with libjpeg, but I'd rather have libjpeg read directly from the std::istream if possible. How can this be done?
You just need to provide wrappers around your istream. Define a struct, for instance
struct JpegStream {
jpeg_source_mgr pub;
std::istream* stream;
byte buffer [4096];
}
Then you need four methods to operate on the stream:
void init_source (j_decompress_ptr cinfo)
{
auto src = (JpegStream*)(cinfo->src);
src->stream-> // seek to 0 here
}
boolean fill_buffer (j_decompress_ptr cinfo)
{
// Read to buffer
JpegStream* src = // as above
src->pub.next_input_byte = src->buffer;
src->pub.bytes_in_buffer = // How many yo could read
return eof() ? FALSE : TRUE;
}
void skip (j_decompress_ptr cinfo, long count)
{
// Seek by count bytes forward
// Make sure you know how much you have cached and subtract that
// set bytes_in_buffer and next_input_byte
}
void term (j_decompress_ptr cinfo)
{
// Close the stream, can be nop
}
and one method to bind them to the JPEG decompression info structure:
void make_stream (j_decompress_ptr cinfo, std::istream* in)
{
JpegStream * src;
/* The source object and input buffer are made permanent so that a series
* of JPEG images can be read from the same file by calling jpeg_stdio_src
* only before the first one. (If we discarded the buffer at the end of
* one image, we'd likely lose the start of the next one.)
* This makes it unsafe to use this manager and a different source
* manager serially with the same JPEG object. Caveat programmer.
*/
if (cinfo->src == NULL)
{
/* first time for this JPEG object? */
cinfo->src = (struct jpeg_source_mgr *)
(*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, POOL_PERMANENT, sizeof(JpegStream));
src = reinterpret_cast<JpegStream*> (cinfo->src);
}
src = reinterpret_cast<JpegStream*> (cinfo->src);
src->pub.init_source = init_source;
src->pub.fill_input_buffer = fill_buffer;
src->pub.skip_input_data = skip;
src->pub.resync_to_restart = jpeg_resync_to_restart; /* use default method */
src->pub.term_source = term;
src->stream = in;
src->pub.bytes_in_buffer = 0; /* forces fill_input_buffer on first read */
src->pub.next_input_byte = NULL; /* until buffer loaded */
}
After calling jpeg_create_decompress, call your make_stream function.
Related
So I've been reading the libjpeg documentation and it is extremely lackluster.
I have been trying to figure out how to read from a custom memory buffer rather than a file and am not sure how to even test if my solution is working correctly.
At the moment my function for loading a jpeg from memory is like so:
struct error_mgr{
jpeg_error_mgr pub;
std::jmp_buf buf;
};
bool load_jpeg(void *mem, size_t size, output_struct &output){
jpeg_source_mgr src;
src.next_input_bytes = static_cast<JOCTET*>(mem)-size;
src.bytes_in_buffer = size;
src.init_source = [](j_compress_ptr){};
src.fill_input_buffer = [](j_decompress_ptr cinfo) -> boolean{
// should never reach end of buffer
throw "libjpeg tried to read past end of file";
return true;
};
src.skip_input_data = [](j_compress_ptr cinfo, long num_bytes){
if(num_bytes < 1) return; // negative or 0 us no-op
cinfo->src.next_input_byte+=num_bytes;
cinfo->src.bytes_in_buffer-=num_bytes;
};
src.resync_to_restart = jpeg_resync_to_restart;
src.term_source = [](j_decompress_ptr){};
struct jpeg_decompress_struct cinfo;
error_mgr err;
cinfo.err = jpeg_std_error(&err.pub);
err.pub.error_exit = [](j_common_ptr cinfo){
error_mgr ptr = reinterpret_cast<error_mgr*>(cinfo->err);
std::longjmp(ptr->buf, 1);
};
if(std::setjmp(err.buf)){
jpeg_destroy_decompress(&cinfo);
return false;
}
cinfo.src = &src;
jpeg_create_decompress(&cinfo);
(void) jpeg_read_header(&cinfo, TRUE);
// do the actual reading of the image
return true;
}
But it never makes it past jpeg_read_header.
I know that this is a jpeg file and I know that my memory is being passed correctly because I have libpng loading images with the same signature and calling function fine, so I'm sure it is how I am setting the source manager in cinfo.
Anybody with more experience in libjpeg know how to do this?
In my code I am setting cinfo.src before calling jpeg_create_decompress, setting it afterwards fixed the issue :)
Using jpeg_mem_src() works for me, with libjpeg-turbo:
struct jpeg_decompress_struct cinfo;
/* ... */
char *ptr;
size_t buffer;
/* Initialize ptr, buffer, then: */
jpeg_mem_src(&cinfo, ptr, buffer);
/* Now, it's time for jpeg_read_header(), etc... */
I using libzip to work with zip files and everything goes fine, until i need to read file from zip
I need to read just a whole text files, so it will be great to achieve something like PHP "file_get_contents" function.
To read file from zip there is a function "int
zip_fread(struct zip_file *file, void *buf, zip_uint64_t nbytes)".
Main problem what i don't know what size of buf must be and how many nbytes i must read (well i need to read whole file, but files have different size). I can just do a big buffer to fit them all and read all it's size, or do a while loop until fread return -1 but i don't think it's rational option.
You can try using zip_stat to get file size.
http://linux.die.net/man/3/zip_stat
I haven't used the libzip interface but from what you write it seems to look very similar to a file interface: once you got a handle to the stream you keep calling zip_fread() until this function return an error (ir, possibly, less than requested bytes). The buffer you pass in us just a reasonably size temporary buffer where the data is communicated.
Personally I would probably create a stream buffer for this so once the file in the zip archive is set up it can be read using the conventional I/O stream methods. This would look something like this:
struct zipbuf: std::streambuf {
zipbuf(???): file_(???) {}
private:
zip_file* file_;
enum { s_size = 8196 };
char buffer_[s_size];
int underflow() {
int rc(zip_fread(this->file_, this->buffer_, s_size));
this->setg(this->buffer_, this->buffer_,
this->buffer_ + std::max(0, rc));
return this->gptr() == this->egptr()
? traits_type::eof()
: traits_type::to_int_type(*this->gptr());
}
};
With this stream buffer you should be able to create an std::istream and read the file into whatever structure you need:
zipbuf buf(???);
std::istream in(&buf);
...
Obviously, this code isn't tested or compiled. However, when you replace the ??? with whatever is needed to open the zip file, I'd think this should pretty much work.
Here is a routine I wrote that extracts data from a zip-stream and prints out a line at a time. This uses zlib, not libzip, but if this code is useful to you, feel free to use it:
#
# compile with -lz option in order to link in the zlib library
#
#include <zlib.h>
#define Z_CHUNK 2097152
int unzipFile(const char *fName)
{
z_stream zStream;
char *zRemainderBuf = malloc(1);
unsigned char zInBuf[Z_CHUNK];
unsigned char zOutBuf[Z_CHUNK];
char zLineBuf[Z_CHUNK];
unsigned int zHave, zBufIdx, zBufOffset, zOutBufIdx;
int zError;
FILE *inFp = fopen(fName, "rbR");
if (!inFp) { fprintf(stderr, "could not open file: %s\n", fName); return EXIT_FAILURE; }
zStream.zalloc = Z_NULL;
zStream.zfree = Z_NULL;
zStream.opaque = Z_NULL;
zStream.avail_in = 0;
zStream.next_in = Z_NULL;
zError = inflateInit2(&zStream, (15+32)); /* cf. http://www.zlib.net/manual.html */
if (zError != Z_OK) { fprintf(stderr, "could not initialize z-stream\n"); return EXIT_FAILURE; }
*zRemainderBuf = '\0';
do {
zStream.avail_in = fread(zInBuf, 1, Z_CHUNK, inFp);
if (zStream.avail_in == 0)
break;
zStream.next_in = zInBuf;
do {
zStream.avail_out = Z_CHUNK;
zStream.next_out = zOutBuf;
zError = inflate(&zStream, Z_NO_FLUSH);
switch (zError) {
case Z_NEED_DICT: { fprintf(stderr, "Z-stream needs dictionary!\n"); return EXIT_FAILURE; }
case Z_DATA_ERROR: { fprintf(stderr, "Z-stream suffered data error!\n"); return EXIT_FAILURE; }
case Z_MEM_ERROR: { fprintf(stderr, "Z-stream suffered memory error!\n"); return EXIT_FAILURE; }
}
zHave = Z_CHUNK - zStream.avail_out;
zOutBuf[zHave] = '\0';
/* copy remainder buffer onto line buffer, if not NULL */
if (zRemainderBuf) {
strncpy(zLineBuf, zRemainderBuf, strlen(zRemainderBuf));
zBufOffset = strlen(zRemainderBuf);
}
else
zBufOffset = 0;
/* read through zOutBuf for newlines */
for (zBufIdx = zBufOffset, zOutBufIdx = 0; zOutBufIdx < zHave; zBufIdx++, zOutBufIdx++) {
zLineBuf[zBufIdx] = zOutBuf[zOutBufIdx];
if (zLineBuf[zBufIdx] == '\n') {
zLineBuf[zBufIdx] = '\0';
zBufIdx = -1;
fprintf(stdout, "%s\n", zLineBuf);
}
}
/* copy some of line buffer onto the remainder buffer, if there are remnants from the z-stream */
if (strlen(zLineBuf) > 0) {
if (strlen(zLineBuf) > strlen(zRemainderBuf)) {
/* to minimize the chance of doing another (expensive) malloc, we double the length of zRemainderBuf */
free(zRemainderBuf);
zRemainderBuf = malloc(strlen(zLineBuf) * 2);
}
strncpy(zRemainderBuf, zLineBuf, zBufIdx);
zRemainderBuf[zBufIdx] = '\0';
}
} while (zStream.avail_out == 0);
} while (zError != Z_STREAM_END);
/* close gzip stream */
zError = inflateEnd(&zStream);
if (zError != Z_OK) {
fprintf(stderr, "could not close z-stream!\n");
return EXIT_FAILURE;
}
if (zRemainderBuf)
free(zRemainderBuf);
fclose(inFp);
return EXIT_SUCCESS;
}
With any streaming you should consider the memory requirements of your app.
A good buffer size is large, but you do not want to have too much memory in use depending on your RAM usage requirements. A small buffer size will require you call your read and write operations more times which are expensive in terms of time performance. So, you need to find a buffer in the middle of those two extremes.
Typically I use a size of 4096 (4KB) which is sufficiently large for many purposes. If you want, you can go larger. But at the worst case size of 1 byte, you will be waiting a long time for you read to complete.
So to answer your question, there is no "right" size to pick. It is a choice you should make so that the speed of your app and the memory it requires are what you need.
I am using Libjpeg version 6b. In version 8 they have a nice function to read data out of the memory called jpeg_mem_src(...), unfortunately ver. 6b does not have this function.
What can I use to read compressed data directly from memory? All I see is jpeg_stdio_src which reads from the hard drive.
Write your own...
/* Read JPEG image from a memory segment */
static void init_source (j_decompress_ptr cinfo) {}
static boolean fill_input_buffer (j_decompress_ptr cinfo)
{
ERREXIT(cinfo, JERR_INPUT_EMPTY);
return TRUE;
}
static void skip_input_data (j_decompress_ptr cinfo, long num_bytes)
{
struct jpeg_source_mgr* src = (struct jpeg_source_mgr*) cinfo->src;
if (num_bytes > 0) {
src->next_input_byte += (size_t) num_bytes;
src->bytes_in_buffer -= (size_t) num_bytes;
}
}
static void term_source (j_decompress_ptr cinfo) {}
static void jpeg_mem_src (j_decompress_ptr cinfo, void* buffer, long nbytes)
{
struct jpeg_source_mgr* src;
if (cinfo->src == NULL) { /* first time for this JPEG object? */
cinfo->src = (struct jpeg_source_mgr *)
(*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
SIZEOF(struct jpeg_source_mgr));
}
src = (struct jpeg_source_mgr*) cinfo->src;
src->init_source = init_source;
src->fill_input_buffer = fill_input_buffer;
src->skip_input_data = skip_input_data;
src->resync_to_restart = jpeg_resync_to_restart; /* use default method */
src->term_source = term_source;
src->bytes_in_buffer = nbytes;
src->next_input_byte = (JOCTET*)buffer;
}
and then to use it:
...
/* Step 2: specify data source (eg, a file) */
jpeg_mem_src(&dinfo, buffer, nbytes);
...
where buffer is a pointer to the memory chunk containing the compressed jpeg image, and nbytes is the length of that buffer.
Answering to poor s093294 who has been waiting for an answer for more than a year. I can't comment, so creating a new answer is the only way.
ERREXIT is a macro in libjpeg. Include jerror.h and you're all set.
Or you can also try to use GNU's fmemopen() function which should be declared in stdio.h header file.
FILE * source = fmemopen(inbuffer, inlength, "rb");
if (source == NULL)
{
fprintf(stderr, "Calling fmemopen() has failed.\n");
exit(1);
}
// ...
jpeg_stdio_src(&cinfo, source);
// ...
fclose(source);
I have found this function which uses libjpeg to write to a file:
int write_jpeg_file( char *filename )
{
struct jpeg_compress_struct cinfo;
struct jpeg_error_mgr jerr;
/* this is a pointer to one row of image data */
JSAMPROW row_pointer[1];
FILE *outfile = fopen( filename, "wb" );
if ( !outfile )
{
printf("Error opening output jpeg file %s\n!", filename );
return -1;
}
cinfo.err = jpeg_std_error( &jerr );
jpeg_create_compress(&cinfo);
jpeg_stdio_dest(&cinfo, outfile);
/* Setting the parameters of the output file here */
cinfo.image_width = width;
cinfo.image_height = height;
cinfo.input_components = bytes_per_pixel;
cinfo.in_color_space = color_space;
/* default compression parameters, we shouldn't be worried about these */
jpeg_set_defaults( &cinfo );
/* Now do the compression .. */
jpeg_start_compress( &cinfo, TRUE );
/* like reading a file, this time write one row at a time */
while( cinfo.next_scanline < cinfo.image_height )
{
row_pointer[0] = &raw_image[ cinfo.next_scanline * cinfo.image_width * cinfo.input_components];
jpeg_write_scanlines( &cinfo, row_pointer, 1 );
}
/* similar to read file, clean up after we're done compressing */
jpeg_finish_compress( &cinfo );
jpeg_destroy_compress( &cinfo );
fclose( outfile );
/* success code is 1! */
return 1;
}
I would actually need to write the jpeg compressed image just to memory buffer, without saving it to a file, to save time. Could somebody give me an example how to do it?
I have been searching the web for a while but the documentation is very rare if any and examples are also difficult to come by.
You can define your own destination manager quite easily. The jpeg_compress_struct contains a pointer to a jpeg_destination_mgr, which contains a pointer to a buffer, a count of space left in the buffer, and 3 pointers to functions:
init_destination (j_compress_ptr cinfo)
empty_output_buffer (j_compress_ptr cinfo)
term_destination (j_compress_ptr cinfo)
You need to fill in the function pointers before you make the first call into the jpeg library, and let those functions handle the buffer. If you create a buffer that is larger than the largest possible output that you expect, this becomes trivial; init_destination just fills in the buffer pointer and count, and empty_output_buffer and term_destination do nothing.
Here's some sample code:
std::vector<JOCTET> my_buffer;
#define BLOCK_SIZE 16384
void my_init_destination(j_compress_ptr cinfo)
{
my_buffer.resize(BLOCK_SIZE);
cinfo->dest->next_output_byte = &my_buffer[0];
cinfo->dest->free_in_buffer = my_buffer.size();
}
boolean my_empty_output_buffer(j_compress_ptr cinfo)
{
size_t oldsize = my_buffer.size();
my_buffer.resize(oldsize + BLOCK_SIZE);
cinfo->dest->next_output_byte = &my_buffer[oldsize];
cinfo->dest->free_in_buffer = my_buffer.size() - oldsize;
return true;
}
void my_term_destination(j_compress_ptr cinfo)
{
my_buffer.resize(my_buffer.size() - cinfo->dest->free_in_buffer);
}
cinfo->dest->init_destination = &my_init_destination;
cinfo->dest->empty_output_buffer = &my_empty_output_buffer;
cinfo->dest->term_destination = &my_term_destination;
There is a predefined function jpeg_mem_src defined in jdatasrc.c. The simplest usage example:
unsigned char *mem = NULL;
unsigned long mem_size = 0;
struct jpeg_compress_struct cinfo;
struct jpeg_error_mgr jerr;
cinfo.err = jpeg_std_error(&jerr);
jpeg_create_compress(&cinfo);
jpeg_mem_dest(&cinfo, &mem, &mem_size);
// do compression
// use mem buffer
Do not forget to deallocate your buffer.
I have tried Mark's solution and on my platform it always gives SEGMENTATION FALUT error when it executes
cinfo->dest->term_destination = &my_term_destination;
And I turned to the jpeglib source codes (jdatadst.c) and found this:
jpeg_mem_dest (j_compress_ptr cinfo, unsigned char ** outbuffer, unsigned long * outsize)
just below the method jpeg_stdio_dest(), and I've tried it by simply fill in the address of the buffer(char*) and the address of the buffer size(int). The destination manager automatically allocates memory for the buffer and the program need to free the memory after use.
It successfully runs on my platform, Beaglebone Black with the pre-installed Angstrom Linux. My libjpeg version is 8d.
All you need to do is pass a FILE-like object to jpeg_stdio_dest().
unsigned char ***image_ptr
unsigned char* ptr;
unsigned char** image_buf;
for(int i=0;i<h;i++){
image_buf[i] = new unsigned char[w*o];
}
ptr = image_buf[0];
while (info.output_scanline < info.image_height) {
jpeg_read_scanlines(&info,&ptr,1);
ptr = image_buf[c];
c++;
}
*image_ptr = image_buf;
This is all you need to read.
JSAMPROW row_pointer;
while (info.next_scanline < info.image_height) {
row_pointer = &image_buf[info.next_scanline][0];
(void) jpeg_write_scanlines(&info, &row_pointer, 1);
}
And this is all you need to write.
So I have this problem.
I have an IplImage that i want to compress to JPEG and do something with it. I use libjpeg.
I found a lot of answers "read through examples and docs" and such and did that. And successfully written a function for that.
FILE* convert2jpeg(IplImage* frame)
{
FILE* outstream = NULL;
outstream=malloc(frame->imageSize*frame->nChannels*sizeof(char))
unsigned char *outdata = (uchar *) frame->imageData;
struct jpeg_error_mgr jerr;
struct jpeg_compress_struct cinfo;
int row_stride;
JSAMPROW row_ptr[1];
jpeg_create_compress(&cinfo);
jpeg_stdio_dest(&cinfo, outstream);
cinfo.image_width = frame->width;
cinfo.image_height = frame->height;
cinfo.input_components = frame->nChannels;
cinfo.in_color_space = JCS_RGB;
jpeg_set_defaults(&cinfo);
jpeg_start_compress(&cinfo, TRUE);
row_stride = frame->width * frame->nChannels;
while (cinfo.next_scanline < cinfo.image_height) {
row_ptr[0] = &outdata[cinfo.next_scanline * row_stride];
jpeg_write_scanlines(&cinfo, row_ptr, 1);
}
jpeg_finish_compress(&cinfo);
jpeg_destroy_compress(&cinfo);
return outstream;
}
Now this function is straight from the examples (except the part of allocating memory, but i need that since i'm not writnig to a file), but it still doesn't work.
It dies on jpeg_start_compress(&cinfo, TRUE); part?
Can anybody help?
I've been able to found a solution using the latest jpeglib available on their website.
New methods in : jpeg_mem_dest(&cinfo, outbuffer, outlen);
bool ipl2jpeg(IplImage *frame, unsigned char **outbuffer, long unsigned int *outlen) {
unsigned char *outdata = (uchar *) frame->imageData;
struct jpeg_compress_struct cinfo = {0};
struct jpeg_error_mgr jerr;
JSAMPROW row_ptr[1];
int row_stride;
*outbuffer = NULL;
*outlen = 0;
cinfo.err = jpeg_std_error(&jerr);
jpeg_create_compress(&cinfo);
jpeg_mem_dest(&cinfo, outbuffer, outlen);
cinfo.image_width = frame->width;
cinfo.image_height = frame->height;
cinfo.input_components = frame->nChannels;
cinfo.in_color_space = JCS_RGB;
jpeg_set_defaults(&cinfo);
jpeg_start_compress(&cinfo, TRUE);
row_stride = frame->width * frame->nChannels;
while (cinfo.next_scanline < cinfo.image_height) {
row_ptr[0] = &outdata[cinfo.next_scanline * row_stride];
jpeg_write_scanlines(&cinfo, row_ptr, 1);
}
jpeg_finish_compress(&cinfo);
jpeg_destroy_compress(&cinfo);
return true;
}
I got it to work using the following code for memory to memory compression.
#include <stdio.h>
#include "jpeg/jpeglib.h"
/*
This a custom destination manager for jpeglib that
enables the use of memory to memory compression.
See IJG documentation for details.
*/
typedef struct {
struct jpeg_destination_mgr pub; /* base class */
JOCTET* buffer; /* buffer start address */
int bufsize; /* size of buffer */
size_t datasize; /* final size of compressed data */
int* outsize; /* user pointer to datasize */
int errcount; /* counts up write errors due to
buffer overruns */
} memory_destination_mgr;
typedef memory_destination_mgr* mem_dest_ptr;
/* ------------------------------------------------------------- */
/* MEMORY DESTINATION INTERFACE METHODS */
/* ------------------------------------------------------------- */
/* This function is called by the library before any data gets written */
METHODDEF(void)
init_destination (j_compress_ptr cinfo)
{
mem_dest_ptr dest = (mem_dest_ptr)cinfo->dest;
dest->pub.next_output_byte = dest->buffer; /* set destination buffer */
dest->pub.free_in_buffer = dest->bufsize; /* input buffer size */
dest->datasize = 0; /* reset output size */
dest->errcount = 0; /* reset error count */
}
/* This function is called by the library if the buffer fills up
I just reset destination pointer and buffer size here.
Note that this behavior, while preventing seg faults
will lead to invalid output streams as data is over-
written.
*/
METHODDEF(boolean)
empty_output_buffer (j_compress_ptr cinfo)
{
mem_dest_ptr dest = (mem_dest_ptr)cinfo->dest;
dest->pub.next_output_byte = dest->buffer;
dest->pub.free_in_buffer = dest->bufsize;
++dest->errcount; /* need to increase error count */
return TRUE;
}
/* Usually the library wants to flush output here.
I will calculate output buffer size here.
Note that results become incorrect, once
empty_output_buffer was called.
This situation is notified by errcount.
*/
METHODDEF(void)
term_destination (j_compress_ptr cinfo)
{
mem_dest_ptr dest = (mem_dest_ptr)cinfo->dest;
dest->datasize = dest->bufsize - dest->pub.free_in_buffer;
if (dest->outsize) *dest->outsize += (int)dest->datasize;
}
/* Override the default destination manager initialization
provided by jpeglib. Since we want to use memory-to-memory
compression, we need to use our own destination manager.
*/
GLOBAL(void)
jpeg_memory_dest (j_compress_ptr cinfo, JOCTET* buffer, int bufsize, int* outsize)
{
mem_dest_ptr dest;
/* first call for this instance - need to setup */
if (cinfo->dest == 0) {
cinfo->dest = (struct jpeg_destination_mgr *)
(*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
sizeof (memory_destination_mgr));
}
dest = (mem_dest_ptr) cinfo->dest;
dest->bufsize = bufsize;
dest->buffer = buffer;
dest->outsize = outsize;
/* set method callbacks */
dest->pub.init_destination = init_destination;
dest->pub.empty_output_buffer = empty_output_buffer;
dest->pub.term_destination = term_destination;
}
/* ------------------------------------------------------------- */
/* MEMORY SOURCE INTERFACE METHODS */
/* ------------------------------------------------------------- */
/* Called before data is read */
METHODDEF(void)
init_source (j_decompress_ptr dinfo)
{
/* nothing to do here, really. I mean. I'm not lazy or something, but...
we're actually through here. */
}
/* Called if the decoder wants some bytes that we cannot provide... */
METHODDEF(boolean)
fill_input_buffer (j_decompress_ptr dinfo)
{
/* we can't do anything about this. This might happen if the provided
buffer is either invalid with regards to its content or just a to
small bufsize has been given. */
/* fail. */
return FALSE;
}
/* From IJG docs: "it's not clear that being smart is worth much trouble"
So I save myself some trouble by ignoring this bit.
*/
METHODDEF(void)
skip_input_data (j_decompress_ptr dinfo, INT32 num_bytes)
{
/* There might be more data to skip than available in buffer.
This clearly is an error, so screw this mess. */
if ((size_t)num_bytes > dinfo->src->bytes_in_buffer) {
dinfo->src->next_input_byte = 0; /* no buffer byte */
dinfo->src->bytes_in_buffer = 0; /* no input left */
} else {
dinfo->src->next_input_byte += num_bytes;
dinfo->src->bytes_in_buffer -= num_bytes;
}
}
/* Finished with decompression */
METHODDEF(void)
term_source (j_decompress_ptr dinfo)
{
/* Again. Absolute laziness. Nothing to do here. Boring. */
}
GLOBAL(void)
jpeg_memory_src (j_decompress_ptr dinfo, unsigned char* buffer, size_t size)
{
struct jpeg_source_mgr* src;
/* first call for this instance - need to setup */
if (dinfo->src == 0) {
dinfo->src = (struct jpeg_source_mgr *)
(*dinfo->mem->alloc_small) ((j_common_ptr) dinfo, JPOOL_PERMANENT,
sizeof (struct jpeg_source_mgr));
}
src = dinfo->src;
src->next_input_byte = buffer;
src->bytes_in_buffer = size;
src->init_source = init_source;
src->fill_input_buffer = fill_input_buffer;
src->skip_input_data = skip_input_data;
src->term_source = term_source;
/* IJG recommend to use their function - as I don't know ****
about how to do better, I follow this recommendation */
src->resync_to_restart = jpeg_resync_to_restart;
}
And in your main compression function replace the jpeg_stdio_dest with
int numBytes = 0; //size of jpeg after compression
char * storage = new char[150000]; //storage buffer
JOCTET *jpgbuff = (JOCTET*)storage; //JOCTET pointer to buffer
jpeg_memory_dest(&cinfo,jpgbuff,150000,&numBytes);
The 150000 is a static size buffer, you probably will have images that will exceed it, so allocate accordingly.
I got in-memory compression to work. See the following
#define OUTPUT_BUF_SIZE 4096 /* choose an efficiently fwrite’able size */
/* Expanded data destination object for memory output */
typedef struct {
struct jpeg_destination_mgr pub; /* public fields */
unsigned char ** outbuffer; /* target buffer */
unsigned long * outsize;
unsigned char * newbuffer; /* newly allocated buffer */
JOCTET * buffer; /* start of buffer */
size_t bufsize;
} my_mem_destination_mgr;
typedef my_mem_destination_mgr * my_mem_dest_ptr;
void
init_mem_destination (j_compress_ptr cinfo)
{
/* no work necessary here */
}
boolean
empty_mem_output_buffer (j_compress_ptr cinfo)
{
size_t nextsize;
JOCTET * nextbuffer;
my_mem_dest_ptr dest = (my_mem_dest_ptr) cinfo->dest;
/* Try to allocate new buffer with double size */
nextsize = dest->bufsize * 2;
nextbuffer = (JOCTET *)malloc(nextsize);
if (nextbuffer == NULL)
ERREXIT1(cinfo, JERR_OUT_OF_MEMORY, 10);
memcpy(nextbuffer, dest->buffer, dest->bufsize);
if (dest->newbuffer != NULL)
free(dest->newbuffer);
dest->newbuffer = nextbuffer;
dest->pub.next_output_byte = nextbuffer + dest->bufsize;
dest->pub.free_in_buffer = dest->bufsize;
dest->buffer = nextbuffer;
dest->bufsize = nextsize;
return TRUE;
}
void
term_mem_destination (j_compress_ptr cinfo)
{
my_mem_dest_ptr dest = (my_mem_dest_ptr) cinfo->dest;
*dest->outbuffer = dest->buffer;
*dest->outsize = dest->bufsize – dest->pub.free_in_buffer;
}
void
jpeg_mem_dest (j_compress_ptr cinfo,
unsigned char ** outbuffer, unsigned long * outsize)
{
my_mem_dest_ptr dest;
if (outbuffer == NULL || outsize == NULL) /* sanity check */
ERREXIT(cinfo, JERR_BUFFER_SIZE);
/* The destination object is made permanent so that multiple JPEG images
* can be written to the same buffer without re-executing jpeg_mem_dest.
*/
if (cinfo->dest == NULL) { /* first time for this JPEG object? */
cinfo->dest = (struct jpeg_destination_mgr *)
(*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
sizeof(my_mem_destination_mgr));
}
dest = (my_mem_dest_ptr) cinfo->dest;
dest->pub.init_destination = init_mem_destination;
dest->pub.empty_output_buffer = empty_mem_output_buffer;
dest->pub.term_destination = term_mem_destination;
dest->outbuffer = outbuffer;
dest->outsize = outsize;
dest->newbuffer = NULL;
if (*outbuffer == NULL || *outsize == 0) {
/* Allocate initial buffer */
dest->newbuffer = *outbuffer = (unsigned char*)malloc(OUTPUT_BUF_SIZE);
if (dest->newbuffer == NULL)
ERREXIT1(cinfo, JERR_OUT_OF_MEMORY, 10);
*outsize = OUTPUT_BUF_SIZE;
}
dest->pub.next_output_byte = dest->buffer = *outbuffer;
dest->pub.free_in_buffer = dest->bufsize = *outsize;
}
//*******************************************************************************************
To use this do something like this in the main
/************/
unsigned long outlen;
unsigned char *outbuffer;
jpeg_mem_dest (&cinfo,&outbuffer,&outlen );
printf(“outlen is %lu\n”,(long unsigned int)outlen);
After fighting with libJpeg for 2 days (pointers, memory stepping, and pulling hair) I gave up and used the all favourite save-to-disk-load-to-memory approach, so if anybody is interested here is the method:
char* convert2jpeg(IplImage* frame, int* frame_size) {
FILE* infile = NULL;
struct stat fileinfo_buf;
if (cvSaveImage(name_buf, frame) < 0) {
printf("\nCan't save image %s", name_buf);
return NULL;
}
if (stat(name_buf, &fileinfo_buf) < 0) {
printf("\nPLAYER [convert2jpeg] stat");
return NULL;
}
*frame_size = fileinfo_buf.st_size;
char* buffer = (char *) malloc(fileinfo_buf.st_size + 1);
if ((infile = fopen(name_buf, "rb")) == NULL) {
printf("\nPLAYER [convert2jpeg] fopen %s", name_buf);
free(buffer);
return NULL;
}
fread(buffer, fileinfo_buf.st_size, 1, infile);
fclose(infile);
return buffer;
}
I hope somebody finds this usefull. I wish somebody from OpenCV developers sees this thread and implements direct to buffer JPEG conversion in OpenCV and spares us the misery and 1 save/load to disk operation.