bmp Datei einlesen und wieder ausgeben



  • Ich habe eine .bmp Datei eingelesen und diese in einem Struct abgelegt nun will ich das ganze wieder zurückschreiben - aber die zurückgeschriebene Datei entsprichte nicht der eingelesenen - es treten immer mal wieder ein Paar Fehler auf. Ich hab die Vermutung, dass das am fehlende CR oder LF liegt, aber wenn ich mir die Datein im Hex anschaue, scheints daran leider nicht zu liegen...

    int GenerateTempBild(struct Bild bild) {
       FILE *fp;
       FILE *ziel;
       int c = 0;
       int counter = 0;
    
       //header einlesen
       char * fhdata = new char [14];
       memset(fhdata, 0, 14);
       memcpy(fhdata,bild.header.headerdata,15);
    
       //infodateneinlesen
       char * fhinfo= new char [40];
       memset(fhinfo, 0, 40);
       memcpy(fhinfo,bild.info.infodata,41);
    
       //datei erzeugen
       ziel=fopen("c:\\temp0001.bmp","w");
    
          if(ziel==NULL)  {
             printf("Konnte Zieldatei nicht erzeugen! \n");
             return EXIT_FAILURE;
          }
          else {
             /* Wir kopieren zeichenweise von quelle nach ziel. */
             //putc(int,ziel);
    		  for(int i =0;i<14;i++)
    		  {
    		  c = (char)(fhdata[i]);
    		  if (c< 0){
    			c = 256 + c;
    		  }
    		  int temp =  putc(c,ziel);
    		  if (temp == -1)
    		  {
    			  printf ("Fehler");
    		  }
    		  }
    		  for(int i =0;i<40;i++)
    		  {
    		  c = (char)(fhinfo[i]);
    		  if (c< 0)
    		  {
    			c = 256 + c;
    		  }
    		  int temp = putc(c,ziel);
    		  if (temp == -1)
    		  {
    			  printf ("Fehler");
    		  }
    		  }
    		  for (int zeile = 0; zeile < bild.daten.hoehe; zeile ++)
    		  {		
    
    				  //c = (char)('\n'); //Zeilenumbruch
    
    				  //int temp = putc(c,ziel);
    				  //c = (char)('\r'); //Zeilenumbruch
    				  //temp = putc(c,ziel);
    				  //temp = 0;
    	          for (int spalte = 0; spalte < bild.daten.breite; spalte ++)
    			  {
    
    			for (int i = 0;i<3;i++){
    
    			c = (char) bild.daten.farbwerte[zeile][spalte][i];
    				  if (c< 0)
    						{
    							c = 256 + c;
    						}	
    					  int temp = putc(c,ziel);
    					  if (temp == -1)
    					  {
    						  printf ("Fehler");
    					  }
    				  }
    			 }
    			}
    	  }
       fclose(ziel);
       return EXIT_SUCCESS;
    }
    

    Ich hoffe ihr könnt damit was anfangen... Finde beim Einlesen den Fehler leider nicht 😞 Daher denke ich es muss irgendwo hier liegen.



  • Einen Teil des Fehlers habe ich nun genauer identifziert - in meiner "neuen" Datei steht immer CRLF für ein Dateiende - in meiner Originaldatei dagegen nur LF - villeicht kann mir da einer helfen...



  • versuch's mal so:

    ziel=fopen("c:\\temp0001.bmp","wb");
    

    😃
    EDIT: Huch, jetzt hab' ich selbst das "b" für Binary vergessen. 😞
    EDIT2: Ich hoffe, du öffnest die Datei auch mit "rb" als Attribut. 😉



  • Danke erstmal - das hatte ich sowas von übersehen 😞 Die Fehler mit dem LF sind nu weg - immerhin was 🙂

    Leider habe ich immer noch diskrepanzen in der Datei, die ich erzeuge zum original - es fehlt immer mal so ein Zeichen - leider immer ein anderes und an für mich ersichtlich keiner konstanten Stelle 😞 Und immer ein Zeichen - echt komisch...

    Meine Einlesefunktion setz ich euch auch nochmal rein:

    Bild GenerateImageData(const char * puffer, long count)  
    {
        //komplette Bilddaten erzeugen
    
        //Fileheader
        Fileheader fh;
        char * fhdata = new char [15];
        memset(fhdata, 0, 15);
    
        memcpy(fhdata, puffer, 14);
    
        //strncpy(fhdata, puffer, 14);
        fh.headerdata = fhdata;
    
        //Bitmapinfo
        BitmapInfo bi;
        //puffer = puffer + 14;
    
        char * bidata = new char [41];
        memset(bidata, 0, 41);
    
        memcpy(bidata, &puffer[14], 40);
    
        //strncpy(bidata, &puffer[14], 40);
        bi.infodata = bidata;
    
        //Nutzdaten
        BildNutzdaten bn;
        //puffer = puffer + 40;
    
        int len = count - 14 - 40 + 1;
    
        char * bndata = new char [len];
        memset(bndata, 0, len);
    
        memcpy(bndata, &puffer[54], len - 1);
        //strcpy(bndata, &puffer[50]);
    
        bn.nutzdatendata = bndata;
    
        //die hoehe und breite schreiben
        bn.hoehe = GetHoehe(bidata);
        bn.breite = GetBreite(bidata);
    
        //eigentliche farbinfos aufbereiten
        BildNutzdaten bnd = GenerateNewBildNutzdaten(bn.hoehe, bn.breite);
    
        int i = 0;
        for (int zeile = 0; zeile < bn.hoehe; zeile ++)
        {
            for (int spalte = 0; spalte < bn.breite; spalte ++)
            {
                long red = (bndata[i]) & 0x000000ff;
                bnd.farbwerte[zeile][spalte][0] = red;
                i ++;
    
                long green = (bndata[i]) & 0x000000ff;
                bnd.farbwerte[zeile][spalte][1] = green;
                i ++;
    
                long blue = (bndata[i]) & 0x000000ff;
                bnd.farbwerte[zeile][spalte][2] = blue;
                i ++;
    
                /*
                bnd.farbwerte[zeile][spalte][0] = (int)(&bndata);
                bndata ++;
                bnd.farbwerte[zeile][spalte][1] = (int)(&bndata);
                bndata ++;
                bnd.farbwerte[zeile][spalte][2] = (int)(&bndata);
                bndata ++;
                */
    
            }
    
            i ++;
        }
    
        bn.farbwerte = bnd.farbwerte;
    
        //Bild mit allen Daten erzeugen
        Bild bild;
        bild.header = fh;
        bild.info = bi;
        bild.daten = bn;
    
        return bild;
    }
    


  • Damit ihr aus wisst, wie mein puffer zustande kommt...

    char * Laden (const char* pfad, long* count)
    {
    
    	FILE* fp;			//fp FilePointer (Dateizeiger)
    	fp = fopen (pfad, "rb");
    	if (fp == NULL)
    	{
    		//Fehler
    	}
    	else 
    	{
    		system("cls");
    		printf ("Datei konnte erfolgreich geladen werden:)!\n");
    
    		fseek(fp, 0, SEEK_END);			//Dateipointer an das Ende der Datei stellen
    		long lSize = ftell(fp);			//Anzahl der Zeichen ermitteln (indem die aktuelle Position ermittelt wird
    		rewind(fp);						//Dateipointer an den Anfang der Datei stellen
    
    		char* buffer = new char [lSize + 1];	//Puffer für den Dateiinhalt
    		memset(buffer, 0, sizeof(char) * (lSize + 1));			//Puffer leeren
    
    		long result = fread(buffer, 1 , sizeof(char) * lSize, fp);	//Dateiinhalt in den Puffer schreiben
    
    		if (buffer[0] == 'B' && buffer[1] == 'M')	//Test auf Bitmap
    		{
    
    		}
    
    		fclose(fp);
    
    		*count = lSize;
            return buffer;		//Puffer als Rückgabewert zurückgeben
    	}
    
        *count = 0;
        return NULL;
    }
    


  • Öööhmm,

    kann das sein, daß Du teilweise auf C++ Pfaden wandelst?

    Inwiefern kommen unsystematische Fehler - bei unterschiedlichen Durchläufen oder unterschiedlichen Dateien/Zeichen 😕

    Ein wenig mehr helfen mußt Du uns schon ...



  • nutze die macht dude



  • Ja das Projekt war mal aus C++ und soll auf C runterkonvertiert worden sein - hoffe aber nicht, dass die Fehler dadurch auftreten. Hab es testweise mit den selben Ergebnis nochmal im C++ laufen lassen.

    Es fehlen vollkommen unterschiedliche Zeichen und auch immer an verschiedenen Stellen so z.B. in den Zeilen (aufeinanderfolgende Fehler):

    561
    692
    830
    968
    1106

    Ansonsten treten die Fehler bei jedem Durchlauf an den Selben stellen auf. Mal fehlt ein h, mal ein f, mal eine 5...



  • Hallo,
    ich habe mir deinen Code nicht so genau angesehen,
    aber üblicherweise liest man den Fileheader und eventuell noch den Infoheader ein und anhand dieser Informationen die Pixeldaten. Du haust den ganzen Salat zusammen in einen Puffer, das ist nicht so schön, aber naja...

    Hast du den Fileheader auf 2 Byte Grenzen ausgerichtet (z.B. mit #pragma pack(2) unter Windows)? Wenn nicht, könnte das der Fehler sein.



  • Das stimmt - erstmal haue ich alles in einen Puffer und lese den Puffer dann einzeln aus - das ist richtig... Und sicher auch unsauber - aber das einzige, was mir eingefallen war und was erstmal so funktionierte...

    Den Header begrenze ich nicht, der Befehl ist mir auch nicht geläufig... Ich werd mal googlen - ein Beispiel wäre aber schön.

    Ich verstehe jedoch nicht, wie mir das begrenzen des Headers helfen soll, wenn doch meine Nutzdaten fehlerhaft sind. Den Header lese ich korrekt aus und schreibe ich auch korrekt wieder zurück...

    Gruß



  • Michmo schrieb:

    //header einlesen 
       char * fhdata = new char [14]; 
       memset(fhdata, 0, 14); 
       memcpy(fhdata,bild.header.headerdata,15); 
        
       //infodateneinlesen 
       char * fhinfo= new char [40]; 
       memset(fhinfo, 0, 40); 
       memcpy(fhinfo,bild.info.infodata,41);
    

    Warum schreibst du hier immer ein Byte mehr?

    Michmo schrieb:

    int len = count - 14 - 40 + 1;
    char* buffer = new char [lSize + 1];    //Puffer für den Dateiinhalt
    

    Ist das +1 nötig? Die Farbwerte sind keine nullterminierte Zeichenketten.

    Michmo schrieb:

    Ich verstehe jedoch nicht, wie mir das begrenzen des Headers helfen soll, wenn doch meine Nutzdaten fehlerhaft sind. Den Header lese ich korrekt aus und schreibe ich auch korrekt wieder zurück

    Wenn du die Bilder mit nem Editor oder sowas betrachten willst, müssen ein paar Dinge berücksichtigt werden, wie z.B. das Alignment des Fileheaders, Teilbarkeit der Zeilenbreite durch vier, Anzahl der Ebenen mindestens 1, usw.

    Mal sehen, vielleicht komme ich morgen dazu, mir deinen Code genauer anzugucken.



  • Michmo schrieb:

    Den Header begrenze ich nicht, der Befehl ist mir auch nicht geläufig... Ich werd mal googlen - ein Beispiel wäre aber schön.

    Das ist ne compilerabhängige Anweisung, bei mir heißt sie #pragma pack.
    Hier mal ein Auszug aus meiner kleinen Bitmap-Bibliothek:

    #pragma pack(2) // Alignment auf 2 setzen 
    // 14 Byte 
    struct bmp_header
    {
    	// Bildtyp, muss "BM" sein. "BM" steht für wohl für Bitmap oder sowas, 
    		//	entspricht der Zahl 19778.
    	unsigned short int type;
    	// Grösse der Bilddatei insgesamt, in Byte.
    	// ( Grösse dieser Struktur, plus Grösse der BMP_Info-Strutur, 
    	//	eventuell plus Farbtabelle, plus Bilddaten. )
    	unsigned long      size;		
    	unsigned short int reserved1; // Reserviert :D
    	unsigned short int reserved2; // Dito.
    	// Zeiger auf den Beginn der Pixeldaten, relativ zum Dateianfang.
    	unsigned long	   offset; 
    };
    
    #pragma pack() // default Alignment
    

Anmelden zum Antworten