Bitmap lesen und schreiben



  • Ja ne sorry, aber ich hab das eben so ausm Quelltext kopiert. Im ganzen gibts ne Methode

    void Bitmap::LoadBitmap(const char *filename){
    FILE             *fp;
    ...}
    

    zum einlesen und eine Methode

    void Bitmap::SaveBitmap(const char *filename){
    FILE             *fp;
    ...}
    

    zum schreiben. Somit hat das eine fp nen anderen Gültigkeitsbereich als das andere fp



  • Hier ein minimal Beispiel:
    Bitmap.hpp

    #ifndef BITMAP_H
    #define BITMAP_H
    
    typedef unsigned short WORD;
    typedef unsigned long DWORD;
    typedef unsigned long LONG;
    
    #include "fstream"
    class Bitmap
    {
     public:
    
    	 void LoadBitmap(const char *Filename);
    	 void SaveBitmap(const char *Filename);
    
    	 void *bits;
    
    	 //BITMAPFILEHEADER
    	 typedef struct
    	 {
    	 WORD bfType;
    	 DWORD bfSize;
    	 DWORD bfReserved;
    	 DWORD bfOffBits;
    	 }BITMAPFILEHEADER;
    
    	 //BITMAPINFOHEADER
    	 typedef struct
    	 {
    	 DWORD biSize;
    	 LONG biWidth;
    	 LONG biHeight;
    	 WORD biPlanes;
    	 WORD biBitCount;
    	 DWORD biCompression;
    	 DWORD biSizeImage;
    	 LONG biXPelsPerMeter;
    	 LONG biYPelsPerMeter;
    	 DWORD biClrUsed;
    	 DWORD biClrImportant;
    	 }BITMAPINFOHEADER;
    
    	 BITMAPFILEHEADER FileHeader;
    	 typedef struct
    	 {
    	 DWORD biSize;
    	 LONG biWidth;
    	 LONG biHeight;
    	 WORD biPlanes;
    	 WORD biBitCount;
    	 DWORD biCompression;
    	 DWORD biSizeImage;
    	 LONG biXPelsPerMeter;
    	 LONG biYPelsPerMeter;
    	 DWORD biClrUsed;
    	 DWORD biClrImportant;
    	 }BITMAPINFOHEADER;
    
    	 BITMAPFILEHEADER FileHeader;
    	 BITMAPINFOHEADER InfoHeader;
    };
    
    #endif // BITMAP_H
    

    Bitmap.cpp

    #include "Bitmap.hpp"
    #include <stdlib.h>
    #include <iostream>
    
    void Bitmap::LoadBitmap(const char *filename)    
    {
        FILE             *fp;          
        int              bitsize;      
        int              infosize;     
    
        if ((fp = fopen(filename, "rb")) == NULL)
            return;
    
        if (fread(&FileHeader, sizeof(FileHeader), 1, fp) < 1)
        {
    	fclose(fp);
            return;
        }
    
        if (FileHeader.bfType != 'MB')
        {
            fclose(fp);
            return;
        }
    
        infosize = FileHeader.bfOffBits - sizeof(FileHeader);
    
        infosize = 40;
        if (fread(&InfoHeader, infosize, 1,fp) < infosize)
        {
            fclose(fp);
            return;
        }
    
        if ((bitsize = InfoHeader.biSize) == 0)
            bitsize = (InfoHeader.biWidth *
                       InfoHeader.biBitCount + 7) / 8 *
      	           abs(InfoHeader.biHeight);
    
        if ((bits = malloc(bitsize)) == NULL)
        {
            fclose(fp);
            return;
        }
    
        if (fread(bits, 1, bitsize, fp) < bitsize)
        {
            fclose(fp);
            return;
        }
    
        fclose(fp);
        return;
    }
    
    void Bitmap::SaveBitmap(const char *Filename)
    {
        FILE *File=NULL;
    
        File=fopen(Filename,"wb");
        fwrite(&FileHeader,sizeof(BITMAPFILEHEADER),1,File);
    
        fwrite(&InfoHeader,sizeof(BITMAPINFOHEADER),1,File);
    
        fclose(File);
    };
    

    main.cpp

    #include <iostream>
        #include <fstream>
        #include <cstdlib>
        #include "Bitmap.hpp"
    
    int main(){
     Bitmap bmp;
    
        bmp.LoadBitmap("penguins.bmp");
        bmp.SaveBitmap("penguins_cod.bmp");
    return 0;
    }
    


  • Und hier die Header:

    Original:
    424D 36C0 0000 0000 0000 3600 0000 2800
    0000 8000 0000 8000 0000 0100 1800 0000
    0000 00C0 0000 130B 0000 130B 0000 0000 
    0000 0000 0000
    
    Kopie:
    424D FE0A 0000 0000 0000 3600 0000 2800
    0000 1E00 0000 1E00 0000 0100 1800 0000
    0000 C80A 0000 0000 0000 0000 0000 0000
    0000 0000 0000 7D7E
    

    Stellenweise passt es. Aber allein dass der Header länger geworden ist ist sehr komisch



  • Den Fehler machst du bei der Angabe von Byte-Anzahl deiner Elemente (z.B. Zeile 14 in bitmap.cpp des letzten Beitrags). Es sollte heißen:

    fwrite(&FileHeader, 1, sizeof(FileHeader), fp)
    


  • Die Reihenfolge ändert das Ergebnis garnicht. Ob jetzt 40 x 1 Byte in die Struktur geschrieben wird oder 1 x 40 Byte ist wohl nicht so der Unterschied. Hat auf jeden nix geändert



  • Was hat denn "sizeof(FileHeader)" für einen Wert? Laut http://de.wikipedia.org/wiki/Windows_Bitmap muß dabei ja 14 rauskommen.
    Ich tippe darauf, daß das Standard-Padding bei deinem Compiler einen zu hohen Wert hat. Beim MSVC gibt es die "#pragma pack(x)"-Anweisung dafür (beim gcc weiß ich nicht, ob der das auch so unterstützt).

    s. z.B. http://www.c-plusplus.net/forum/265354



  • Was soll denn eigentlich das hier bewirken:

    infosize = FileHeader.bfOffBits - sizeof(FileHeader); 
    
        infosize = 40;
    

    Du berechnest erst die Headergröße und überschreibst den Wert sofort wieder. Und beim Schreiben nimmst du auch wieder eine (möglicherweise andere) Header-Größe an.

    PS: HAst du schon mal an fstream gedacht?



  • Wie wärs mit C++ (hat CStoll schon gesagt)?



  • Da infosize zunächst noch nich richtig eingelesen werden kann, setz ich den Wert manuell auf 40, was meiner Meinung nach ein korrekter Wert ist.

    Mit fstream hab ichs auch versucht. Da kam ähnlicher Mist bei raus. Ganz ganz komisch. Gibt es keine fertigen Packete für sowas? Ich muss es ja nich unbedingt selbst schreiben. Aber ich kann auch im Internet nix finden.

    Gruß
    jabaa



  • Deswegen solltest du trotzdem mal prüfen, ob die beiden Header-Strukturen die richtige Größe haben. Wenn dein Compiler dort einige Füll-Bytes einbaut, um die Elemente besser im Speicher ausrichten zu können, passt die Daten-Anordnung nicht mehr zum Dateiinhalt.



  • Hallo jabaa,

    hast du meinen Beitrag nicht gelesen oder aber nicht verstanden, was ich dir mit "Padding" nahelegen wollte?

    So wie CStoll geschrieben hat, baut der Compiler (aus Performance-Gründen) einige Füll-Bytes ("Padding") ein, um z.B. Integer auf einer durch 4 teilbaren Adresse abzulegen.
    Um das Abzustellen, gibt es die '#pragma pack(1)' - Direktive (aber wie schon geschrieben, je nach Compiler etwas modifiziert)...

    Und mein Link zeigt eine Bitmap-Leseroutine aus diesem Forum...


Anmelden zum Antworten