LoadBMPCpp
From GPWikiSample code to load 8 bit indexed and 24 bit RGB BMP files. The Load() method gets the file into memory, use the other public functions to access the image properties and data after loading. // BMP Loader - Codehead 08/11/04 // #include <iostream> #include <fstream> #include <memory.h> #define IMG_OK 0x1 #define IMG_ERR_NO_FILE 0x2 #define IMG_ERR_MEM_FAIL 0x4 #define IMG_ERR_BAD_FORMAT 0x8 #define IMG_ERR_UNSUPPORTED 0x40 class BMPImg { public: BMPImg(); ~BMPImg(); int Load(char* szFilename); int GetBPP(); int GetWidth(); int GetHeight(); unsigned char* GetImg(); // Return a pointer to image data unsigned char* GetPalette(); // Return a pointer to VGA palette private: unsigned int iWidth,iHeight,iEnc; short int iBPP,iPlanes; int iImgOffset,iDataSize; unsigned char *pImage, *pPalette, *pData; // Internal workers int GetFile(char* szFilename); int ReadBmpHeader(); int LoadBmpRaw(); int LoadBmpRLE8(); int LoadBmpPalette(); void FlipImg(); // Inverts image data, BMP is stored in reverse scanline order }; BMPImg::BMPImg() { pImage=pPalette=pData=NULL; iWidth=iHeight=iBPP=iPlanes=iEnc=0; } BMPImg::~BMPImg() { if(pImage) { delete [] pImage; pImage=NULL; } if(pPalette) { delete [] pPalette; pPalette=NULL; } if(pData) { delete [] pData; pData=NULL; } } int BMPImg::Load(char* szFilename) { int iRet; // Clear out any existing image and palette if(pImage) { delete [] pImage; pImage=NULL; } if(pPalette) { delete [] pPalette; pPalette=NULL; } // Get the file into memory iRet=GetFile(szFilename); if(iRet!=IMG_OK) return iRet; // Process the header iRet=ReadBmpHeader(); if(iRet!=IMG_OK) return iRet; if(iBPP<8) // We'll only bother with 8 bit and above return IMG_ERR_UNSUPPORTED; // Get the image data switch(iEnc) { case 0: // Uncompressed iRet=LoadBmpRaw(); // 8 / 24 Bit. (24 bit is in BGR order) break; case 1: // RLE 8 (Indexed 256 colour only) iRet=LoadBmpRLE8(); break; case 2: // RLE 4 (16 Colour indexed, Outdated, not covered here) return IMG_ERR_UNSUPPORTED; case 3: // Bitfields (16/32 bit only, Rare, not covered here) return IMG_ERR_UNSUPPORTED; default: return IMG_ERR_UNSUPPORTED; } if(iRet!=IMG_OK) return iRet; // Flip image to correct scanline reversal FlipImg(); // Load palette if present iRet=LoadBmpPalette(); if(iRet!=IMG_OK) return iRet; // Free the file data delete [] pData; pData=NULL; return IMG_OK; } int BMPImg::GetFile(char* szFilename) { using namespace std; ifstream fIn; unsigned long ulSize; // Open the specified file fIn.open(szFilename,ios::binary); if(fIn==NULL) return IMG_ERR_NO_FILE; // Get file size fIn.seekg(0,ios_base::end); ulSize=fIn.tellg(); fIn.seekg(0,ios_base::beg); // Allocate some space // Check and clear pDat, just in case if(pData) { delete [] pData; pData=NULL; } pData=new unsigned char[ulSize]; if(pData==NULL) { fIn.close(); return IMG_ERR_MEM_FAIL; } // Read the file into memory fIn.read((char*)pData,ulSize); fIn.close(); return IMG_OK; } int BMPImg::ReadBmpHeader() { int iInfo; if(pData==NULL) return IMG_ERR_NO_FILE; if(pData[0x0]!='B' || pData[0x1]!='M') // BMP ID Bytes, should be 'BM' return IMG_ERR_BAD_FORMAT; memcpy(&iImgOffset,&pData[0xA],4); // Offset to image data memcpy(&iInfo,&pData[0xE],4); // Info header size, should be 0x28 if(iInfo!=0x28) return IMG_ERR_BAD_FORMAT; memcpy(&iWidth,&pData[0x12],4); // Image width memcpy(&iHeight,&pData[0x16],4); // Image height memcpy(&iPlanes,&pData[0x1A],2); // Colour planes memcpy(&iBPP,&pData[0x1C],2); // BPP memcpy(&iEnc,&pData[0x1E],4); // Encoding iDataSize=(iWidth*iHeight*(iBPP/8)); // Calculate Image Data size return IMG_OK; } int BMPImg::LoadBmpRaw() { if(pImage) { delete [] pImage; pImage=NULL; } // Allocate space for the image data pImage=new unsigned char[iDataSize]; if(pImage==NULL) return IMG_ERR_MEM_FAIL; memcpy(pImage,&pData[iImgOffset],iDataSize); return IMG_OK; } int BMPImg::LoadBmpRLE8() { unsigned char bOpCode,bVal; unsigned char *pSrc; int iDcode=1,iCount,iPos,iIndex; // Allocate space for the image if(pImage) delete [] pImage; pImage=new unsigned char[iDataSize]; if(pImage==NULL) return IMG_ERR_MEM_FAIL; // Get the start of the RLE data pSrc=&pData[iImgOffset]; iPos=0; iIndex=0; while(iDcode) { // Stay on even bytes while(iPos%2) { iPos++; } bOpCode=pSrc[iPos]; bVal=pSrc[iPos+1]; iPos+=2; if(bOpCode>0) // Run mode, Repeat 'bVal' 'OpCode' times { for(iCount=0;iCount!=bOpCode;iCount++) { pImage[iIndex]=bVal; ++iIndex; } } else // Absolute Mode (Opcode=0), various options { switch(bVal) { case 0: // EOL, no action break; case 1: // EOF, STOP! iDcode=0; break; case 2: // Reposition, Never used break; default: // Copy the next 'bVal' bytes directly to the image for(iCount=bVal;iCount!=0;iCount--) { pImage[iIndex]=pSrc[iPos]; ++iIndex; ++iPos; } break; } } if(iIndex>iDataSize) // Stop if image size exceeded. iDcode=0; } return IMG_OK; } int BMPImg::LoadBmpPalette() { int iIndex; unsigned char *pPalPos, *pDatPos; if(pPalette) { delete [] pPalette; pPalette=NULL; } if(iBPP>8) // NULL Palette for RGB images return IMG_OK; // Create space for palette pPalette=new unsigned char[768]; if(pPalette==NULL) return IMG_ERR_MEM_FAIL; // Set starting position for pointers pPalPos=pPalette; pDatPos=&pData[0x36]; // Get colour values, skip redundant 4th value for(iIndex=0;iIndex!=256;++iIndex) { pPalPos[0]=pDatPos[2]; // Red pPalPos[1]=pDatPos[1]; // Green pPalPos[2]=pDatPos[0]; // Blue pPalPos+=3; pDatPos+=4; } return IMG_OK; } void BMPImg::FlipImg(void) { unsigned char bTemp; unsigned char *pLine1, *pLine2; int iLineLen,iIndex; iLineLen=iWidth*(iBPP/8); pLine1=pImage; pLine2=&pImage[iLineLen * (iHeight - 1)]; for( ;pLine1<pLine2;pLine2-=(iLineLen*2)) { for(iIndex=0;iIndex!=iLineLen;pLine1++,pLine2++,iIndex++) { bTemp=*pLine1; *pLine1=*pLine2; *pLine2=bTemp; } } } int BMPImg::GetBPP() { return iBPP; } int BMPImg::GetWidth() { return iWidth; } int BMPImg::GetHeight() { return iHeight; } unsigned char* BMPImg::GetImg() { return pImage; } unsigned char* BMPImg::GetPalette() { return pPalette; } |


