protected boolean saveTGA(OutputStream output) { byte header[] = new byte[18]; if (format == ALPHA) { // save ALPHA images as 8bit grayscale header[2] = 0x0B; header[16] = 0x08; header[17] = 0x28; } else if (format == RGB) { header[2] = 0x0A; header[16] = 24; header[17] = 0x20; } else if (format == ARGB) { header[2] = 0x0A; header[16] = 32; header[17] = 0x28; } else { throw new RuntimeException("Image format not recognized inside save()"); } // set image dimensions lo-hi byte order header[12] = (byte) (width & 0xff); header[13] = (byte) (width >> 8); header[14] = (byte) (height & 0xff); header[15] = (byte) (height >> 8); try { output.write(header); int maxLen = height * width; int index = 0; int col; //, prevCol; int[] currChunk = new int[128]; // 8bit image exporter is in separate loop // to avoid excessive conditionals... if (format == ALPHA) { while (index < maxLen) { boolean isRLE = false; int rle = 1; currChunk[0] = col = pixels[index] & 0xff; while (index + rle < maxLen) { if (col != (pixels[index + rle]&0xff) || rle == 128) { isRLE = (rle > 1); break; } rle++; } if (isRLE) { output.write(0x80 | (rle - 1)); output.write(col); } else { rle = 1; while (index + rle < maxLen) { int cscan = pixels[index + rle] & 0xff; if ((col != cscan && rle < 128) || rle < 3) { currChunk[rle] = col = cscan; } else { if (col == cscan) rle -= 2; break; } rle++; } output.write(rle - 1); for (int i = 0; i < rle; i++) output.write(currChunk[i]); } index += rle; } } else { // export 24/32 bit TARGA while (index < maxLen) { boolean isRLE = false; currChunk[0] = col = pixels[index]; int rle = 1; // try to find repeating bytes (min. len = 2 pixels) // maximum chunk size is 128 pixels while (index + rle < maxLen) { if (col != pixels[index + rle] || rle == 128) { isRLE = (rle > 1); // set flag for RLE chunk break; } rle++; } if (isRLE) { output.write(128 | (rle - 1)); output.write(col & 0xff); output.write(col >> 8 & 0xff); output.write(col >> 16 & 0xff); if (format == ARGB) output.write(col >>> 24 & 0xff); } else { // not RLE rle = 1; while (index + rle < maxLen) { if ((col != pixels[index + rle] && rle < 128) || rle < 3) { currChunk[rle] = col = pixels[index + rle]; } else { // check if the exit condition was the start of // a repeating colour if (col == pixels[index + rle]) rle -= 2; break; } rle++; } // write uncompressed chunk output.write(rle - 1); if (format == ARGB) { for (int i = 0; i < rle; i++) { col = currChunk[i]; output.write(col & 0xff); output.write(col >> 8 & 0xff); output.write(col >> 16 & 0xff); output.write(col >>> 24 & 0xff); } } else { for (int i = 0; i < rle; i++) { col = currChunk[i]; output.write(col & 0xff); output.write(col >> 8 & 0xff); output.write(col >> 16 & 0xff); } } } index += rle; } } output.flush(); return true; } catch (IOException e) { e.printStackTrace(); return false; } }