erstellen eines BMP



  • Zur Not könntest du das auch ohne eine Zusatzbibliothek (quasi von Hand) erledigen - File öffnen, Bitmap-Header schreiben, (eventuell Farbtabelle schreiben), Daten schreiben, File schließen.

    (wie der Bitmap-Header aufgebaut ist, mußt du am besten mal Google oder die MSDN fragen)



  • jasper



  • Dieser Thread wurde von Moderator/in HumeSikkins aus dem Forum C++ in das Forum Rund um die Programmierung verschoben.

    Im Zweifelsfall bitte auch folgende Hinweise beachten:
    C/C++ Forum :: FAQ - Sonstiges :: Wohin mit meiner Frage?

    Dieses Posting wurde automatisch erzeugt.



  • ohne ZUSATZUBIBO wäre wirklich schön. ich habe mir auch schon einige seiten angeschaut, wie so ein BMP aufgebaut ist. nun würde ich aber gerne mal ein beispiel sehen, um selber so ein file zu schreiben.
    kann man eine BMP file irgendwie im editor öffnen, um zu sehen, wie soetwas aussehen muss?

    DANKE.
    STICK.



  • BMPs von Hand zu erstellen ist eigentlich recht einfach, wenn man sich auf 24Bit Formate beschränkt, denn das ist ungepackt und man spart sich die Huddelei, eine Farbtabelle berechnen zu müssen.

    Sie dir mal diese Seite an:
    http://www.fortunecity.com/skyscraper/windows/364/bmpffrmt.html

    Besonders einfach ist es, wenn du die WinAPI nutzen kannst, denn dort sind diese Strukturen schon definiert, so dass du sie nur füllen brauchst und dann in der richtigen Reihenfolge in eine Datei schreiben musst.

    Ein Stolperstein wäre noch, dass du dran denken musst, dass du pro Pixel immer 4 Bytes speicherst, die Reihenfolge bgra ist, und dass Zeilen immer auf Vielfache von 4 aufgerundet abgespeichert werden müssen.



  • hi. die seite habe ich auch gerade geöffnet. trotzdem danke.
    STICK.



  • hallo.
    mit hilfe dieser seite habe ich jetzt folgenden code zusammengestellt. leider kann ich mir die erstellte datei nicht anschauen, ist also noch irgendetwas falsch.
    kann vielleicht jemand einen fehler sehen?

    bmfh.bOffBits musste ich aus dem programm herausnehmen, weil der debugger sagt, dass die kein element von BITMAPFILEHEADER ist, warum auch immer.

    DANKE!
    STICK_THAI.

    #include <iostream.h>
    #include <fstream.h>
    #include <windows.h>
    
    int ***BILD;
    
    int main ()
    {
    	BITMAP		bmp;
    	ofstream	myfile;
    	int		i,j,k;
    
    	BILD = new int **[3];
    	for (k=0;k<3;k++)
    		BILD[k] = new int *[16];
    	for (k=0;k<3;k++)
    	{
    		for (i=0;i<16;i++)
    			BILD[k][i] = new int [16];
    	}
    
    	for (k=0;k<3;k++)
    	{
    		for (i=0;i<16;i++)
    		{
    			for (j=0;j<16;j++)
    				BILD[k][i][j] = j;
    		}
    	}
    
    	BITMAPFILEHEADER    bmfh;
    	BITMAPINFOHEADER    bmih;
    
    	bmfh.bfType      = 0x4D42;  // ist das okay so?
    	bmfh.bfSize	 = 808; // = 16*16*(24/8) + 40 (für header) = 768 + 40
    	bmfh.bfReserved1 = 0;
    	bmfh.bfReserved2 = 0;
    //	bmfh.bOffBits	 = 0;
    
    	bmih.biSize	    = 40; // hier bin ich mir auch nicht so sicher.
    	bmih.biWidth	    = 16;
    	bmih.biHeight	    = -16;
    	bmih.biPlanes	    = 1;
    	bmih.biBitCount	    = 24;
    	bmih.biCompression  = 0;
    	bmih.biSizeImage    = 0;
    	bmih.biXPelsPerMeter= 0;
    	bmih.biYPelsPerMeter= 0;
    	bmih.biClrUsed	    = 0;
    	bmih.biClrImportant = 0;
    
    	myfile.open("test.bmp");
    	myfile<<bmfh.bfType<<" "<<(BYTE)bmfh.bfSize<<" "
                  <<(BYTE)bmfh.bfReserved1<<" "
                  <<(BYTE)bmfh.bfReserved2<</*" "
                  <<(BYTE)bmfh.bOffBits<<*/"\n";
    	myfile<<(BYTE)bmih.biSize<<" "<<(BYTE)bmih.biWidth<<" "
                  <<(BYTE)bmih.biHeight<<" "<<(BYTE)bmih.biPlanes<<" "
                  <<(BYTE)bmih.biBitCount<<" "<<(BYTE)bmih.biCompression<<" "
    	      <<(BYTE)bmih.biSizeImage<<" "<<(BYTE)bmih.biXPelsPerMeter<<" "
                  <<(BYTE)bmih.biYPelsPerMeter<<" "<<(BYTE)bmih.biClrUsed<<" "
                  <<(BYTE)bmih.biYPelsPerMeter<<"\n";
    
    	for (i=0;i<16;i++)
    	{
    		for (j=0;j<16;j++)
    		{
    			for (k=0;k<3;k++)
                            {
    			   myfile << (BYTE) BILD[k][i][j] << " ";
                               myfile << "00 ";
                            }
    		}
    		myfile << "\n";
    	}
    
    	myfile.close();
    
    	return 0;
    }
    


  • Also zuerst einmal ist da die Frage, ob die Datei mit dem Modus binär geöffnet wird.
    Ich würde es auch nicht Elementweise mit << schreiben, sondern
    a) Mir einen entsprechend großen Speicherbereich erstellen.
    b) In diesem Speicher dann das Bitmap komplett mit Header erstellen.
    (dazu muss man aber fit sein in Sachen Pointer)
    c) alles in einem Rutsch schreiben mit write.

    So kannst du vor dem Speichern im Debugger schön den Speicher betrachten und hast so die Gewissheit, dass es dann auch so in die Datei geschrieben wird.



  • Deine Speicherreservierung für die Pixel ist auch nicht so schön und schreit förmlich nach Speicherlecks.
    Zumal dir die WinAPI ja schon die passende struct liefert.
    Du musst nicht Zeilenweise reservieren, sondern kannst auch alles auf einmal bestellen.

    RGBQUAD *pPixels = new RGBQUAD(Höhe*Breite);
    ...
    delete[] pPixels;
    

    Das schöne ist, dass hierbei gleich gewährleistet ist, dass an 4 Byte ausgerichtet wird, da ja die struct eben so groß ist.



  • okay. ich bearbeite mal deine vorschläge. wenn's immer noch nicht klappt, melde ich mich noch einmal.

    an sich ist es doch aber nicht falsch, wenn ich

    myfile << IRGENDWAS;
    

    verwende, richtig?
    DANKE.



  • Wenn für IRGENDWAS der ofstream<< Operator richtig überladen ist, ist alles in Ordnung.
    Außerdem musst man hier halt immer aufpassen, dass man die richtige Reihenfolge einhält.
    Und sowas wie du da gemacht hast, einfach mal was auskommentieren, geht da natürlich schon mal gar nicht.

    Weißt du, es gibt einfach Fälle, da ist es besser Daten hintereinander zu schreiben wie am Fließband. Z.B. wenn man das Alphabet ausgeben möchte. Dann nimmt man die stream << Dinger und schickt in einer Schleife alle Buchstaben raus.

    Und es gibt Fälle, da will man seine Daten im Speicher erst aufbereiten, wie halt du mit den Pixeln und dem Header.
    Und dann schreibt man alles als größen Block in einem Stück.



  • also,

    ich habe den code jetzt deinen vorschlägen angepasst (abgesehen von dem "entsprechend großen Speicherbereich" ), aber leider hauts noch nicht hin. könnte das an "bmfh.bOffBits" liegen? warum gibts damit probleme?

    welchen typ sollte der grosse speicherbereich haben? ist es BYTE?

    DANKE.
    STICK.



  • Poste mal deinen überarbeiten Code.



  • hier kommt er schon.

    #include <iostream.h>
    #include <fstream.h>
    #include <windows.h>
    
    int main ()
    {
    	ofstream		myfile;
    	BITMAPFILEHEADER	bmfh;
    	BITMAPINFOHEADER    bmih;
    	int			i,j;
    	RGBQUAD			*pPixels = new RGBQUAD [8*8];
    
    	for (i=0;i<64;i++)
    	{
    		pPixels[i].rgbBlue = (BYTE)i;
    		pPixels[i].rgbGreen= (BYTE)i;
    		pPixels[i].rgbRed  = (BYTE)i;
    		pPixels[i].rgbReserved=(BYTE)0;
    	}
    
    	bmfh.bfType		= 0x4D42;
    	bmfh.bfSize		= 296; // = 8*8*(4) + 40 (für header) >> ist es 8*8*3 oder 8*8*4 ???
    	bmfh.bfReserved1	= 0;
    	bmfh.bfReserved2	= 0;
    //	bmfh.bOffBits		= 0;
    
    	bmih.biSize		= 40;
    	bmih.biWidth		= 16;
    	bmih.biHeight		= -16;
    	bmih.biPlanes		= 1;
    	bmih.biBitCount		= 24;
    	bmih.biCompression	= 0;
    	bmih.biSizeImage	= 0;
    	bmih.biXPelsPerMeter= 0;
    	bmih.biYPelsPerMeter= 0;
    	bmih.biClrUsed		= 0;
    	bmih.biClrImportant	= 0;
    
    	myfile.open("test.bmp",ios::out);
    	myfile<<bmfh.bfType<<" "<<(BYTE)bmfh.bfSize<<" "<<(BYTE)bmfh.bfReserved1<<" "
    		  <<(BYTE)bmfh.bfReserved2<</*" "<<(BYTE)bmfh.bOffBits<<*/"\n";
    	myfile<<(BYTE)bmih.biSize<<" "<<(BYTE)bmih.biWidth<<" "<<(BYTE)bmih.biHeight<<" "
    		  <<(BYTE)bmih.biPlanes<<" "<<(BYTE)bmih.biBitCount<<" "<<(BYTE)bmih.biCompression<<" "
    		  <<(BYTE)bmih.biSizeImage<<" "<<(BYTE)bmih.biXPelsPerMeter<<" "<<(BYTE)bmih.biYPelsPerMeter<<" "
    		  <<(BYTE)bmih.biClrUsed<<" "<<(BYTE)bmih.biYPelsPerMeter<<"\n";
    
    	j=0;
    	for (i=0;i<64;i++)
    	{
    		if (j==8)
    		{
    			myfile << pPixels[i].rgbBlue << " " << pPixels[i].rgbGreen    << " " 
    				   << pPixels[i].rgbRed  << " " << pPixels[i].rgbReserved << "\n";
    			j=0;		
    		}
    
    		else
    		{
    			myfile << pPixels[i].rgbBlue << " " << pPixels[i].rgbGreen    << " " 
    				   << pPixels[i].rgbRed  << " " << pPixels[i].rgbReserved;
    			j++;
    		}
    	}
    
    	delete[] pPixels;
    	myfile.close();
    
    	return 0;
    }
    


  • Die Sache mit dem Pixelarray sieht schon mal gut aus,
    aber kannst du mir mal verraten, was die Sache mit dem Newline soll?
    Was hat ein Newline in einer Binärdatei zu suchen?

    Du hast doch mit pPixels schon ein schönes Array, das kannst du doch nun bequem schreiben mit write.
    Was soll die Verrenkung mit der Schleife.



  • Und die Sache mit dem bmfh.bOffBits ist dazu da, dass angegeben wird, wo die Pixeldaten in der Datei anfangen.

    Nehmen wir mal an, der Header sei 100 Bytes groß, dann beginnen die Pixeldaten an Position 100.

    EDIT: Für bfSize nimmst du den Speicherverbrauch von einem Pixel, der beträgt 4 Byte.



  • - die verrenkung mit der schleife habe ich, damit ich die einzelnen pixelelemente, die sich in dem array pPixels befinden, ansprechen kann, aber vielleicht sollte ich mir mal die funktion WRITE anschauen.
    - wenn ich keine newline habe, woher weiss ein program wie PHOTOSHOP dann, wann eine neue zeile im bild kommt?
    - was "bmfh.bOffBits" bedeutet, ist mir bereits klar. aber warum sagt mein programm andauernd, dass es kein element von BITMAPFILEHEADER ist?



  • Vermutlich weil es bfOffBits heißt und nicht bOffBits.

    Photoshop weiß es deshalb, weil es weiß, dass das Bild 8 Pixel breit ist, weil
    in biWidth (hoffentlich) der richtige Wert steht.



  • nochmal kurz. wir bekomme ich die grösse meine pPixels arrays heraus? das brauche ich ja für die WRITE funktion.

    so klappts jedenfalls nicht:

    myfile.write(pPixels,64);
    


  • Du kannst schon die Größe mit 64 Angeben.
    Aber der erste Parameter muss nach const char* gecastet werden, weil
    write das 1. Argument so erwartet.

    myfile.write((const char*) pPixels, 64);


Anmelden zum Antworten