OpenGL and libjpeg: Using Software Libraries in C
OpenGL and libjpeg: Using Software Libraries in C

This is a PSA for anyone who’d ever want to load jpegs into an OpenGL program (in c)…

Loading textures into OpenGL is a pain. The API expects the image information to be presented to it in binary form, of which the user may choose from:

(Full listing @http://www.opengl.org/sdk/docs/man/xhtml/glTexImage2D.xml)

The first pain a user faces is getting a binary stream loaded. While the rest of OpenGL is calling blackbox functions, the user must write a file opening routine:

FILE *image = fopen("texture.raw", "rb");
//must be a power of two in both dimensions
int height = 512;
int width = 512;
GLuint texture;
glGenTextures(1, texture);
glBindTexture(GL_TEXTURE_2D, texture);
glTexImage2D(GL_TEXTURE_2D, 0, 3, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, image);

But then its not always so obvious how to convert a given image into a raw format, how to skip past the header if it’s an almost raw format, etc.

Most users want to use a common format that’s easy to work with. Since lftextures uses digital still cameras as it’s input, loading the jpegs directly seemed like a fantastic idea.

Fantastic until you see the code:

FILE *fd;
unsigned char *image;
int width, height, depth;
fd = fopen("texture.jpg", "rb");
struct jpeg_decompress_struct cinfo;
struct jpeg_error_mgr jerr;
JSAMPROW row_pointer[1];
unsigned long location = 0;
cinfo.err = jpeg_std_error(&jerr);
jpeg_create_decompress(&cinfo);
jpeg_stdio_src(&cinfo, fd);
jpeg_read_header(&cinfo, 0);
cinfo.scale_num = 1;
cinfo.scale_denom = SCALE;
jpeg_start_decompress(&cinfo);
width = cinfo.output_width;
height = cinfo.output_height;
depth = cinfo.num_components; //should always be 3
image = (unsigned char *) malloc(width * height * depth);
row_pointer[0] = (unsigned char *) malloc(width * depth);
/* read one scan line at a time */
while( cinfo.output_scanline < cinfo.output_height )
{
	jpeg_read_scanlines( &cinfo, row_pointer, 1 );
	for( i=0; i< (width * depth); i++)
	image[location++] = row_pointer[0][i];
}
fclose(fd);
jpeg_finish_decompress(&cinfo);
jpeg_destroy_decompress(&cinfo);
free(row_pointer[1]);

Then you’ll want to load this into a texture; the code is the same as above except we’ll use the GL_TEXTURE_RECTANGLE_ARB extension to allow for any sized image:

GLuint texture;
glGenTextures(1, texture);
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, texture);
glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, depth, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, image);
Last and most importantly; to use the libjpeg library you need to include it:
#include  
and compile like so:
gcc -ljpeg this.c

Other examples:
http://www.cim.mcgill.ca/~junaed/libjpeg.php
http://www.jpegcameras.com/libjpeg/example.c%3frev=1.4

libjpeg specification:
http://www.jpegcameras.com/libjpeg/libjpeg.html

  1. opengl

    on February 19, 2010 at 00:26

    opengl…

    How do I find a windows vista supported driver for a Radeon S9250 graphics card? Can anyone tell me more about opengl?…

  2. matti

    on February 19, 2010 at 09:25

    On ATI’s official site, the drop-down menu for drivers doesn’t have an option for the Radeon 9250 when Windows vista is selected. It does have one when Windows XP is selected. Downgrade to XP, run linux, use the XP driver in compatibilty mode, or buy a new graphics card.

  3. jacekmigacz

    on February 22, 2012 at 04:21

    free(row_pointer[0]) is missing

  4. matti

    on February 22, 2012 at 09:37

    !!! It is missing! It’s even missing in the source code I based these snippets on.

    I was under the {false,correct} impression that a `JSAMPROW row_pointer[1];` would be unallocated when the variable lost scope…


Leave a Comment?

Send me an email, then I'll place our discussion on this page (with your permission).


Return | About/Contact