computerkranker hat geschrieben:Ein bisschen Code hast nicht gerade rum liegen.
War das eine Frage? Also ich hätte einen BMP + TGA Loader mit Bitmap-Klasse in C++ Code anzubieten:
Man erstellt zuerst ein Objekt der Klasse bitmap_class und kann dann mit den Methoden load_bmp_from_file() oder load_tga_from_file() ein BMP- oder ein TGA-Bitmap einladen. Dieses kann man dann mittels draw_to_device() auf jedem beliebigen Device Context angezeigt werden. Außerdem kann man TGAs in BMPs umwandeln (im Speicher). Speichern der BMPs hab ich noch nicht eingerichtet, die Klasse befindet sich noch im Aufbau, weshalb es auch noch wenig optimiert ist.
Auch werden bisher nur unkomprimierte TGAs und BMPs in 32 und 24 Bit Farbtiefe unterstützt.
(Der TGA-Loader ist größtenteils von Nehe übernommen. =>
http://nehe.gamedev.net/)
Code: Alles auswählen
//Includefile for bitmaps
class bitmap_class
{
private: BITMAPFILEHEADER bmpfileheader;
BITMAPINFOHEADER bmpinfoheader;
unsigned char* data;
public: BITMAPFILEHEADER get_bmpfileheader( void ) {return bmpfileheader;}
BITMAPINFOHEADER get_bmpinfoheader( void ) {return bmpinfoheader;}
unsigned char* get_data( void ) {return data;}
bitmap_class( void );
void set_bmpfileheader( BITMAPFILEHEADER param) { bmpfileheader = param;}
void set_bmpinfoheader( BITMAPINFOHEADER param) { bmpinfoheader = param;}
void set_data_size( int size) {data = (unsigned char*) malloc(size);}
void set_buffer_to_data( unsigned char* adresse, int size) {memcpy(data, adresse, size);}
bool load_bmp_from_file(char* filename); //Methode for loading bmps from harddisc
bool load_tga_from_file(char* filename);
bool create_bmp_from_image_data(char* image_data, int size_x, int size_y, int bit_per_pixel);
void draw_to_device(HDC hdc, int pos_x, int pos_y, int size_x, int size_y, int source_x, int source_y, int source_size_x, int souce_size_y, unsigned char* buffer, BITMAPINFO* bitmapinfo);
};
void bitmap_class::draw_to_device(HDC hdc, int pos_x, int pos_y, int size_x, int size_y, int source_x, int source_y, int source_size_x, int source_size_y, unsigned char* buffer, BITMAPINFO* bmpinfo)
{
SetDIBitsToDevice( hdc, // handle of device context
pos_x, // x-coordinate of upper-left corner of dest. rect.
pos_y, // y-coordinate of upper-left corner of dest. rect.
size_x, // source rectangle width
size_y, // source rectangle height
source_x, // x-coordinate of lower-left corner of source rect.
source_y, // y-coordinate of lower-left corner of source rect.
source_size_x, // first scan line in array
source_size_y, // number of scan lines
buffer, // address of array with DIB bits
bmpinfo, // address of structure with bitmap info.
DIB_RGB_COLORS // RGB or palette indices
);
}
bitmap_class::bitmap_class( void )
{
data = NULL; //Set data for image data to zero
}
bool bitmap_class::create_bmp_from_image_data(char* image_data, int size_x, int size_y, int bit_per_pixel)
{
if ((bit_per_pixel != 32 && bit_per_pixel != 24) || image_data == NULL || size_x <= 0 || size_y <= 0) //check for possible false parameters and return false
{
return false;
}
int image_size = size_x * size_y * (bit_per_pixel / 8);
if (data != NULL) //If there is already another bitmap loaded, free these image byte
{
free(data);
}
this->data = (unsigned char*) malloc(image_size); //Reserve memory for image Data
memcpy(this->data, (unsigned char*)image_data, image_size); //Copy the bytedata to data-buffer for use later
int temp = 0;
for(unsigned int i=0; i< (int)(image_size); i += (bit_per_pixel/8)) // Loop Through The Image Data
{ // Swaps The 1st And 3rd Bytes ('R'ed and 'B'lue)
temp=this->data[i]; // Temporarily Store The Value At Image Data 'i'
this->data[i] = this->data[i + 2]; // Set The 1st Byte To The Value Of The 3rd Byte
this->data[i + 2] = temp; // Set The 3rd Byte To The Value In 'temp' (1st Byte Value)
}
bmpinfoheader.biSize = sizeof(BITMAPINFOHEADER); //Fill the bitmapinfoheader with infos from bitmap
bmpinfoheader.biWidth = size_x;
bmpinfoheader.biHeight = size_y;
bmpinfoheader.biPlanes = 1;
bmpinfoheader.biBitCount = bit_per_pixel;
bmpinfoheader.biCompression = BI_RGB;
bmpinfoheader.biSizeImage = 0;
bmpinfoheader.biXPelsPerMeter = 96;
bmpinfoheader.biYPelsPerMeter = 96;
bmpinfoheader.biClrUsed = 0;
bmpinfoheader.biClrImportant = 0;
return true;
}
bool bitmap_class::load_tga_from_file(char *filename) // Loads A TGA File Into Memory
{
TextureImage texture;
GLubyte TGAheader[12]={0,0,2,0,0,0,0,0,0,0,0,0}; // Uncompressed TGA Header
GLubyte TGAcompare[12]; // Used To Compare TGA Header
GLubyte header[6]; // First 6 Useful Bytes From The Header
GLuint bytesPerPixel; // Holds Number Of Bytes Per Pixel Used In The TGA File
GLuint imageSize; // Used To Store The Image Size When Setting Aside Ram
GLuint temp; // Temporary Variable
GLuint type=GL_RGBA; // Set The Default GL Mode To RBGA (32 BPP)
FILE *file = fopen(filename, "rb"); // Open The TGA File
if( file==NULL || // Does File Even Exist?
fread(TGAcompare,1,sizeof(TGAcompare),file)!=sizeof(TGAcompare) || // Are There 12 Bytes To Read?
memcmp(TGAheader,TGAcompare,sizeof(TGAheader))!=0 || // Does The Header Match What We Want?
fread(header,1,sizeof(header),file)!=sizeof(header)) // If So Read Next 6 Header Bytes
{
if (file == NULL) // Did The File Even Exist? *Added Jim Strong*
return FALSE; // Return False
else // Otherwise
{
fclose(file); // If Anything Failed, Close The File
return FALSE; // Return False
}
}
texture.width = header[1] * 256 + header[0]; // Determine The TGA Width (highbyte*256+lowbyte)
texture.height = header[3] * 256 + header[2]; // Determine The TGA Height (highbyte*256+lowbyte)
if( texture.width <=0 || // Is The Width Less Than Or Equal To Zero
texture.height <=0 || // Is The Height Less Than Or Equal To Zero
(header[4]!=24 && header[4]!=32)) // Is The TGA 24 or 32 Bit?
{
fclose(file); // If Anything Failed, Close The File
return FALSE; // Return False
}
texture.bpp = header[4]; // Grab The TGA's Bits Per Pixel (24 or 32)
bytesPerPixel = texture.bpp/8; // Divide By 8 To Get The Bytes Per Pixel
imageSize = texture.width*texture.height*bytesPerPixel; // Calculate The Memory Required For The TGA Data
texture.imageData=(GLubyte *)malloc(imageSize); // Reserve Memory To Hold The TGA Data
if( texture.imageData==NULL || // Does The Storage Memory Exist?
fread(texture.imageData, 1, imageSize, file)!=imageSize) // Does The Image Size Match The Memory Reserved?
{
if(texture.imageData!=NULL) // Was Image Data Loaded
free(texture.imageData); // If So, Release The Image Data
fclose(file); // Close The File
return FALSE; // Return False
}
for(GLuint i=0; i<int(imageSize); i+=bytesPerPixel) // Loop Through The Image Data
{ // Swaps The 1st And 3rd Bytes ('R'ed and 'B'lue)
temp=texture.imageData[i]; // Temporarily Store The Value At Image Data 'i'
texture.imageData[i] = texture.imageData[i + 2]; // Set The 1st Byte To The Value Of The 3rd Byte
texture.imageData[i + 2] = temp; // Set The 3rd Byte To The Value In 'temp' (1st Byte Value)
}
fclose (file); // Close The File
data = (unsigned char*) malloc(imageSize); //Reserve memory for image Data
memcpy(this->data, texture.imageData, imageSize); //Copy the bytedata to data-buffer for use later
bmpinfoheader.biSize = sizeof(BITMAPINFOHEADER); //Fill the bitmapinfoheader with infos from bitmap
bmpinfoheader.biWidth = texture.width;
bmpinfoheader.biHeight = texture.height;
bmpinfoheader.biPlanes = 1;
bmpinfoheader.biBitCount = texture.bpp;
bmpinfoheader.biCompression = BI_RGB;
bmpinfoheader.biSizeImage = 0;
bmpinfoheader.biXPelsPerMeter = 96;
bmpinfoheader.biYPelsPerMeter = 96;
bmpinfoheader.biClrUsed = 0;
bmpinfoheader.biClrImportant = 0;
return true; // Texture Building Went Ok, Return True
}
bool bitmap_class::load_bmp_from_file(char* filename)
{
int bytesread;
int bit_size;
ifstream file(filename, ios::in | ios::binary);
if (!file)
{
return false;
}
else
{
file.read((char*)&bmpfileheader, sizeof(BITMAPFILEHEADER));
file.read((char*)&bmpinfoheader, sizeof(BITMAPINFOHEADER));
bit_size = (bmpfileheader.bfSize) - bmpfileheader.bfOffBits; //Size of bit-map
data = (unsigned char*) malloc(bit_size); //Change size of bit-data
file.read((char*)data, bit_size); //Read bit data in temp buffer
file.close();
return true;
}
}
Der Vorteil von DIBitmaps ist, dass man praktisch nur die Daten aus dem Bitmap im Speicher brauch und dann mit nur einer Funktion einen Pointer auf die Bitdaten und auf den Infoheader bereich legt und schon kann man das Bitmap überall anzeigen lassen. Speichern geht natürlich dann auch recht einfach, indem man die Daten + Header einfach wieder in eine Datei schreibt und speichert.