26

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.

Richard Knop
  • 81,041
  • 149
  • 392
  • 552

5 Answers5

19

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;
Mark Ransom
  • 299,747
  • 42
  • 398
  • 622
  • I imagine that these function pointers are what `jpeg_stdio_dest` affects? – Ben Voigt Dec 30 '10 at 04:44
  • @Ben Voigt, looking at the source to `jpeg_stdio_dest` that's exactly what it does. It allocates a structure and sets it into `cinfo->dest`, then sets the pointers. I'm thinking my own sample code may be a little incomplete since it doesn't create a `jpeg_destination_mgr` structure, but I'll look into that later. – Mark Ransom Dec 30 '10 at 05:33
  • Oh, of course. You can [store your own data (the `std::vector`) immediately following the function pointers and not need global variables](http://blogs.msdn.com/b/oldnewthing/archive/2010/12/20/10107027.aspx). – Ben Voigt Dec 30 '10 at 05:37
  • @Ben, I like the way you think. – Mark Ransom Dec 30 '10 at 05:44
  • I probably wouldn't have thunk it if Raymond hadn't just blogged about it recently (although I have used the method with OVERLAPPED structures before, it's been long enough it wouldn't have come to mind). – Ben Voigt Dec 30 '10 at 05:46
  • 7
    Since jpeglib release 8a of April 2010, there is an API `jpeg_mem_dest` to do this (see http://freecode.com/projects/libjpeg) – mpromonet Nov 07 '14 at 18:40
  • @BenVoigt I hate the way Microsoft continually shakes up their web links. Your blog link is dead now, and I can't even find it on Raymond's blog history. Wayback machine to the rescue: https://web.archive.org/web/20150731202315/http://blogs.msdn.com/b/oldnewthing/archive/2010/12/20/10107027.aspx – Mark Ransom Nov 03 '22 at 16:04
  • 1
    @BenVoigt took another stab at it and finally figured out where Microsoft moved the page to! https://devblogs.microsoft.com/oldnewthing/20101220-01/?p=11963 – Mark Ransom Nov 03 '22 at 22:49
15

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.

dmitriykovalev
  • 534
  • 3
  • 6
  • 1
    Not in my `jdatasrc.c` (libjpeg-6b). – Daniel Baulig Nov 06 '13 at 00:08
  • 2
    The latest stable release of libjpeg is 9, you can get it here http://www.ijg.org/files/jpegsr9.zip and it does contain jpeg_mem_src. – dmitriykovalev Dec 02 '13 at 00:13
  • Do you call free or delete on the mem buffer? I called delete [] and valgrind gave me a mismatched delete warning. Used free() and the warning disappeared. – shehzan Apr 21 '15 at 21:52
  • @shehzan You have to use free(). libjpeg is a C library, it knows nothing of C++ `new` and `delete`. – rvighne Apr 12 '17 at 05:57
  • Note that you cannot use jpeg_mem_src from a shared library; if you do, the memory will be allocated on a different heap and all sorts of things will explode when you try to free it in your own heap. I have no idea why they didn't include a jpeg_mem_free to free the memory when you're done – taxilian Aug 24 '18 at 20:11
3

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.

Gus Z
  • 31
  • 3
0
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.

DavidPostill
  • 7,734
  • 9
  • 41
  • 60
s kettle
  • 1
  • 5
  • 9
    **Warning** - please do not use obscenities in your posts. I've removed it for you. Note that other users may have flagged your post as "rude or abusive" leading to possible rep loss or suspension. Please read [Be Nice](http://superuser.com/help/be-nice): "Avoid vulgar terms and anything sexually suggestive" – DavidPostill Oct 16 '16 at 13:55
0

All you need to do is pass a FILE-like object to jpeg_stdio_dest().

Conrad Meyer
  • 2,851
  • 21
  • 24