/***************************************************************** * fltga.c: FBM Release 1.0 25-Feb-90 Ian MacPhedran * * Author Ian MacPhedran. * Permission is given to use any portion of this file, (including * its entirety) for whatever you wish. Howvever, please note that * it was written for Michael Mauldin's FBM Library, and conditions * therein are more restrictive. * * FBM is Copyright (C) 1989,1990 by Michael Mauldin. Permission * is granted to use this file in whole or in part for any purpose, * educational, recreational or commercial, provided that this * copyright notice is retained unchanged. This software is * available to all free of charge by anonymous FTP and in the * UUNET archives. * * CONTENTS * read_tga (image, rfile, mstr, mlen) * write_tga (image, wfile) * * HISTORY * 25-Jun-90 Michael Mauldin (mlm@cs.cmu.edu) Carnegie Mellon * Package for Release 1.0 * * 13-Mar-89 Ian J. MacPhedran * Add write_tga * * 07-Mar-89 Ian J. MacPhedran, University of Saskatchewan. * Created. *****************************************************************/ #include #include "fbm.h" #ifndef lint static char *fbmid = "$FBM fltga.c <1.0> 25-Jun-90 by Ian MacPhedran, source code available \ free from MLM@CS.CMU.EDU and from UUNET archives$"; #endif /* For convenience, the TGA header file is included herein. */ /* * Header file for Targa file definitions. * * These definitions will allow a consistant interface to build Targa (.TGA) * image files. * * Created NOV-15-1988 IJMP * */ /* File header definition */ struct TGA_ImageHeader { unsigned char IDLength;/* Length of Identifier String */ unsigned char CoMapType; /* 0 = NoMap */ unsigned char ImgType; /* Image Type (1,2,3,9,10) */ unsigned char Index_lo, Index_hi; /* Index of first colour map entry */ unsigned char Length_lo, Length_hi; /* Length of colour map (number of entries) */ unsigned char CoSize; /* Length of colour map entry */ unsigned char X_org_lo, X_org_hi; /* X Origin of Image */ unsigned char Y_org_lo, Y_org_hi; /* Y Origin of Image */ unsigned char Width_lo, Width_hi; /* Width of Image */ unsigned char Height_lo, Height_hi; /* Height of Image */ unsigned char PixelSize; /* Pixel Size (8,16,24) */ unsigned AttBits : 4; /* Number of Attribute Bits per pixel */ unsigned Rsrvd : 1; /* Reserved bit */ unsigned OrgBit : 1; /* Origin Bit (0=lower left, 1=upper left) */ unsigned IntrLve : 2; /* Interleaving Flag */ }; char TGA_ImageIDField[256]; /* Definitions for Image Types */ #define TGA_MapRGBType 1 #define TGA_RawRGBType 2 #define TGA_RawMonoType 3 #define TGA_MapEnCodeType 9 #define TGA_RawEnCodeType 10 /* * read_tga(image, rfile, mstr, mlen) * from tga2rast.c: * Version 1.0 - first released for public consumption, 21 Feb, 1989 * */ #define MAXCOLOURS 16384 /* Define flags for mode - these indicate special conditions */ #define GREYSC 0 #define COLOUR 1 #define MAPPED 2 #define RLENCD 4 #define INTERL 8 #define FOURWY 16 unsigned char ColourMap[MAXCOLOURS][3]; int RLE_count=0,RLE_flag=0; read_tga(image, rfile, mstr, mlen) FBM *image; FILE *rfile; char *mstr; int mlen; { /* Define Identifiers */ struct TGA_ImageHeader *tga; int i, j, l; unsigned int temp1, temp2, mode; unsigned char r, g, b; unsigned long k, baseline,linewidth; unsigned char *Red, *Grn, *Blu, *Redk, *Grnk, *Bluk; /* Input the Targa file header */ if ((tga=(struct TGA_ImageHeader *) malloc(sizeof(struct TGA_ImageHeader))) == NULL) { fprintf(stderr,"Can't allocate TGA memory\n"); exit(1); } if ((i = fread(tga,1,18,rfile)) != 18) { fprintf(stderr,"Read only %d bytes in header\n",i); exit(1); } switch (tga->ImgType) { case TGA_MapRGBType: case TGA_RawRGBType: case TGA_RawMonoType: case TGA_MapEnCodeType: case TGA_RawEnCodeType: break; default: fprintf(stderr,"Targa File Type %d",tga->ImgType); fprintf(stderr," not supported!\n"); exit(1); } /* Create output image header */ temp1 = tga->Height_lo; temp2 = tga->Height_hi; image->hdr.rows = temp1 + temp2 * 256; temp1 = tga->Width_lo; temp2 = tga->Width_hi; image->hdr.cols = temp1 + temp2 * 256; /* If this is odd number of bytes, add one */ if ((image->hdr.cols & 1) != 0) image->hdr.cols++; /* If greyscale, use only one plane */ if (tga->ImgType == TGA_RawMonoType) { image->hdr.planes = 1; mode = GREYSC; } else { image->hdr.planes = 3; mode = COLOUR; } /* Uses 8 bits, sort of - 16 bits/pixel is 5 bits per colour */ image->hdr.bits = 8; image->hdr.physbits = 8; image->hdr.rowlen = image->hdr.cols; image->hdr.plnlen = image->hdr.rows * image->hdr.cols; /* Ignore colour map for this version. */ image->hdr.clrlen = 0; image->hdr.aspect = 1.0; image->hdr.title[0] = '\0'; image->hdr.credits[0] = '\0'; /* Get the Image */ alloc_fbm(image); /* Read ID String, if present */ if (tga->IDLength != 0) fread(TGA_ImageIDField,1,tga->IDLength,rfile); /* If present, read the colour map information */ if (tga->CoMapType != 0) { temp1 = tga->Index_lo + tga->Index_hi * 256; temp2 = tga->Length_lo + tga->Length_hi * 256; if ((temp1+temp2+1) >= MAXCOLOURS) { fprintf(stderr,"Too many colours %d\n",(temp1+temp2+1)); exit(1); } for (i=temp1; i<(temp1+temp2); i++) get_map_entry(&ColourMap[i][0],&ColourMap[i][1], &ColourMap[i][2],tga->CoSize,mode); if ((tga->ImgType != TGA_RawRGBType) && (tga->ImgType != TGA_RawMonoType) && (tga->ImgType != TGA_RawEnCodeType)) mode = mode | MAPPED; } /* Check Run Length Encoding */ if ((tga->ImgType == TGA_MapEnCodeType) || (tga->ImgType == TGA_RawEnCodeType)) mode = mode | RLENCD; /* Check for interlacing of the Targa file */ switch (tga->IntrLve) { case 2: /* Four way interlace */ mode = mode | FOURWY; case 1: /* Two way interlace */ mode = mode | INTERL; case 0: /* No interlace */ break; default: /* Reserved - we'll let it pass */ break; } /* Set up byte map for writing */ Red = image->bm; if ((mode & COLOUR) != GREYSC) { Grn = Red + image->hdr.plnlen; Blu = Grn + image->hdr.plnlen; } /* Read the Targa file body and convert to image format */ linewidth = tga->Width_lo + tga->Width_hi * 256; for (i=0; i< image->hdr.rows; i++) { /* No interlace */ if ((mode & INTERL) == 0) { j = i; } /* Two way interlace */ else if ((mode & FOURWY) != 0) { if (2*i < image->hdr.rows) j = 2*i; else { j = i - image->hdr.rows/2; j = 2*j + 1; } } /* Four way interlace */ else { if (4*i < image->hdr.rows) j = 4*i; else if (2*i < image->hdr.rows) { j = i - image->hdr.rows/4; j = 4*j + 1; } else if (4*i < 3*image->hdr.rows) { j = i - image->hdr.rows/2; j = 4*j + 2; } else { j = i - image->hdr.rows/2 - image->hdr.rows/4; j = 4*j + 3; } } k = (image->hdr.rows - 1 - j) * image->hdr.cols; Redk = Red + k; if ((mode & COLOUR) != GREYSC) { Grnk = Grn + k; Bluk = Blu + k; } for (j=0; jPixelSize,mode); *Redk++=r; if ((mode & COLOUR) != GREYSC) { *Grnk++=g; *Bluk++=b; } } } free(tga); } get_map_entry(Red,Grn,Blu,Size,mode) unsigned char *Red,*Grn,*Blu; int Size,mode; { unsigned int j,k,l,m; unsigned char i,r,g,b; /* read appropriate number of bytes, break into rgb & put in map */ switch (Size) { case 8: /* Grey Scale already, read and triplicate */ fread(&i,1,1,stdin); r = i; g = i; b = i; break; case 16: /* 5 bits each of red green and blue */ case 15: /* Watch for byte order */ fread(&j,1,1,stdin); fread(&k,1,1,stdin); l = j + k*256; r = ((l >> 10) & 31) << 3; g = ((l >> 5) & 31) << 3; b = (l & 31) << 3; break; case 32: /* Read alpha byte & throw away */ case 24: /* Eight bits each of red green and blue */ fread(&i,1,1,stdin); b = i; fread(&i,1,1,stdin); g = i; fread(&i,1,1,stdin); r = i; if (Size == 32) fread(&i,1,1,stdin); break; default: fprintf(stderr,"Unknown Pixel Size\n"); exit(1); } *Red = r; *Grn = g; *Blu = b; } get_pixel(rRed,rGrn,rBlu,Size,mode) unsigned char *rRed,*rGrn,*rBlu; int Size,mode; { static unsigned char Red, Grn, Blu; unsigned char i,j,k; static unsigned int l; /* Check if run length encoded. */ if ((mode & RLENCD) != 0) { if (RLE_count == 0) /* Have to restart run */ { fread(&i,1,1,stdin); RLE_flag = (i & 0x80) >> 7; if (RLE_flag == 0) { /* Stream of unencoded pixels */ RLE_count = i + 1; } else { /* Single pixel replicated */ RLE_count = i - 127; } RLE_count--; /* Decrement count & get pixel */ } else { /* Have already read count & (at least) first pixel */ RLE_count--; if (RLE_flag != 0) { /* Replicated pixels */ goto PixEncode; } } } /* Read appropriate number of bytes, break into RGB */ switch(Size) { case 8: /* Grey Scale - read a byte and triplicate */ fread(&i,1,1,stdin); Red = i; Grn = i; Blu = i; l = i; break; case 16: /* Five bits each of red green and blue */ case 15: /* Watch byte order */ fread(&j,1,1,stdin); fread(&k,1,1,stdin); l = j + k*256; Red = ((k & 0x7C) << 1); Grn = ((k & 0x03) << 6) + ((j & 0xE0) >> 2); Blu = ((j & 0x1F) << 3); break; case 32: /* Read alpha byte & throw away */ case 24: /* Eight bits each of red green and blue */ fread(&i,1,1,stdin); Blu = i; fread(&i,1,1,stdin); Grn = i; fread(&i,1,1,stdin); Red = i; if (Size == 32) fread(&i,1,1,stdin); l = 0; break; default: fprintf(stderr,"Unknown Pixel Size\n"); exit(1); } PixEncode: if ((mode & MAPPED) == MAPPED) { *rRed = ColourMap[l][0]; *rGrn = ColourMap[l][1]; *rBlu = ColourMap[l][2]; } else { *rRed = Red; *rGrn = Grn; *rBlu = Blu; } } /* * write_tga(image, wfile) * */ write_tga(image, wfile) FBM *image; FILE *wfile; { unsigned char *Red, *Grn, *Blu, *Redk, *Grnk, *Bluk; unsigned char *Redc, *Grnc, *Bluc, *Redck, *Grnck, *Bluck; struct TGA_ImageHeader *tga; unsigned char buffer[MAXCOLOURS]; unsigned int mode; unsigned long index, index2; int i, j, k, l; if (image->hdr.cols > (MAXCOLOURS / 2)) { fprintf(stderr,"Line too wide is %d, must be %d\n", image->hdr.cols, MAXCOLOURS/2); exit(1); } if ((image->hdr.planes != 1) && (image->hdr.planes != 3)) { fprintf(stderr,"TGA files must 1 or 3 planes deep\n"); exit(1); } if (image->hdr.planes == 1) mode = GREYSC; else mode = COLOUR; if ((tga=(struct TGA_ImageHeader *) malloc(sizeof(struct TGA_ImageHeader))) == NULL) { fprintf(stderr,"Can't allocate TGA memory\n"); exit(1); } tga->IDLength = 0; /* Don't write ID into file */ tga->CoMapType = 0; /* Use raw bytes, not mapped */ tga->ImgType = TGA_RawRGBType; if ((mode & COLOUR) == GREYSC) tga->ImgType = TGA_RawMonoType; tga->Index_hi = 0; tga->Index_lo = 0; /* Colour Mapped stuff */ tga->Length_hi = 0; tga->Length_lo = 0; tga->CoSize = 8; tga->X_org_lo = 0; tga->X_org_hi = 0; /* Origin at 0,0 */ tga->Y_org_lo = 0; tga->Y_org_hi = 0; tga->Width_hi = (unsigned char)(image->hdr.cols / 256); tga->Width_lo = (unsigned char)(image->hdr.cols % 256); tga->Height_hi = (unsigned char)(image->hdr.rows / 256); tga->Height_lo = (unsigned char)(image->hdr.rows % 256); tga->PixelSize = 16; if ((mode & COLOUR) == GREYSC) tga->PixelSize = 8; /* All funny bits set to zero */ tga->AttBits = 0; tga->Rsrvd = 0; tga->OrgBit = 0; tga->IntrLve = 0; fwrite(tga,1,18,wfile); /* Write out header */ Red = image->bm; l = image->hdr.cols; if ((mode & COLOUR) == COLOUR) { l = l * 2; Grn = Red + image->hdr.plnlen; Blu = Grn + image->hdr.plnlen; } if (image->hdr.clrlen > 0) { mode = mode | MAPPED; Redc = image->cm; if ((mode & COLOUR) == COLOUR) { Grnc = Redc + image->hdr.clrlen/3; Bluc = Grnc + image->hdr.clrlen/3; } } Redk = Red + image->hdr.plnlen - image->hdr.cols; if ((mode & COLOUR) == COLOUR) { Grnk = Grn + image->hdr.plnlen - image->hdr.cols; Bluk = Blu + image->hdr.plnlen - image->hdr.cols; } /* Okay, ready to write */ for (j=0; jhdr.rows; j++) { for (i=0; ihdr.cols; i++) { index = *Redk++; if ((mode & COLOUR) == COLOUR) index = (index << 16) + ((*Grnk++) << 8) + *Bluk++; if ((mode & MAPPED) == MAPPED) { index2 = index; Redck = Redc + index2; index = *Redck; if ((mode & COLOUR) == COLOUR) { Grnck = Grnc + index2; Bluck = Bluc + index2; index = (index << 16) + ((unsigned long)*Grnck << 8) + *Bluck; } } if ((mode & COLOUR) == COLOUR) { index2 = ((index & 0x00f80000) >> 9) + ((index & 0x0000f800) >> 6) + ((index & 0x000000f8) >> 3); k = 2 * i; buffer[k] = (unsigned char)(index2 % 256); k = k + 1; buffer[k] = (unsigned char)(index2 / 256); } else { buffer[i] = (unsigned char)index; } } fwrite(buffer,l,1,wfile); Redk = Redk - 2 * image->hdr.cols; if ((mode & COLOUR) == COLOUR) { Grnk = Grnk - 2 * image->hdr.cols; Bluk = Bluk - 2 * image->hdr.cols; } } free(tga); }