Ray Tracing 002: Other Image Formats


Other Image Formats with stb_image.h

The stb_image.h single-file library makes it pretty easy to write and convert images to other file formats. I love the simplicity of the PPM format, but it’s not very web-friendly. If you want to share the image you will likely end up having to convert it to a different format.

Here’s a sample in C++:

// stb-example.cpp
#include <iostream>

#define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h"
#define STB_IMAGE_WRITE_IMPLEMENTATION
#include "stb_image_write.h"

int main() {
  int x, y, n;
  // unsigned char *data = stbi_load("foo.png", &x, &y, &n, 0);
  unsigned char *data = NULL;
  const char* filename = "./stb-example.png";

  int nx = 200;
  int ny = 100;

  // yeah, malloc is probably not the best approach
  // @todo Find out today's best practices for memory management
  data = (unsigned char*) malloc(nx * ny * 3);
  if (data == NULL) {
    printf("Could not alloc image buffer.\n");
    return 0;
  } 

  for (int j = ny-1; j >= 0; j--) {
    for (int i = 0; i < nx; i++) {
      float r = float(i) / float(nx);
      float g = float(j) / float(ny);
      float b = 0.2;

      int ir = int(255.99 * r);
      int ig = int(255.99 * g);
      int ib = int(255.99 * b);

      data[((ny-j-1)*nx+i)*3+0] = ir;
      data[((ny-j-1)*nx+i)*3+1] = ig;
      data[((ny-j-1)*nx+i)*3+2] = ib;
    }
  }

  stbi_write_png(filename, nx, ny, 3, data, 0);
}

// Makefile
CC = g++
CFLAGS = -g
INCFLAGS = -I./ -I./stb/
RM = /bin/rm -f

all: stb-example
stb-example: stb-example.o
  $(CC) $(CFLAGS) -o stb-example stb-example.o
stb-example.o: stb-example.cpp
  $(CC) $(CFLAGS) $(INCFLAGS) -c stb-example.cpp
clean:
  $(RM) *.o stb-example *.png
run: stb-example
  ./stb-example

The complete example is also available in my git repo at github.com/celeph/ray-tracing.

Credits and Further Reading

Next Steps