// bmpops.cpp : implementation of the BMPFile class // // This handles the reading and writing of BMP files. // // #include "afx.h" #include "bmpfile.h" #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif BMPFile::BMPFile() { } BMPFile::~BMPFile() { } //////////////////////////////////////////////////////////////////////////// // load a .BMP file - 1,4,8,24 bit // // allocates and returns an RGB buffer containing the image. // modifies width and height accordingly - NULL, 0, 0 on error BYTE * BMPFile::LoadBMP(CString fileName, UINT *width, UINT *height) { BITMAP inBM; BYTE m1,m2; long filesize; short res1,res2; long pixoff; long bmisize; long compression; unsigned long sizeimage; long xscale, yscale; long colors; long impcol; BYTE *outBuf=NULL; // for safety *width=0; *height=0; // init DWORD m_bytesRead=0; FILE *fp; fp=fopen(fileName,"rb"); if (fp==NULL) { return NULL; } else { long rc; rc=fread((BYTE *)&(m1),1,1,fp); m_bytesRead+=1; if (rc==-1) {fclose(fp); return NULL;} rc=fread((BYTE *)&(m2),1,1,fp); m_bytesRead+=1; if (rc==-1) {fclose(fp); return NULL;} if ((m1!='B') || (m2!='M')) { fclose(fp); return NULL; } //////////////////////////////////////////////////////////////////////////// // // read a ton of header stuff rc=fread((long *)&(filesize),4,1,fp); m_bytesRead+=4; if (rc!=1) {fclose(fp); return NULL;} rc=fread((int *)&(res1),2,1,fp); m_bytesRead+=2; if (rc!=1) {fclose(fp); return NULL;} rc=fread((int *)&(res2),2,1,fp); m_bytesRead+=2; if (rc!=1) {fclose(fp); return NULL;} rc=fread((long *)&(pixoff),4,1,fp); m_bytesRead+=4; if (rc!=1) {fclose(fp); return NULL;} rc=fread((long *)&(bmisize),4,1,fp); m_bytesRead+=4; if (rc!=1) {fclose(fp); return NULL;} rc=fread((long *)&(inBM.bmWidth),4,1,fp); m_bytesRead+=4; if (rc!=1) {fclose(fp); return NULL;} rc=fread((long *)&(inBM.bmHeight),4,1,fp); m_bytesRead+=4; if (rc!=1) {fclose(fp); return NULL;} rc=fread((int *)&(inBM.bmPlanes),2,1,fp); m_bytesRead+=2; if (rc!=1) {fclose(fp); return NULL;} rc=fread((int *)&(inBM.bmBitsPixel),2,1,fp); m_bytesRead+=2; if (rc!=1) {fclose(fp); return NULL;} rc=fread((long *)&(compression),4,1,fp); m_bytesRead+=4; if (rc!=1) {fclose(fp); return NULL;} rc=fread((long *)&(sizeimage),4,1,fp); m_bytesRead+=4; if (rc!=1) {fclose(fp); return NULL;} rc=fread((long *)&(xscale),4,1,fp); m_bytesRead+=4; if (rc!=1) {fclose(fp); return NULL;} rc=fread((long *)&(yscale),4,1,fp); m_bytesRead+=4; if (rc!=1) {fclose(fp); return NULL;} rc=fread((long *)&(colors),4,1,fp); m_bytesRead+=4; if (rc!=1) {fclose(fp); return NULL;} rc=fread((long *)&(impcol),4,1,fp); m_bytesRead+=4; if (rc!=1) {fclose(fp); return NULL;} //////////////////////////////////////////////////////////////////////////// // i don't do RLE files if (compression!=BI_RGB) { //m_errorText="This is a compressed file."; fclose(fp); return NULL; } if (colors == 0) { colors = 1 << inBM.bmBitsPixel; } //////////////////////////////////////////////////////////////////////////// // read colormap RGBQUAD *colormap = NULL; switch (inBM.bmBitsPixel) { case 24: break; // read pallete case 1: case 4: case 8: colormap = new RGBQUAD[colors]; if (colormap==NULL) { fclose(fp); return NULL; } int i; for (i=0;ipixoff) { fclose(fp); delete [] colormap; fclose(fp); return NULL; } while ((long)m_bytesRead=0;row--) { // which row are we working on? rowOffset=(long unsigned)row*row_size; if (inBM.bmBitsPixel==24) { for (int col=0;col> bit_count) & mask; // lookup the color from the colormap - stuff it in our buffer // swap red and blue *(outBuf + rowOffset + col * 3 + 2) = colormap[pix].rgbBlue; *(outBuf + rowOffset + col * 3 + 1) = colormap[pix].rgbGreen; *(outBuf + rowOffset + col * 3 + 0) = colormap[pix].rgbRed; } // read DWORD padding while ((m_bytesRead-pixoff)&3) { char dummy; if (fread(&dummy,1,1,fp)!=1) { delete [] outBuf; if (colormap) delete [] colormap; fclose(fp); return NULL; } m_bytesRead++; } } } } if (colormap) { delete [] colormap; } fclose(fp); } return outBuf; } //////////////////////////////////////////////////////////////////////////// // write a 24-bit BMP file // // image MUST be a packed buffer (not DWORD-aligned) // image MUST be vertically flipped ! // image MUST be BGR, not RGB ! // BOOL BMPFile::SaveBMP(CString fileName, // output path BYTE * buf, // BGR buffer UINT width, // pixels UINT height) { short res1=0; short res2=0; long pixoff=54; long compression=0; long cmpsize=0; long colors=0; long impcol=0; char m1='B'; char m2='M'; DWORD widthDW = WIDTHBYTES(width * 24); long bmfsize=sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + widthDW * height; long byteswritten=0; BITMAPINFOHEADER header; header.biSize=40; // header size header.biWidth=width; header.biHeight=height; header.biPlanes=1; header.biBitCount=24; // RGB encoded, 24 bit header.biCompression=BI_RGB; // no compression header.biSizeImage=0; header.biXPelsPerMeter=0; header.biYPelsPerMeter=0; header.biClrUsed=0; header.biClrImportant=0; FILE *fp; fp=fopen(fileName,"wb"); if (fp==NULL) { return FALSE; } // should probably check for write errors here... fwrite((BYTE *)&(m1),1,1,fp); byteswritten+=1; fwrite((BYTE *)&(m2),1,1,fp); byteswritten+=1; fwrite((long *)&(bmfsize),4,1,fp); byteswritten+=4; fwrite((int *)&(res1),2,1,fp); byteswritten+=2; fwrite((int *)&(res2),2,1,fp); byteswritten+=2; fwrite((long *)&(pixoff),4,1,fp); byteswritten+=4; fwrite((BITMAPINFOHEADER *)&header,sizeof(BITMAPINFOHEADER),1,fp); byteswritten+=sizeof(BITMAPINFOHEADER); long row=0; long rowidx; long row_size; row_size=header.biWidth*3; long rc; for (row=0;row 8) { fclose(fp); return; } if (nbits == 8) { putc(pixbuf, fp); pixbuf=0; nbits=0; byteswritten++; } } // cols if (nbits > 0) { putc(pixbuf, fp); // write partially filled byte byteswritten++; } // DWORD align while ((byteswritten -pixeloffset) & 3) { putc(0, fp); byteswritten++; } } //rows if (byteswritten!=filesize) { //Some error. fclose(fp); return; } fclose(fp); }