tags:

views:

1317

answers:

3

Hey all,

I'm on Ubuntu Intrepid and I'm using jpeglib62 6b-14. I was working on some code, which only gave a black screen with some garbled output at the top when I tried to run it. After a few hours of debugging I got it down to pretty much the JPEG base, so I took the example code, wrote a little piece of code around it and the output was exactly the same.

I'm convinced jpeglib is used in a lot more places on this system and it's simply the version from the repositories so I'm hesitant to say that this is a bug in jpeglib or the Ubuntu packaging.

I put the example code below (most comments stripped). The input JPEG file is an uncompressed 640x480 file with 3 channels, so it should be 921600 bytes (and it is). The output image is JFIF and around 9000 bytes, and mangled, as you can see.

If you could help me with even a hint, I'd be very grateful.

Thanks!

#include <stdio.h>
#include <stdlib.h>
#include "jpeglib.h"
#include <setjmp.h>

int main ()
{
  // read data
  FILE *input = fopen("input.jpg", "rb");
  JSAMPLE *image_buffer = (JSAMPLE*) malloc(sizeof(JSAMPLE) * 640 * 480 * 3);
  if(input == NULL or image_buffer == NULL)
    exit(1);
  fread(image_buffer, 640 * 3, 480, input);

  // initialise jpeg library
  struct jpeg_compress_struct cinfo;
  struct jpeg_error_mgr jerr;
  cinfo.err = jpeg_std_error(&jerr);
  jpeg_create_compress(&cinfo);

  // write to foo.jpg
  FILE *outfile = fopen("foo.jpg", "wb");
  if (outfile == NULL)
    exit(1);
  jpeg_stdio_dest(&cinfo, outfile);

  // setup library
  cinfo.image_width = 640;
  cinfo.image_height = 480;
  cinfo.input_components = 3; // 3 components (R, G, B)
  cinfo.in_color_space = JCS_RGB; // RGB
  jpeg_set_defaults(&cinfo); // set defaults

  // start compressing
  int row_stride = 640 * 3; // number of characters in a row
  JSAMPROW row_pointer[1]; // pointer to the current row data
  jpeg_start_compress(&cinfo, TRUE); // start compressing to jpeg

  while (cinfo.next_scanline < cinfo.image_height) {
    row_pointer[0] = & image_buffer[cinfo.next_scanline * row_stride];
    (void) jpeg_write_scanlines(&cinfo, row_pointer, 1);
  }

  jpeg_finish_compress(&cinfo);

  // clean up
  fclose(outfile);
  jpeg_destroy_compress(&cinfo);
}
+2  A: 

You're reading a JPEG file into memory (without decompressing it) and writing out that buffer as if it were uncompressed, that's why you're getting garbage. You need to decompress the image first before you can feed it into the JPEG compressor.

In other words, the JPEG compressor assumes that its input is raw pixels.

You can convert your input image into raw RGB using ImageMagick:

convert input.jpg rgb:input.raw

It should be exactly 921600 bytes in size.

EDIT: Your question is misleading when you state that your input JPEG file in uncompressed. Anyway, I compiled your code and it works fine, compresses the image correctly. If you can upload the file you're using as input, it might be possible to debug further. If not, I suggest you test your program using an image created from a known JPEG using ImageMagick:

convert some_image_that_is_really_a_jpg.jpg -resize 640x480! rgb:input.jpg
codelogic
Thanks for your answer, but:"The input JPEG file is an uncompressed 640x480 file with 3 channels, so it should be 921600 bytes (and it is)."It's uncompressed, and it *is* 921600 bytes in size!
dazjorz
What the...? When I run compress on the original image, then run jpeginfo on the result (which is also 621600 bytes), I get "Not a JPEG file: starts with 0x80 0x78" and then when I run the program on it, I get a valid result image! What's going on here?! :S
dazjorz
(eh, 921600 bytes, sorry)
dazjorz
Turns out the input image was 921600 bytes by some weird coincidence. It had a jpeg header, so something was wrong anyway. I'm now uncompressing it (using SDL) before recompressing. Thanks :-)
dazjorz
+1  A: 

You are reading the input file into memmory compressed and then you are recompressing it before righting to file. You need to decompress the image_buffer before compressing it again. Or alternativly instead of reading in a jpeg read a .raw image

hhafez
Thanks for your answer, but:"The input JPEG file is an uncompressed 640x480 file with 3 channels, so it should be 921600 bytes (and it is)."It's uncompressed, and it *is* 921600 bytes in size!
dazjorz
+1  A: 

What exactly do you mean by "The input JPEG file is an uncompressed"? Jpegs are all compressed.

In your code, it seems that in the loop you give one row of pixels to libjpeg and ask it to compress it. It doesn't work that way. libjpeg has to have at least 8 rows to start compression (sometimes even more, depending on parameters). So it's best to leave libjpeg to control the input buffer and don't do its job for it.

I suggest you read how cjpeg.c does its job. The easiest way I think is to put your data in a raw type known by libjpeg (say, BMP), and use libjpeg to read the BMP image into its internal representation and compress from there.

PolyThinker
This is from the jpeg example code, it's supposed to be done like this. And not all jpegs are compressed - in that way, this jpeg has the raw image data readily available, therefore the size: 640 * 480 * 3, exactly one byte per color channel per cell. Therefore uncompressed.
dazjorz
However, per the reply up above - it seems the image at least has a jpeg header, which it maybe shouldn't have. It's still exactly 921600 bytes though - so there may be some compression. I'll write some decompression code.
dazjorz