Hilfe!! BMP Datei unter C bearbeiten



  • Ohne die pragma Anweisung wird sie ebenfalls zu groß, nämlich 16 anstatt 14 Byte.

    Lass dir doch mal die Größe der Struktur einmal mit der #pragma Anweisung und einmal ohne anzeigen:

    printf("%d\n", sizeof( BITMAPFILEHEADER ) );
    

    Strukturen werden standardmäßig im Speicher auf Adressen ausgerichtet, die durch 4 teilbar sind, um schneller darauf zugreifen zu können.
    Weil die Struktur BITMAPFILEHEADER von Haus aus 14 Bytes groß ist, werden 2 Füllbytes eingefügt, damit diese Teilbarkeit durch 4 möglich ist.
    Ein bisschen kannst du hier darüber lesen:
    http://www.hs-augsburg.de/~sandman/c_von_a_bis_z/c_017_011.htm

    typedef unsigned short WORD; oder typedef unsigned int WORD;
    

    die Beide sind vom Größe doch gleich, oder? (beide sind 16bits oder 2 Byte)

    Die Größe der Datentypen kannst du dir mit dem sizeof Oparator anzeigen lassen:

    printf("%d\n", sizeof( unsigned short int ) );
    printf("%d\n", sizeof( unsigned  int ) );
    

    2:

    // Achtung! Hier überschreibst du den Inhalt von bitmapFileheader !
    //  printf("Rueckgabenwert von 'fread' ist : %d\n",fread(&bitmapFileheader,sizeof(BITMAPFILEHEADER),1,file));
    

    durch dies Code möchte ich eigentlich das Funktion'fread' kennenlernen, so wie ich es verstanden habe, habe ich nur eine 'printf'-Fkt zu viele. warum habe ich die Inhalt von bitmapFileheader dadurch geändert! 😞 😞 verstehe ich nicht.
    🙂

    Hier wird die Struktur mit fread eingelesen:

    if(fread(&bitmapFileheader,sizeof(BITMAPFILEHEADER),1,file)!=1)              
    {
        printf("FileHeader kann nicht gelesen werden!!\n");
        fclose(file);
        return 1;
    }
    

    Nach dem Einlesen Zeigt der Dateizeiger nicht mehr an den Anfang dieser Struktur, sondern wird in der Datei um 14 Byte weiter gesetzt.
    Nach Abarbeitung der Zeile

    printf("Rueckgabenwert von 'fread' ist : %d\n",fread(&bitmapFileheader,sizeof(BITMAPFILEHEADER),1,file));
    

    wurde noch einmal eingelesen aber ein anderer Inhalt steht in bitmapFileheader drin, nämlich die ersten 14 Byte der BITMAPINFOHEADER Struktur.



  • 1:
    wieder etwas gelernert,

    printf("Rueckgabenwert von 'fread' ist : %d\n",fread(&bitmapFileheader,sizeof(BITMAPFILEHEADER),1,file));
    

    diese Problem habe ich jetzt verstanden!(hoffe ich 😃 ) so zu sagen, arbeitet 'fread' mit aktuelle Zeiger-Position. meine aktuelle Zeiger-Position hat nachdem

    if(fread(&bitmapFileheader,sizeof(BITMAPFILEHEADER),1,file)!=1)              
    {
        printf("FileHeader kann nicht gelesen werden!!\n");
        fclose(file);
        return 1;
    }
    

    eigentlich FileHeader schon verlassen, der steht direkt vor die "Tür" von INFOHEADER. habe ich so richtig verstaneden? 🙂

    2:

    printf("%d\n", sizeof( unsigned short int ) );
    printf("%d\n", sizeof( unsigned  int ) );
    

    für mich ist das.. naja, unglaublich!! 😉 weil in meine Bücher steht da :Beide sind 16 Bits(2 Byte)! (ANSI) ABER das Computer sagt mir: "2" und "4",Ohhhh!!

    Strukturen werden standardmäßig im Speicher auf Adressen ausgerichtet, die durch 4 teilbar sind, um schneller darauf zugreifen zu können.
    Weil die Struktur BITMAPFILEHEADER von Haus aus 14 Bytes groß ist, werden 2 Füllbytes eingefügt, damit diese Teilbarkeit durch 4 möglich ist.

    kann ich so vorstellen, dass die Datei (ohne #pragma) alle um 2 Byte nach rechts verschoben sind.
    Und zum Zhema "4-teilbar" habe ich etwas vorher schon gelesen, bloß wenn ich späte bei FarbeWert einlesen bei jede Pixel, soll ich aufachten, dass ich immer jede Zell mit 4-fach-Anzahl einlesen soll, damit das zu DWORD passen kann. sind die Beide die selbe gemeint? 😕
    noch mal Danke schön! 🙂



  • gy100002000 schrieb:

    in meine Bücher steht da :Beide sind 16 Bits(2 Byte)! (ANSI) ABER das Computer sagt mir: "2" und "4",Ohhhh!!

    Dann sind deine Bücher wahrscheinlich sehr alt, da ein int, soweit ich weiß, schon seit Beginn der 32-Bit-Ära (Win95) 4 Bytes groß ist.



  • jo!! alles klar! http://www.galileo-press.de/openbook/c_von_a_bis_z/c_007_000.htm#Xxx999329 da habe ich noch mal nachgelesen, int ist 4 Byte! Vorher habe ich immer so vorgestellt, dass Zahlentype überall gleich sind. :p Danke!



  • gy100002000 schrieb:

    ...
    diese Problem habe ich jetzt verstanden!(hoffe ich 😃 ) so zu sagen, arbeitet 'fread' mit aktuelle Zeiger-Position. meine aktuelle Zeiger-Position hat nachdem

    if(fread(&bitmapFileheader,sizeof(BITMAPFILEHEADER),1,file)!=1)              
    {
        printf("FileHeader kann nicht gelesen werden!!\n");
        fclose(file);
        return 1;
    }
    

    eigentlich FileHeader schon verlassen, der steht direkt vor die "Tür" von INFOHEADER. habe ich so richtig verstaneden? 🙂

    Ja, der Fuß ist quasi schon in der Türschwelle.

    gy100002000 schrieb:

    ...kann ich so vorstellen, dass die Datei (ohne #pragma) alle um 2 Byte nach rechts verschoben sind...

    Naja, was ist schon rechts bzw. links.
    Die Datei selbst wird dabei nicht verschoben.
    Den Beginn der Adresse der Struktur im RAM kannst du dir anzeigen lassen:
    printf("%p", &bitmapFileheader );
    Ohne #pragma wird die Adresse vermutlich die gleiche sein, hab ich noch nicht ausprobiert. Da wäre dann also auch nichts verschoben. Allerdings ist die Struktur ohne #pragma um 2 Byte größer und verschluckt dir deshalb beim Einlesen 2 Byte von der BITMAPINFOHEADER Struktur.

    Der Fuß ist also schon über die Türschwelle drüber.

    gy100002000 schrieb:

    Und zum Zhema "4-teilbar" habe ich etwas vorher schon gelesen, bloß wenn ich späte bei FarbeWert einlesen bei jede Pixel, soll ich aufachten, dass ich immer jede Zell mit 4-fach-Anzahl einlesen soll, damit das zu DWORD passen kann. sind die Beide die selbe gemeint? 😕
    noch mal Danke schön! 🙂

    Jede Zell? Meinst du jeden Pixel?
    Einzelnd Pixel einlesen macht man eigentlich nicht, die liest man mit einem Rutsch in einen Puffer ein.



  • Hallo! Big Brother, Danke noch mal!
    ich habe mit

    printf("%p", &bitmapFileheader );
    

    mit und ohne "#pragma" ausführen lassen, die computer gibt mir die selb Werte aus. d.h. die BITMAPFILEHEADER und BITMAPINFOHEADER haben immer die gleich Beginnenstelle. wenn die BITMAPFILEHEADER zu größ ist, z.B >14 Byte, werde BITMAPINFOHEADER NICHT automatisch um 2 Byte verschieben, sonder BITMAPINFOHEADER fänge immer bei den alte Adresse an.

    und was zu "4-teilbar" habe ich sowas gelesen: z.B. jede Pixel eines BMP Datei mit (256 stufen) besitze 1 Byte. und wenn die Bildbereite 79 Pixel wäre, wird aber für diese Zeil trotzdem 80 Pixel(bzw. 80 Byte) gelesen, und wenn wenn bildbereite 75 Pixel wäre, wird es zu 76 gemacht, denn 80 und 76 sind vielfach von "4" .

    das Programm habe ich weiter bearbeitet, code:

    fread(&bitmapInfoheader,sizeof(BITMAPINFOHEADER),1,file);	
    	printf("%p\n", &bitmapInfoheader ); 
    	printf("%d\n",sizeof(bitmapInfoheader));
    	printf("%d\n",bitmapInfoheader.biWidth);
    	printf("%d\n",bitmapInfoheader.biSizeImage);
    

    für die Inhalt von BITMAPINFOHEADER habe ich ganz komisch Werte bekommen, eigentlich nicht sein darf! deswegen habe ich zuerste gedacht, dass ich für BITMAPINFOHEADER auch #pragma benutzen soll. aber mit sizeof() habe ich sicher gestellt, dass bitmapInfoheader 40 Byte ist. also richitge Größe! deswegen habe ich eine 2. Idee, vielleicht ist deshalb nicht richtig, weil ich gerade mit dem Programm ausprobiert ohne #pragma. Die bimapFileheader und bitmapInfoheader sind von Speicheradresse schon übereinandere gelegt. Obwohl ich späte #pragma wieder zugefügt habe, kann ich die speicherAdress nicht mehr leeren. deshalb habe ich VC++ neu gestartet. lass die Programm noch mal laufen. naja! geht auch nicht!!
    um zu kontrollieren, ob die Zeiger auch die richtige Stelle zeigt, habe ich noch drei Zeilen Code geschrieben,

    file=fopen(fname,"rb"); 
    	p=ftell(file);
    	printf("Point-Position_1:%d\n",p);  // neue Code 
                 .
                 .
         if(fread(&bitmapFileheader,sizeof(BITMAPFILEHEADER),1,file)!=1)               
        { 
                printf("FileHeader kann nicht gelesen werden!!\n"); 
                fclose(file); 
                return 1; 
       } 
    
    	p=ftell(file);
    	printf("Point-Position_2:%d\n",p);  // neue Code 
    
                 .
                 .
    fread(&bitmapInfoheader,sizeof(BITMAPINFOHEADER),1,file);	
    
    	p=ftell(file);
    	printf("Point-Position_3:%d\n",p);  // neue Code
    

    1: 0 2:14 . wie ich erwartet, ist es alles so weiter im Ordnung. aber als ich den

    p=ftell(file);
    	printf("Point-Position_3:%d\n",p);
    

    eingefügt habe, bekommt cih eine Fehlmeldung : Debug Assertion Failed! 😕
    versteh ich nicht!! 😞



  • hier ist noch mal die Code:

    #include <stdio.h> 
    
    typedef unsigned short WORD; 
    typedef unsigned long DWORD; 
    typedef long LONG; 
    
    #pragma pack(2) 
    typedef struct tagBITMAPFILEHEADER 
    { 
        WORD   bfType;                 
        DWORD  bfSize;                 
        WORD   bfReserved1;           
        WORD   bfReserved2;           
        DWORD  bfOffBits;   
    } BITMAPFILEHEADER; 
    #pragma pack() 
    
    typedef struct tagBITMAPINFOHEADER 
    { 
        DWORD biSize;               
        LONG biWidth;               
        LONG biHeight;             
        WORD biPlanes;   
        WORD biBitCount;   
        DWORD biCompression; 
        DWORD biSizeImage;   
        LONG  bXPelsPerMeter;       
        LONG  biYPelsPerMeter;   
        DWORD biClrUsed; 
        DWORD biClrImportant;         
    
    } BITMAPINFOHEADER; 
    
    int main() 
    { 
        FILE *file; 
        char* fname = "2.bmp"; 
    	int p;
    
        BITMAPFILEHEADER bitmapFileheader; 
    	BITMAPINFOHEADER bitmapInfoheader;
    
        //printf("%d %d\n", sizeof(BITMAPFILEHEADER), sizeof(BITMAPINFOHEADER)); 
    	//printf("%d %d\n", sizeof(bitmapFileheader), sizeof(bitmapInfoheader));
    
        file=fopen(fname,"rb"); 
    	p=ftell(file);
    	printf("aktuelle-Point-Position_1:%d\n",p);
    
        if(file==NULL)                   
        { 
            printf("Datei kann nicht geoeffnet werden!!\n"); 
            return 1; 
        } 
    
        if(fread(&bitmapFileheader,sizeof(BITMAPFILEHEADER),1,file)!=1)               
        { 
                printf("FileHeader kann nicht gelesen werden!!\n"); 
                fclose(file); 
                return 1; 
       } 
    
    	p=ftell(file);
    	printf("aktuelle-Point-Position_2:%d\n",p);
    
    	printf("bitmapFileheader.bfType : %d\n",bitmapFileheader.bfType);
    
    	printf("bitmapFileheader.bfOffBits : %d\n",bitmapFileheader.bfOffBits);
    
    					//printf("%d\n", sizeof( unsigned short int ) );
    					//printf("%d\n", sizeof( unsigned  int ) );
    
    // Achtung! Hier überschreibst du den Inhalt von bitmapFileheader ! 
    //  printf("Rueckgabenwert von 'fread' ist : %d\n",fread(&bitmapFileheader,sizeof(BITMAPFILEHEADER),1,file)); 
    
       if( bitmapFileheader.bfType != 0x4D42 )               
        { 
             printf("keine BMP Datei!!\n"); 
             fclose(file); 
            return 1; 
       } 
        if ( fclose(file) ) 
        { 
            perror(fname); 
            return 1; 
        } 
    
    	printf("Adress von bitmapFileheader : %p\n", &bitmapFileheader ); 
    
    	fread(&bitmapInfoheader,sizeof(BITMAPINFOHEADER),1,file);
    
             //p=ftell(file);
    	//printf("aktuelle-Point-Position_3:%d\n",p);
    	// wenn ich die beide obere Zeilen einfügen würde, bekomme ich hier eine Fehlmeldung!
    
    	printf("Adress von bitmapInfoheader : %p\n", &bitmapInfoheader ); 
    
    	printf("Größe von bitmapInfoheader: %d\n",sizeof(bitmapInfoheader));
    	printf("bitmapInfoheader.biWidth : %d\n",bitmapInfoheader.biWidth);
    	printf("bitmapInfoheader.biSizeImage %d\n",bitmapInfoheader.biSizeImage);
    
        return 0; 
    }
    


  • Nenee, die #pragma Anweisung muss schon sein.
    Wenn du die weglässt, werden 2 Byte zuviel eingelesen, der Dateizeiger zeigt dann 2 Byte zu weit.
    Die 2 Byte landen in den Füllbytes, an die kommst du nicht ran.
    Das sind die ersten 2 Byte von der nächsten Struktur, dem BITMAPINFOHEADER.
    Genau genommen, 2 Byte von DWORD biSize;



  • Jo!! Fehler habe ich gefunden!!
    ich habe die Code

    if ( fclose(file) ) 
        { 
            perror(fname); 
            return 1; 
        }
    

    einfach weggelassen!! dann funktioniert alles!
    durch

    fread(&bitmapInfoheader,sizeof(BITMAPINFOHEADER),1,file);	
    	p=ftell(file);
    	printf("aktuelle-Point-Position_3:%d\n",p);
    
    	printf("Adress von bitmapInfoheader : %p\n", &bitmapInfoheader ); 
    
    	printf("Größe von bitmapInfoheader: %d\n",sizeof(bitmapInfoheader));
    	printf("bitmapInfoheader.biWidth : %d\n",bitmapInfoheader.biWidth);
    	printf("bitmapInfoheader.biSizeImage %d\n",bitmapInfoheader.biSizeImage);
    	printf("bitmapInfoheader.biHeight : %d\n",bitmapInfoheader.biHeight);
    
        return 0;
    

    habe ich geprüft, dass alles im Ordnung sind!! 🙂 640*480 und usw.

    Oh man!! unglaublich, ich kann doch was!! 😃 das habe ich mich selbe nicht zugetraut! 😃
    aber zurück zu Fehler:

    if( bitmapFileheader.bfType != 0x4D42 )               
        { 
             printf("keine BMP Datei!!\n"); 
             fclose(file); 
            return 1; 
       } 
        /*if ( fclose(file) ) 
        { 
            perror(fname); 
            return 1; 
        } */
    

    warum hat es an diese Stelle mein File wieder zugemacht!! verstehe ich nicht!! 😕



  • ich glaube, ich weiß, woan es liegt:
    bei fclose(file), wenn es erfolgreich ausgeführt werden, ist das Rückgabewert:0 wenn nicht, dann EOF

    if ( fclose(file) ) 
        { 
            perror(fname); 
            return 1; 
        }
    

    diese Programm mache als Erst: fclose(file).d.h. mein Fil ist zuerst ZU!!!!
    deswegen habe ich die komische Wert von bitmapInfoheader.biheight, usw. bekommen. 😃



  • ja! vielleicht noch eine Frage? brauche ich an diese Stelle unbediente

    perror(fname); 
    									return 1;
    

    ???
    ich habe es umgestellt:

    if( bitmapFileheader.bfType != 0x4D42 )               
        { 
             printf("keine BMP Datei!!\n"); 
             fclose(file); 
    		 i=1;
            return 1; 
       } 
    	//printf("Rückgabewert von fclose(file)%d\n",fclose(file));
    	if ( i==1 ) 
    	{ 
    		perror(fname); 
    		return 1; 
    	}
    

    int i=0; habe ich ganz am Anfang definiert!



  • gy100002000 schrieb:

    ja! vielleicht noch eine Frage? brauche ich an diese Stelle unbediente

    perror(fname); 
    									return 1;
    

    ???
    ich habe es umgestellt:

    if( bitmapFileheader.bfType != 0x4D42 )               
        { 
             printf("keine BMP Datei!!\n"); 
             fclose(file); 
    		 i=1;
            return 1; 
       } 
    	//printf("Rückgabewert von fclose(file)%d\n",fclose(file));
    	if ( i==1 ) 
    	{ 
    		perror(fname); 
    		return 1; 
    	}
    

    int i=0; habe ich ganz am Anfang definiert!

    In C ist es üblich, das Funktionen im Fehlerfall eine 1 zurückgeben.
    Natürlich gibt es hier auch Ausnahmen.
    Der Rückgabewert 0 bedeutet of so viel wie 'kein Fehler'.
    Überleg dir mal, ob nach Abarbeitung von Zeile 6 die Zeile 9 ausgeführt werden kann.



  • Überleg dir mal, ob nach Abarbeitung von Zeile 6 die Zeile 9 ausgeführt werden kann.

    naja! eigentlich nicht! Weil nachdem

    return 1;
    

    wird das Programm schon gestoppt!

    if ( i==1 ) 
        { 
            perror(fname); 
            return 1; 
        }
    

    hat eigentlich kein Sinn! 😃

    ahja! was ich nicht verstehe ist, wofür ist

    perror(fname);
    

    brauchen wir das wirklich?



  • gy100002000 schrieb:

    ahja! was ich nicht verstehe ist, wofür ist

    perror(fname);
    

    Wofür das ist, kannst du leicht nachprüfen:

    FILE* fp;
    	char* file = "Bin ich eine Datei, oder ein Verzeichnis?";
    	fp = fopen( file, "r" );
    	if ( !fp )
    		perror(file);
    

    Es wird eine Meldung auf dem Fehler-Ausgabe-Kanal ( stderr ) ausgegeben.
    Kennst du die MSDN? Da kannst du über solche Funktionen genaueres erfahren.

    gy100002000 schrieb:

    brauchen wir das wirklich?

    Kommt drauf an. Prinzipiell sollte man alles auf Fehler prüfen, was möglich ist.
    Wenn dein Programm irgendwann mal sehr groß werden sollte, könntest du unter Umständen sehr lange mit der Fehlersuche beschäftigt sein. Wenn ein Fehler 'verschluckt' wird und dadurch möglicher weise eine zusätzliche Verkettung weiterer Fehler entsteht, die sich unter Umständen in einer ganz anderen Datei etliche Megabyte vom Entstehungsort entfernt bemerkbar macht.



  • alles klar! ich werde noch mal bei MSDN nachschauen. auf jeden Fall besten Dank! 🙂
    muss ich ehrlich zugeben, C ist nicht so einfach wie MATLAB ! 😃 aber langsam mach's auch spass!! 🙂


Anmelden zum Antworten