Bitmap erzeugen mit Pixelbreite nicht durch 4 teilbar



  • 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