loading Targa images

if you ever wanted to load images with an embedded alpha channel, TGA (Targa) is a feasible format as long as the image is not too big and too complex. this is because the bitmap is stored uncompressed and tends to be very large in filesize, so for sketches intended to run online, the only compression applied to it will be the LZW one of the .jar file the image will reside in. in my tests i got results between 25-50% of the original filesize. below is some code for loading such an image. like the default loadImage() function, loadTarga() also returns a standard BImage object.

void setup() {
  BImage img=loadTarga(”test.tga”);
  // resize screen to image dimensions
  size(img.width,img.height);
  image(img,0,0);
}

BImage loadTarga(String file) {
  // load image file as byte array
  byte[] buffer=loadBytes(file);

  // check if it’s a TGA and has 8bits/colour channel
  if (buffer[2] == 2 && buffer[17] == 8) {
    // get image dimensions
    int w=(b2i(buffer[13])<<8) + b2i(buffer[12]);
    int h=(b2i(buffer[15])<<8) + b2i(buffer[14]);
    // check if image has alpha
    boolean hasAlpha=(buffer[16] == 32);

    // setup new image object
    BImage img=new BImage(w,h);
    img.format=(hasAlpha ? RGBA : RGB);

    // targa’s are written upside down, so we need to parse it in reverse
    int index = (h-1) * w;
    // actual bitmap data starts at byte 18
    int offset=18;

    // read out line by line
    for (int y = h-1; y >= 0; y–) {
      for (int x = 0; x < w; x++) {
        // merge RGB components first
        img.pixels[index + x] = b2i(buffer[offset++]) |
            b2i(buffer[offset++])<<8 |
            b2i(buffer[offset++])<<16;
        // then set alpha based on data or revert to 100%
        // (if there’s only a 24bit image)
        if (hasAlpha) img.pixels[index + x]|=b2i(buffer[offset++])<<24;
        else img.pixels[index + x]|=0xff000000;
      }
      // next scanline
      index -= w;
    }
    return img;
  }
  println(”loadTarga(): wrong image format”);
  return null;
}

// byte to integer conversion
int b2i(byte b) {
  return (int)(b<0 ? 256+b : b);
}