Bitmap Laden
-
Guten Abend,
Ich habe mir heute einen Bitmap Loader geschrieben - und er treibt mich in die Verzweiflung - leider macht er nicht ganz, was er soll.
nachdem ich e eine 150x200 Pixel große Bitmap geladen und gespeichert habe, ist die Differenz der Dateien am Ende knapp 1KB, ...
Wenn ich das gespeicherte BMP mit Irfant View angucke, fehlt auch eine halbe Zeile - der Windows Interne Bildanzeiger streikt ganz.
class Image { public: Image(); Image(const Image& other); ~Image(); Image& operator =(const Image& other); virtual void Release(); bool IsEmpty() const; // Dreckig, da keine Datenkappslung public: unsigned long width; unsigned long height; unsigned long bits_per_pixel; unsigned char* data; }; //////////////////////////////////////////////////////////////////////////////// #include "BMPLoader.hpp" BMPLoader::BMPLoader() { } BMPLoader::~BMPLoader() { } BMPLoader::BMPLoader(const std::string& filename, Image& image) { LoadImage(filename, image); } bool BMPLoader::LoadImage(const std::string& filename, Image& image) { if(filename.empty()) return false; FILE* file = NULL; if((file = fopen(filename.c_str(), "rb")) == NULL) return false; // Bitmap File Header auslesen BMPFileHeader bfh; fread((void*) &bfh.bm_type[0], 1, 1, file); fread((void*) &bfh.bm_type[1], 1, 1, file); fread((void*) &bfh.file_size, 4, 1, file); fread((void*) &bfh.reserved1, 2, 1, file); fread((void*) &bfh.reserved2, 2, 1, file); fread((void*) &bfh.offset_bits, 4, 1, file); if(bfh.bm_type[0] != 'B' && bfh.bm_type[1] != 'M') return false; // Bitmap Infor Header auslesen BMPInfoHeader bih; fread((void*) &bih.size_header, 4, 1, file); fread((void*) &bih.width, 4, 1, file); fread((void*) &bih.height, 4, 1, file); fread((void*) &bih.planes, 2, 1, file); fread((void*) &bih.bits_per_pixel, 2, 1, file); fread((void*) &bih.compression, 4, 1, file); fread((void*) &bih.size_image, 4, 1, file); fread((void*) &bih.x_pels_per_meter, 4, 1, file); fread((void*) &bih.y_pels_per_meter, 4, 1, file); fread((void*) &bih.color_used, 4, 1, file); fread((void*) &bih.color_important, 4, 1, file); #if defined _DEBUG printf("magic number %c\n", bfh.bm_type[0]); printf("magic number %c\n", bfh.bm_type[1]); printf("file size %u\n", bfh.file_size); printf("reserved1 %d\n", bfh.reserved1); printf("reserved2 %d\n", bfh.reserved2); printf("offset bits %u\n", bfh.offset_bits); printf("size header %u\n", bih.size_header); printf("widt %d\n", bih.width); printf("height %d\n", bih.height); printf("planes %d\n", bih.planes); printf("bits per pixel %d\n", bih.bits_per_pixel); printf("compression %u\n", bih.compression); printf("size image %u\n", bih.size_image); printf("x pels per meter %d\n", bih.x_pels_per_meter); printf("y pels per meter %d\n", bih.y_pels_per_meter); printf("color used %u\n", bih.color_used); printf("color important %u\n", bih.color_important); #endif // TODO: Andere Kompressionsverfahren implementieren if(bih.compression != COMPRESSION_RGB) return false; // TODO: Andere Farbarten implementieren if(bih.bits_per_pixel != 24) return false; image.Release(); image.width = bih.width; image.height = bih.height; image.bits_per_pixel = bih.bits_per_pixel; // Speicher anlegen image.data = new unsigned char[image.width * image.height * 3]; // Farbwerte auslesen fread((void*) image.data, 3, image.width * image.height, file); fclose(file); return(true); } bool BMPLoader::SaveImage(const std::string& filename, const Image& image) { if(filename.empty() || image.IsEmpty()) return false; FILE* file = NULL; if((file = fopen(filename.c_str(), "wb")) == NULL) return false; // TODO: Andere Farbarten implementieren if(image.bits_per_pixel != 24) return false; // Bitmap File Header erstellen BMPFileHeader bfh; bfh.bm_type[0] = 'B'; bfh.bm_type[1] = 'M'; // Breite x Höhe x Farbkanalanzahl (je 1 byte) + (Größe File Header + Größe Info Header?) oder offset?! bfh.file_size = image.width * image.height * 3 + 54; bfh.reserved1 = 0; bfh.reserved2 = 0; bfh.offset_bits = 54; // bei allen 24 Bit Bildern! // Bitmap File Header speichern fwrite((void*) &bfh.bm_type[0], 1, 1, file); fwrite((void*) &bfh.bm_type[1], 1, 1, file); fwrite((void*) &bfh.file_size, 4, 1, file); fwrite((void*) &bfh.reserved1, 2, 1, file); fwrite((void*) &bfh.reserved2, 2, 1, file); fwrite((void*) &bfh.offset_bits,4, 1, file); // Bitmap Info Header erstellen BMPInfoHeader bih; bih.size_header = 40; bih.width = image.width; bih.height = image.height; bih.planes = 1; bih.bits_per_pixel = image.bits_per_pixel; bih.compression = COMPRESSION_RGB; // Breite x Höhe x Farbkanalanzahl (je 1 byte) + Größe File Header + Größe Info Header bih.size_image = image.width * image.height * 3; bih.x_pels_per_meter = 0; bih.y_pels_per_meter = 0; bih.color_used = 0; bih.color_important = 0; // Bitmap Info Header speichern fwrite((void*) &bih.size_header, 4, 1, file); fwrite((void*) &bih.width, 4, 1, file); fwrite((void*) &bih.height, 4, 1, file); fwrite((void*) &bih.planes, 2, 1, file); fwrite((void*) &bih.bits_per_pixel, 2, 1, file); fwrite((void*) &bih.compression, 4, 1, file); fwrite((void*) &bih.size_image, 4, 1, file); fwrite((void*) &bih.x_pels_per_meter, 4, 1, file); fwrite((void*) &bih.y_pels_per_meter, 4, 1, file); fwrite((void*) &bih.color_used, 4, 1, file); fwrite((void*) &bih.color_important, 4, 1, file); // Farbwerte speichern fwrite((void*) image.data, 3, image.width * image.height, file); fclose(file); return true; } //////////////////////////////////////////////////////////////////////////////// class BMPLoader : public ImageLoader { public: BMPLoader(); BMPLoader(const std::string& filename, Image& image); virtual ~BMPLoader(); public: virtual bool LoadImage(const std::string& filename, Image& image); virtual bool SaveImage(const std::string& filename, const Image& image); public: struct BMPFileHeader { char bm_type[2]; unsigned long file_size; short int reserved1; short int reserved2; unsigned long offset_bits; }; struct BMPInfoHeader { unsigned int size_header; long width; long height; short int planes; short int bits_per_pixel; unsigned long compression; unsigned long size_image; long x_pels_per_meter; long y_pels_per_meter; unsigned long color_used; unsigned long color_important; }; enum BitCompression { // keine Kompression COMPRESSION_RGB = 0, COMPRESSION_RLE8, COMPRESSION_RLE4, COMPRESSION_BITFIELDS }; };MfG Mandy
-
Die einzelnen Zeilen eines Bitmaps liegen auf Doppelwort-Bereichen, also immer ohne Rest durch 4 teilbaren Adressen. Also werden maximal 3 Bytes (ich gehe jetzt mal nicht von einem exotischen System aus) hinzugefügt, die normalerweise auf 0 gesetzt werden (müssen sie aber nicht).
Und das ist denke ich das Problem, z.B. ist die Größe der Bilddaten nicht
w*h*3 // wenn man von 24 bit ausgeht // sondern h*((w*(bitcount >> 3) + 3) & ~3).
Diese Größen müssen dann beim Laden und Speichern beachtet, und biSizeImage auch angepasst werden.Edit: Klammern vergessen
-
was du da machst ist echt schönes C...
...mit klassen.
mach das besser mit den stream operatoren, da kannst du am ende auch sicher sein, dass alles da ist