[Hilfestellung]Erstellen eines BMP-Files (richtiger Header) aus unsigned char.



  • Ja, dies ist die "Color table" (siehe entsprechenden Eintrag in der Wiki) und diese sind als semi-optional eingestuft (d.h. es ist besser sie hinzuzufügen als wegzulassen), aber bei BPP <= 8 zwingend erforderlich!
    Aber je nach Bitmap-Header Version können vorher auch noch "channel bitmasks" und "color space types" kommen (s. Diagramm " The structure of the bitmap image file" in der Wiki).



  • Verwende besser ein Array ausreichender Größe, befülle es entsprechend und benutze genau 1x fwrite. Ist dann auch einfacher im Debugger nachzuverfolgen.



  • Hallo nochmal,

    habe mich nach ein paar Wochen seit dem letzten Post wirklich ran gemacht und eine Funktion mit einem Array und einer fwrite-Anweisung nutzt und möchte gern mal eure Manöverkritik dazu hören.

    void BMP_WriteBitmap(unsigned char* PictureBuffer, char* FileName)
    {	
    	FILE* fBmpFile = fopen(FileName, "wb");
    
    	if (fBmpFile == NULL)
    	{
    		printf("Error:\tUnable to save file %s.bmp.\n", FileName);
    		exit(0);
    	}
    	else
    	{
    		unsigned int bitmapCompleteSize = WIDTH * HEIGHT + 1078;
    		unsigned char uc_BitmapFile[bitmapCompleteSize];
    		unsigned int bCsLo = bitmapCompleteSize % 65536;
    		unsigned int bCsHi = bitmapCompleteSize / 65536;
    		unsigned int bitmapDataSize = WIDTH * HEIGHT;
    /**************************************************************************/
    /*	BMP-Header	*/
    		uc_BitmapFile[0] = '\x42';
    		uc_BitmapFile[1] = '\x4D';
    		uc_BitmapFile[2] = bCsLo % 256;
    		uc_BitmapFile[3] = bCsLo / 256;
    		uc_BitmapFile[4] = bCsHi % 256;
    		uc_BitmapFile[5] = bCsHi / 256;
    		uc_BitmapFile[6] = '\x00';
    		uc_BitmapFile[7] = '\x00';
    		uc_BitmapFile[8] = '\x00';
    		uc_BitmapFile[9] = '\x00';
    		uc_BitmapFile[10] = '\x36';
    		uc_BitmapFile[11] = '\x04';
    		uc_BitmapFile[12] = '\x00';
    		uc_BitmapFile[13] = '\x00';
    /**************************************************************************/
    /*	BMP-Information	*/
    		uc_BitmapFile[14] = '\x28';
    		uc_BitmapFile[15] = '\x00';
    		uc_BitmapFile[16] = '\x00';
    		uc_BitmapFile[17] = '\x00';
    		uc_BitmapFile[18] = WIDTH % 256;
    		uc_BitmapFile[19] = WIDTH / 256;
    		uc_BitmapFile[20] = '\x00';
    		uc_BitmapFile[21] = '\x00';
    		uc_BitmapFile[22] = HEIGHT % 256;
    		uc_BitmapFile[23] = HEIGHT / 256;
    		uc_BitmapFile[24] = '\x00';
    		uc_BitmapFile[25] = '\x00';
    		uc_BitmapFile[26] = '\x01';
    		uc_BitmapFile[27] = '\x00';
    		uc_BitmapFile[28] = '\x08';
    		uc_BitmapFile[29] = '\x00';
    		uc_BitmapFile[30] = '\x00';
    		uc_BitmapFile[31] = '\x00';
    		uc_BitmapFile[32] = '\x00';
    		uc_BitmapFile[33] = '\x00';
    		uc_BitmapFile[34] = '\x00';
    		uc_BitmapFile[35] = '\x00';
    		uc_BitmapFile[36] = '\x00';
    		uc_BitmapFile[37] = '\x00';
    		uc_BitmapFile[38] = '\x00';
    		uc_BitmapFile[39] = '\x00';
    		uc_BitmapFile[40] = '\x00';
    		uc_BitmapFile[41] = '\x00';
    		uc_BitmapFile[42] = '\x00';
    		uc_BitmapFile[43] = '\x00';
    		uc_BitmapFile[44] = '\x00';
    		uc_BitmapFile[45] = '\x00';
    		uc_BitmapFile[46] = '\x00';
    		uc_BitmapFile[47] = '\x00';
    		uc_BitmapFile[48] = '\x00';
    		uc_BitmapFile[49] = '\x00';
    		uc_BitmapFile[50] = '\x00';
    		uc_BitmapFile[51] = '\x00';
    		uc_BitmapFile[52] = '\x00';
    		uc_BitmapFile[53] = '\x00';
    /**************************************************************************/
    /*	colormap	*/
    		int i;
    		for (i = 0; i <= 255; i++)
    		{
    			uc_BitmapFile[54 + 4 * i] = (char)i;
    			uc_BitmapFile[55 + 4 * i] = (char)i;
    			uc_BitmapFile[56 + 4 * i] = (char)i;
    			uc_BitmapFile[57 + 4 * i] = '\x00';
    		}
    /**************************************************************************/
    /*	Data	*/
    		memcpy(&uc_BitmapFile[1078], PictureBuffer, bitmapDataSize);
    		fwrite(uc_BitmapFile, sizeof(unsigned char), bitmapCompleteSize, fBmpFile);
    		fclose(fBmpFile);
    	}
    }
    


  • 1. BITTE schau dir endlich structs in c an.
    dateistructukturen und dateiformate legt man immer in structs an.
    man kann es zwar theoretisch so machen wie du, aber das ist unübersichtllich und außerdem schlechter stil (also nichts gegen dich - als anfänger kann man das nicht wissen).

    2. du solltest di rückgabewerte von fread überprüfen. nur so kannst du festestellen, ob daten korrekt in die datei geschrieben wurden.
    möglicherweise liegt hier ein solcher fall vor.

    3. warum wird bei dir die weite (width) und die höhe (height) des bildes als array gespeichert?

    4. eine bmp-datei enthält nicht nur einen header, sondern auch eine info-struktur. du hast hier alles auf 0 gesetzt. leider kann man anhand des arraynamen (z.b. "uc_BitmapFile[39]") nicht erkennen, welches element einer bmp-datei du gerade in die datei schreibst.

    5. generell: array nur dann nutzen, wenn es sinn macht (z.b. bei die pixeldaten kann man als array speichern), sonst bitte die dateitypen in c benutzen.



  • Hmm warum beklagst du dich wegen dem einen Array? Wenn aufmerksam meinen letzten und den Beitrag davor gelesen hättest, dann wüsstest du, dass dieser mich quasi direkt aufgevordert hat NUR EIN Array und EIN Write zu nutzen. Da dies einer der wenigen Beiträge zu meiner Frage war, bin ich diesem nachgegangen. Wenn du einen besseren Tip hast, bin ich dir dafür dankbar. Was für Infos du meinst, kann ich mir vorstellen, habe mir ja das entsprechende Wiki angesehen und anschließend ein in OpenCV gespeichertes Bild genommen und danach dieses char-Array entwickelt. Warum ich z.B. Weite und Höhe in der Art speichere wird auch aus den Wikis/ einem Beispielbild klar. Ein Struct hilft mir ebenfalls nicht weiter, weil ich am Ende diesen String genau so in eine Datei schreiben muss (es funktioniert ja auch)! Das Struct bläht meinen Code nur aus und hat keinen weiteren Nutzen. (Du darfst mich natürlich gern korrigieren)



  • Statt

    uc_BitmapFile[0] = '\x42';
            uc_BitmapFile[1] = '\x42';
            uc_BitmapFile[2] = '\x42';
            uc_BitmapFile[3] = bCsLo / 256;
            uc_BitmapFile[4] = bCsHi % 256;
            uc_BitmapFile[5] = bCsHi / 256;
            uc_BitmapFile[6] = '\x00';
            uc_BitmapFile[7] = '\x00';
            uc_BitmapFile[8] = '\x00';
            uc_BitmapFile[9] = '\x00';
            uc_BitmapFile[10] = '\x36';
            uc_BitmapFile[11] = '\x04';
            uc_BitmapFile[12] = '\x00';
            uc_BitmapFile[13] = '\x00';
    

    schreibt man üblicherweise bei der Initialisierung lieber

    char uc[14]={0x42,0x42,0x42,bCsLo/256,bCsHi%256,bCsHi/256,0x00,
                 0x00,0x00,0x00,     0x36,     0x04,     0x00,0x00
                };
    

    Das ist kürzer und übersichtlicher, oder manchmal auch ohne endende 0, also

    char uc[14]={0x42,0x42,0x42,bCsLo/256,bCsHi%256,bCsHi/256,0x00,
                 0x00,0x00,0x00,     0x36,     0x04
                };
    

    Die Dimension sollte man (außer evtl. bei Stringliteralinitialisierungen) immer mit angeben, manche Compiler warnen, wenn man sich mal verzählt, also

    int i[4]={0,1,3,4,5};
    

    wäre so ein Kandidat, der Compiler kann besser zählen als man selbst und vor allen Dingen, ein Compiler verrechnet sich nicht.

    Zum anderen Thema Array oder struct kann ich nur sagen: in diesem Fall bieten sich Array und struct an (wegen der Übersichtlichkeit), bei struct sollte man aber auf das Bytepadding achten, viele Compiler bieten aber hier was an.
    Also fachlich separate Werte gehören in jeweils ein eigenes Array und dann jeweils als struct-Element definieren, also in etwa

    typedef struct {
    char marker[2];
    char header[10];
    char data[500];
    } Bitmap;
    
    Bitmap bitmap={{0,1},{1,1,2,2},{99,88,77,...}};
    ...
    fwrite/fread(&bitmap,sizeof bitmap,1,fileptr);
    


  • mirrowwinger schrieb:

    Hmm warum beklagst du dich wegen dem einen Array? Wenn aufmerksam meinen letzten und den Beitrag davor gelesen hättest, dann wüsstest du, dass dieser mich quasi direkt aufgevordert hat NUR EIN Array und EIN Write zu nutzen. Da dies einer der wenigen Beiträge zu meiner Frage war, bin ich diesem nachgegangen. Wenn du einen besseren Tip hast, bin ich dir dafür dankbar. Was für Infos du meinst, kann ich mir vorstellen, habe mir ja das entsprechende Wiki angesehen und anschließend ein in OpenCV gespeichertes Bild genommen und danach dieses char-Array entwickelt. Warum ich z.B. Weite und Höhe in der Art speichere wird auch aus den Wikis/ einem Beispielbild klar. Ein Struct hilft mir ebenfalls nicht weiter, weil ich am Ende diesen String genau so in eine Datei schreiben muss (es funktioniert ja auch)! Das Struct bläht meinen Code nur aus und hat keinen weiteren Nutzen. (Du darfst mich natürlich gern korrigieren)

    keine ahnung, wer dir diesen müll empfiehlt.

    so macht man das normalerweise:

    typedef struct {
         short magic_number;
         unsigned int filesize;
         unsigned int reserved;
         unsigned int offset;
    } BMP_HEADER;
    

    mit der info-strutkur machst du das genauso.

    alles andere ist totaler schwachsinn.

    Wutz, was soll den das? kein mensch macht das mit einem array. ich sehe da auch überhauptkeinen vorteil.

    mach es einfach als struct, das du befüllst und dann in die datei schreibst.



  • Du hast keine Ahnung.



  • Wutz schrieb:

    Du hast keine Ahnung.

    doch.

    selbst die leute von linux-kernel machen es so, wenn sie ein neues dateisystem implementieren.
    keine ahnung, wo du das mit dem array aufgeschnappt hast! ich hab das noch nie gesehen!

    alle machen es so! und wenn du mir nicht glaubst, dann schau dir mal den quellcode von irgendwelche libs an!

    und nein, du wirst keine arrays für sowas finden.

    wahrscheinlich kommst du jetzt wieder mit der üblichen "little-endian/big-endian" sachen angeschissen.

    dazu noch ein wort: wer wirklich plattformunabhängig programmieren will, für den ist c eindeutig die falsche sprache. wer sowas machen will, braucht java, vielleicht auch python.

    außerdem kann ich das so entscheiden:

    #ifdef _BIG_ENDIAN_
    #define BMP_MAGIC 0x424D
    #endif
    
    #ifdef _LITTLE_ENDIAN_
    #define BMP_MAGIC 0x4D42
    #endif
    

    so what?

    ich finde, dass ist schon eine sehr linke tour, einem anfänger, der es nicht besser weiß, so einen müll einzureden.

    so wie du das am anfang hattest, was das im grude schon ok. du solltest bloß alle variablen in structs zusammenfassen.



  • mirrowwinger hast du jetzt verstanden, was zu tun ist?


Anmelden zum Antworten