Bitmap erzeugen mit Pixelbreite nicht durch 4 teilbar



  • Hi, ich schreibe ein programm, welches eine bitmap-datei beliebiger pixel größe erstellt und einheitlich mit farbe füllt.
    Die Größe einer Zeile in Byte muss durch 4 teilbar sein oder?
    Wenn ich jetzt also 201Pixel breit haben möchte, dann wäre die jede Zeile
    201*3(24bit)=603Byte <--- nicht durch 4 teilbar
    Das heißt ich muss auf 612 Byte pro Zeile aufstocken oder?
    Das heißt ich muss pro Zeile 3 Pixel dranhängen?

    Ich hab ein 2d Array(bestehend aus eineer Struktur(Blau, Rot, Grün) in dem ich die Farben eintrage, welche werte bekommen die jeweils letzten 3 Pixel jeder Zeile, also was muss ich für die Farben eintragen?
    Ich habe gelesen "mit 0 auffüllen", daraqufhin habe ich in alle drei farben 0 eingetragen, aber dann bekomm ich ein ganz komisches bild.

    kann mir jemand helfen?



  • Häh. Bitte was? Wie erstellst du dein Bitmap? Was sind das für wage Annahmen die du triffst?



  • Ganz so vage sind die Annahmen eigentlich nicht.

    Ein Auffüllen auf eine durch 4 teilbare Anzahl an Bytes mit 0x00 ist korrekt...



  • #include <stdio.h>
    #include <stdlib.h>
    
    typedef struct {
    	#pragma pack(push, 2)
      unsigned short bfType; 
      unsigned int bfSize; 
      unsigned short bfReserved1; 
      unsigned short bfReserved2; 
      unsigned int bfOffBits;
      #pragma pack(pop)
    } BITMAPFILEHEADER;
    
    typedef struct {
    	#pragma pack(push, 2)
      unsigned int biSize; 
      long biWidth; 
      long biHeight; 
      unsigned short biPlanes; 
      unsigned short biBitCount;
      unsigned int biCompression; 
      unsigned int biSizeImage; 
      long biXPelsPerMeter; 
      long biYPelsPerMeter; 
      unsigned int biClrUsed; 
      unsigned int biClrImportant; 
      #pragma pack(pop)
    } BITMAPINFOHEADER;
    
    typedef struct{ 
    	#pragma pack(push, 2)
      unsigned char rgbtBlue; 
      unsigned char rgbtGreen; 
      unsigned char rgbtRed; 
      #pragma pack(pop)
    } RGBTRIPLE;
    
    void main(){
    
    	BITMAPFILEHEADER *fileheader;
    	BITMAPINFOHEADER *infoheader;
    	RGBTRIPLE *farben[204][150];
    
       long B=201, H=150;
       unsigned short farbtiefe = 24;
       int i,j,c,d;
       FILE *fin;
    
       c=B%4;
    
       fileheader=(BITMAPFILEHEADER*)malloc(sizeof(BITMAPFILEHEADER));
       fileheader->bfType=19778;
       fileheader->bfSize=sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + (B+4-c)*H*farbtiefe/8;
       fileheader->bfReserved1 = fileheader->bfReserved2 = 0;
       fileheader->bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
    
       infoheader=(BITMAPINFOHEADER*)malloc(sizeof(BITMAPINFOHEADER));
       infoheader->biSize   = sizeof(BITMAPINFOHEADER);
       infoheader->biWidth  = B;
       infoheader->biHeight = H;
       infoheader->biPlanes = 1;
       infoheader->biBitCount = farbtiefe;
       infoheader->biCompression=0;
       infoheader->biSizeImage=0;
       infoheader->biXPelsPerMeter=10000; 
       infoheader->biYPelsPerMeter=10000; 
       infoheader->biClrUsed=0; 
       infoheader->biClrImportant=0; 
    
    for(i=0;i<B;i++)
    {
    	for(j=0;j<H;j++){
    		farben[i][j]=(RGBTRIPLE *)malloc(sizeof(RGBTRIPLE));
    		farben[i][j]->rgbtBlue=255;
    		farben[i][j]->rgbtGreen=255;
    		farben[i][j]->rgbtRed=0;
    	}
    }
    d=B+4-c;
    for(B+1;B<(d);B++)
    {
    	for(j=0;j<H;j++)
    	{
    		farben[B][j]=(RGBTRIPLE *)malloc(sizeof(RGBTRIPLE));
    		farben[B][j]->rgbtBlue=0;
    		farben[B][j]->rgbtGreen=0;
    		farben[B][j]->rgbtRed=0;
    	}
    }
    
    fin = fopen("D:\unbenannt.bmp","w");
    
    fwrite(fileheader,sizeof(BITMAPFILEHEADER),1,fin);
    fwrite(infoheader,sizeof(BITMAPINFOHEADER),1,fin);
    
    for(j=0;j<H;j++)
    	{
    		for(i=0;i<B;i++){
    			fwrite(farben[i][j],sizeof(RGBTRIPLE),1,fin);
    		}
    	}
    
    free(fileheader);
    free(infoheader);
    
    fclose(fin);
    }
    

    Hier der Quellcode, das ist alles zur Probe, ich möchte erstmal ein Bild mit einer Pixelbreite die nicht durch 4 teilbar ist erzeugen, bevor ich zum mich daran mache die Benutzereingabe zu erstellen, daher der feste array und die feste Pixelbreite die nicht durch 4 teilbar ist.

    Ich denke es liegt an der art, wie ich die Pixeldaten in die datei schreibe. vllt gibts dort ein problem mit den for-Schleifen...
    In der datei muss ja die pixelfarbreihenfolge immer gleich sein, sprich: BlauGrünRotBlauGrünRot..etc, sobald ich die schleifen vertausche(innen-außen) dann ändert sich auch dsas bild, als wenn er die pixeldaten nicht korrekt in die datei schreibt.



  • schonma gedebuggt?



  • ja und laut dem schreibt er schon die daten korrekt in den array. ich weiß nur nicht wie sin in der datei ausgewertet werden.



  • Deine zweite for-Schleife sollte sich nur durch Start- und Endwert der Breite unterscheiden:

    d=B+4-c;
    for(i=B;B<(d);i++)
    {
        for(j=0;j<H;j++)
        {
            farben[i][j]=(RGBTRIPLE *)malloc(sizeof(RGBTRIPLE));
            farben[i][j]->rgbtBlue=0;
            farben[i][j]->rgbtGreen=0;
            farben[i][j]->rgbtRed=0;
        }
    }
    

    Was mir sonst noch aufgefallen ist:
    Du forderst für jedes Pixel Speicher via malloc an. 204x150 mal 3 Byte.
    Wäre es nicht sinnvoller EIN Speicherbereich für das Bild zu nehmen?
    Zudem gibst du diesen Speicher nicht frei.

    Für ein einfarbiges Bild reicht es aber auch ein Pixel 204x150 mal auszugeben.
    Die Extrapixel können dann auch die gleiche Farbe haben.



  • könntest du mir das mit dem speicher zeigen wie das geht? ich hab rum probiert, bin aber an dem 2d array irgendwie gescheitert.

    Wenn ich das so eingebe, stürzt es ab. bei B darf er ja denk ich auch nicht anfangen, weil das ja die letzte Pixelspalte ist, die noch die farbe haben sollte. also B+1 oder?

    Wie ist das? Ich habe ein 3x3 pixel bild, mit einer einheitlichen farbe:

    0xff 0xff 0xff 0x00
    0xff 0xff 0xff 0x00
    0xff 0xff 0xff 0x00

    wäre das so korrekt?



  • Deine zweite for-Schleife sollte sich nur durch Start- und Endwert der Breite unterscheiden:

    d=B+4-c;
    for(i=B;B<(d);i++)
    {
        for(j=0;j<H;j++)
        {
            farben[i][j]=(RGBTRIPLE *)malloc(sizeof(RGBTRIPLE));
            farben[i][j]->rgbtBlue=0;
            farben[i][j]->rgbtGreen=0;
            farben[i][j]->rgbtRed=0;
        }
    }
    

    Was mir sonst noch aufgefallen ist:
    Du forderst für jedes Pixel Speicher via malloc an. 204x150 mal 3 Byte.
    Wäre es nicht sinnvoller EIN Speicherbereich für das Bild zu nehmen?
    Zudem gibst du diesen Speicher nicht frei.

    Für ein einfarbiges Bild reicht es aber auch ein Pixel 204x150 mal auszugeben.
    Die Extrapixel können dann auch die gleiche Farbe haben.



  • Rückgabewerte von Funktionen, die durchaus schief gehen können, sollten tunlichst überprüft werden.
    Wenn du das gemacht hättest, hättest du folgenden Fehler wahrscheinlich sofort als solchen erkannt:

    fin = fopen("D:\unbenannt.bmp","w");
    //-> Escape-Sequenz beachten
    fin = fopen("D:\\unbenannt.bmp","w");
    


  • Vicious Falcon schrieb:

    Rückgabewerte von Funktionen, die durchaus schief gehen können, sollten tunlichst überprüft werden.
    Wenn du das gemacht hättest, hättest du folgenden Fehler wahrscheinlich sofort als solchen erkannt:

    fin = fopen("D:\unbenannt.bmp","w");
    //-> Escape-Sequenz beachten
    fin = fopen("D:\\unbenannt.bmp","w");
    

    Danke für den Tipp, leider ändert das an der funktion des programms nichts.



  • Sorry für den Doppelpost (Empfangsprobleme 😞 )

    Zu B: Deine erste Schleife geht von 0 bis < B, B wird also nicht erreicht. (von 0 bis 200 sind 201 Punkte)

    RGBTRIPLE farben[150][204];
    
    farben[h][b].rgbtBlue = 32;
    

    Evtl. musst du dieses Array auch mit packed kennzeichnen oder 32-bit Farbtiefe nehmen.



  • zu B: hast recht 🙂

    alles klar ich probier ein wenig rum. danke erstmal



  • Ich gebe dir einmal ein kleines, hoffentlich funktionierendes Beispiel

    int WriteBmp(const char* pFilename, unsigned int w, unsigned int h, unsigned int bc, char* pbits, int len)
    {
    	FILE *fin;
    	BITMAPFILEHEADER bfh;
    	BITMAPINFOHEADER bih;
    	fin = fopen(pFilename,"w");
    	if(!fin)
    		return 0;
    	memset(&bfh, 0, sizeof(BITMAPFILEHEADER));
    	memset(&bih, 0, sizeof(BITMAPINFOHEADER));
    	bfh.bfType = 19778;
    	bih.biSize		= sizeof(BITMAPINFOHEADER);
    	bih.biPlanes = 1;
    	bih.biSizeImage	= (h)*((w*(bc / 8) + 3) & ~3);
    	bih.biWidth= w;
    	bih.biHeight= h;
    	bfh.bfSize = sizeof(bfh);
    	bfh.bfSize+= h*4*((w*bc+31)/32);
    	bfh.bfSize+= sizeof(BITMAPINFOHEADER);
    	bfh.bfOffBits = sizeof(BITMAPINFOHEADER) + sizeof(BITMAPFILEHEADER);
    	bih.biBitCount= bc;
    	fwrite(&bfh,sizeof(BITMAPFILEHEADER),1,fin);
    	fwrite(&bih,sizeof(BITMAPINFOHEADER),1,fin);
    	fwrite(pbits,len,1,fin);
    	fclose(fin);
    	return 1;
    }
    
    int main()
    {
    	RGBTRIPLE *farben;
    	long B=201, H=150;
    	unsigned short farbtiefe = 24;
    	int sizeImg;
    
    	sizeImg = (H)*((B*(farbtiefe / 8) + 3) & ~3);
    	farben = malloc(sizeof(RGBTRIPLE)*sizeImg);
    	if(!farben)
    		return 0;
    	memset(farben,0xFF,sizeof(RGBTRIPLE)*sizeImg);
    
    	WriteBmp("d:\\unb.bmp",B,H,24,(char*)farben,sizeImg);
        free(farben);
        return 0;
    }
    

    Die ein oder andere Klammer ist überflüssig. Der Speicher wird nur einmal angefordert und jedes Byte auf 0xFF gesetzt. Das Resultat ist daher ein komplett weißes Bitmap.
    Die Größe des Speichers wird der Einfachheit halber mit übergeben.

    Edit: Nicht benötigte Variablen entfernt (Copy & Pasteproblem)
    Man, da waren ja noch mehr 🙄



  • Super danke, das geht auf jeden fall, vielen dank.



  • Zu den Füllbytes die benötigt werden, um auf eine durch vier teilbare Breite zu kommen, möchte ich anmerken, dass es egal ist welchen Wert sie haben. Du kannst da auch deine geheimen Botschaften drin verstecken. Sie werden einfach nur nicht angezeigt. Interessant könnte es nur werden, wenn du mit Filtern, die die Umgebungspixel auswerten, arbeitest. Die dürfen aber auch bei schwarzen Pixel nicht den Rand mit einbeziehen.


Anmelden zum Antworten