//========================================================================= #define PROGRAMMER "SOLUTIONS, NoFrills" #define PROG_CODE "soln" #define COURSE "ECE-1021" #define YEAR (2003) #define TERM "Fall" #define SECTION (0) #define ASSIGNMENT "HW #8B" #define REVISION (0) #define TITLE "BMP Basics" #define SUBTITLE "Structures and entire image in memory" #define EMAIL "wbahn@eas.uccs.edu" #define FILENAME "08b0soln.c" //========================================================================= // PROBLEM: // // Write a program that allows opens a BMP file and copies it to a new // file while converting it to B&W using the RMS method. // SOLUTION: // // This is the same program as HW#7A except that structures are used. // // The level of detail in the structures here is quite a bit more than what // is expected from the student programs, but not nearly as much as is // found in bmp.h //== INCLUDE FILES ======================================================== #include // printf() #include // sqrt() #include // exit() #include // strlen() //== STRUCTURE DEFINITIONS ================================================ typedef struct BMP BMP; typedef struct BMPFILEHEADER BMPFILEHEADER; typedef struct BMPINFOHEADER BMPINFOHEADER; typedef struct BMPIMAGEDATA BMPIMAGEDATA; typedef struct COLORTRIPLET COLORTRIPLET; //------------------------------------------------------------------------- // BMP STRUCTURE //------------------------------------------------------------------------- struct BMP { BMPFILEHEADER *bf; BMPINFOHEADER *bi; BMPIMAGEDATA *bd; }; #define NottaBMP(ptr) (NULL == (ptr)) #define IsaBMP(ptr) (NULL != (ptr)) //------------------------------------------------------------------------- // BMP STRUCTURE //------------------------------------------------------------------------- struct BMPFILEHEADER { char bfType[2]; // The characters "BM" unsigned long bfSize; // The size of the file in bytes unsigned int bfReserved1; // Unused - must be zero unsigned int bfReserved2; // Unused - must be zero unsigned long bfOffBits; // Offset to start of Pixel Data }; //------------------------------------------------------------------------- // BMP STRUCTURE //------------------------------------------------------------------------- struct BMPINFOHEADER { unsigned long biSize; // Header Size - Must be at least 40 unsigned long biWidth; // Image width in pixels unsigned long biHeight; // Image height in pixels unsigned int biPlanes; // Must be 1 unsigned int biBitCount; // Bits per pixel - (1,2,4,8,16,24,32} unsigned long biCompression; // Compression type (0 = uncompressed) unsigned long biSizeImage; // Image Size - uncompressed may be zero unsigned long biXPelsPerMeter; // Preferred resolution (pixels/meter) unsigned long biYPelsPerMeter; // Preferred resolution (pixels/meter) unsigned long biClrUsed; // Color Map entries that are used unsigned long biClrImportant; // Number of significant colors }; // BMP functions - primitives // BMP functions - manipulatives unsigned char GetBMPPixelComponent(BMP *bmp, int row, int col, int color); unsigned char SetBMPPixel(BMP *bmp, int row, int col, unsigned char red, unsigned char green, unsigned char blue); //------------------------------------------------------------------------- // BMPIMAGEDATA STRUCTURE //------------------------------------------------------------------------- struct BMPIMAGEDATA { int rows; // Number of rows (equal to biHeight) int cols; // Number of cols (equal to biWidth) COLORTRIPLET **image; // row is an array of pointers unsigned long bytes; int padding; }; // BMPIMAGEDATA functions - primitives BMPIMAGEDATA *CreateBMP_DATA(BMP *bmp, int rows, int cols); void FreeBMP_DATA(BMPIMAGEDATA *bd); COLORTRIPLET **GetBMP_DATAimage(BMPIMAGEDATA *bd); COLORTRIPLET **SetBMP_DATAimage(BMPIMAGEDATA *bd, COLORTRIPLET **image); // BMPIMAGEDATA functions - manipulatives COLORTRIPLET *GetBMP_DATATriplet(BMPIMAGEDATA *bd, int row, int col); COLORTRIPLET *SetBMP_DATATriplet(BMPIMAGEDATA *bd, int row, int col, COLORTRIPLET *color); //------------------------------------------------------------------------- // COLORTRIPLE STRUCTURE //------------------------------------------------------------------------- struct COLORTRIPLET { unsigned char red; unsigned char green; unsigned char blue; }; // COLORTRIPLET functions - primitives COLORTRIPLET *CreateCT(void); int DestroyCT(COLORTRIPLET *color); unsigned char SetCTr(COLORTRIPLET *color, unsigned char red); unsigned char SetCTg(COLORTRIPLET *color, unsigned char green); unsigned char SetCTb(COLORTRIPLET *color, unsigned char blue); unsigned char GetCTr(COLORTRIPLET *color); unsigned char GetCTg(COLORTRIPLET *color); unsigned char GetCTb(COLORTRIPLET *color); // COLORTRIPLET functions - manipulatives COLORTRIPLET *SetCT(COLORTRIPLET *color, unsigned char r, unsigned char g, unsigned char b); unsigned char GetCTgray(COLORTRIPLET *color); unsigned char SetCTgray(COLORTRIPLET *color, unsigned char shade); //== MACRO DEFINITIONS ==================================================== #define FALSE (0) #define TRUE (!FALSE) #define RED (2) #define GREEN (1) #define BLUE (0) //== TOP LEVEL SUPPORT FUNCTION PROTOTYPES ================================ void PrintHeader(void); char *GetFileName(char *name, char *ext, int size); void ExitIfError(int errcode); BMP *NewBMP(void); int ImportBMP(BMP *bmp, char *filename); int ExportBMP(BMP *bmp, char *filename); int DisplayBMP_STATS(BMP *bmp); void ConvertToGray(BMP *bmp); //== MAIN FUNCTION ======================================================== int main(void) { char *bmp_infilename; char *bmp_outfilename; BMP *bmp; int errcode; PrintHeader(); // TASK: Get file names from User printf("Enter the name of the color BMP file to read: "); bmp_infilename = GetFileName(NULL, "BMP", 0); printf("Enter the name of the B&W BMP file to create: "); bmp_outfilename = GetFileName(NULL, "BMP", 0); // TASK: Import BMP data into memory printf("Importing file: %s .....", bmp_infilename); bmp = NewBMP(); // Create a new BMP structure for the data errcode = ImportBMP(bmp, bmp_infilename); // Import data from input file ExitIfError(errcode); printf("Import Complete.\n"); // TASK: Convert image to Gray Scale DisplayBMP_STATS(bmp); printf("Converting to Gray Scale ....."); ConvertToGray(bmp); // Convert Image to Grayscale printf("Gray Scale Conversion Complete.\n"); // TASK: Export Modified BMP data to disk printf("Exporting file: %s .....", bmp_outfilename); errcode = ExportBMP(bmp, bmp_outfilename); // Export data to output file ExitIfError(errcode); printf("Export Complete.\n"); return(0); } //== SUPPORT FUNCTIONS ==================================================== void PrintHeader(void) { printf("========================================" "=======================================\n"); printf("Course....... %s-%i (%s %i)\n", COURSE, SECTION, TERM, YEAR); printf("Programmer... %s (%s)\n", PROGRAMMER, PROG_CODE); printf("Assignment... %s (Rev %i) (Source Code in %s)\n", ASSIGNMENT, REVISION, FILENAME); printf("Description.. %s\n", TITLE); printf(" %s\n", SUBTITLE); printf("========================================" "=======================================\n"); return; } //== LOWER LEVEL FUNCTION PROTOTYPES ====================================== FILE *OpenAndVerify(char *name, char *mode); //unsigned char GrayScale(COLORTRIPLET *color); unsigned char RMS(unsigned char r, unsigned char g, unsigned char b); BMPFILEHEADER *GetBMP_FILE(BMP *bmp); BMPINFOHEADER *GetBMP_INFO(BMP *bmp); BMPIMAGEDATA *GetBMP_DATA(BMP *bmp); BMPIMAGEDATA *CreateBMP_DATA(BMP *bmp, int rows, int cols); unsigned long GetBMP_FILE_OffBits(BMPFILEHEADER *bf); unsigned long GetBMP_OffBits(BMP *bmp); void FreeBMP_DATA(BMPIMAGEDATA *bd); int ImportBMP_FILE(BMPFILEHEADER *bf, FILE *fp); int ImportBMP_INFO(BMPINFOHEADER *bi, FILE *fp); int ImportBMP_DATA(BMP *bmp, FILE *fp); int ExportBMP_FILE(BMPFILEHEADER *bf, FILE *fp); int ExportBMP_INFO(BMPINFOHEADER *bi, FILE *fp); int ExportBMP_DATA(BMP *bmp, FILE *fp); int CheckBMP_FILE(BMPFILEHEADER *bf); int CheckBMP_INFO(BMPINFOHEADER *bi); int CheckBMP_DATA(BMP *bmp); int DisplayBMP_FILE(BMPFILEHEADER *bf); int DisplayBMP_INFO(BMPINFOHEADER *bi); int GetHeight(BMPINFOHEADER *bi); int GetRows(BMP *bmp); int GetWidth(BMPINFOHEADER *bi); int GetCols(BMP *bmp); /* COLORTRIPLET *GetColor(BMP *bmp, int row, int col, COLORTRIPLET *color); COLORTRIPLET *SetColor(BMP *bmp, int row, int col, COLORTRIPLET *color); unsigned char GetColorComponent(BMP *bmp, int row, int col, int color); unsigned char SetColorComponent(BMP *bmp, int r, int c, int color, int mag); COLORTRIPLET *SetColorRGB(BMP *bmp, int row, unsigned char r, unsigned char g, unsigned char b); */ //== TOP LEVEL SUPPORT FUNCTION DEFINITIONS =============================== char *GetFileName(char *name, char *ext, int size) { int length; char c; int endloop; int extgiven; // Check if size is negative if(0>size) return(NULL); // Check to see if string is static or dynamic if((NULL == name) || (0 == size)) { // String is dynamic length = 0; name = realloc(name, length + 1); name[length] = '\0'; } else { // String is static or fixed length if(size < (strlen(ext)+3) ) // Extension too long, ignore it. ext = NULL; } endloop = FALSE; extgiven = FALSE; while(!endloop) { // Check if there is enough room for another character in string. if( (0 < size) && !(length < size) ) endloop = TRUE; switch(c = getchar()) { case EOF: // End of File found case 10: // Form Feed encountered case 13: // Carriage Return encountered endloop = TRUE; break; case '.': // Extension Delimiter found extgiven = TRUE; default : // All characters (including delimiter above) name = realloc(name, length + 2); name[length++] = c; name[length] = '\0'; break; } } // Check if user supplied an extension and use default if appropriate. if( (!extgiven)&&(NULL != ext) ) { if(0 == size) // dynamic array { // Allocated additional memory for the extension name = realloc(name, length + strlen(ext) + 2); } else // static or fixed length array { // Ensure that the static array can take the extension name[size - strlen(ext) - 2] = '\0'; } strcat(name, "."); strcat(name, ext); } return(name); } void ExitIfError(int errcode) { if(errcode) { printf("Abort! (Error #%i detected)\n", errcode); exit(errcode); } return; } BMP *NewBMP(void) { BMP *bmp; bmp = malloc(sizeof(BMP)); if(NULL == bmp) return(NULL); bmp->bf = malloc(sizeof(BMPFILEHEADER)); bmp->bi = malloc(sizeof(BMPINFOHEADER)); bmp->bd = malloc(sizeof(BMPIMAGEDATA)); bmp->bd->image = NULL; return(bmp); } int ImportBMP(BMP *bmp, char *filename) { FILE *fp; int errcode; if(NULL == bmp) return(1); if(NULL == GetBMP_FILE(bmp)) return(2); if(NULL == GetBMP_INFO(bmp)) return(3); if(NULL == GetBMP_DATA(bmp)) return(4); fp = fopen(filename, "rb"); if(NULL == fp) return(5); ImportBMP_FILE(GetBMP_FILE(bmp), fp); errcode = CheckBMP_FILE(GetBMP_FILE(bmp)); if(errcode) return(errcode); ImportBMP_INFO(GetBMP_INFO(bmp), fp); errcode = CheckBMP_INFO(GetBMP_INFO(bmp)); if(errcode) return(errcode); CreateBMP_DATA(bmp, GetHeight(GetBMP_INFO(bmp)), GetWidth(GetBMP_INFO(bmp))); errcode = ImportBMP_DATA(bmp, fp); if(errcode) return(errcode); return(0); } int ExportBMP(BMP *bmp, char *filename) { FILE *fp; int errcode; if(NULL == bmp) return(1); if(NULL == GetBMP_FILE(bmp)) return(2); if(NULL == GetBMP_INFO(bmp)) return(3); if(NULL == GetBMP_DATA(bmp)) return(4); fp = fopen(filename, "wb"); if(NULL == fp) return(5); errcode = CheckBMP_FILE(GetBMP_FILE(bmp)); if(errcode) return(errcode); ExportBMP_FILE(GetBMP_FILE(bmp), fp); errcode = CheckBMP_INFO(GetBMP_INFO(bmp)); if(errcode) return(errcode); ExportBMP_INFO(GetBMP_INFO(bmp), fp); errcode = ExportBMP_DATA(bmp, fp); if(errcode) return(errcode); return(0); } int DisplayBMP_STATS(BMP *bmp) { DisplayBMP_FILE(GetBMP_FILE(bmp)); DisplayBMP_INFO(GetBMP_INFO(bmp)); return(0); } void ConvertToGray(BMP *bmp) { int row, rows; int col, cols; unsigned char red, green, blue, gray; rows = GetRows(bmp); cols = GetCols(bmp); for(row = 0; row < rows; row++) { for(col = 0; col < cols; col++) { red = GetBMPPixelComponent(bmp, row, col, RED); green = GetBMPPixelComponent(bmp, row, col, GREEN); blue = GetBMPPixelComponent(bmp, row, col, BLUE); gray = RMS(red, green, blue); SetBMPPixel(bmp, row, col, gray, gray, gray); } } return; } //== LOWER LEVEL SUPPORT FUNCTION DEFINITIONS ============================= FILE *OpenAndVerify(char *name, char *mode) { FILE *fp; fp = fopen(name, mode); if(NULL == fp) { printf("ABORT! - Failed to open file <%s> (mode %s)\n", name, mode); exit(1); } return fp; } unsigned char GrayScale(COLORTRIPLET *color) { unsigned long r, g, b; r = (unsigned long) color->red; g = (unsigned long) color->green; b = (unsigned long) color->blue; return( (unsigned char) sqrt( (double)(r*r + g*g + b*b)/(3.0) ) ); } unsigned char RMS(unsigned char red, unsigned char green, unsigned char blue) { unsigned long r, g, b; r = (unsigned long) red; g = (unsigned long) green; b = (unsigned long) blue; return( (unsigned char) sqrt( (double)(r*r + g*g + b*b)/(3.0) ) ); } BMPFILEHEADER *GetBMP_FILE(BMP *bmp) { if(NULL == bmp) return(NULL); return(bmp->bf); } BMPINFOHEADER *GetBMP_INFO(BMP *bmp) { if(NULL == bmp) return(NULL); return(bmp->bi); } BMPIMAGEDATA *GetBMP_DATA(BMP *bmp) { if(NULL == bmp) return(NULL); return(bmp->bd); } int ImportBMP_FILE(BMPFILEHEADER *bf, FILE *fp) { fseek(fp, 0, SEEK_SET); // Go to beginning of File Header fread(&(bf->bfType), 1, 2, fp); fread(&(bf->bfSize), 4, 1, fp); fread(&(bf->bfReserved1), 2, 1, fp); fread(&(bf->bfReserved2), 2, 1, fp); fread(&(bf->bfOffBits), 4, 1, fp); return(0); } int ImportBMP_INFO(BMPINFOHEADER *bi, FILE *fp) { fseek(fp, 14, SEEK_SET); // Go to beginning of Info Header fread(&(bi->biSize), 4, 1, fp); fread(&(bi->biWidth), 4, 1, fp); fread(&(bi->biHeight), 4, 1, fp); fread(&(bi->biPlanes), 2, 1, fp); fread(&(bi->biBitCount), 2, 1, fp); fread(&(bi->biCompression), 4, 1, fp); fread(&(bi->biSizeImage), 4, 1, fp); fread(&(bi->biXPelsPerMeter), 4, 1, fp); fread(&(bi->biYPelsPerMeter), 4, 1, fp); fread(&(bi->biClrUsed), 4, 1, fp); fread(&(bi->biClrImportant), 4, 1, fp); return(0); } int ImportBMP_DATA(BMP *bmp, FILE *fp) { int row, rows; int col, cols; int i, padbytes; unsigned char red, green, blue, padbyte; fseek(fp, GetBMP_OffBits(bmp), SEEK_SET); rows = GetRows(bmp); cols = GetCols(bmp); padbytes = 4 - (3*cols)%4; for(row = 0; row < rows; row++) { for(col = 0; col < cols; col++) { fread(&blue, 1, 1, fp); fread(&green, 1, 1, fp); fread(&red, 1, 1, fp); SetBMPPixel(bmp, row, col, red, green, blue); } for(i = 0; i < padbytes; i++) // Dummy read for Padding Bytes fread(&padbyte, 1, 1, fp); } return(0); } int ExportBMP_FILE(BMPFILEHEADER *bf, FILE *fp) { fseek(fp, 0, SEEK_SET); // Go to beginning of File Header fwrite(&(bf->bfType), 1, 2, fp); fwrite(&(bf->bfSize), 4, 1, fp); fwrite(&(bf->bfReserved1), 2, 1, fp); fwrite(&(bf->bfReserved2), 2, 1, fp); fwrite(&(bf->bfOffBits), 4, 1, fp); return(0); } int ExportBMP_INFO(BMPINFOHEADER *bi, FILE *fp) { fseek(fp, 14, SEEK_SET); // Go to beginning of Info Header fwrite(&(bi->biSize), 4, 1, fp); fwrite(&(bi->biWidth), 4, 1, fp); fwrite(&(bi->biHeight), 4, 1, fp); fwrite(&(bi->biPlanes), 2, 1, fp); fwrite(&(bi->biBitCount), 2, 1, fp); fwrite(&(bi->biCompression), 4, 1, fp); fwrite(&(bi->biSizeImage), 4, 1, fp); fwrite(&(bi->biXPelsPerMeter), 4, 1, fp); fwrite(&(bi->biYPelsPerMeter), 4, 1, fp); fwrite(&(bi->biClrUsed), 4, 1, fp); fwrite(&(bi->biClrImportant), 4, 1, fp); return(0); } unsigned long GetBMP_FILE_OffBits(BMPFILEHEADER *bf) { return(bf->bfOffBits); } unsigned long GetBMP_OffBits(BMP *bmp) { return(GetBMP_FILE_OffBits(GetBMP_FILE(bmp))); } int ExportBMP_DATA(BMP *bmp, FILE *fp) { int row, rows; int col, cols; int i, padbytes; unsigned char red, green, blue, padbyte=0; fseek(fp, GetBMP_OffBits(bmp), SEEK_SET); rows = GetRows(bmp); cols = GetCols(bmp); padbytes = 4 - (3*cols)%4; for(row = 0; row < rows; row++) { for(col = 0; col < cols; col++) { red = GetBMPPixelComponent(bmp, row, col, RED); green = GetBMPPixelComponent(bmp, row, col, GREEN); blue = GetBMPPixelComponent(bmp, row, col, BLUE); fwrite(&blue, 1, 1, fp); fwrite(&green, 1, 1, fp); fwrite(&red, 1, 1, fp); } for(i = 0; i < padbytes; i++) // Dummy read for Padding Bytes fwrite(&padbyte, 1, 1, fp); } return(0); } int CheckBMP_FILE(BMPFILEHEADER *bf) { if( 'B' != (bf->bfType)[0] ) return(101); if( 'M' != (bf->bfType)[1] ) return(102); if( 0 != bf->bfReserved1 ) return(103); if( 0 != bf->bfReserved2 ) return(104); return(0); } int CheckBMP_INFO(BMPINFOHEADER *bi) { if( 40 != bi->biSize ) return(201); if( 1 != bi->biPlanes ) return(202); if( 24 != bi->biBitCount ) return(203); if( 0 != bi->biCompression ) return(204); return(0); } int DisplayBMP_FILE(BMPFILEHEADER *bf) { printf("BMP File Header data:\n"); printf(" File Type: ....... %c%c\n", (bf->bfType)[0], (bf->bfType)[1]); printf(" File Size: ....... %lu bytes\n", bf->bfSize); printf(" Reserved1: ....... %u\n", bf->bfReserved1); printf(" Reserved2: ....... %u\n", bf->bfReserved2); printf(" Data Offset: ..... %lu bytes\n", bf->bfOffBits); return(0); } int DisplayBMP_INFO(BMPINFOHEADER *bi) { printf("BMP Info Header data:\n"); printf(" Info Header: ..... %lu bytes\n", bi->biSize); printf(" Image Width: ..... %lu pixels\n", bi->biWidth); printf(" Image Height: .... %lu pixels\n", bi->biHeight); printf(" Image Planes: .... %u\n", bi->biPlanes); printf(" Bits Per Pixel: .. %u\n", bi->biBitCount); printf(" Compression: ..... %lu\n", bi->biCompression); printf(" Image Size: ...... %lu\n", bi->biSizeImage); printf(" X Resolution: .... %lu pixels/meter\n", bi->biXPelsPerMeter); printf(" Y Resolution: .... %lu pixels/meter\n", bi->biYPelsPerMeter); printf(" Colors Used: ..... %lu\n", bi->biClrUsed); printf(" Sig Colors: ...... %lu\n", bi->biClrImportant); return(0); } int GetHeight(BMPINFOHEADER *bi) { return((int)bi->biHeight); } int GetRows(BMP *bmp) { return(GetHeight(GetBMP_INFO(bmp))); } int GetWidth(BMPINFOHEADER *bi) { return((int)bi->biWidth); } int GetCols(BMP *bmp) { return(GetWidth(GetBMP_INFO(bmp))); } //------------------------------------------------------------------------- // BMP Structure functions //------------------------------------------------------------------------- unsigned char GetBMPPixelComponent(BMP *bmp, int row, int col, int color); unsigned char SetBMPPixel(BMP *bmp, int row, int col, unsigned char red, unsigned char green, unsigned char blue); unsigned char GetBMPPixelComponent(BMP *bmp, int row, int col, int color) { switch(color) { case RED: return(GetCTr(GetBMP_DATATriplet(GetBMP_DATA(bmp), row, col))); case GREEN: return(GetCTg(GetBMP_DATATriplet(GetBMP_DATA(bmp), row, col))); case BLUE: return(GetCTb(GetBMP_DATATriplet(GetBMP_DATA(bmp), row, col))); } return(0); } unsigned char SetBMPPixel(BMP *bmp, int row, int col, unsigned char red, unsigned char green, unsigned char blue) { SetCTr(GetBMP_DATATriplet(GetBMP_DATA(bmp), row, col), red); SetCTg(GetBMP_DATATriplet(GetBMP_DATA(bmp), row, col), green); SetCTb(GetBMP_DATATriplet(GetBMP_DATA(bmp), row, col), blue); return(0); } //------------------------------------------------------------------------- // BMPIMAGEDATA Structure functions //------------------------------------------------------------------------- // BMPIMAGEDATA functions - primitives BMPIMAGEDATA *CreateBMP_DATA(BMP *bmp, int rows, int cols) { BMPIMAGEDATA *bd; int row; bd = GetBMP_DATA(bmp); FreeBMP_DATA(bd); SetBMP_DATAimage(bd, malloc(rows*sizeof(COLORTRIPLET *))); bd->bytes = 0; for(row = 0; row < rows; row++) { bd->image[row] = malloc(cols*sizeof(COLORTRIPLET)); bd->bytes += cols*sizeof(COLORTRIPLET); } return(bd); } void FreeBMP_DATA(BMPIMAGEDATA *bd) { if(NULL == bd) return; free(bd->image); free(bd); return; } COLORTRIPLET **GetBMP_DATAimage(BMPIMAGEDATA *bd) { return(bd->image); } COLORTRIPLET **SetBMP_DATAimage(BMPIMAGEDATA *bd, COLORTRIPLET **image) { bd->image = image; return(GetBMP_DATAimage(bd)); } // BMPIMAGEDATA functions - manipulatives COLORTRIPLET *GetBMP_DATATriplet(BMPIMAGEDATA *bd, int row, int col) { return(&(GetBMP_DATAimage(bd)[row][col])); } COLORTRIPLET *SetBMP_DATATriplet(BMPIMAGEDATA *bd, int row, int col, COLORTRIPLET *color) { COLORTRIPLET *actual; actual = GetBMP_DATATriplet(bd, row, col); SetCT(actual, GetCTr(color), GetCTg(color), GetCTb(color)); return(actual); } //------------------------------------------------------------------------- // COLORTRIPLET Structure functions //------------------------------------------------------------------------- // COLORTRIPLET functions - primitives unsigned char SetCTr(COLORTRIPLET *color, unsigned char red) { color->red = red; return(GetCTr(color)); } unsigned char SetCTg(COLORTRIPLET *color, unsigned char green) { color->green = green; return(GetCTr(color)); } unsigned char SetCTb(COLORTRIPLET *color, unsigned char blue) { color->blue = blue; return(GetCTb(color)); } unsigned char GetCTr(COLORTRIPLET *color) { return(color->red); } unsigned char GetCTg(COLORTRIPLET *color) { return(color->green); } unsigned char GetCTb(COLORTRIPLET *color) { return(color->blue); } // COLORTRIPLET functions - manipulatives COLORTRIPLET *SetCT(COLORTRIPLET *color, unsigned char r, unsigned char g, unsigned char b) { SetCTr(color, r); SetCTg(color, g); SetCTb(color, b); return(color); } unsigned char GetCTgray(COLORTRIPLET *color) { return(RMS(GetCTr(color), GetCTg(color), GetCTb(color))); } unsigned char SetCTgray(COLORTRIPLET *color, unsigned char shade) { SetCT(color, shade, shade, shade); return(shade); }