#if !defined(EPS_HEADER_HH_INCLUDED) #define EPS_HEADER_HH_INCLUDED // // Primary header file for epsiron image processor eps-header.hh // // Ito Lab. at Naruto University of Education, Japan // // Version history: // Ver 0.5 : 2007-10-07 // Ver 0.6 : 2007-10-28 Litte and big endian // #include #include #include #include using namespace std; FILE * esp_in = stdin; FILE * esp_out = stdout; FILE * esp_err = stderr; // // structure of BMP file format // typedef struct tagBITMAPFILEHEADER { unsigned short int bfType; unsigned int bfSize; unsigned short int bfReserved1; unsigned short int bfReserved2; unsigned int bfOffBits; } BITMAPFILEHEADER; typedef struct tagBITMAPINFOHEADER{ unsigned int biSize; int biWidth; int biHeight; unsigned short int biPlanes; unsigned short int biBitCount; unsigned int biCompression; unsigned int biSizeImage; int biXPelsPerMeter; int biYPelsPerMeter; unsigned int biClrUsed; unsigned int biClrImportant; } BITMAPINFOHEADER; typedef struct tagRGBQUAD{ unsigned char rgbBlue; unsigned char rgbGreen; unsigned char rgbRed; unsigned char rgbReserved; } RGBQUAD; // // Esp processor's constants // const int MIN_GRAY_LEVEL = 0; // Minimum gray level const int MAX_GRAY_LEVEL = 255; // Maximum gray level const int NR_GRAY_LEVEL = MAX_GRAY_LEVEL - MIN_GRAY_LEVEL + 1; // Number of gray level const int NR_GRAY_PLANE = 1; // Number of planes for gray sclae image const int MIN_COLOR_LEVEL = 0; // Minimum color level const int MAX_COLOR_LEVEL = 255; // Maximum color level const int NR_COLOR_LEVEL = MAX_COLOR_LEVEL - MIN_COLOR_LEVEL + 1; // Number of color level const int R_PLANE = 0; // Red plane number is 0. const int G_PLANE = 1; // Green plane number is 1. const int B_PLANE = 2; // Blue plane number is 2. const int NR_COLOR_PLANE = 3; // Number of planes for RGB color const int MAX_FILENAME_LEN = 2048; // Maximum length of file name const int EPS_LITTLE_ENDIAN = 0; // Little endian (Intel etc.) const int EPS_BIG_ENDIAN = 1; // Big endian (Sparc, IBM Power PC etc.) // Mathematics constants const double PI = 4.0 * atan(1.0); // The ratio of circumference of a circle to its diameter // // Bitmap image class // class image { public: unsigned char *** q; // Multi-plane image q[Plane_No][Line_No][Pixel_No] // Plane #0: Red or band 0 // Plane #1: Green or band 1 // Plane #2: Blue or band 2 // ........ // unsigned char ** p; // Gray scale image p[Line_No][Pixel_No] // p = q[0]; static const int RET_ERROR = 0; // Return code with error static const int RET_OK = -1; // Return code with no error private: int nr_planes; // Number of planes int nr_lines; // Number of lines int nr_pixels; // Number of pixels int endian; // Little or big endian public: // Constructors image(); image( int nr_plane_arg, int nr_line_arg, int nr_pixels_arg); // Destructor ~image(); image(const image &src); // Copy constructor image& operator=(const image &src); // Substitution operator = void clear(void); // Clear all image data int get_nr_planes(void); // Get number of planes int get_nr_lines(void); // Get number of lines int get_nr_pixels(void); // Get number of pixels int get_pixel( // Get gray scale pixel value int line_nr, int pixel_nr, int range); int get_pixel( // Get multi plane pixel value int plane_nr, int line_nr, int pixel_nr, int range); // Allocate or resize image array void imake( // Multi plane image int nr_planes_arg, int nr_lines_arg, int nr_pixels_arg); void gmake( // Gray scale image int nr_lines_arg, int nr_pixels_arg); void cmake( // Color image int nr_lines_arg, int nr_pixels_arg); void gload(void); // Load image from BMP file and convert gray scale void gload(char * fn); void cload(void); // Load image from BMP file void cload(char * fn); void gsave(void); // Convert gray scale and save image to 8 bit BMP file void gsave(char * fn); void csave(void); // Save image to 24 bit BMP file void csave(char * fn); private: void check_size_of_variables (void); int alloc( int nr_planes_arg, // Number of planes in this image int nr_lines_arg, // Number of lines in this image int nr_pixels_arg); // Number of pixels in this image void unalloc(); void copy_proc(const image &src); // Use in copy constructor and '=' int rgb2gray( int r, int g, int b); int inspect_bmp_header( FILE * fp_bmp, BITMAPFILEHEADER& bmp_fh, BITMAPINFOHEADER& bmp_info, int& rec_len); void make_bmp_header( FILE * fp_bmp, int nr_planes_arg, int nr_lines_arg, int nr_pixles_arg, int& rec_len); void fread_le( void * val, int size, FILE * fp); void fwrite_le( void * val, int size, FILE * fp); }; // Constructor of image class image::image() { check_size_of_variables (); q = NULL; p = NULL; nr_planes = 0; nr_lines = 0; nr_pixels = 0; } image::image( int nr_planes_arg, // Number of planes in this image int nr_lines_arg, // Number of lines in this image int nr_pixels_arg) // Number of pixels in this image { check_size_of_variables (); if (alloc(nr_planes_arg, nr_lines_arg, nr_pixels_arg) == RET_OK) { clear(); } } // Check size of variable in BMP header void image::check_size_of_variables (void) { if (sizeof(unsigned char) != 1 || sizeof(unsigned short int) != 2 || sizeof(unsigned int) != 4 || sizeof(int) != 4) { fprintf(esp_err, "Incompatible variable size. Please check the specification of your C++ compiler.\n"); fprintf(esp_err, "You cannot handle any BMP files\n"); } // Diagnose the endian unsigned short int wdata = 0x55aa; unsigned char * p = (unsigned char *)&wdata; endian = EPS_LITTLE_ENDIAN; if ( * p == 0x55 && * (p + 1) == 0xaa) endian = EPS_BIG_ENDIAN; } // Destructor of image class image::~image() { unalloc(); } // Copy constructor image::image( const image &src) { copy_proc(src); } // Substitution operator = image& image::operator=(const image &src) { unalloc(); copy_proc(src); return (*this); } // Copy members void image::copy_proc( const image &src) { if (src.q == NULL) return; if (alloc(src.nr_planes, src.nr_lines, src.nr_pixels) == RET_OK) { for (int ip = 0; ip < nr_planes; ip ++) { for (int iy = 0; iy < nr_lines; iy ++) { for (int ix = 0; ix < nr_pixels; ix ++) { q[ip][iy][ix] = src.q[ip][iy][ix]; } } } } } // // Memory allocation for image array // // return code: RET_OK, RET_ERROR // int image::alloc( int nr_planes_arg, // Number of planes in this image int nr_lines_arg, // Number of lines in this image int nr_pixels_arg) // Number of pixels in this image { int error_flag = RET_OK; if (nr_planes_arg == 0 || nr_planes_arg < 0 || nr_lines_arg == 0 || nr_lines_arg < 0 || nr_pixels_arg == 0 || nr_pixels_arg < 0) { error_flag = RET_ERROR; } else { nr_planes = nr_planes_arg; nr_lines = nr_lines_arg; nr_pixels = nr_pixels_arg; q = (unsigned char ***)malloc(sizeof(unsigned char **) * nr_planes); if (q == NULL) { error_flag = RET_ERROR; } else { for (int ip = 0; ip < nr_planes; ip ++) { q[ip] = (unsigned char **)malloc(sizeof(unsigned char *) * nr_lines); if (q[ip] == NULL) { error_flag = RET_ERROR; break; } if (error_flag == RET_ERROR) break; for (int iy = 0; iy < nr_lines; iy ++) { q[ip][iy] = (unsigned char *)malloc(sizeof(unsigned char) * nr_pixels); if (q[ip][iy] == NULL) { error_flag = RET_ERROR; break; } } if (error_flag == RET_ERROR) break; } } } if (error_flag == RET_ERROR) { printf("Memory allocation error in image construction\n"); q = NULL; p = NULL; nr_planes = 0; nr_lines = 0; nr_pixels = 0; } else { p = q[0]; // Set plane #0 to gray scale image } return error_flag; } // // Memory unallocation for image array // void image::unalloc() { if (q != NULL) { for (int ip = 0; ip < nr_planes; ip ++) { for (int iy = 0; iy < nr_lines; iy ++) { free(q[ip][iy]); } free (q[ip]); } free(q); q = NULL; p = NULL; nr_planes = 0; nr_lines = 0; nr_pixels = 0; } } // // Clear all image data // void image::clear(void) { if (q != NULL) { for (int ip = 0; ip < nr_planes; ip ++) { for (int iy = 0; iy < nr_lines; iy ++) { for (int ix = 0; ix < nr_pixels; ix ++) { q[ip][iy][ix] = 0; } } } } } int image::get_nr_planes(void) { return nr_planes; } int image::get_nr_lines(void) { return nr_lines; } int image::get_nr_pixels(void) { return nr_pixels; } // Get gray scale pixel value // Inside this image: return pixel value // Outside this image: nearest inside image value within specified range // otherwise MIN_GRAY_LEVEL // if range < 0 then always MIN_GRAY_LEVEL int image::get_pixel( int line_nr, int pixel_nr, int range) { if ( range < 0 && (line_nr < 0 || line_nr >= nr_lines) || (pixel_nr < 0 || pixel_nr >= nr_pixels)) return MIN_GRAY_LEVEL; if (line_nr < - range) { return MIN_GRAY_LEVEL; } else if (line_nr < 0) { if (pixel_nr < - range) return MIN_GRAY_LEVEL; else if (pixel_nr < 0) return p[ 0][ 0]; else if (pixel_nr >= nr_pixels + range) return MIN_GRAY_LEVEL; else if (pixel_nr >= nr_pixels) return p[ 0][nr_pixels - 1]; else return p[ 0][pixel_nr ]; } else if (line_nr >= nr_lines + range) { return MIN_GRAY_LEVEL; } else if (line_nr >= nr_lines) { if (pixel_nr < - range) return MIN_GRAY_LEVEL; else if (pixel_nr < 0) return p[nr_lines - 1][ 0]; else if (pixel_nr >= nr_pixels + range) return MIN_GRAY_LEVEL; else if (pixel_nr >= nr_pixels) return p[nr_lines - 1][nr_pixels - 1]; else return p[nr_lines - 1][pixel_nr ]; } else { if (pixel_nr < - range) return MIN_GRAY_LEVEL; else if (pixel_nr < 0) return p[line_nr ][0 ]; else if (pixel_nr >= nr_pixels + range) return MIN_GRAY_LEVEL; else if (pixel_nr >= nr_pixels) return p[line_nr ][nr_pixels - 1]; else return p[line_nr ][pixel_nr ]; } } // Get multi plane pixel value // Inside this image: return pixel value // Outside this image: nearest inside image value within specified range // otherwise MIN_GRAY_LEVEL // if range < 0 then always MIN_GRAY_LEVEL int image::get_pixel( int plane_nr, int line_nr, int pixel_nr, int range) { if (plane_nr < 0 || plane_nr >= nr_planes) return MIN_GRAY_LEVEL; if ( range < 0 && (line_nr < 0 || line_nr >= nr_lines) || (pixel_nr < 0 || pixel_nr >= nr_pixels)) return MIN_GRAY_LEVEL; if (line_nr < - range) { return MIN_GRAY_LEVEL; } else if (line_nr < 0) { if (pixel_nr < - range) return MIN_GRAY_LEVEL; else if (pixel_nr < 0) return q[plane_nr][ 0][ 0]; else if (pixel_nr >= nr_pixels + range) return MIN_GRAY_LEVEL; else if (pixel_nr >= nr_pixels) return q[plane_nr][ 0][nr_pixels - 1]; else return q[plane_nr][ 0][pixel_nr ]; } else if (line_nr >= nr_lines + range) { return MIN_GRAY_LEVEL; } else if (line_nr >= nr_lines) { if (pixel_nr < - range) return MIN_GRAY_LEVEL; else if (pixel_nr < 0) return q[plane_nr][nr_lines - 1][ 0]; else if (pixel_nr >= nr_pixels + range) return MIN_GRAY_LEVEL; else if (pixel_nr >= nr_pixels) return q[plane_nr][nr_lines - 1][nr_pixels - 1]; else return q[plane_nr][nr_lines - 1][pixel_nr ]; } else { if (pixel_nr < - range) return MIN_GRAY_LEVEL; else if (pixel_nr < 0) return q[plane_nr][line_nr ][ 0]; else if (pixel_nr >= nr_pixels + range) return MIN_GRAY_LEVEL; else if (pixel_nr >= nr_pixels) return q[plane_nr][line_nr ][nr_pixels - 1]; else return q[plane_nr][line_nr ][pixel_nr ]; } } // // Make memory block for this bitmap image // void image:: imake( int nr_planes_arg, int nr_lines_arg, int nr_pixels_arg) { if (alloc(nr_planes_arg, nr_lines_arg, nr_pixels_arg) == RET_OK) { clear(); } } void image::gmake( int nr_lines_arg, int nr_pixels_arg) { imake(NR_GRAY_PLANE, nr_lines_arg, nr_pixels_arg); } void image::cmake( int nr_lines_arg, int nr_pixels_arg) { imake(NR_COLOR_PLANE, nr_lines_arg, nr_pixels_arg); } // // Load and convert gray scale image from BMP file (8/24/32bit, no compression only) // void image::gload(void) { char fn[MAX_FILENAME_LEN]; fprintf(esp_out, "\nLoad and convert gray scale image from BMP file.\n"); fprintf(esp_out, "The BMP file should be 8/24/32 bit and no compression format.\n"); fprintf(esp_out, "Input BMP file name including file extension(ex. bmp, BMP) : "); fgets(fn, MAX_FILENAME_LEN - 1, esp_in); if (fn[strlen(fn) - 1] == 0x0d || fn[strlen(fn) - 1] == 0x0a ) fn[strlen(fn) - 1] = 0; if (fn[strlen(fn) - 2] == 0x0d || fn[strlen(fn) - 2] == 0x0a ) fn[strlen(fn) - 2] = 0; gload(fn); } void image::gload( char * fn) { if (fn == NULL || fn[0] == 0) { gload(); return; } unalloc(); FILE * fp_bmp; fp_bmp = fopen(fn, "rb"); if (fp_bmp == NULL) { fprintf(esp_err, "BMP file: %s cannot open.\n", fn); return; } fprintf(esp_out, "\nLoading and converting to gray scale image from BMP file: %s\n", fn); BITMAPFILEHEADER bmp_fh; BITMAPINFOHEADER bmp_info; int rec_len; // 4 bytes alinemented if (inspect_bmp_header(fp_bmp, bmp_fh, bmp_info, rec_len) == RET_OK) { if (alloc(NR_GRAY_PLANE, abs(bmp_info.biHeight), bmp_info.biWidth) == 0) { fprintf(esp_out, "Memory allocation error in loading BMP file\n"); } else { fprintf(esp_out, "BMP has %d bit format.\n", bmp_info.biBitCount); fprintf(esp_out, "Number of lines : %8d\n", abs(bmp_info.biHeight)); fprintf(esp_out, "Number of pixels : %8d\n", bmp_info.biWidth ); fprintf(esp_out, "Color value is automatically converted to gray scale,\n"); fprintf(esp_out, "where Gray = 0.299 * R + 0.587 * G + 0.114 * B.\n"); unsigned char gray_table[256]; if (bmp_info.biBitCount == 8) { for (int ict = 0; ict < 256; ict ++) { int r, g, b, a; b = fgetc(fp_bmp); if (b == EOF) b = 0; // Ignore read error. g = fgetc(fp_bmp); if (g == EOF) g = 0; // Ignore read error. r = fgetc(fp_bmp); if (r == EOF) r = 0; // Ignore read error. a = fgetc(fp_bmp); // Reserved gray_table[ict] = rgb2gray(r, g, b); } } // if bmp_info.biHeight < 0 ==> Line direction is Upper to Lower lines. // if bmp_info.biHeight > 0 ==> Line direction is Lower to Upper lines. int a, r, g, b; int gr; for (int iy = 0; iy < abs(bmp_info.biHeight); iy ++) { fseek(fp_bmp, bmp_fh.bfOffBits + rec_len * ((bmp_info.biHeight < 0) ? iy : (abs(bmp_info.biHeight) - (iy + 1))), SEEK_SET); for (int ix = 0; ix < bmp_info.biWidth; ix ++) { if (bmp_info.biBitCount == 8) { a = fgetc(fp_bmp); if (a == EOF) a = 0; // Ignore read error. if (a < 0) a = 0; if (a >= 256) a = 255; gr = gray_table[a]; } else if (bmp_info.biBitCount == 24) { b = fgetc(fp_bmp); if (b == EOF) b = 0; // Ignore read error. g = fgetc(fp_bmp); if (g == EOF) g = 0; // Ignore read error. r = fgetc(fp_bmp); if (r == EOF) r = 0; // Ignore read error. gr = rgb2gray(r, g, b); } else { // bmp_info.biBitCount == 32 b = fgetc(fp_bmp); if (b == EOF) b = 0; // Ignore read error. g = fgetc(fp_bmp); if (g == EOF) g = 0; // Ignore read error. r = fgetc(fp_bmp); if (r == EOF) r = 0; // Ignore read error. a = fgetc(fp_bmp); // Dummy data // Ignore read error. gr = rgb2gray(r, g, b); } p[iy][ix] = gr; } } } } fclose (fp_bmp); } // // Load color image from BMP file (8/24/32bit, no compression only) // void image::cload(void) { char fn[MAX_FILENAME_LEN]; fprintf(esp_out, "\nLoad color image from BMP file.\n"); fprintf(esp_out, "The BMP file should be 8/24/32 bit and no compression format.\n"); fprintf(esp_out, "Input BMP file name including file extension(ex. bmp, BMP) : "); fgets(fn, MAX_FILENAME_LEN - 1, esp_in); if (fn[strlen(fn) - 1] == 0x0d || fn[strlen(fn) - 1] == 0x0a ) fn[strlen(fn) - 1] = 0; if (fn[strlen(fn) - 2] == 0x0d || fn[strlen(fn) - 2] == 0x0a ) fn[strlen(fn) - 2] = 0; cload(fn); } void image::cload( char * fn) { if (fn == NULL || fn[0] == 0) { cload(); return; } unalloc(); FILE * fp_bmp; fp_bmp = fopen(fn, "rb"); if (fp_bmp == NULL) { fprintf(esp_err, "BMP file: %s cannot open.\n", fn); return; } fprintf(esp_out, "\nLoading color image from BMP file: %s\n", fn); BITMAPFILEHEADER bmp_fh; BITMAPINFOHEADER bmp_info; int rec_len; // 4 bytes alinemented if (inspect_bmp_header(fp_bmp, bmp_fh, bmp_info, rec_len) == RET_OK) { if (alloc(NR_COLOR_PLANE, abs(bmp_info.biHeight), bmp_info.biWidth) == 0) { fprintf(esp_out, "Memory allocation error in loading BMP file\n"); } else { fprintf(esp_out, "BMP has %d bit format.\n", bmp_info.biBitCount); fprintf(esp_out, "Number of lines : %8d\n", abs(bmp_info.biHeight)); fprintf(esp_out, "Number of pixels : %8d\n", bmp_info.biWidth ); fprintf(esp_out, "RGB color data are being loading.\n"); unsigned char color_table[256][3]; RGBQUAD ct; if (bmp_info.biBitCount == 8) { for (int ict = 0; ict < 256; ict ++) { fread_le(&ct , sizeof(ct), fp_bmp); color_table[ict][R_PLANE] = ct.rgbRed; color_table[ict][G_PLANE] = ct.rgbGreen; color_table[ict][B_PLANE] = ct.rgbBlue; } } // if bmp_info.biHeight < 0 ==> Line direction is Upper to Lower lines. // if bmp_info.biHeight > 0 ==> Line direction is Lower to Upper lines. int a, r, g, b; for (int iy = 0; iy < abs(bmp_info.biHeight); iy ++) { fseek(fp_bmp, bmp_fh.bfOffBits + rec_len * ((bmp_info.biHeight < 0) ? iy : (abs(bmp_info.biHeight) - (iy + 1))), SEEK_SET); for (int ix = 0; ix < bmp_info.biWidth; ix ++) { if (bmp_info.biBitCount == 8) { a = fgetc(fp_bmp); if (a == EOF) a = 0; // Ignore read error. if (a < 0) a = 0; if (a >= 256) a = 255; r = color_table[a][R_PLANE]; g = color_table[a][G_PLANE]; b = color_table[a][B_PLANE]; } else if (bmp_info.biBitCount == 24) { b = fgetc(fp_bmp); if (b == EOF) b = 0; // Ignore read error. g = fgetc(fp_bmp); if (g == EOF) g = 0; // Ignore read error. r = fgetc(fp_bmp); if (r == EOF) r = 0; // Ignore read error. } else { // bmp_info.biBitCount == 32 b = fgetc(fp_bmp); if (b == EOF) b = 0; // Ignore read error. g = fgetc(fp_bmp); if (g == EOF) g = 0; // Ignore read error. r = fgetc(fp_bmp); if (r == EOF) r = 0; // Ignore read error. a = fgetc(fp_bmp); // Dummy data // Ignore read error. } q[R_PLANE][iy][ix] = r; q[G_PLANE][iy][ix] = g; q[B_PLANE][iy][ix] = b; } } } } fclose (fp_bmp); } // // Inspect BMP file header // Return code: RET_OK, RET_ERROR // int image::inspect_bmp_header( FILE * fp_bmp, BITMAPFILEHEADER& bmp_fh, BITMAPINFOHEADER& bmp_info, int& rec_len) { // Read head information fread_le(&bmp_fh.bfType, sizeof(bmp_fh.bfType), fp_bmp); if (bmp_fh.bfType != 'B' + ('M' << 8)) { fprintf(esp_err, "Illegal BMP format. First 2 letters are not \"BM\".\n"); fprintf(esp_err, "1st Letter (HEX): %02X\n", bmp_fh.bfType & 0x00ff); fprintf(esp_err, "2nd Letter (HEX): %02X\n", bmp_fh.bfType >> 8); return RET_ERROR; } fread_le(&bmp_fh.bfSize, sizeof(bmp_fh.bfSize), fp_bmp); fread_le(&bmp_fh.bfReserved1, sizeof(bmp_fh.bfReserved1), fp_bmp); fread_le(&bmp_fh.bfReserved2, sizeof(bmp_fh.bfReserved2), fp_bmp); fread_le(&bmp_fh.bfOffBits, sizeof(bmp_fh.bfOffBits), fp_bmp); fread_le(&bmp_info.biSize, sizeof(bmp_info.biSize), fp_bmp); if (bmp_info.biSize != sizeof(BITMAPINFOHEADER)) { fprintf(esp_err, "Illegal BMP format. Information size is not %d.\n", sizeof(BITMAPINFOHEADER)); fprintf(esp_err, "Information size: %d\n", bmp_info.biSize); return RET_ERROR; } fread_le(&bmp_info.biWidth , sizeof(bmp_info.biWidth), fp_bmp); fread_le(&bmp_info.biHeight , sizeof(bmp_info.biHeight), fp_bmp); fread_le(&bmp_info.biPlanes , sizeof(bmp_info.biPlanes), fp_bmp); fread_le(&bmp_info.biBitCount , sizeof(bmp_info.biBitCount), fp_bmp); fread_le(&bmp_info.biCompression , sizeof(bmp_info.biCompression), fp_bmp); fread_le(&bmp_info.biSizeImage , sizeof(bmp_info.biSizeImage), fp_bmp); fread_le(&bmp_info.biXPelsPerMeter , sizeof(bmp_info.biXPelsPerMeter), fp_bmp); fread_le(&bmp_info.biYPelsPerMeter , sizeof(bmp_info.biYPelsPerMeter), fp_bmp); fread_le(&bmp_info.biClrUsed , sizeof(bmp_info.biClrUsed), fp_bmp); fread_le(&bmp_info.biClrImportant , sizeof(bmp_info.biClrImportant), fp_bmp); if (bmp_info.biCompression != 0) { fprintf(esp_err, "Illegal BMP format. Compression is not supported.\n"); fprintf(esp_err, "Compression code : %d\n", bmp_info.biCompression); return RET_ERROR; } if (bmp_info.biWidth == 0 || bmp_info.biWidth < 0) { fprintf(esp_err, "Illegal BMP format. Bit width is %d.\n", bmp_info.biWidth); return RET_ERROR; } if (bmp_info.biHeight == 0) { fprintf(esp_err, "Illegal BMP format. Bit height is %d.\n", bmp_info.biHeight); return RET_ERROR; } if (bmp_info.biBitCount != 8 && bmp_info.biBitCount != 24 && bmp_info.biBitCount != 32) { fprintf(esp_err, "Illegal BMP format. Unsupported bit count.\n"); fprintf(esp_err, "Bit count in one pixel : %d\n", bmp_info.biBitCount); return RET_ERROR; } // Record length of image data rec_len = (bmp_info.biWidth * bmp_info.biBitCount) / 8; if ((rec_len % 4) != 0) { rec_len = ((rec_len / 4) + 1) * 4; // 4 bytes alinemented } return RET_OK; } // // Save gray scale image to BMP file (8 bit, no compression only) // void image::gsave(void) { if (q == NULL) { fprintf(esp_err, "\nNo gray scale image in this class\n"); return; } if (nr_planes != NR_GRAY_PLANE && nr_planes != NR_COLOR_PLANE) { fprintf(esp_err, "\nInvalid number of planes. Current number of planes is %d.\n", nr_planes); return; } char fn[MAX_FILENAME_LEN]; fprintf(esp_out, "\nSave gray scale image to BMP file.\n"); fprintf(esp_out, "The BMP file will have 8 bit and no compression format.\n"); fprintf(esp_out, "Input BMP file name including file extension(ex. bmp, BMP) : "); fgets(fn, MAX_FILENAME_LEN - 1, esp_in); if (fn[strlen(fn) - 1] == 0x0d || fn[strlen(fn) - 1] == 0x0a ) fn[strlen(fn) - 1] = 0; if (fn[strlen(fn) - 2] == 0x0d || fn[strlen(fn) - 2] == 0x0a ) fn[strlen(fn) - 2] = 0; gsave(fn); } void image::gsave( char * fn) { if (q == NULL) { fprintf(esp_err, "\nNo gray scale image in this class\n"); return; } if (nr_planes != NR_GRAY_PLANE && nr_planes != NR_COLOR_PLANE) { fprintf(esp_err, "\nInvalid number of planes. Current number of planes is %d.\n", nr_planes); return; } if (fn == NULL || fn[0] == 0) { gsave(); return; } FILE * fp_bmp; fp_bmp = fopen(fn, "wb"); if (fp_bmp == NULL) { fprintf(esp_err, "BMP file: %s cannot open.\n", fn); return; } if (nr_planes == NR_COLOR_PLANE) { fprintf(esp_out, "\nConverting color to gray scale image, \n"); fprintf(esp_out, "where Gray = 0.299 * R + 0.587 * G + 0.114 * B.\n"); } fprintf(esp_out, "\nSaving gray scale image to BMP file: %s\n", fn); fprintf(esp_out, "Number of lines : %8d\n", nr_lines); fprintf(esp_out, "Number of pixels : %8d\n", nr_pixels); int rec_len; // 4 bytes alinement make_bmp_header(fp_bmp, NR_GRAY_PLANE, nr_lines, nr_pixels, rec_len); unsigned char a; int nr_padding = rec_len - NR_GRAY_PLANE * nr_pixels; for (int iy = nr_lines - 1; iy >= 0 ; iy --) { for (int ix = 0; ix < nr_pixels; ix ++) { if (nr_planes == NR_GRAY_PLANE) { a = p[iy][ix]; } else { // nr_planes == NR_COLOR_PLANE a = rgb2gray( q[R_PLANE][iy][ix], q[G_PLANE][iy][ix], q[B_PLANE][iy][ix]); } fputc(a, fp_bmp); } for (int ia = 0; ia < nr_padding; ia ++) { fputc(0, fp_bmp); } } fclose(fp_bmp); } // // Save color image to BMP file (24 bit, no compression only) // void image::csave(void) { if (q == NULL) { fprintf(esp_err, "\nNo color image in this class\n"); return; } if (nr_planes != NR_GRAY_PLANE && nr_planes != NR_COLOR_PLANE) { fprintf(esp_err, "\nInvalid number of planes. Current number of planes is %d.\n", nr_planes); return; } FILE * fp_bmp; char fn[MAX_FILENAME_LEN]; fprintf(esp_out, "\nSave color image to BMP file.\n"); fprintf(esp_out, "The BMP file will have 24 bit and no compression format.\n"); fprintf(esp_out, "Input BMP file name including file extension(ex. bmp, BMP) : "); fgets(fn, MAX_FILENAME_LEN - 1, esp_in); if (fn[strlen(fn) - 1] == 0x0d || fn[strlen(fn) - 1] == 0x0a ) fn[strlen(fn) - 1] = 0; if (fn[strlen(fn) - 2] == 0x0d || fn[strlen(fn) - 2] == 0x0a ) fn[strlen(fn) - 2] = 0; csave(fn); } void image::csave( char * fn) { if (q == NULL) { fprintf(esp_err, "\nNo color image in this class\n"); return; } if (nr_planes != NR_GRAY_PLANE && nr_planes != NR_COLOR_PLANE) { fprintf(esp_err, "\nInvalid number of planes. Current number of planes is %d.\n", nr_planes); return; } if (fn == NULL || fn[0] == 0) { gsave(); return; } FILE * fp_bmp; fp_bmp = fopen(fn, "wb"); if (fp_bmp == NULL) { fprintf(esp_err, "BMP file: %s cannot open.\n", fn); return; } fprintf(esp_out, "\nSaving color image to BMP file: %s\n", fn); fprintf(esp_out, "Number of lines : %8d\n", nr_lines); fprintf(esp_out, "Number of pixels : %8d\n", nr_pixels); int rec_len; // 4 bytes alinement make_bmp_header(fp_bmp, NR_COLOR_PLANE, nr_lines, nr_pixels, rec_len); unsigned char a; int nr_padding = rec_len - nr_planes * nr_pixels; for (int iy = nr_lines - 1; iy >= 0 ; iy --) { for (int ix = 0; ix < nr_pixels; ix ++) { if (nr_planes == NR_GRAY_PLANE) { a = p[iy][ix]; fputc(a, fp_bmp); // Blue fputc(a, fp_bmp); // Green fputc(a, fp_bmp); // Red } else { // nr_planes == NR_COLOR_PLANE fputc(q[B_PLANE][iy][ix], fp_bmp); // Blue fputc(q[G_PLANE][iy][ix], fp_bmp); // Green fputc(q[R_PLANE][iy][ix], fp_bmp); // Red } } for (int ia = 0; ia < nr_padding; ia ++) { fputc(0, fp_bmp); } } fclose(fp_bmp); } // // Make BMP file header // void image::make_bmp_header( FILE * fp_bmp, // INPUT: File pointer of BMP file int nr_planes_arg, // INPUT: Number of planes should be 1 or 3 int nr_lines_arg, // INPUT: Number of lines in BMP file int nr_pixels_arg, // INPUT:Number of pixels in BMP file int& rec_len) // OUTPUT: Record length of bitmap data with 4 bytes alinement { BITMAPFILEHEADER bmp_fh; BITMAPINFOHEADER bmp_info; // Record length of image data rec_len = nr_planes_arg * nr_pixels_arg; if ((rec_len % 4) != 0) { rec_len = ((rec_len / 4) + 1) * 4; // 4 bytes alinement } fseek(fp_bmp, 0L, SEEK_SET); bmp_fh.bfType = 'B' + ('M' << 8); bmp_fh.bfOffBits = 14 // Size of BITMAPFILEHEADER // Don't use sizeof(BITMAPFILEHEADER) so as to aline with 4 bytes + 40; // Size of BITMAPINFOHEADER bmp_fh.bfSize = bmp_fh.bfOffBits + nr_lines_arg * rec_len; if (nr_planes_arg == NR_GRAY_PLANE) { bmp_fh.bfOffBits += sizeof(RGBQUAD) * 256; bmp_fh.bfSize += sizeof(RGBQUAD) * 256; } bmp_fh.bfReserved1 = 0; bmp_fh.bfReserved2 = 0; bmp_info.biSize = 40; // Size of BITMAPINFOHEADER bmp_info.biWidth = nr_pixels_arg; bmp_info.biHeight = nr_lines_arg; bmp_info.biPlanes = 1; bmp_info.biBitCount = nr_planes_arg * 8; bmp_info.biCompression = 0; bmp_info.biSizeImage = nr_lines_arg * rec_len; bmp_info.biXPelsPerMeter = (int)(100.0 / 2.56 * 300.0); // 300 dpi; bmp_info.biYPelsPerMeter = (int)(100.0 / 2.56 * 300.0); // 300 dpi; bmp_info.biClrUsed = 256; bmp_info.biClrImportant = 256; fwrite_le(&bmp_fh.bfType, sizeof(bmp_fh.bfType), fp_bmp); fwrite_le(&bmp_fh.bfSize, sizeof(bmp_fh.bfSize), fp_bmp); fwrite_le(&bmp_fh.bfReserved1, sizeof(bmp_fh.bfReserved1), fp_bmp); fwrite_le(&bmp_fh.bfReserved2, sizeof(bmp_fh.bfReserved2), fp_bmp); fwrite_le(&bmp_fh.bfOffBits, sizeof(bmp_fh.bfOffBits), fp_bmp); fwrite_le(&bmp_info.biSize, sizeof(bmp_info.biSize), fp_bmp); fwrite_le(&bmp_info.biWidth, sizeof(bmp_info.biWidth), fp_bmp); fwrite_le(&bmp_info.biHeight, sizeof(bmp_info.biHeight), fp_bmp); fwrite_le(&bmp_info.biPlanes, sizeof(bmp_info.biPlanes), fp_bmp); fwrite_le(&bmp_info.biBitCount, sizeof(bmp_info.biBitCount), fp_bmp); fwrite_le(&bmp_info.biCompression, sizeof(bmp_info.biCompression), fp_bmp); fwrite_le(&bmp_info.biSizeImage, sizeof(bmp_info.biSizeImage), fp_bmp); fwrite_le(&bmp_info.biXPelsPerMeter, sizeof(bmp_info.biXPelsPerMeter), fp_bmp); fwrite_le(&bmp_info.biYPelsPerMeter, sizeof(bmp_info.biYPelsPerMeter), fp_bmp); fwrite_le(&bmp_info.biClrUsed, sizeof(bmp_info.biClrUsed), fp_bmp); fwrite_le(&bmp_info.biClrImportant, sizeof(bmp_info.biClrImportant), fp_bmp); if (nr_planes_arg == NR_GRAY_PLANE) { RGBQUAD ct; for(int i = 0; i < 256; i ++) { ct.rgbBlue = i; ct.rgbGreen = i; ct.rgbRed = i; ct.rgbReserved = 0; fwrite_le(&ct.rgbBlue, sizeof(ct.rgbBlue), fp_bmp); fwrite_le(&ct.rgbGreen, sizeof(ct.rgbGreen), fp_bmp); fwrite_le(&ct.rgbRed, sizeof(ct.rgbRed), fp_bmp); fwrite_le(&ct.rgbReserved, sizeof(ct.rgbReserved), fp_bmp); } } } // // Convert r, g, and b to gray scale // int image::rgb2gray( int r, int g, int b) { int a; a = (int)(0.299 * r + 0.587 * g + 0.114 * b + 0.5); if (a < MIN_GRAY_LEVEL) a = MIN_GRAY_LEVEL; if (a > MAX_GRAY_LEVEL) a = MAX_GRAY_LEVEL; return a; } // // Read data from file with little endian // void image::fread_le( void * val, int size, FILE * fp) { unsigned char * p = (unsigned char *)val; if (endian == EPS_LITTLE_ENDIAN) { while(size --) { * (p ++) = (unsigned char)fgetc(fp); } } else { p += (size - 1); while(size --) { * (p --) = (unsigned char)fgetc(fp); } } } // // Write data to file with little endian // void image::fwrite_le( void * val, int size, FILE * fp) { unsigned char * p = (unsigned char *)val; if (endian == EPS_LITTLE_ENDIAN) { while(size --) { fputc(* p ++, fp); } } else { p += (size - 1); while(size --) { fputc(* p --, fp); } } } #endif // EPS_HEADER_HH_INCLUDED