/*========================================================================= FILENAME.CPP Author: Gary Liddon @ Created: Project: Purpose: Copyright (c) 1998 G R Liddon ===========================================================================*/ /*---------------------------------------------------------------------- Includes -------- */ /* Std Lib ------- */ /* Glib ---- */ #include #include /* Local ----- */ /*---------------------------------------------------------------------- Tyepdefs && Defines ------------------- */ /*---------------------------------------------------------------------- Structure defintions -------------------- */ /*---------------------------------------------------------------------- Function Prototypes ------------------- */ using namespace std; /*---------------------------------------------------------------------- Vars ---- */ /*---------------------------------------------------------------------- Data ---- */ struct RGB { u8 r,g,b; }; class BITMAP { public: BITMAP(void) { m_width=0; m_height=0; } void setSize(int width,int height) { bitMap.resize(width*height); m_width=width; m_height=height; } void clear(void) { if (m_width && m_height) memset(&bitMap[0],0,m_width*m_height); } void line(unsigned int y,unsigned int x,u8 pix) { if (x >= m_width) { GObject::Error(ERR_WARNING,"Out of X boundary - %d %d\n", x, m_width); x = m_width-1; } if (y >= m_height) { GObject::Error(ERR_WARNING,"Out of Y boundary - %d %d\n", y, m_height); y = m_height-1; } bitMap[y*m_width+x]=pix; } u8 const * getBitMap(void) const {return(&bitMap[0]);} protected: int m_width; int m_height; vector bitMap; }; /*---------------------------------------------------------------------- Function: Purpose: Params: Returns: ---------------------------------------------------------------------- */ #include #include #include #include #define BI_RGB 0 #define BI_RLE8 1 #define BI_RLE4 2 #define BI_BITFIELDS 3 #define OS2INFOHEADERSIZE 12 #define WININFOHEADERSIZE 40 typedef struct BITMAPFILEHEADER { unsigned long bfType; unsigned long bfSize; unsigned short bfReserved1; unsigned short bfReserved2; unsigned long bfOffBits; } BITMAPFILEHEADER; /* Used for both OS/2 and Windows BMP. * Contains only the parameters needed to load the image */ typedef struct BITMAPINFOHEADER { unsigned long biWidth; unsigned long biHeight; unsigned short biBitCount; unsigned long biCompression; } BITMAPINFOHEADER; typedef struct WINBMPINFOHEADER /* size: 40 */ { unsigned long biWidth; unsigned long biHeight; unsigned short biPlanes; unsigned short biBitCount; unsigned long biCompression; unsigned long biSizeImage; unsigned long biXPelsPerMeter; unsigned long biYPelsPerMeter; unsigned long biClrUsed; unsigned long biClrImportant; } WINBMPINFOHEADER; typedef struct OS2BMPINFOHEADER /* size: 12 */ { unsigned short biWidth; unsigned short biHeight; unsigned short biPlanes; unsigned short biBitCount; } OS2BMPINFOHEADER; /* read_bmfileheader: * Reads a BMP file header and check that it has the BMP magic number. */ static int read_bmfileheader(Gifstream & f, BITMAPFILEHEADER *fileheader) { fileheader->bfType = f.Get16(); fileheader->bfSize= f.Get32(); fileheader->bfReserved1= f.Get16(); fileheader->bfReserved2= f.Get16(); fileheader->bfOffBits= f.Get32(); if (fileheader->bfType != 19778) return -1; return 0; } /* read_win_bminfoheader: * Reads information from a BMP file header. */ static int read_win_bminfoheader(Gifstream & f, BITMAPINFOHEADER *infoheader) { WINBMPINFOHEADER win_infoheader; win_infoheader.biWidth = f.Get32(); win_infoheader.biHeight = f.Get32(); win_infoheader.biPlanes = f.Get16(); win_infoheader.biBitCount = f.Get16(); win_infoheader.biCompression = f.Get32(); win_infoheader.biSizeImage = f.Get32(); win_infoheader.biXPelsPerMeter = f.Get32(); win_infoheader.biYPelsPerMeter = f.Get32(); win_infoheader.biClrUsed = f.Get32(); win_infoheader.biClrImportant = f.Get32(); infoheader->biWidth = win_infoheader.biWidth; infoheader->biHeight = win_infoheader.biHeight; infoheader->biBitCount = win_infoheader.biBitCount; infoheader->biCompression = win_infoheader.biCompression; return 0; } /* read_os2_bminfoheader: * Reads information from an OS/2 format BMP file header. */ static int read_os2_bminfoheader(Gifstream & f, BITMAPINFOHEADER *infoheader) { OS2BMPINFOHEADER os2_infoheader; os2_infoheader.biWidth = f.Get16(); os2_infoheader.biHeight = f.Get32(); os2_infoheader.biPlanes = f.Get32(); os2_infoheader.biBitCount = f.Get32(); infoheader->biWidth = os2_infoheader.biWidth; infoheader->biHeight = os2_infoheader.biHeight; infoheader->biBitCount = os2_infoheader.biBitCount; infoheader->biCompression = 0; return 0; } /* read_bmicolors: * Loads the color pallete for 1,4,8 bit formats. */ static void read_bmicolors(int ncols, RGB *pal, Gifstream & f,int win_flag) { int i; for (i=0; i> 1; } } pix = b[j]; bmp->line(line,i,pix); } } /* read_4bit_line: * Support function for reading the 4 bit bitmap file format. */ static void read_4bit_line(int length, Gifstream & f, BITMAP *bmp, int line) { unsigned char b[8]; unsigned long n; int i, j, k; int temp; int pix; for (i=0; i> 4; b[k*2] = temp & 15; n = n >> 8; } } pix = b[j]; bmp->line(line,i,pix); } } /* read_8bit_line: * Support function for reading the 8 bit bitmap file format. */ static void read_8bit_line(int length, Gifstream & f, BITMAP *bmp, int line) { unsigned char b[4]; unsigned long n; int i, j, k; int pix; for (i=0; i> 8; } } pix = b[j]; bmp->line(line,i,pix); } } /* read_24bit_line: * Support function for reading the 24 bit bitmap file format, doing * our best to convert it down to a 256 color pallete. */ static void read_24bit_line(int length, Gifstream & f, BITMAP *bmp, int line) { #if 0 int i, nbytes; RGB c; nbytes=0; for (i=0; iline[line][i*3+_rgb_r_shift_24/8] = c.r; bmp->line[line][i*3+_rgb_g_shift_24/8] = c.g; bmp->line[line][i*3+_rgb_b_shift_24/8] = c.b; nbytes += 3; } nbytes = nbytes % 4; if (nbytes != 0) for (i=nbytes; i<4; i++) f.get();; #endif } /* read_image: * For reading the noncompressed BMP image format. */ static void read_image(Gifstream & f, BITMAP *bmp, BITMAPINFOHEADER *infoheader) { int i, line; for (i=0; i<(int)infoheader->biHeight; i++) { line = i; switch (infoheader->biBitCount) { case 1: read_1bit_line(infoheader->biWidth, f, bmp, infoheader->biHeight-i-1); break; case 4: read_4bit_line(infoheader->biWidth, f, bmp, infoheader->biHeight-i-1); break; case 8: read_8bit_line(infoheader->biWidth, f, bmp, infoheader->biHeight-i-1); break; case 24: read_24bit_line(infoheader->biWidth, f, bmp, infoheader->biHeight-i-1); break; } } } /* read_RLE8_compressed_image: * For reading the 8 bit RLE compressed BMP image format. */ static void read_RLE8_compressed_image(Gifstream & f, BITMAP *bmp, BITMAPINFOHEADER *infoheader) { unsigned char count, val, val0; int j, pos, line; int eolflag, eopicflag; eopicflag = 0; line = infoheader->biHeight - 1; while (eopicflag == 0) { pos = 0; /* x position in bitmap */ eolflag = 0; /* end of line flag */ while ((eolflag == 0) && (eopicflag == 0)) { count = f.get(); val = f.get(); if (count > 0) { /* repeat pixel count times */ for (j=0;jline(line,pos,val); pos++; } } else { switch (val) { case 0: /* end of line flag */ eolflag=1; break; case 1: /* end of picture flag */ eopicflag=1; break; case 2: /* displace picture */ count = f.get(); val = f.get(); pos += count; line -= val; break; default: /* read in absolute mode */ for (j=0; jline(line,pos,val0); pos++; } if (j%2 == 1) val0 = f.get(); /* align on word boundary */ break; } } if (pos > (int)infoheader->biWidth) eolflag=1; } line--; if (line < 0) eopicflag = 1; } } /* read_RLE4_compressed_image: * For reading the 4 bit RLE compressed BMP image format. */ static void read_RLE4_compressed_image(Gifstream & f, BITMAP *bmp, BITMAPINFOHEADER *infoheader) { unsigned char b[8]; unsigned char count; unsigned short val0, val; int j, k, pos, line; int eolflag, eopicflag; eopicflag = 0; /* end of picture flag */ line = infoheader->biHeight - 1; while (eopicflag == 0) { pos = 0; eolflag = 0; /* end of line flag */ while ((eolflag == 0) && (eopicflag == 0)) { count = f.get(); val = f.get(); if (count > 0) { /* repeat pixels count times */ b[1] = val & 15; b[0] = (val >> 4) & 15; for (j=0; jline(line,pos,b[j%2]); pos++; } } else { switch (val) { case 0: /* end of line */ eolflag=1; break; case 1: /* end of picture */ eopicflag=1; break; case 2: /* displace image */ count = f.get(); val = f.get(); pos += count; line -= val; break; default: /* read in absolute mode */ for (j=0; j> 4; b[2*k] = val0 & 15; val0 = val0 >> 4; } } bmp->line(line,pos,b[j%4]); pos++; } break; } } if (pos > (int)infoheader->biWidth) eolflag=1; } line--; if (line < 0) eopicflag = 1; } } /* load_bmp: * Loads a Windows BMP file, returning a bitmap structure and storing * the pallete data in the specified pallete (this should be an array of * at least 256 RGB structures). * * Thanks to Seymour Shlien for contributing this function. */ void load_bmp(Frame & frm,char const *filename) { BITMAPFILEHEADER fileheader; BITMAPINFOHEADER infoheader; RGB pal[256]; BITMAP bmp; Gifstream f(Gifstream::LITTLE_ENDIAN); int ncol; unsigned long biSize; f.open(filename,ios::in|ios::binary); if (!f) GObject::Error(ERR_FATAL,"couldn't open file %s",filename); if (read_bmfileheader(f, &fileheader) != 0) { GObject::Error(ERR_FATAL,"error reading bmp hdr for %s",filename); } biSize = f.Get32(); if (biSize == WININFOHEADERSIZE) { if (read_win_bminfoheader(f, &infoheader) != 0) GObject::Error(ERR_FATAL,"error reading windows bmp info hdr for %s",filename); /* compute number of colors recorded */ ncol = (fileheader.bfOffBits - 54) / 4; read_bmicolors(ncol, pal, f, 1); } else if (biSize == OS2INFOHEADERSIZE) { if (read_os2_bminfoheader(f, &infoheader) != 0) GObject::Error(ERR_FATAL,"error reading os2 bmp info hdr for %s",filename); /* compute number of colors recorded */ ncol = (fileheader.bfOffBits - 26) / 3; read_bmicolors(ncol, pal, f, 0); } else { GObject::Error(ERR_FATAL,"error finding correct hdr for bmp %s",filename); } if (infoheader.biBitCount != 4 && infoheader.biBitCount != 8) GObject::Error(ERR_FATAL,"only handles 4 && 8 bit bmps not %d : %s",infoheader.biBitCount,filename); bmp.setSize(infoheader.biWidth, infoheader.biHeight); bmp.clear(); switch (infoheader.biCompression) { case BI_RGB: read_image(f, &bmp, &infoheader); break; case BI_RLE8: read_RLE8_compressed_image(f, &bmp, &infoheader); break; case BI_RLE4: read_RLE4_compressed_image(f, &bmp, &infoheader); break; default: GObject::Error(ERR_FATAL,"unknown compression foramt for %s",filename); break; } f.close(); { Palette palObj; for (int f=0;f