/** * tga_reader.c * * Copyright (c) 2014 Kenji Sasaki * Released under the MIT license. * https://github.com/npedotnet/TGAReader/blob/master/LICENSE * * English document * https://github.com/npedotnet/TGAReader/blob/master/README.md * * Japanese document * http://3dtech.jp/wiki/index.php?TGAReader * */ #include "tga_reader.h" static const TGA_ORDER _TGA_READER_ARGB = {16, 8, 0, 24}; const TGA_ORDER *TGA_READER_ARGB = &_TGA_READER_ARGB; static const TGA_ORDER _TGA_READER_ABGR = {0, 8, 16, 24}; const TGA_ORDER *TGA_READER_ABGR = &_TGA_READER_ABGR; static const TGA_ORDER _TGA_READER_RGBA = {24, 16, 8, 0}; const TGA_ORDER *TGA_READER_RGBA = &_TGA_READER_RGBA; void *tgaMalloc(size_t size) { return malloc(size); } void tgaFree(void *memory) { free(memory); } int tgaGetWidth(const unsigned char *buffer) { return (buffer[12] & 0xFF) | (buffer[13] & 0xFF) << 8; } int tgaGetHeight(const unsigned char *buffer) { return (buffer[14] & 0xFF) | (buffer[15] & 0xFF) << 8; } #define COLORMAP 1 #define RGB 2 #define GRAYSCALE 3 #define COLORMAP_RLE 9 #define RGB_RLE 10 #define GRAYSCALE_RLE 11 #define RIGHT_ORIGIN 0x10 #define UPPER_ORIGIN 0x20 static unsigned char *decodeRLE(int width, int height, int depth, const unsigned char *buffer, int offset); static int *createPixelsFromColormap(int width, int height, int depth, const unsigned char *bytes, int offset, const unsigned char *palette, int colormapOrigin, int descriptor, const TGA_ORDER *order); static int *createPixelsFromRGB(int width, int height, int depth, const unsigned char *bytes, int offset, int descriptor, const TGA_ORDER *order); static int *createPixelsFromGrayscale(int width, int height, int depth, const unsigned char *bytes, int offset, int descriptor, const TGA_ORDER *order); int *tgaRead(const unsigned char *buffer, const TGA_ORDER *order) { // header // int idFieldLength = buffer[0] & 0xFF; // int colormapType = buffer[1] & 0xFF; int type = buffer[2] & 0xFF; int colormapOrigin = (buffer[3] & 0xFF) | (buffer[4] & 0xFF) << 8; int colormapLength = (buffer[5] & 0xFF) | (buffer[6] & 0xFF) << 8; int colormapDepth = buffer[7] & 0xFF; // int originX = (buffer[8] & 0xFF) | (buffer[9] & 0xFF) << 8; // unsupported // int originY = (buffer[10] & 0xFF) | (buffer[11] & 0xFF) << 8; // unsupported int width = tgaGetWidth(buffer); int height = tgaGetHeight(buffer); int depth = buffer[16] & 0xFF; int descriptor = buffer[17] & 0xFF; int *pixels = NULL; // data switch(type) { case COLORMAP: { int imageDataOffset = 18 + (colormapDepth / 8) * colormapLength; pixels = createPixelsFromColormap(width, height, colormapDepth, buffer, imageDataOffset, buffer, colormapOrigin, descriptor, order); } break; case RGB: pixels = createPixelsFromRGB(width, height, depth, buffer, 18, descriptor, order); break; case GRAYSCALE: pixels = createPixelsFromGrayscale(width, height, depth, buffer, 18, descriptor, order); break; case COLORMAP_RLE: { int imageDataOffset = 18 + (colormapDepth / 8) * colormapLength; unsigned char *decodeBuffer = decodeRLE(width, height, depth, buffer, imageDataOffset); pixels = createPixelsFromColormap(width, height, colormapDepth, decodeBuffer, 0, buffer, colormapOrigin, descriptor, order); tgaFree(decodeBuffer); } break; case RGB_RLE: { unsigned char *decodeBuffer = decodeRLE(width, height, depth, buffer, 18); pixels = createPixelsFromRGB(width, height, depth, decodeBuffer, 0, descriptor, order); tgaFree(decodeBuffer); } break; case GRAYSCALE_RLE: { unsigned char *decodeBuffer = decodeRLE(width, height, depth, buffer, 18); pixels = createPixelsFromGrayscale(width, height, depth, decodeBuffer, 0, descriptor, order); tgaFree(decodeBuffer); } break; default: break; } return pixels; } static unsigned char *decodeRLE(int width, int height, int depth, const unsigned char *buffer, int offset) { int elementCount = depth/8; unsigned char elements[4]; int decodeBufferLength = elementCount * width * height; unsigned char *decodeBuffer = (unsigned char *)tgaMalloc(decodeBufferLength); int decoded = 0; while(decoded < decodeBufferLength) { int packet = buffer[offset++] & 0xFF; if((packet & 0x80) != 0) { // RLE int i, j, count; for(i=0; iredShift; int gs = order->greenShift; int bs = order->blueShift; int as = order->alphaShift; switch(depth) { case 24: pixels = (int *)tgaMalloc(4*width*height); if((descriptor & RIGHT_ORIGIN) != 0) { if((descriptor & UPPER_ORIGIN) != 0) { // UpperRight int i, j; for(i=0; i= 0) { int index = 3*colormapIndex+18; int b = palette[index+0] & 0xFF; int g = palette[index+1] & 0xFF; int r = palette[index+2] & 0xFF; int a = 0xFF; color = (r<= 0) { int index = 3*colormapIndex+18; int b = palette[index+0] & 0xFF; int g = palette[index+1] & 0xFF; int r = palette[index+2] & 0xFF; int a = 0xFF; color = (r<= 0) { int index = 3*colormapIndex+18; int b = palette[index+0] & 0xFF; int g = palette[index+1] & 0xFF; int r = palette[index+2] & 0xFF; int a = 0xFF; color = (r<= 0) { int index = 3*colormapIndex+18; int b = palette[index+0] & 0xFF; int g = palette[index+1] & 0xFF; int r = palette[index+2] & 0xFF; int a = 0xFF; color = (r<= 0) { int index = 4*colormapIndex+18; int b = palette[index+0] & 0xFF; int g = palette[index+1] & 0xFF; int r = palette[index+2] & 0xFF; int a = palette[index+3] & 0xFF; color = (r<= 0) { int index = 4*colormapIndex+18; int b = palette[index+0] & 0xFF; int g = palette[index+1] & 0xFF; int r = palette[index+2] & 0xFF; int a = palette[index+3] & 0xFF; color = (r<= 0) { int index = 4*colormapIndex+18; int b = palette[index+0] & 0xFF; int g = palette[index+1] & 0xFF; int r = palette[index+2] & 0xFF; int a = palette[index+3] & 0xFF; color = (r<= 0) { int index = 4*colormapIndex+18; int b = palette[index+0] & 0xFF; int g = palette[index+1] & 0xFF; int r = palette[index+2] & 0xFF; int a = palette[index+3] & 0xFF; color = (r<redShift; int gs = order->greenShift; int bs = order->blueShift; int as = order->alphaShift; switch(depth) { case 24: pixels = (int *)tgaMalloc(4*width*height); if((descriptor & RIGHT_ORIGIN) != 0) { if((descriptor & UPPER_ORIGIN) != 0) { // UpperRight int i, j; for(i=0; iredShift; int gs = order->greenShift; int bs = order->blueShift; int as = order->alphaShift; switch(depth) { case 8: pixels = (int *)tgaMalloc(4*width*height); if((descriptor & RIGHT_ORIGIN) != 0) { if((descriptor & UPPER_ORIGIN) != 0) { // UpperRight int i, j; for(i=0; i