libjpeg sample code howto
This is a sample file that demonstrates how to open and write a jpeg image file using the libjpeg library. This file is a starting point for manipulating jpeg images, and you can use the file "as is" without worrying about the internals of the libjpeg library. Below, I provide some explanations about the workings of the sample file, how to build/run it and how it actually works internally.
Where is it?
Here. Unpack the tarball like this in a terminal:
tar xzf jpeg_sample.tar.gz
This will unpack the compressed tar file and create a directory called sample, with a makefile, a jpeg file and a source file called jpeg_sample.c.
Compile, how?
Provided you have gcc and libjpeg development libraries installed, type make and that will compile and build the program. The final executable will be called jpeg_sample.
What exactly is in this sample code?
The jpeg_sample.c file shows how to use the libjpeg library to read a jpeg file into an uncompressed buffer, and also how to write an uncompressed (i.e. raw) buffer as a jpeg image file. It contains two functions called read_jpeg_file(char *filename) and write_jpeg_file(char *filename) to do exactly these two things. The argument char *filename in both the functions is the name of the file to read from or write to, respectively.
How does it really work?
Okay, this is a simple use of libjpeg that I'm going to discuss, and you'll have to use for your assignment. As you might know, JPEG files are compressed images, meaning the actual image data is squeezed in a smaller file, almost like a zip or gz file (try compressing a jpeg image, you won't be able to compress it much compared to a text file). The major task is to decompress this compressed image into an uncompressed buffer and manipulate the image data in that buffer. When we're done, we have to write this uncompressed buffer back to a jpeg file.
Now lets look at the code a bit. The read_jpeg_file function reads a jpeg image file into the unsigned character buffer called raw_image.
/* we will be using this uninitialized pointer later to
store raw, uncompressed image */
unsigned char *raw_image = NULL;
This buffer will be filled by the read_jpeg_file function. Now what of the image dimensions? Look into the read_jpeg_file function and you'll see these lines:
/* reading the image header which contains image information */
jpeg_read_header( &cinfo, TRUE );
/* Uncomment the following to output image information, if needed. */
/*--
printf( "JPEG File Information: \n" );
printf( "Image width and height: %d pixels and %d pixels.\n",\\
cinfo.image_width, cinfo.image_height );
printf( "Color components per pixel: %d.\n", cinfo.num_components );
printf( "Color space: %d.\n", cinfo.jpeg_color_space );
--*/
The cinfo structure contains information about the jpeg image being read. This information includes (but not limited to) image width and height, and color information (how many bytes per pixel, which is either 3 for color or 1 for grayscale). For example, from the code snipped above, cinfo.image_width would give the width of the jpeg image being read. To handle images of any sizes and accordingly allocate memory for the raw_image buffer, you have to save this information in the global variables called width and height. The following code snippet shows how.
/*This is from the beginning of the file*/
/* dimensions of the image we want to write */
/*Thes values are dummy values, doesn't matter what you put here.*/
int width = 1600;
int height = 1200;
.....
.....
/* this is the modification of the read_jpeg_file function, with
added code for setting input image dimensions */
/* Start decompression jpeg here */
jpeg_start_decompress( &cinfo );
/* save image dimension information */
width = cinfo.image_width;
height = cinfo.image_height;
bytes_per_pixel = cinfo.num_components;
/* allocate memory to hold the uncompressed image */
raw_image = (unsigned char*)malloc( width*height*bytes_per_pixel );
....
/* The rest is unchanged */
Doing it like this would ensure whatever dimensions the image might have, it is saved in a global variable for use later, particularly for writing the jpeg file back using write_jpeg_file.