Name |
Stores |
Compression |
Advantages |
Disadvantages |
|
jpg |
JPEG |
RGB |
DCT+zip (lossy) |
Amazingly tight compression, especially for photos. |
libjpeg is big, and no alpha channel. Can cause artifacts on sharp edges. |
png |
Portable Network Graphics |
RGBA or color table |
zip (lossless) |
Good compression for repeating patterns or flat colors, and can represent alpha channel properly. |
libpng is big, and not present by default on Windows machines. |
gif |
Graphics Interchange Format |
color table |
zip (lossless) |
Supported even by ancient code. Allows animation (like blinking banner ads!) |
Can't store 24-bit color images (only 8-bit table at most). |
bmp |
Windows Bitmap |
RGB |
None (usually) |
Builtin editors on Windows. Simple format. Also known as "pcx", which is the same format. |
Files are big. No alpha channel. |
tga |
TARGA |
RGBA |
Runlength |
Simple format--easy to read. See C++ ltga library and docs.
Unlike every other format, most tga files store the data from bottom to
top, which nicely matches OpenGL's default Y axis. |
Not completely
standardized. For example, some targas store un-premultiplied
alpha (normal R, G, B, A); others store premultiplied alpha
(RA,GA,BA,A). Files are big. |
ppm |
Portable Pixel Map |
RGB |
None |
Very simple ASCII header followed by binary data. |
ASCII header can include comments. Files are big. No alpha channel. |
int wid=200, ht=100;From OpenGL, you can dump out a PPM screenshot using glReadPixels anytime before glutSwapBuffers. This code is also in "ogl/ppm.h":
std::ofstream out("out.ppm",std::ios_base::binary);
out<<"P6\n" // <- ASCII header, then binary RGB data
<<wid<<" "<<ht<<"\n"
<<"255\n"; // maximum channel value is 255 (so 8-bit channels)
for (int y=0;y<ht;y++)
for (int x=0;x<wid;x++) {
unsigned char r=0xff,g=0,b=0; // red
float radius=sqrt(x*x+y*y);
if (radius<60) b=0xff; // purple
out<<r<<g<<b;
}
void savePPM(int start_x,int start_y,int w,int h,char *fname)
{
FILE *f=fopen(fname,"wb");
if (!f) return;
std::vector<unsigned char> out(3*w*h);
glPixelStorei(GL_PACK_ALIGNMENT,1); /* byte aligned output */
glReadPixels(start_x,start_y,w,h, GL_RGB,GL_UNSIGNED_BYTE,&out[0]);
fprintf(f,"P6\n%d %d\n255\n",w,h);
for (int y=0;y<h;y++) { /* flip image bottom-to-top on output */
fwrite(&out[3*(h-1-y)*w],1,3*w,f);
}
fclose(f);
}
#include "soil/SOIL.h" /* Simple OpenGL Image Library, www.lonesock.net/soil.html (plus Dr. LawlorFrom Nigel Stewart's GLT library, I extracted "ogl/image.h" and "ogl/image.cpp", and added a compact "readTextureFromFile" interface. It can read or write PPM, BMP, or TGA; and it has some #ifdef GLT_PNG code to read or write PNG via libpng.
's modifications) */
#include "soil/SOIL.c" /* just slap in implementation files here, for easier linking */
#include "soil/stb_image_aug.c"
GLuint load_soil_texture(const char *filename)
{
GLuint tex = SOIL_load_OGL_texture
(
filename,
SOIL_LOAD_AUTO,
SOIL_CREATE_NEW_ID,
SOIL_FLAG_MIPMAPS | SOIL_FLAG_INVERT_Y,
GL_RGBA8
);
glBindTexture(GL_TEXTURE_2D,tex);
return tex;
}
#include "ogl/image.h"
#include "ogl/image.cpp"
...
glBindTexture(GL_TEXTURE_2D,sometex);
readTextureFromFile("cat.ppm");
#include <jpeglib.h> /* needs -ljpeg, see http://www.ijg.org/ */Yes, this is a pain, but trust me--reading JPEG yourself is a whole lot worse!
// Read this JPEG file into the current OpenGL texture.
bool read_jpeg(const char *filename)
{
// Open file and set up decompressor:
FILE *f=fopen(filename,"rb");
if (f==NULL) return false; // couldn't open file.
struct jpeg_error_mgr jerr;
struct jpeg_decompress_struct cinfo;
cinfo.err = jpeg_std_error(&jerr);
jpeg_create_decompress(&cinfo);
jpeg_stdio_src(&cinfo, f);
jpeg_read_header(&cinfo, TRUE);
// Now we know the image size: allocate buffer
int w=cinfo.image_width, h=cinfo.image_height;
int bands=cinfo.num_components;
std::vector<unsigned char> buf(3*w*h); /* whole RGB buffer of data */
// Copy data out of JPEG file, row-by-row:
jpeg_start_decompress(&cinfo);
for (int y=0;y<h;y++) {
JSAMPLE *rows[1]; rows[0]=&buf[3*w*(h-1-y)];
jpeg_read_scanlines(&cinfo,rows,1);
}
jpeg_destroy_decompress(&cinfo);
fclose(f);
// Finally upload the read-in data
gluBuild2DMipmaps(GL_TEXTURE_2D,GL_RGBA8,
w,h, GL_RGB,GL_UNSIGNED_BYTE,&buf[0]);
return true;
}