Code:
#include <cstring>
#include <cctype>
#include <fstream>
typedef unsigned char Uint8;
typedef unsigned short Uint16;
typedef unsigned int Uint32;
enum ImageExtensions { NO_EXT, EXT_INVALID, BMP, JPG, PNG, TGA };
enum ImageLoad { LOAD_IMAGE_SUCCESS, LOAD_IMAGE_INVALID, LOAD_IMAGE_UNSUPPORTED_BITDEPTH };
class Image
{
public:
Image(){};
~Image(){delete[] pixels;}
bool Load(char*);
bool Save(char*);
int GetWidth();
int GetHeight();
private:
int GetExt(char*);
int LoadBMP(char*);
int LoadJPG(char*);
int LoadPNG(char*);
int LoadTGA(char*);
int SaveBMP(const char*);
int BytesToInt(char*);
short BytesToShort(char*);
void IntToBytes(char*, Uint32);
void ShortToBytes(char*, Uint16);
int w, h;
Uint32 *pixels;
};
//------------------------------------------------------------------//
//********************* PUBLIC FUNCTIONS ***************************//
//------------------------------------------------------------------//
bool Image::Load(char* filename)
{
switch(GetExt(filename))
{
case NO_EXT:
return false;
case EXT_INVALID:
return false;
case BMP:
LoadBMP(filename);
break;
case JPG:
break;
case PNG:
break;
case TGA:
break;
}
return true;
}
bool Image::Save(char* filename)
{
SaveBMP(filename);
return 0;
}
int Image::GetWidth()
{
return w;
}
int Image::GetHeight()
{
return h;
}
//------------------------------------------------------------------//
//********************* PRIVATE FUNCTIONS **************************//
//------------------------------------------------------------------//
int Image::GetExt(char* filename)
{
//This function gets a file extension and checks if it is valid
char ext[10]="\0";
char *e_ptr = ext;
char *f_ptr = filename;
Uint16 count = 0;
Uint16 index = 0;
//Get index of last full stop
while(*f_ptr++)
{
count++;
if(*f_ptr == '.') index = count;
}
if(!index) return NO_EXT;
f_ptr = filename+index;
//Copy The extension converting to upper case
while(*e_ptr++ = toupper(*f_ptr++));
//Check against valid extensions
if(!strcmp(ext, ".BMP")) return BMP;
if(!strcmp(ext, ".JPG")) return JPG;
if(!strcmp(ext, ".JPEG")) return JPG;
if(!strcmp(ext, ".PNG")) return PNG;
if(!strcmp(ext, ".TGA")) return TGA;
if(!strcmp(ext, ".TARGA"))return TGA;
return EXT_INVALID;
}
int Image::LoadBMP(char* filename)
{
ifstream in;
in.open(filename, ios::binary);
if(! in.is_open()) return LOAD_IMAGE_INVALID;
char bytes[4];
in.seekg(18, ios::beg);
in.read(bytes, 4);
w=BytesToInt(bytes);
in.read(bytes, 4);
h=BytesToInt(bytes);
in.seekg(2, ios::cur);
in.read(bytes, 2);
short bpp=BytesToShort(bytes);
if(bpp != 24) return LOAD_IMAGE_UNSUPPORTED_BITDEPTH;
//Allocate space for image data
pixels = new Uint32[w*h];
Uint32 *px = pixels;
in.seekg(54, ios::beg);
for(int y=h; y>0; y--)
{
for(int x=0; x<w; x++)
{
in.read(bytes, 3);
*px=((Uint8)bytes[2]<<16)+((Uint8)bytes[1]<<8)+(Uint8)bytes[0];
px++;
}
}
in.close();
return true;
}
int Image::BytesToInt(char* i)
{
return ((Uint8)i[3]<<24)+((Uint8)i[2]<<16)+((Uint8)i[1]<<8)+(Uint8)i[0];
}
short Image::BytesToShort(char* i)
{
return ((Uint8)i[1]<<8)+(Uint8)i[0];
}
int Image::SaveBMP(const char* filename)
{
ofstream out;
out.open(filename, ios::binary);
if(! out.is_open()) return 1;
char bytes[4]={'B','M','B', 'M'};
//-------HEADER--------------//
out.write(bytes, 2); //Write bitmap ID
IntToBytes(bytes, w*h*3+54);
out.write(bytes, 4); //Uint32 File Size In Bytes
IntToBytes(bytes, 0);
out.write(bytes, 4); //Uint16 reserved 1 and 2
IntToBytes(bytes, 44);
out.write(bytes, 4); //Int Offset To Image Data
//------- FILE INFO --------//
IntToBytes(bytes, 40);
out.write(bytes, 4); //Uint32 Header Size In Bytes
IntToBytes(bytes, (Uint32)w);
out.write(bytes, 4); //Int Image Width
IntToBytes(bytes, (Uint32)h);
out.write(bytes, 4); //Int Image Height
ShortToBytes(bytes, 1);
out.write(bytes, 2); //Unsigned Short Planes = 1
ShortToBytes(bytes, 24);
out.write(bytes, 2); //Unsigend Short Bit Depth = 24
IntToBytes(bytes, 0);
out.write(bytes, 4); //Unsigned Int Compression = 0 (No compression)
IntToBytes(bytes, w*h*3);
out.write(bytes, 4); //Unsigned Int Image Size In Bytes
IntToBytes(bytes, 2835);
out.write(bytes, 4);
out.write(bytes, 4); //Int X_Res, Y_Rex (pixes per meter)
IntToBytes(bytes, 0);
out.write(bytes, 4); //Uint32 number of paletted colours =0
out.write(bytes, 4); //Uint32 Important colours
//------ IMAGE DATA --------//
Uint32 *px = pixels;
for(int y=h; y>0; y--)
{
for(int x=0; x<w; x++)
{
IntToBytes(bytes, *px);
out.write(bytes, 3);
px++;
}
}
out.close();
return 0;
}
void Image::IntToBytes(char* bytes, Uint32 num)
{
bytes[3] = num >> 24;
bytes[2] = (num >> 16) & 255;
bytes[1] = (num >> 8) & 255;
bytes[0] = num & 255;
}
void Image::ShortToBytes(char* bytes, Uint16 num)
{
bytes[1] = num >> 8;
bytes[0] = num & 255;
}