LoadBMPCpp
From GPWiki
The wiki is now hosted by GameDev.NET at wiki.gamedev.net. All gpwiki.org content has been moved to the new server. However, the GPWiki forums are still active! Come say hello. Sample 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; } |


