/**************************************************************************** * targa.c * * This module contains the code to read and write the Targa output file * format. * * from Persistence of Vision(tm) Ray Tracer * Copyright 1996 Persistence of Vision Team *--------------------------------------------------------------------------- * NOTICE: This source code file is provided so that users may experiment * with enhancements to POV-Ray and to port the software to platforms other * than those supported by the POV-Ray Team. There are strict rules under * which you are permitted to use this file. The rules are in the file * named POVLEGAL.DOC which should be distributed with this file. If * POVLEGAL.DOC is not available or for more info please contact the POV-Ray * Team Coordinator by leaving a message in CompuServe's Graphics Developer's * Forum. The latest version of POV-Ray may be found there as well. * * This program is based on the popular DKB raytracer version 2.12. * DKBTrace was originally written by David K. Buck. * DKBTrace Ver 2.0-2.12 were written by David K. Buck & Aaron A. Collins. * *****************************************************************************/ /**************************************************************************** * * Explanation: * * - * * --- * * May 1994 : Support for 24-bit RLE Targa output files added: John Baily * and David Payne. * * Jul 1994 : Resume trace support and minor algorithm fix (one more still * needed, see comments in Write_Targa_Line); resume will force * Targa format to match the original trace format -- the T or C * format flag is adjusted as necessary: Charles Marslett, * * Jun 1995 : Added support for 32-bit Targa input and output files. * The alpha channel has a value of 0 for 100% transparency * and a value of 255 for 0% transparency. [DB] * *****************************************************************************/ #include "frame.h" #include "povproto.h" #include "povray.h" #include "targa.h" /***************************************************************************** * Local preprocessor defines ******************************************************************************/ #define boolean int /***************************************************************************** * Local typedefs ******************************************************************************/ typedef struct pix { DBL blue, green, red, transm; } pix; /***************************************************************************** * Local variables ******************************************************************************/ static int Targa_Line_Number; static unsigned char idbuf[256]; /***************************************************************************** * Static functions ******************************************************************************/ static void convert_targa_color PARAMS((IMAGE_COLOUR *, unsigned, unsigned char *)); static int Open_Targa_File PARAMS((FILE_HANDLE *handle, char *name, int *width, int *height, int buffer_size, int mode)); static void Write_Targa_Line PARAMS((FILE_HANDLE *handle, COLOUR *line_data, int line_number)); static int Read_Targa_Line PARAMS((FILE_HANDLE *handle, COLOUR *line_data, int *line_number)); static void Close_Targa_File PARAMS((FILE_HANDLE *handle)); static void Write_Targa_Pixel PARAMS((FILE_HANDLE *handle, DBL b, DBL g, DBL r, DBL f)); /***************************************************************************** * * FUNCTION * * Get_Targa_File_Handle * * INPUT * * OUTPUT * * RETURNS * * AUTHOR * * POV-Ray Team * * DESCRIPTION * * - * * CHANGES * * - * ******************************************************************************/ FILE_HANDLE *Get_Targa_File_Handle() { FILE_HANDLE *handle; handle = (FILE_HANDLE *)POV_MALLOC(sizeof(FILE_HANDLE), "TGA file handle"); handle->Open_File_p = Open_Targa_File; handle->Write_Line_p = Write_Targa_Line; handle->Read_Line_p = Read_Targa_Line; handle->Read_Image_p = Read_Targa_Image; handle->Close_File_p = Close_Targa_File; handle->file = NULL; handle->buffer = NULL; handle->buffer_size = 0; return(handle); } /***************************************************************************** * * FUNCTION * * Open_Targa_File * * INPUT * * OUTPUT * * RETURNS * * AUTHOR * * POV-Ray Team * * DESCRIPTION * * - * * CHANGES * * Jun 1995 : Added code for 32 bit Targa files. [DB] * * Sept 1995: Modified header output for Targa files. [AED] * ******************************************************************************/ static int Open_Targa_File (handle, name, width, height, buffer_size, mode) FILE_HANDLE *handle; char *name; int *width; int *height; int buffer_size; int mode; { unsigned char tgaheader[18]; handle->mode = mode; handle->filename = name; Targa_Line_Number = 0; switch (mode) { case READ_MODE: /* We can't resume from stdout. */ if (opts.Options & TO_STDOUT || (handle->file = fopen(name, READ_FILE_STRING)) == NULL) { Status_Info("\n"); return(0); } /* Read targa header information. */ if (fread(tgaheader, 18, 1, handle->file) != 1) { return(0); } /* Decipher the header information */ switch (tgaheader[2]) { case 2 : opts.OutputFormat = 'T'; break; case 10 : opts.OutputFormat = 'C'; break; default : return(0); } switch (tgaheader[16]) { case 24 : break; case 32 : opts.Options |= OUTPUT_ALPHA; break; default : return(0); } /* First_Column set to x offset. Bytes 8, 9 */ opts.First_Column = tgaheader[8] + (tgaheader[9] << 8); /* First line set to y offset. Bytes 10, 11 */ opts.First_Line = Targa_Line_Number = tgaheader[10] + (tgaheader[11]<<8); handle->width = *width = tgaheader[12] + (tgaheader[13] << 8); handle->height = *height = tgaheader[14] + (tgaheader[15] << 8); handle->buffer_size = buffer_size; Status_Info("\nResuming interrupted trace from %s",handle->filename); break; case WRITE_MODE: if (opts.Options & TO_STDOUT) { buffer_size = 0; handle->file = stdout; } else if ((handle->file = fopen (name, WRITE_FILE_STRING)) == NULL) { return(0); } if (buffer_size != 0) { handle->buffer = POV_MALLOC((size_t)buffer_size, "TGA file buffer"); setvbuf (handle->file, handle->buffer, _IOFBF, buffer_size); } /* Output TGA file header info */ putc(0, handle->file); /* Byte 0 - Length of Image ID field */ putc(0, handle->file); /* Byte 1 - Color map type (0 is no color map) */ switch(opts.OutputFormat) /* Byte 2 - TGA file type */ { case 't': /* Uncompressed True-Color Image */ case 'T': case 's': case 'S': putc(2, handle->file); break; case 'c': /* Run-length compressed True-Color Image */ case 'C': putc(10, handle->file); break; } putc(0, handle->file); /* Byte 3 - Index of first color map entry LSB */ putc(0, handle->file); /* Byte 4 - Index of first color map entry MSB */ putc(0, handle->file); /* Byte 5 - Color map length LSB */ putc(0, handle->file); /* Byte 6 - Color map legth MSB */ putc(0, handle->file); /* Byte 7 - Color map size */ /* x origin set to "First_Column" Bytes 8, 9 */ putc(opts.First_Column % 256, handle->file); putc(opts.First_Column / 256, handle->file); /* y origin set to "First_Line" Bytes 10, 11 */ putc(opts.First_Line % 256, handle->file); putc(opts.First_Line / 256, handle->file); /* write width and height Bytes 12 - 15 */ putc(*width % 256, handle->file); putc(*width / 256, handle->file); putc(*height % 256, handle->file); putc(*height / 256, handle->file); /* We write 24 or 32 bits/pixel (16 million colors and alpha channel) * and also store the orientation and Alpha channel depth. Bytes 16, 17. */ if (opts.Options & OUTPUT_ALPHA) { putc(32, handle->file); /* 32 bits/pixel (BGRA) */ putc(0x28, handle->file); /* Data starts at top left, 8 bits Alpha */ } else { putc(24, handle->file); /* 24 bits/pixel (BGR) */ putc(0x20, handle->file); /* Data starts at top left, 0 bits Alpha */ } /* TGA file Image ID field data would go here (up to 255 chars) */ handle->width = *width; handle->height = *height; handle->buffer_size = buffer_size; break; case APPEND_MODE: if (opts.Options & TO_STDOUT) { buffer_size = 0; handle->file = stdout; } else if ((handle->file = fopen (name, APPEND_FILE_STRING)) == NULL) { return(0); } else if (buffer_size != 0) { handle->buffer = POV_MALLOC((size_t)buffer_size, "TGA file buffer"); setvbuf (handle->file, handle->buffer, _IOFBF, buffer_size); } break; } return(1); } /***************************************************************************** * * FUNCTION * * Write_Targa_Pixel * * INPUT * * handle - Current file handel * r, g, b, f - Color values to write * * OUTPUT * * RETURNS * * AUTHOR * * Dan Farmer * * DESCRIPTION : * * Moves redundant code to a single function. Adding 16 bit grayscale * conditional code to each occurance of writing a pixel was getting a bit * too wordy. * * CHANGES * * Jun 1995 : Added code for 32 bit Targa files. [DB] * * Sept 1995: Modified handling of Alpha channel to use only opts.Options * Sept 1995: Modified handling of grayscale to use only opts.Options * ******************************************************************************/ static void Write_Targa_Pixel (handle, b, g, r, f) FILE_HANDLE *handle; DBL r, g, b, f; { unsigned int gray; if (opts.Options & HF_GRAY_16) { /* Ouput heightfield in POV red/green format */ gray = ((0.30 * r) + (0.59 * g) + (0.11 * b)) * 65535; if ((putc(0 , handle->file) == EOF) || (putc(gray & 0xFF, handle->file) == EOF) || (putc((gray >> 8) & 0xFF, handle->file) == EOF)) { Error("Error writing TGA output data to %s.\n",handle->filename); } } else { /* Normal 24/32 bit pixel coloring */ if ((putc((int) floor(b * 255.0), handle->file) == EOF) || (putc((int) floor(g * 255.0), handle->file) == EOF) || (putc((int) floor(r * 255.0), handle->file) == EOF)) { Error("Error writing TGA output data to %s.\n",handle->filename); } if (opts.Options & OUTPUT_ALPHA) { if (putc((int) floor((1.0 - f) * 255.0), handle->file) == EOF) { Error("Error writing TGA output data to %s.\n",handle->filename); } } } } /***************************************************************************** * * FUNCTION * * Write_Targa_Line * * INPUT * * OUTPUT * * RETURNS * * AUTHOR * * POV-Ray Team * * DESCRIPTION * * - * * CHANGES * * Jun 1995 : Added code for 32 bit Targa files. [DB] * ******************************************************************************/ static void Write_Targa_Line (handle, line_data, line_number) FILE_HANDLE *handle; COLOUR *line_data; int line_number; { register int x; int ptype, cnt, llen, startx; boolean writenow; pix curpix, nexpix; switch (opts.OutputFormat) { case 't': case 'T': case 's': case 'S': for (x = 0; x < handle->width; x++) { Write_Targa_Pixel (handle, line_data[x][BLUE], line_data[x][GREEN], line_data[x][RED], line_data[x][TRANSM]); } break; case 'c': case 'C': llen = handle->width; startx = 0; cnt = 1; curpix.blue = line_data[startx][BLUE]; curpix.green = line_data[startx][GREEN]; curpix.red = line_data[startx][RED]; curpix.transm = line_data[startx][TRANSM]; ptype = 0; writenow = FALSE; for (;;) { nexpix.blue = line_data[startx+cnt][BLUE]; nexpix.green = line_data[startx+cnt][GREEN]; nexpix.red = line_data[startx+cnt][RED]; nexpix.transm = line_data[startx+cnt][TRANSM]; if ((nexpix.red == curpix.red) && (nexpix.blue == curpix.blue) && (nexpix.green == curpix.green) && (nexpix.transm == curpix.transm)) { if (ptype == 0) { cnt++; if ((cnt >= 128) || ((startx + cnt) >= llen)) { writenow = TRUE; } } else { cnt--; writenow = TRUE; } } else { if ((ptype == 1) || (cnt <= 1)) { ptype = 1; curpix = nexpix; cnt++; if ((cnt >= 128) || ((startx + cnt) >= llen)) { writenow = TRUE; } } else { writenow = TRUE; } } if (writenow) { /* This test SHOULD be unnecessary! However, it isn't! [CWM] */ if (startx + cnt > llen) { cnt = llen - startx; } if (ptype == 0) { putc((int) ((cnt - 1) | 0x80), handle->file); Write_Targa_Pixel (handle, curpix.blue, curpix.green, curpix.red, curpix.transm); curpix = nexpix; } else { putc((int) cnt - 1, handle->file); for (x = 0; x < cnt; x++) { Write_Targa_Pixel (handle, line_data[startx+x][BLUE], line_data[startx+x][GREEN], line_data[startx+x][RED], line_data[startx+x][TRANSM]); } } startx = startx + cnt; writenow = FALSE; ptype = 0; cnt = 1; if (startx >= llen) { break; /* Exit while */ } } } break; /* End of case */ } if (handle->buffer_size == 0) { /* Close and reopen file (if not stdout) for integrity in case we crash */ fflush(handle->file); if (!(opts.Options & TO_STDOUT)) { handle->file = freopen(handle->filename, APPEND_FILE_STRING, handle->file); } } } /***************************************************************************** * * FUNCTION * * Read_Targa_Line * * INPUT * * OUTPUT * * RETURNS * * AUTHOR * * POV-Ray Team * * DESCRIPTION * * - * * CHANGES * * Jun 1995 : Added code for 32 bit Targa files. [DB] * ******************************************************************************/ static int Read_Targa_Line (handle, line_data, line_number) FILE_HANDLE *handle; COLOUR *line_data; int *line_number; { int x, data, cnt; DBL rdata, gdata, bdata, fdata; switch (opts.OutputFormat) { case 't': case 'T': case 's': case 'S': for (x = 0; x < handle->width; x++) { /* Read the BLUE data byte. If EOF is reached on the first * character read, then this line hasn't been rendered yet. * Return 0. If an EOF occurs somewhere within the line, this * is an error - return -1. */ if ((data = getc(handle->file)) == EOF) { if (x == 0) { return(0); } else { return(-1); } } line_data[x][BLUE] = (DBL) data / 255.0; /* Read the GREEN data byte. */ if ((data = getc(handle->file)) == EOF) { return(-1); } line_data[x][GREEN] = (DBL) data / 255.0; /* Read the RED data byte. */ if ((data = getc(handle->file)) == EOF) { return(-1); } line_data[x][RED] = (DBL) data / 255.0; /* Read alpha channel. */ if (opts.Options & OUTPUT_ALPHA) { if ((data = getc(handle->file)) == EOF) { return(-1); } line_data[x][TRANSM] = 1.0 - (DBL)data / 255.0; } else { line_data[x][TRANSM] = 0.0; } } break; case 'c': case 'C': cnt = 0; do { if ((data = getc(handle->file)) == EOF) { if (cnt == 0) { return(0); } else { return(-1); } } if (data & 0x80) { x = data & 0x7F; if ((data = getc(handle->file)) == EOF) { return(-1); } bdata = (DBL) data / 255.0; if ((data = getc(handle->file)) == EOF) { return(-1); } gdata = (DBL) data / 255.0; if ((data = getc(handle->file)) == EOF) { return(-1); } rdata = (DBL) data / 255.0; /* Read alpha channel if any. */ if (opts.Options & OUTPUT_ALPHA) { if ((data = getc(handle->file)) == EOF) { return(-1); } fdata = 1.0 - (DBL)data / 255.0; } else { fdata = 0.0; } do { line_data[cnt][BLUE] = bdata; line_data[cnt][GREEN] = gdata; line_data[cnt][RED] = rdata; line_data[cnt][TRANSM] = fdata; cnt++; } while (--x != -1); } else { x = data & 0x7F; do { if ((data = getc(handle->file)) == EOF) { return(-1); } bdata = (DBL) data / 255.0; if ((data = getc(handle->file)) == EOF) { return(-1); } gdata = (DBL) data / 255.0; if ((data = getc(handle->file)) == EOF) { return(-1); } rdata = (DBL) data / 255.0; /* Read alpha channel if any. */ if (opts.Options & OUTPUT_ALPHA) { if ((data = getc(handle->file)) == EOF) { return(-1); } fdata = 1.0 - (DBL)data / 255.0; } else { fdata = 0.0; } line_data[cnt][BLUE] = bdata; line_data[cnt][GREEN] = gdata; line_data[cnt][RED] = rdata; line_data[cnt][TRANSM] = fdata; cnt++; } while (--x != -1); } } while (cnt < handle->width); if (cnt != handle->width) { return(-1); } break; } *line_number = Targa_Line_Number++; return(1); } /***************************************************************************** * * FUNCTION * * Close_Targa_File * * INPUT * * OUTPUT * * RETURNS * * AUTHOR * * POV-Ray Team * * DESCRIPTION * * - * * CHANGES * * - * ******************************************************************************/ static void Close_Targa_File (handle) FILE_HANDLE *handle; { if (handle->file) { fflush(handle->file); if (!(opts.Options & TO_STDOUT)) fclose (handle->file); } if (handle->buffer != NULL) { POV_FREE (handle->buffer); } handle->file = NULL; handle->buffer = NULL; } /***************************************************************************** * * FUNCTION * * convert_targa_color * * INPUT * * OUTPUT * * RETURNS * * AUTHOR * * POV-Ray Team * * DESCRIPTION * * - * * CHANGES * * - * ******************************************************************************/ static void convert_targa_color(tcolor, pixelsize, bytes) IMAGE_COLOUR *tcolor; unsigned pixelsize; unsigned char *bytes; { switch (pixelsize) { case 1: tcolor->Red = bytes[0]; tcolor->Green = bytes[0]; tcolor->Blue = bytes[0]; tcolor->Filter = 0; tcolor->Transmit = 0; break; case 2: tcolor->Red = ((bytes[1] & 0x7c) << 1); tcolor->Green = (((bytes[1] & 0x03) << 3) | ((bytes[0] & 0xe0) >> 5)) << 3; tcolor->Blue = (bytes[0] & 0x1f) << 3; tcolor->Filter = 0; tcolor->Transmit = 255 - (bytes[1] & 0x80 ? 255 : 0); break; case 3: tcolor->Red = bytes[2]; tcolor->Green = bytes[1]; tcolor->Blue = bytes[0]; tcolor->Filter = 0; tcolor->Transmit = 0; break; case 4: tcolor->Red = bytes[2]; tcolor->Green = bytes[1]; tcolor->Blue = bytes[0]; tcolor->Filter = 0; tcolor->Transmit = 255 - bytes[3]; break; default: Error("Bad pixelsize in TGA color.\n"); } } /***************************************************************************** * * FUNCTION * * Read_Targa_Image * * INPUT * * OUTPUT * * RETURNS * * AUTHOR * * POV-Ray Team * * DESCRIPTION * * Reads a Targa image into an RGB image buffer. Handles 8, 16, 24, 32 bit * formats. Raw or color mapped. Simple raster and RLE compressed pixel * encoding. Right side up or upside down orientations. * * CHANGES * * Jun 1995 : Added code for 32 bit Targa files. [DB] * ******************************************************************************/ void Read_Targa_Image(Image, name) IMAGE *Image; char *name; { int h; int temp; unsigned i, j, k; unsigned char cflag = 0, *map_line = NULL, bytes[4], tgaheader[18]; unsigned ftype, idlen, cmlen, cmsiz, psize, orien; unsigned width, height; FILE *filep; IMAGE_LINE *line_data = NULL; IMAGE_COLOUR *cmap, pixel; /* Start by trying to open the file */ if ((filep = Locate_File(name, READ_FILE_STRING,".tga",".TGA",TRUE)) == NULL) { Error ("Error opening TGA image.\n"); } if (fread(tgaheader, 18, 1, filep) != 1) { Error ("Error reading header of TGA image.\n"); } /* Decipher the header information */ idlen = tgaheader[ 0]; ftype = tgaheader[ 2]; cmlen = tgaheader[ 5] + (tgaheader[ 6] << 8); cmsiz = tgaheader[ 7] / 8; width = tgaheader[12] + (tgaheader[13] << 8); height = tgaheader[14] + (tgaheader[15] << 8); psize = tgaheader[16] / 8; orien = tgaheader[17] & 0x20; /* Right side up ? */ Image->iwidth = width; Image->iheight = height; Image->width = (DBL)width; Image->height = (DBL)height; Image->Colour_Map_Size = cmlen; Image->Colour_Map = NULL; /* Determine if this is a supported Targa type */ if (ftype == 9 || ftype == 10 || ftype == 11) { cflag = 1; } else { if (ftype == 1 || ftype == 2 || ftype == 3) { cflag = 0; } else { Error("Unsupported file type %d in TGA image.\n", ftype); } } /* Skip over the picture ID information */ if (idlen > 0 && fread(idbuf, idlen, 1, filep) != 1) { Error ("Error reading header from TGA image.\n"); } /* Read in the the color map (if any) */ if (cmlen > 0) { if (psize != 1) { Error("Unsupported color map bit depth (%d bpp) in TGA image.\n", psize * 8); } cmap = (IMAGE_COLOUR *)POV_MALLOC(cmlen * sizeof(IMAGE_COLOUR), "TGA color map"); for (i = 0; i < cmlen; i++) { for (j = 0; j < cmsiz; j++) { if ((temp = fgetc(filep)) == EOF) { Error("Error reading color map from TGA image.\n"); } else { bytes[j] = (unsigned char)temp; } } convert_targa_color(&cmap[i], cmsiz, bytes); } Image->Colour_Map = cmap; } else { Image->Colour_Map = NULL; } /* Allocate the buffer for the image */ if (cmlen > 0) { Image->data.map_lines = (unsigned char **)POV_MALLOC(height * sizeof(unsigned char *), "TGA image"); } else { Image->data.rgb_lines = (IMAGE_LINE *)POV_MALLOC(height * sizeof(IMAGE_LINE), "TGA image"); } for (i = 0; i < height; i++) { k = width * sizeof(unsigned char); if (cmlen > 0) { map_line = (unsigned char *)POV_MALLOC((size_t)k, "TGA image line"); Image->data.map_lines[i] = map_line; } else { line_data = &Image->data.rgb_lines[i]; line_data->red = (unsigned char *)POV_MALLOC((size_t)k, "TGA image line"); line_data->green = (unsigned char *)POV_MALLOC((size_t)k, "TGA image line"); line_data->blue = (unsigned char *)POV_MALLOC((size_t)k, "TGA image line"); if (psize > 3) { line_data->transm = (unsigned char *)POV_MALLOC((size_t)k, "TGA image line"); } else { line_data->transm = (unsigned char *)NULL; } } } /* Read the image into the buffer */ if (cflag) { /* RLE compressed images */ if (cmlen > 0) { if (orien) { map_line = Image->data.map_lines[0]; } else { map_line = Image->data.map_lines[height-1]; } } else { if (orien) { line_data = &Image->data.rgb_lines[0]; } else { line_data = &Image->data.rgb_lines[height-1]; } } i = 0; /* row counter */ j = 0; /* column counter */ while (i < height) { /* Grab a header */ if ((h = fgetc(filep)) == EOF) { Error("Error reading data from TGA image.\n"); } if (h & 0x80) { /* Repeat buffer */ h &= 0x7F; for (k = 0; k < psize; k++) { if ((temp = fgetc(filep)) == EOF) { Error("Error reading data from TGA image.\n"); } else { bytes[k] = (unsigned char)temp; } } if (cmlen == 0) { convert_targa_color(&pixel, psize, bytes); } for (; h >= 0; h--) { if (cmlen > 0) { map_line[j] = bytes[0]; } else { line_data->red[j] = (unsigned char)pixel.Red; line_data->green[j] = (unsigned char)pixel.Green; line_data->blue[j] = (unsigned char)pixel.Blue; if (psize > 3) { line_data->transm[j] = (unsigned char)pixel.Transmit; } } if (++j == width) { i++; if (cmlen > 0) { if (orien) { map_line = Image->data.map_lines[i]; } else { map_line = Image->data.map_lines[height-i-1]; } } else { line_data += (orien ? 1 : -1); } j = 0; } } } else { /* Copy buffer */ for (; h >= 0; h--) { for (k = 0; k < psize ; k++) { if ((temp = fgetc(filep)) == EOF) { Error("Error reading data from TGA image.\n"); } else { bytes[k] = (unsigned char)temp; } } if (cmlen > 0) { map_line[j] = bytes[0]; } else { convert_targa_color(&pixel, psize, bytes); line_data->red[j] = (unsigned char)pixel.Red; line_data->green[j] = (unsigned char)pixel.Green; line_data->blue[j] = (unsigned char)pixel.Blue; if (psize > 3) { line_data->transm[j] = (unsigned char)pixel.Transmit; } } if (++j == width) { i++; if (cmlen > 0) { if (orien) { map_line = Image->data.map_lines[i]; } else { map_line = Image->data.map_lines[height-i-1]; } } else { line_data += (orien ? 1 : -1); } j = 0; } } } } } else { /* Simple raster image file, read in all of the pixels */ if (cmlen == 0) { if (orien) { line_data = &Image->data.rgb_lines[0]; } else { line_data = &Image->data.rgb_lines[height-1]; } } for (i = 0; i < height; i++) { if (cmlen > 0) { if (orien) { map_line = Image->data.map_lines[i]; } else { map_line = Image->data.map_lines[height-i-1]; } } for (j = 0; j < width; j++) { for (k = 0; k < psize; k++) { if ((temp = fgetc(filep)) == EOF) { Error("Error reading data from TGA image.\n"); } else { bytes[k] = (unsigned char)temp; } } if (cmlen > 0) { map_line[j] = bytes[0]; } else { convert_targa_color(&pixel, psize, bytes); line_data->red[j] = (unsigned char)pixel.Red; line_data->green[j] = (unsigned char)pixel.Green; line_data->blue[j] = (unsigned char)pixel.Blue; if (psize > 3) { line_data->transm[j] = (unsigned char)pixel.Transmit; } } } if (cmlen == 0) { line_data += (orien ? 1 : -1); } } } /* Any data following the image is ignored. */ /* Close the image file */ fclose(filep); }