In BMP-Datei schreiben



  • Moin,
    ich hab da ein kleines Problem mit meinem Programm, das eine BMP Datei mit 640*480 Pixeln schreiben soll. Hier erstmal der Code:

    #include <fstream>
    #include <ctime>
    #include <windows.h>
    using namespace std;
    
    struct BMPHEADER
    {
           SHORT id; //BMP-File ID "BM"
           DWORD size; //Größe der Datei
           DWORD res1; //reserviert
           DWORD res2;
           DWORD BMPdata; //Offset vom Programmanfang zu Bilddaten
    };
    
    struct INFHEADER
    {
           DWORD biSize; //Strukturgröße von BMPHEADER
           DWORD biWidth;  //Breite des Bildes
           DWORD biHeigth; //Höhe des Bildes
           WORD biPlanes;  //"Zeichenebenen"
           WORD biBitCount; //Farbtiefe
           DWORD comp;      //Kompression
           DWORD SizeImage; //Größe der Bilddaten in Byte
           DWORD XPixelperMeter; //nicht notwendig (=0)
           DWORD YPixelperMeter; //ebenso
           DWORD ClrUsed;      //verwendete Farben 
           DWORD ClrImportant;  //wichtige Farben(0: alle Farben wichtig)
    };
    
    BMPHEADER bmpfheader = {19778,sizeof(BMPHEADER)+sizeof(INFHEADER)+3*(640*480),
                            0,0,sizeof(BMPHEADER)+sizeof(INFHEADER)};  //19778  
                            //bezeichnet "BM" Kennung, Offsetangabe so ok?
    INFHEADER infhead = {sizeof(BMPHEADER),640,480,0,24,0,640*480*3,0,0,0,0};
    char Array[640][480][3]; //640*480 Pixel, 3Byte pro Pixel
    
    int main()
    {
    srand(time(0));
    for(int i= 0; i<100;i++)
      {
         for(int k=0;k<100;k++)
           {
                 for(int j=0;j<3;j++)
                 {
                 Array[i][k][j] = rand()%256; //Fülle Pixel mit Zufallswerten
                 }
           }
       }       
    ofstream Bild("hallo.bmp", ios::out|ios::binary|ios::trunc);
    
    Bild.write(reinterpret_cast<char*>(&bmpfheader), sizeof(BMPHEADER));
    Bild.write(reinterpret_cast<char*>(&infhead), sizeof(INFHEADER));
    Bild.write(reinterpret_cast<char*>(Array),3*(640*480));
    Bild.close();
    return 0; 
    }
    

    Ich hab mich hier vorerst auf 24-Bit-Farbtiefe beschränkt, da die eigentlichen Bilddateien direkt hinter dem INFHEADER folgen und keine Farbpalette benötigt wird. Der Code selbst lässt sich wunderbar kompilieren, nur die geschriebene BMP-Datei lässt sich nicht Öffnen("Error Opening this document"). Ich bin der BMP-Datei auch schon mit dem Hexeditor zu Leibe gerückt, die "BM" Kennung am Anfang schreibt er jedenfalls ordentlich rein. Ich habe auch schon probiert mit #pragma pack(0) das Alignment auszuschalten, aber das hat auch nicht geholfen. Sieht vielleicht jemand, was ich falsch mache?



  • Matzer schrieb:

    Ich habe auch schon probiert mit #pragma pack(0) das Alignment auszuschalten, aber das hat auch nicht geholfen. Sieht vielleicht jemand, was ich falsch mache?

    pack(0) ist ja auch Quatsch. Mein Compiler sagt dazu:
    warning C4086: expected pragma parameter to be '1', '2', '4', '8', or '16'



  • Du hast den Bitmap-Header nicht wirklich korrekt zusammengesetzt:

    Matzer schrieb:

    struct BMPHEADER
    {
           SHORT id; //BMP-File ID "BM"
           DWORD size; //Größe der Datei
           DWORD res1; //reserviert
           DWORD res2;
           DWORD BMPdata; //Offset vom Programmanfang zu Bilddaten
    };
    

    Das DWORD res2 ist überflüssig - und zerstört in der Folge auch die Offset-Berechnungen.

    struct INFHEADER
    {
           DWORD biSize; //Strukturgröße von BMPHEADER
           DWORD biWidth;  //Breite des Bildes
           DWORD biHeigth; //Höhe des Bildes
           WORD biPlanes;  //"Zeichenebenen"
           WORD biBitCount; //Farbtiefe
           DWORD comp;      //Kompression
           DWORD SizeImage; //Größe der Bilddaten in Byte
           DWORD XPixelperMeter; //nicht notwendig (=0)
           DWORD YPixelperMeter; //ebenso
           DWORD ClrUsed;      //verwendete Farben 
           DWORD ClrImportant;  //wichtige Farben(0: alle Farben wichtig)
    };
    

    biWidth und biHeigth sind LONG-Werte (letzteres kann auch negativ werden), genauso die beiden PxielperMeter-Werte.

    BMPHEADER bmpfheader = {19778,sizeof(BMPHEADER)+sizeof(INFHEADER)+3*(640*480),
                            0,0,sizeof(BMPHEADER)+sizeof(INFHEADER)};  //19778  
                            //bezeichnet "BM" Kennung, Offsetangabe so ok?
    

    Abgesehen davon, daß eine 0 zu viel ist (siehe oben), sieht die Angabe gut aus.

    INFHEADER infhead = {sizeof(BMPHEADER),640,480,0,24,0,640*480*3,0,0,0,0};
    

    falscher Größenwert (du brauchst 'sizeof(INFHEADER)'), biPlanes sollte 1 sein - und für die Datengröße kannst du auch 0 einsetzen.

    char Array[640][480][3]; //640*480 Pixel, 3Byte pro Pixel
    

    Der Platz reicht zwar, aber ich bin mir jetzt nicht ganz sicher, ob die Anordnung zum Bitmap passt.



  • Vielen Dank für die Hinweise, hat wunderbar geklappt. Ich stell den (funktionierenden) Source hier nochmal rein, vielleicht kann es ja jemand gebrauchen:

    #include <fstream>
    #include <ctime>
    #include <windows.h>
    using namespace std;
    
    #pragma pack(1)
    struct BMPHEADER
    {
           SHORT id;
           DWORD size;
           DWORD res1;
           DWORD adress_BMP_data;
    };
    
    struct INFHEADER
    {
           DWORD biSize;
           LONG biWidth;
           LONG biHeigth;
           WORD biPlanes;
           WORD biBitCount;
           DWORD comp;
           DWORD SizeImage;
           LONG XPixelperMeter;
           LONG YPixelperMeter;
           DWORD ClrUsed;
           DWORD ClrImportant;
    };
    
    BMPHEADER bmpfheader = {19778,sizeof(BMPHEADER)+sizeof(INFHEADER)+3*(640*480),
                            0,sizeof(BMPHEADER)+sizeof(INFHEADER) };
    INFHEADER infhead = {sizeof(INFHEADER),640,480,1,24,0,640*480*3,0,0,0,0};
    char Array[640][480][3];
    
    int main()
    {
    srand(time(0));
    for(int i= 0; i<640;i++)
      {
         for(int k=0;k<480;k++)
           {
                 for(int j=0;j<3;j++)
                 {
                 Array[i][k][j] = rand()%256;
                 }
           }
       }    
    
    ofstream Bild("hallo.bmp", ios::out|ios::binary|ios::trunc);
    
    Bild.write(reinterpret_cast<char*>(&bmpfheader), sizeof(BMPHEADER));
    Bild.write(reinterpret_cast<char*>(&infhead), sizeof(INFHEADER));
    Bild.write(reinterpret_cast<char*>(Array),3*(640*480));
    Bild.close();
    return 0;
    }
    


  • Wow, so eine schönes Bild hatte ich ja noch nie...


Anmelden zum Antworten