Bitmap lesen und schreiben



  • Hallo,
    ich möchte eine Bitmap Datei einlesen, diese dann verändern und wieder speichern. Ich habe auch schon 3 oder 4 Beispiele gefunden, die sich entweder erst garnich kompilieren lassen oder nichts vernünftiges tun.

    Das große Problem ist eigentlich das Einlesen. Dazu verwende ich 2 Strukturen

    struct BITMAPFILEHEADER {
        unsigned short bfType;
        unsigned long bfSize;
        unsigned short bfReserved1;
        unsigned short bfReserved2;
        unsigned long bfOffBits;
        };
    
        struct BITMAPINFOHEADER {
        unsigned long biSize;
        unsigned long biWidth;
        unsigned long biHeight;
        unsigned short biPlanes;
        unsigned short biBitCount;
        unsigned long biCompression;
        unsigned long biSizeImage;
        unsigned long biXPelsPerMeter;
        unsigned long biYPelsPerMeter;
        unsigned long biClrUsed;
        unsigned long biClrImportant;
        };
    

    Mit

    fp = fopen(filename, "rb")
    

    öffne ich die Datei zum binären lesen und mit

    fp = fopen(filename, "wb")
    

    eine andere Datei zum binären schreiben.

    Mit

    fread(&FileHeader, sizeof(FileHeader), 1, fp)
    fread(&InfoHeader, sizeof(InfoHeader), 1, fp)
    

    lese ich dann das Bild ein.

    Wenn ich aber dann mit

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

    den Dateiheader in eine andere Datei übertrage, kommt nur das "MB" am Anfang an. Alles andere sieht eher zufällig aus, obwohl ich es vorher auf 0 gesetzt habe.

    Ich hoffe, jemand hat nen Tip

    Gruß
    jabaa



  • Wie wäre es wenn du statt zweimal fp für verschiedene Dateien, fpRead und fpWrite nimmst? So holst du dir 2 Handels auf Files die dann zT gelesen und zT geschrieben werden .. das da murks bei rumkommt ist nicht verwunderlich 😉 Falls du das natürlich alles in der richtigen Reihenfolge machst, dann brauchen mer mehr Code 🙂 Ich nehme mal einfach an das du die Datei auf dem selben Rechner erstellst und es daher nichts mit Endianess zu tun haben kann ...



  • 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