code: package org.sunflow.image.readers;
  
  import java.io.BufferedInputStream;
  import java.io.FileInputStream;
  import java.io.IOException;
  import java.io.InputStream;
  
  import org.sunflow.image.Bitmap;
  import org.sunflow.image.BitmapReader;
  import org.sunflow.image.Color;
  import org.sunflow.image.formats.BitmapG8;
  import org.sunflow.image.formats.BitmapRGB8;
  import org.sunflow.image.formats.BitmapRGBA8;
  
  public class TGABitmapReader implements BitmapReader {
      private static final int[] CHANNEL_INDEX = { 2, 1, 0, 3 };
  
      public Bitmap load(String filename, boolean isLinear) throws IOException, BitmapFormatException {
          InputStream f = new BufferedInputStream(new FileInputStream(filename));
          byte[] read = new byte[4];
  
          // read header
          int idsize = f.read();
          int cmaptype = f.read(); // cmap byte (unsupported)
          if (cmaptype != 0)
              throw new BitmapFormatException(String.format("Colormapping (type: %d) is unsupported", cmaptype));
          int datatype = f.read();
  
          // colormap info (5 bytes ignored)
          f.read();
          f.read();
          f.read();
          f.read();
          f.read();
  
          f.read(); // xstart, 16 bits (ignored)
          f.read();
          f.read(); // ystart, 16 bits (ignored)
          f.read();
  
          // read resolution
          int width = f.read();
          width |= f.read() << 8;
          int height = f.read();
          height |= f.read() << 8;
  
          int bits = f.read();
          int bpp = bits / 8;
  
          int imgdscr = f.read();
  
          // skip image ID if present
          if (idsize != 0)
              f.skip(idsize);
  
          // allocate byte buffer to hold the image
          byte[] pixels = new byte[width * height * bpp];
          if (datatype == 2 || datatype == 3) {
              if (bpp != 1 && bpp != 3 && bpp != 4)
                  throw new BitmapFormatException(String.format("Invalid bit depth in uncompressed TGA: %d", bits));
              // uncompressed image
              for (int ptr = 0; ptr < pixels.length; ptr += bpp) {
                  // read bytes
                  f.read(read, 0, bpp);
                  for (int i = 0; i < bpp; i++)
                      pixels[ptr + CHANNEL_INDEX[i]] = read[i];
              }
          } else if (datatype == 10) {
              if (bpp != 3 && bpp != 4)
                  throw new BitmapFormatException(String.format("Invalid bit depth in run-length encoded TGA: %d", bits));
              // RLE encoded image
              for (int ptr = 0; ptr < pixels.length;) {
                  int rle = f.read();
                  int num = 1 + (rle & 0x7F);
                  if ((rle & 0x80) != 0) {
                      // rle packet - decode length and copy pixel
                      f.read(read, 0, bpp);
                      for (int j = 0; j < num; j++) {
                          for (int i = 0; i < bpp; i++)
                              pixels[ptr + CHANNEL_INDEX[i]] = read[i];
                          ptr += bpp;
                      }
                  } else {
                      // raw packet - decode length and read pixels
                      for (int j = 0; j < num; j++) {
                          f.read(read, 0, bpp);
                          for (int i = 0; i < bpp; i++)
                              pixels[ptr + CHANNEL_INDEX[i]] = read[i];
                          ptr += bpp;
                      }
                  }
              }
          } else
              throw new BitmapFormatException(String.format("Unsupported TGA image type: %d", datatype));
  
          if (!isLinear) {
              // apply reverse correction
              for (int ptr = 0; ptr < pixels.length; ptr += bpp) {
                  for (int i = 0; i < 3 && i < bpp; i++)
                      pixels[ptr + i] = Color.NATIVE_SPACE.rgbToLinear(pixels[ptr + i]);
              }
          }
  
          // should image be flipped in Y?
          if ((imgdscr & 32) == 32) {
              for (int y = 0, pix_ptr = 0; y < (height / 2); y++) {
                  int bot_ptr = bpp * (height - y - 1) * width;
                  for (int x = 0; x < width; x++) {
                      for (int i = 0; i < bpp; i++) {
                          byte t = pixels[pix_ptr + i];
                          pixels[pix_ptr + i] = pixels[bot_ptr + i];
                          pixels[bot_ptr + i] = t;
                      }
                      pix_ptr += bpp;
                      bot_ptr += bpp;
                  }
              }
  
          }
          f.close();
          switch (bpp) {
              case 1:
                  return new BitmapG8(width, height, pixels);
              case 3:
                  return new BitmapRGB8(width, height, pixels);
              case 4:
                  return new BitmapRGBA8(width, height, pixels);
          }
          throw new BitmapFormatException("Inconsistent code in TGA reader");
      }
  }