.bmp Paletten/Pixelindex



  • Hi,
    ich bin dabei ein Programm mit C99/Netbeans zu schreiben, dass eine bmp-Datei öffnen, auswerten, verändern und später in anderem, unkomprimiertem Format abspeichern soll (ohne Verwendung von Windows-Funktionen).
    Ich hab also eine unkomprimierte bmp-Datei in byteweise in ein char-array geladen, eine Struktur entsprechend der Dateiheader, Palette und Pixeldaten erstellt und einem Pointer vom Typ dieser Struktur die Adresse des Arrays zugewiesen. Das Auslesen der Header klappt. Ebenso kann ich mir die blau-grün-rot Werte der Palettenfelder ausgeben lassen. Nun wollte ich ein weiteres Array für alle Pixel erstellen, dass in jedem Feld ein Objekt der Struktur mit den drei Farb-Wert-Chars enthält. Dann bin ich in einer Schleife jeden Pixel durchgegangen, hab den Farbcode für die Palette genommen und in der Palette eben an dem Index (Pixelfarbcode) die Farben blau,grün,rot in mein neues Array gepackt.
    Das Problem ist, dass die Indexe die in jedem Pixel gespeichert sind überhaupt nicht zu der Palette passen.

    Ich hab mir mal beides ausgeben lassen (also Palette mit 256 blau-grün-rot-Farbwertpaaren und den Inhalt der Pixel) und während in der Palette alles bei 0 anfängt und dann ca. bis in den nachfolgenden 100 Feldern die Farben gespeichert hat, hab ich in den Pixeln ganz komische Werte wie -71 und -41.
    Testweise bin ich die Pixel mal durchgelaufen und hab immer wenn zB. -41 drin stand eine andere Zahl reingeschrieben und das in der Datei gespeichert. Das hatte völlig korrekt zur Folge, dass eine Farbe auf dem Bild konsequent durch eine andere ausgetauscht wurde. Daraus schließe ich, dass diese ganzen minus-Werte in den Pixeln doch korrekte Indizes darstellen müssen.

    Wieso passen die in den Pixeln enthaltenen Indizes nicht zum Palettenarray?
    In den Pixeln steht bei mir -71,-41,30 und das Palettenarray hat Inhalte nur von Index 0 bis Index 100.
    Fangen die bei der Palette mit dem Indexieren etwa hinten an?



  • Hast du mal die RGB-Werte der Pixel rausgesucht und mit den Paletteneinträgen verglichen



  • Hast du mal versucht das Array als unsigned char zu deklarieren.



  • Dieser Thread wurde von Moderator/in rüdiger aus dem Forum C (C89 und C99) 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.



  • Ein kleiner Fehler meinerseits: in den Pixeln stehen natürlich nur negative Zahlen, wenn man sie als vorzeichenbehaftet betrachtet (was das printf("%d gemacht hat, da meine Struktur die Werte in einem char-array speichert. Habs in unsigned geändert und jetzt werden sie als 215 und andere 200er-Werte angezeigt). Eigentlich müsste das doch passen. Hier mal mit ein paar Codeteilen:

    struct tagRGBQUAD {//Palette
          unsigned char    rgbBlue;
          unsigned char    rgbGreen;
          unsigned char    rgbRed;
          unsigned char    rgbReserved;
        }__attribute__ ((packed)) Palette[256];
    

    das ist die Struktur, deren Pointer auf mein Gesamtarray nach dem Head zeigt.
    Das heißt ich hab 256 mal diese aufeinanderfolgenden Chars. Diese Aufteilung und der Zugriff funktioniert auch. Also wenn ich mir alle 256 Farbsets ausgeben lasse, kriege ich da wirklich die Farben, die im Bild vorkommen.

    Die 24bit-BMP hat in für jeden Pixel dann statt einem einfachen unsigned char drei chars für jede Farben. Um das zu überführen versuche ich also die alten Pixelwerte als Index für das Palettenarray zu verwenden und die Farbwerte der Palette an den jeweiligen Stellen in ein neues Array vom Typ der Struktur:

    typedef struct tagRGBTRIPLE {//Für die Farbdaten in jedem Pixel (24bit)
      unsigned char rgbtBlue;
      unsigned char rgbtGreen;
      unsigned char rgbtRed;
    } RGBTRIPLE;
    

    zu kopieren.

    Hier mal alle singnifikanten Auszüge:

    typedef struct BeideHeader{
        struct tagBITMAPFILEHEADER {
           WORD  bfType;
           DWORD bfSize;
           WORD  bfReserved1;
           WORD  bfReserved2;
           DWORD bfOffBits;
        }__attribute__ ((packed)) BITMAPFILEHEADER;
        struct tagBITMAPINFOHEADER{
          DWORD  biSize;
          LONG   biWidth;
          LONG   biHeight;
          WORD   biPlanes;
          WORD   biBitCount;
          DWORD  biCompression;
          DWORD  biSizeImage;
          LONG   biXPelsPerMeter;
          LONG   biYPelsPerMeter;
          DWORD  biClrUsed;
          DWORD  biClrImportant;
        }__attribute__ ((packed)) BITMAPINFOHEADER;
        struct tagRGBQUAD {//Palette
          unsigned char    rgbBlue;
          unsigned char    rgbGreen;
          unsigned char    rgbRed;
          unsigned char    rgbReserved;
        }__attribute__ ((packed)) Palette[256];
        struct pixeldaten{
           unsigned char pixelcode;
        }__attribute__ ((packed)) Pixel[];
    
    }__attribute__ ((packed)) Header;
    
    typedef struct tagRGBTRIPLE {//Für die Farbdaten in jedem Pixel (24bit)
      unsigned char rgbtBlue;
      unsigned char rgbtGreen;
      unsigned char rgbtRed;
    } RGBTRIPLE;
    
    int main()
    {
       FILE *quelle,*kopie,*bild4;
       char puffer[8];
       char name[20];
    
       printf("Welche Datei wollen Sie zum Lesen öffnen: ");
       //scanf("%s",name);
       if((quelle=fopen("C:/MinGW/bild3.bmp","rb")) == NULL)
          {
             fprintf(stderr,"Kann %s nicht oeffnen\n",name);
             exit (0);
          }
        if((bild4=fopen("C:/MinGW/bild4.bmp","wb")) == NULL)
          {
             fprintf(stderr,"Kann %s nicht oeffnen\n",name);
             exit (0);
          }
       if((kopie=fopen("C:/MinGW/kopie2.txt","w")) == NULL)
          { 
             fprintf(stderr,"Kann kopie nicht oeffnen\n");
             exit (0);
          }
    fseek(quelle, 0, SEEK_END); // seek to end of file Dateigröße rausfinden
    long size = ftell(quelle); // get current file pointer
    fseek(quelle, 0, SEEK_SET); // seek back to beginning of file
    cout<<"\nDateiGroeße ist: "<<size<<"\n";
    
       unsigned char a[size]; int i=0;char b[size];
       while(i<size)
       { //b[i]=fgetc(bild4);
           a[i++]=fgetc(quelle);
           //cout<<a[i-1]<<" ";
    
       }Header *header1=(Header*)a;cout<<" bilder in array geladen ";
       Header *header2=(Header*)b;
       fclose(quelle);
    
       //Palettenfarbcodes durch konkrete Farbnummer ersetzten und in pixela speichern
       RGBTRIPLE pixela[640*480];
       i=0;
       while(i<640*480){
           pixela[i].rgbtBlue=header1->Palette[header1->Pixel[i].pixelcode].rgbBlue;
           pixela[i].rgbtGreen=header1->Palette[header1->Pixel[i].pixelcode].rgbGreen;
           pixela[i].rgbtRed=header1->Palette[header1->Pixel[i].pixelcode].rgbRed;
           cout<<" "<<pixela[i].rgbtBlue<<pixela[i].rgbtGreen<<pixela[i].rgbtRed<<" ";
           cout<<endl;
    


  • Ein 16- oder 24-Bit-Bitmap hat meistens überhaupt keine Farbpalette, die du verwenden kannst, da stehen die Farbwerte direkt in den Pixeln. Ansonsten mußt du deinen Header auswerten, um zu sehen, ob und wieviele Einträge die Farbpalette hat (Felder biBitCount und biClrUsed).



  • Problem gelöst.
    Ich glaube es hat schon länger funktioniert und ich habs nur nicht bemerkt, weil ich die Aufgabe mit cout gemacht hab und wenn man damit ein char ausgibt hat man eben ein Zeichen, dass vielleicht nicht angezeigt werden kann, weswegen man dann denkt da ist nichts. Wenn ichs mit printf("%d ausgeb gehts.

    Also in Count und Used steht wieviele der Farben konkret benutzt werden, und soweit ich gelesen hab, ist die Palette sonst immer 256byte lang.
    Und nur die 8bit.bmp hat überhaupt eine Palette, die 24bit.bmp nicht.
    Was ich versucht hab war ja einfach eine Konvertierung per Hand sozusagen zu machen. Also 8bit->24bit. Dazu muss man den DateiHeader verändern und sagen dass der Offset, zum Anfang der Pixel nur noch 54 sein soll (weil 1024byte der Palette wegfallen) und dass es eine bitcount=24 (24bit/pixel datei ist).
    Dann eben ein neues Array erstellen, wo man in jedes Feld statt dem Palettenindex der 8bit.bmp die entsprechende Farbe aus der Palette reinsteckt.
    Das Array zusammen mit dem Header in einer neuen Datei speichern und fertig.

    Falls jemand an ähnlichem Problem scheitern sollte hier mal das ganze Programm (enthält noch Kommentare und einige überflüssige Sachen für später, läuft aber)

    /* 
     * File:   main.cpp
     * Author: X
     *
     * Created on 8. April 2011, 23:41
     */
    
    #include <iostream>
    #include <stdio.h>
    #include <stdlib.h>
    #define ZEILENLAENGE 8
    using namespace std;
    
    //Größen: Beide Header: 54byte
    //8bit.bmp: Header: 54byte, Palette: 256 * 4 byte, Pixel: 640*480 byte
    //24bit.bmp: Header: 54byte, Palette: 0 byte, Pixel: 640*480*3 byte
    typedef char                CHAR;
    typedef short               SHORT;
    typedef long                LONG;
    typedef unsigned long       DWORD;
    typedef int                 BOOL;
    typedef unsigned char       BYTE;
    typedef unsigned short      WORD;
    typedef struct BeideHeader{
        struct tagBITMAPFILEHEADER {
           WORD  bfType;//immer 19778
           DWORD bfSize;//je nachdem siehe oben
           WORD  bfReserved1;//0
           WORD  bfReserved2;//0
           DWORD bfOffBits;//8bit.bmp: 1078 (256*4+54), 24bit: 54
        }__attribute__ ((packed)) BITMAPFILEHEADER;
        struct tagBITMAPINFOHEADER{
          DWORD  biSize;//40
          LONG   biWidth;//640
          LONG   biHeight;//480
          WORD   biPlanes;//1
          WORD   biBitCount;//8 (für 256 farben)
          DWORD  biCompression;//0 (unkompromiert)
          DWORD  biSizeImage;//PixelArrayGröße: 640*480 byte, bzw. 640*480*3
          LONG   biXPelsPerMeter;//23622
          LONG   biYPelsPerMeter;//23622
          DWORD  biClrUsed;//0 bedeutet dass alle farben
          DWORD  biClrImportant;//0 der palette gebraucht werden
        }__attribute__ ((packed)) BITMAPINFOHEADER;
    
      union ChooseFormat{
            struct Achtbit{
                struct tagRGBQUAD {//Palette
                  unsigned char    rgbBlue;
                  unsigned char    rgbGreen;
                  unsigned char    rgbRed;
                  unsigned char    rgbReserved;
                }__attribute__ ((packed)) Palette[256];
                struct pixeldaten{
                   unsigned char pixelcode;
                }__attribute__ ((packed)) Pixel[];
            }achtbit;
            struct Vierzbit{
                struct pixeldaten{
                   unsigned char pixelcode;
                }__attribute__ ((packed)) Pixel[];
            }vierzbit;
        }chooseformat;
    
    }__attribute__ ((packed)) Header;
     /*   struct tagRGBQUAD {//Palette
            unsigned char    rgbBlue;
            unsigned char    rgbGreen;
            unsigned char    rgbRed;
            unsigned char    rgbReserved;
        }__attribute__ ((packed)) Palette[256];
        struct pixeldaten{
            unsigned char pixelcode;
        }__attribute__ ((packed)) Pixel[];
    }__attribute__ ((packed)) Header;*/
    
    typedef struct tagRGBTRIPLE {//Für die Farbdaten in jedem Pixel (24bit)
      unsigned char rgbtBlue;
      unsigned char rgbtGreen;
      unsigned char rgbtRed;
    } RGBTRIPLE;
    
    int main()
    {
       FILE *quelle,*kopie,*bild4;
       char puffer[8];
       char name[20];
    
       printf("Welche Datei wollen Sie zum Lesen öffnen: ");
    
       if((quelle=fopen("C:/MinGW/bild3.bmp","rb")) == NULL)
          {
             fprintf(stderr,"Kann %s nicht oeffnen\n",name);
             exit (0);
          }
        if((bild4=fopen("C:/MinGW/bild4.bmp","wb")) == NULL)
          {
             fprintf(stderr,"Kann %s nicht oeffnen\n",name);
             exit (0);
          }
       if((kopie=fopen("C:/MinGW/kopie2.txt","w")) == NULL)
          { 
             fprintf(stderr,"Kann kopie nicht oeffnen\n");
             exit (0);
          }
    fseek(quelle, 0, SEEK_END); // seek to end of file Dateigröße rausfinden
    long size = ftell(quelle); // get current file pointer
    fseek(quelle, 0, SEEK_SET); // seek back to beginning of file
    cout<<"\nDateiGroeße ist: "<<size<<"\n";
    
       unsigned char a[640*480*3+54]; int i=0;//unsigned char a[size]; int i=0;char b[size];
       while(i<size)
       { //b[i]=fgetc(bild4);
           a[i++]=fgetc(quelle);
           //cout<<a[i-1]<<" ";
    
       }Header *header1=(Header*)a;cout<<" bilder in array geladen ";
       //Header *header2=(Header*)b;
       fclose(quelle);
    
       //Palettenfarbcodes durch konkrete Farbnummer ersetzten und in pixela speichern
       RGBTRIPLE pixela[640*480];
       i=0;
       while(i<640*480){//die farben hinter dem index in jedem pixel ins array pixela
           pixela[i].rgbtBlue=header1->chooseformat.achtbit.Palette[header1->chooseformat.achtbit.Pixel[i].pixelcode].rgbBlue;//pixela[i].rgbtBlue=header1->Palette[header1->Pixel[i].pixelcode].rgbBlue;
           pixela[i].rgbtGreen=header1->chooseformat.achtbit.Palette[header1->chooseformat.achtbit.Pixel[i].pixelcode].rgbGreen;
           pixela[i].rgbtRed=header1->chooseformat.achtbit.Palette[header1->chooseformat.achtbit.Pixel[i].pixelcode].rgbRed;
           //printf(" %d%d%d ",pixela[i].rgbtBlue,pixela[i].rgbtGreen,pixela[i].rgbtRed);
    
           i++;
       }
       //danach diese pixelfarbwerte aus pixela ins haupt-dateiarray kopieren.
       //und zwar ab da wo die palette anfängt. die und die pixel werden überwschrieben.
       i=54;int j=0;
       while(j<640*480){
           a[i]=pixela[j].rgbtBlue;
           a[i+1]=pixela[j].rgbtGreen;
           a[i+2]=pixela[j].rgbtRed;
           i+=3;j++;
       }
    
       //unsigned char pixelb[640*480*3]=pixela;
       cout<<"\nPixel in 24bit\n";
    //Manipulation des 8bit-Dateiheaders zum 24bit-Header
    //Bildgröße
       header1->BITMAPFILEHEADER.bfSize=54+640*480*3;
       header1->BITMAPFILEHEADER.bfOffBits=54;
       header1->BITMAPINFOHEADER.biSizeImage=640*480*3;
       header1->BITMAPINFOHEADER.biBitCount=24;
       //header1->chooseformat.achtbit.Pixel=&a[54];
    fwrite(a,1,sizeof(a),bild4);
    
       /* umranden
       //header2->Pixel[320*440].pixelcode=header1->Pixel[320*440].pixelcode;
       i=0; int grunfeldsize=0,rotfeldsize=0;
       while(i<640*480){
           //-41(weiß)  -56(hellgrün)  -76(dunkelgrün) 30(rot) -46(gelb) 
           //printf(" %d ",header1->Pixel[i].pixelcode);
    
           //if(header1->Pixel[i].pixelcode==-43){header1->Pixel[i].pixelcode=30;}
           if(header1->Pixel[i].pixelcode==-76){//wenn der pixel dunkelgrün ist
               grunfeldsize++; //feldgröße hochzählen
               if( //wenn der links daneben weder grün noch rot ist ->randpixel also färben
                ((header1->Pixel[i-1].pixelcode!=-76) && (header1->Pixel[i-1].pixelcode!=30) )
               ||((header1->Pixel[i+1].pixelcode!=-76) && (header1->Pixel[i+1].pixelcode!=30) )//oder der rechts daneben
               ||((header1->Pixel[i-640].pixelcode!=-76) && (header1->Pixel[i-640].pixelcode!=30) )//oder der dadrüber
               ||((header1->Pixel[i+640].pixelcode!=-76) && (header1->Pixel[i+640].pixelcode!=30) )//oder der dadrunter
                       )//dann ist der aktuelle ein randpixel->umfärben
                   header1->Pixel[i].pixelcode=30;
           }
           else if(header1->Pixel[i].pixelcode==30)rotfeldsize++;
           i++;
       } 
    cout<<" px ubertragen ";fwrite(a,1,sizeof(a),bild4);
    cout<<"\n feldsizes: grun:"<<grunfeldsize<<" rot:"<<rotfeldsize<<"\n\n";
    umranden ende*/
    
       //i=0;
       //while(i<size){
       //    fputc(a[i],bild4);i++;cout<<".";
       //}fclose(bild4);cout<<" bild gespeichert ";
    /*
       //Pixel in 2D-Array
       char reihen[header1->BITMAPINFOHEADER.biHeight]
       [header1->BITMAPINFOHEADER.biWidth];
       int j=0,k=0;cout<<"\nj<"<<header1->BITMAPINFOHEADER.biHeight<<" k<"<<header1->BITMAPINFOHEADER.biWidth<<"\n";
       for(j;j<header1->BITMAPINFOHEADER.biHeight;j++){k=0;//cin>>i;
           for(k;k<header1->BITMAPINFOHEADER.biWidth;k++){
               reihen[j][k]=header1->Pixel[j*k].pixelcode;
               //cout<<" "<<reihen[j][k];
           }//cout<<"\n";fputs(reihen[j],kopie);
       }
    */
    
    //BITMAPFILEHEADER *header1=(BITMAPFILEHEADER*)quelle;
       //Header *header1=(Header*)quelle;
    
    //fputs(header1->bfType,stdout);
    cout<<"\n"<<"bfTyp ";
    cout<<header1->BITMAPFILEHEADER.bfType
            <<"\n";
    cout<<"bfSize ";
    cout<<header1->BITMAPFILEHEADER.bfSize
            <<"\n";
    cout<<"bfReserved1 ";
    cout<<header1->BITMAPFILEHEADER.bfReserved1
            <<"\n";
    cout<<"bfReserved2 ";
    cout<<header1->BITMAPFILEHEADER.bfReserved2
            <<"\n";
    cout<<"bfOffbits ";
    cout<<header1->BITMAPFILEHEADER.bfOffBits
            <<"\n\n";
    
    cout<<"biSize ";
    cout<<header1->BITMAPINFOHEADER.biSize
            <<"\n";
    cout<<"biWidth ";
    cout<<header1->BITMAPINFOHEADER.biWidth
            <<"\n";
    cout<<"biHeight ";
    cout<<header1->BITMAPINFOHEADER.biHeight
            <<"\n";
    cout<<"biPlanes ";
    cout<<header1->BITMAPINFOHEADER.biPlanes
            <<"\n";
    cout<<"biBitCount ";
    cout<<header1->BITMAPINFOHEADER.biBitCount
            <<"\n";
    cout<<"biCompression ";
    cout<<header1->BITMAPINFOHEADER.biCompression
            <<"\n";
    cout<<"biSizeImage ";
    cout<<header1->BITMAPINFOHEADER.biSizeImage
            <<"\n";
    cout<<"biXPelsPerMeter ";
    cout<<header1->BITMAPINFOHEADER.biXPelsPerMeter
            <<"\n";
    cout<<"biYPelsPerMeter ";
    cout<<header1->BITMAPINFOHEADER.biYPelsPerMeter
            <<"\n";
    cout<<"biClrUsed ";
    cout<<header1->BITMAPINFOHEADER.biClrUsed
            <<"\n";
    cout<<"biClrImportant ";
    cout<<header1->BITMAPINFOHEADER.biClrImportant
            <<"\n";
    
                                /*
    cout<<"Palette"<<endl;
    i=0;
    while(i<256){
        cout<<i<<" B: "<<header1->Palette[i].rgbBlue
                <<" G: "<<header1->Palette[i].rgbGreen<<" R: "
                <<header1->Palette[i].rgbRed<<" Res: "
                <<header1->Palette[i].rgbReserved<<endl;i++;
    }                           */
    /*
       while(fgets(puffer,ZEILENLAENGE,quelle))
       { fputs(puffer,stdout);
           fputs(puffer,kopie);
       }*/
       return 0;
    }
    


  • Ich habe es nicht getestet, aber läuft das mit Standardeinstellugen (bzgl. der Stackgröße) des Compilers?

    unsigned char a[640*480*3+54]; // knapp 0.9 MB
    ..
    RGBTRIPLE pixela[640*480]; // nochmal
    

    Solche Datenmengen sind eigentlich besser im Freispeicher aufgehoben.



  • Ich hätte die Header-Daten auch nicht in eine große Struktur gepackt (gerade die optional vorhandenen Anteile wie die Farbpalette). Außerdem solltest du sichergehen, daß das Bild-Format mit deinen Vorstellungen übereinstimmt.
    Und der Programmanfang sieht auch noch sehr provisorisch aus 😃



  • Ja ich hab einfach netbeans und mingw installiert und sonst nichts verändert.
    Wie macht man denn sowas in den Freispeicher (Ram?).
    Ich fands auch erst etwas beunruhigend soein riesiges Array zu erstellen, aber es muss wohl sein.
    Also wenn man das gesamte Array auf mehrere kleinere Strukturen verteilen wollte würde man das mit KleineStruktur* x= &a[anfangDesTeilbereichs] machen oder?
    Ich dachte mir nur, dass der Head sowieso bei allen .bmp gleich aussieht, nur der Bereich danach eben nicht. Und wenn das nicht so ist, muss man zum Zuordnen der Teilstrukturen doch erstmal wissen wie der aufgebaut ist und woher sollte man das wissen? Und würde das dann überhaupt noch mit dem attribut-packed hinhauen; ich könnte mir vorstellen dass der dieses lückenlose Lesen dann nur bis zu den struct-Grenzen macht.

    Was ich noch gar nicht verstehe ist, dass diese Aufgabe irgentwie mit malloc() gelöst werden soll. Die ist zwar noch nicht fertig (es kommt noch das lesen von komprimierten .bmp und das Erkennen und Umranden von einfarbigen Rechtecken), aber bis jetzt weiß man doch immer wie groß alles ist und muss kein dynamisch verändertes Array haben...

    Inzwischen hab ich ein bisschen aufgeräumt und die Bildgröße variabel gemacht:

    #include <iostream>
    #include <stdio.h>
    #include <stdlib.h>
    #define ZEILENLAENGE 8
    using namespace std;
    
    //Größen: Beide Header: 54byte
    //8bit.bmp: Header: 54byte, Palette: 256 * 4 byte, Pixel: 640*480 byte
    //24bit.bmp: Header: 54byte, Palette: 0 byte, Pixel: 640*480*3 byte
    typedef char                CHAR;
    typedef short               SHORT;
    typedef long                LONG;
    typedef unsigned long       DWORD;
    typedef int                 BOOL;
    typedef unsigned char       BYTE;
    typedef unsigned short      WORD;
    typedef struct BeideHeader{
        struct tagBITMAPFILEHEADER {
           WORD  bfType;//immer 19778
           DWORD bfSize;//je nachdem siehe oben
           WORD  bfReserved1;//0
           WORD  bfReserved2;//0
           DWORD bfOffBits;//8bit.bmp: 1078 (256*4+54), 24bit: 54
        }__attribute__ ((packed)) BITMAPFILEHEADER;
        struct tagBITMAPINFOHEADER{
          DWORD  biSize;//40
          LONG   biWidth;//640
          LONG   biHeight;//480
          WORD   biPlanes;//1
          WORD   biBitCount;//8 (für 256 farben)
          DWORD  biCompression;//0 (unkompromiert)
          DWORD  biSizeImage;//PixelArrayGröße: 640*480 byte, bzw. 640*480*3
          LONG   biXPelsPerMeter;//23622
          LONG   biYPelsPerMeter;//23622
          DWORD  biClrUsed;//0 bedeutet dass alle farben
          DWORD  biClrImportant;//0 der palette gebraucht werden
        }__attribute__ ((packed)) BITMAPINFOHEADER;
    
      union ChooseFormat{
            struct Achtbit{
                struct tagRGBQUAD {//Palette
                  unsigned char    rgbBlue;
                  unsigned char    rgbGreen;
                  unsigned char    rgbRed;
                  unsigned char    rgbReserved;
                }__attribute__ ((packed)) Palette[256];
                struct pixeldaten{
                   unsigned char pixelcode;
                }__attribute__ ((packed)) Pixel[];
            }achtbit;
            struct Vierzbit{
                struct pixeldaten{
                   unsigned char pixelcode;
                }__attribute__ ((packed)) Pixel[];
            }vierzbit;
        }chooseformat;
    
    }__attribute__ ((packed)) Header;
     /*   struct tagRGBQUAD {//Palette
            unsigned char    rgbBlue;
            unsigned char    rgbGreen;
            unsigned char    rgbRed;
            unsigned char    rgbReserved;
        }__attribute__ ((packed)) Palette[256];
        struct pixeldaten{
            unsigned char pixelcode;
        }__attribute__ ((packed)) Pixel[];
    }__attribute__ ((packed)) Header;*/
    
    typedef struct tagRGBTRIPLE {//Für die Farbdaten in jedem Pixel (24bit)
      unsigned char rgbtBlue;
      unsigned char rgbtGreen;
      unsigned char rgbtRed;
    } RGBTRIPLE;
    
    int main()
    {
       FILE *quelle,*kopie,*bild4;
       char puffer[8];
       char name[20];int i=0;
    
        if((quelle=fopen("C:/MinGW/bild4.bmp","r+b")) == NULL)
          {
             fprintf(stderr,"Kann %s nicht oeffnen\n",name);
             exit (0);
          }
    
     //Es wird die Dateigröße ermittelt um das GesamtArray dimensionieren zu können
    fseek(quelle, 0, SEEK_END); //springe zum ende der datei
    long size = ftell(quelle); //merke die aktuelle cursorposition
    fseek(quelle, 0, SEEK_SET); //springe wieder zum anfang
    //size enthält die dateilänge cout<<"\nDateiGroeße ist: "<<size<<"\n";
    
    //Es wird die Bildgröße ausgelesen um das PixelArray dimensionieren zu können.
    unsigned char headtemp[54];//array nur für den head (54byte)
    while(i<54){//0-53 ist head
        headtemp[i++]=fgetc(quelle);//byteweise ins array
    }fseek(quelle, 0, SEEK_SET);//fget-cursor auf anfang
    Header *tmph=(Header*)headtemp;//arrayadresse in strukturpointer
    int height=tmph->BITMAPINFOHEADER.biHeight;//480 höhe in height speichern
    int width=tmph->BITMAPINFOHEADER.biWidth;//640 breite in weight speichern
    
    //array für die gesamte datei 54byte-head, 1024byte-palette, width*heightbyte-pixel
    //das array wird gleich so groß gewählt, um für die umgewandelte 24bit.bmp
    //groß genug zu sein. Also: 54byte-head, keine Palette aber width*heightbytes
    //für die pixel und das mal drei, für jede farbe ein byte
    unsigned char a[width*height*3+54];
       i=0;
       while(i<size)//die komplette datei
       {    a[i++]=fgetc(quelle);//charweise ins array
    
     }Header *header1=(Header*)a;//arrayadresse in strukturpointer
    
     //Palettenfarbcodes durch konkrete Farbnummer ersetzten und in pixela speichern
     RGBTRIPLE pixela[width*height];//Array vom typ eines 24bit.bmp-pixels
     //das heißt aus drei farben bestehend und von der größe der bildfläche
    
     i=0;
     //in diesem array für jeden pixel die drei farben speichern.
     while(i<width*height){
           pixela[i].rgbtBlue=header1->chooseformat.achtbit.Palette[header1->chooseformat.achtbit.Pixel[i].pixelcode].rgbBlue;
           pixela[i].rgbtGreen=header1->chooseformat.achtbit.Palette[header1->chooseformat.achtbit.Pixel[i].pixelcode].rgbGreen;
           pixela[i].rgbtRed=header1->chooseformat.achtbit.Palette[header1->chooseformat.achtbit.Pixel[i].pixelcode].rgbRed;
           //i ist der aktuelle bildpixel. aus dem pixelarray in der struktur weiß
           //man welcher farbwert an diese stelle gehört. diese zahl wird als index
           //für die palette benutzt. die palette enthält in einem array für jeden
           //farbwert eine struktur die alle drei farben beinhaltet. diese werden einzeln
           //in die struktur in pixela-array übertragen. man kann den arrayinhalt in
           //diesem fall nicht byteweise blind kopieren, da die strukturen des paletten
           //arrays noch ein weiteres, viertes byte enthalten, das nicht verwendet wird
           //und in dem fall in dem fall in die quere kommen würde.
           i++;
       }
    
       //danach diese farbwerte für jeden pixel aus pixela ins haupt-dateiarray a kopieren.
       //und zwar ab da wo die palette anfängt. die und die alten pixel werden überschrieben.
       i=54;int j=0;//es wird ins gesamtarray ab stelle 54 hineinkopiert, da hier der head zuende ist
       while(j<width*height){
           //es werden zwei indizes benötigt, da hier werte aus einem quasi 2d-array
           //(d.h. array das struktur enthält) in ein normales 1d-array kopiert werden
           //sollen. i zählt die felder im 1d-hauptarray 'a' hoch wohingegen j die 3er strukturen durchzählt.
           a[i]=pixela[j].rgbtBlue;
           a[i+1]=pixela[j].rgbtGreen;
           a[i+2]=pixela[j].rgbtRed;
           i+=3;
           j++;
       }//hiernach wurden also palette und pixelwerte komplett ersetzt, angepasst werden muss noch der head
    
        //Manipulation des 8bit-Dateiheaders zum 24bit-Header
    
        //Bildgröße: bildfläche * 3byte + 54byte für head
       header1->BITMAPFILEHEADER.bfSize=54+width*height*3;
    
       //OffsetBits: Abstand von Dateianfang bis Pixelanfang ==Headlänge->54byte
       header1->BITMAPFILEHEADER.bfOffBits=54;
    
       //neue bildgröße (nur für pixel): wie bildfläche nur ohne head
       header1->BITMAPINFOHEADER.biSizeImage=width*height*3;
    
       //Format: 3byte pro pixel(24bit), vorher warens 1byte(8bit)
       header1->BITMAPINFOHEADER.biBitCount=24;
    
    fwrite(a,1,sizeof(a),quelle);//komplettes array byteweise in datei schreiben
    fclose(quelle);//datei freigeben
    
       /* umranden
       //header2->Pixel[320*440].pixelcode=header1->Pixel[320*440].pixelcode;
       i=0; int grunfeldsize=0,rotfeldsize=0;
       while(i<640*480){
           //-41(weiß)  -56(hellgrün)  -76(dunkelgrün) 30(rot) -46(gelb) 
           //printf(" %d ",header1->Pixel[i].pixelcode);
    
           //if(header1->Pixel[i].pixelcode==-43){header1->Pixel[i].pixelcode=30;}
           if(header1->Pixel[i].pixelcode==-76){//wenn der pixel dunkelgrün ist
               grunfeldsize++; //feldgröße hochzählen
               if( //wenn der links daneben weder grün noch rot ist ->randpixel also färben
                ((header1->Pixel[i-1].pixelcode!=-76) && (header1->Pixel[i-1].pixelcode!=30) )
               ||((header1->Pixel[i+1].pixelcode!=-76) && (header1->Pixel[i+1].pixelcode!=30) )//oder der rechts daneben
               ||((header1->Pixel[i-640].pixelcode!=-76) && (header1->Pixel[i-640].pixelcode!=30) )//oder der dadrüber
               ||((header1->Pixel[i+640].pixelcode!=-76) && (header1->Pixel[i+640].pixelcode!=30) )//oder der dadrunter
                       )//dann ist der aktuelle ein randpixel->umfärben
                   header1->Pixel[i].pixelcode=30;
           }
           else if(header1->Pixel[i].pixelcode==30)rotfeldsize++;
           i++;
       } 
    cout<<" px ubertragen ";fwrite(a,1,sizeof(a),bild4);
    cout<<"\n feldsizes: grun:"<<grunfeldsize<<" rot:"<<rotfeldsize<<"\n\n";
    umranden ende*/
    
       //i=0;
       //while(i<size){
       //    fputc(a[i],bild4);i++;cout<<".";
       //}fclose(bild4);cout<<" bild gespeichert ";
    /*
       //Pixel in 2D-Array
       char reihen[header1->BITMAPINFOHEADER.biHeight]
       [header1->BITMAPINFOHEADER.biWidth];
       int j=0,k=0;cout<<"\nj<"<<header1->BITMAPINFOHEADER.biHeight<<" k<"<<header1->BITMAPINFOHEADER.biWidth<<"\n";
       for(j;j<header1->BITMAPINFOHEADER.biHeight;j++){k=0;//cin>>i;
           for(k;k<header1->BITMAPINFOHEADER.biWidth;k++){
               reihen[j][k]=header1->Pixel[j*k].pixelcode;
               //cout<<" "<<reihen[j][k];
           }//cout<<"\n";fputs(reihen[j],kopie);
       }
    */
    
    //BITMAPFILEHEADER *header1=(BITMAPFILEHEADER*)quelle;
       //Header *header1=(Header*)quelle;
    
    //fputs(header1->bfType,stdout);
    cout<<"\n"<<"bfTyp ";
    cout<<header1->BITMAPFILEHEADER.bfType
            <<"\n";
    cout<<"bfSize ";
    cout<<header1->BITMAPFILEHEADER.bfSize
            <<"\n";
    cout<<"bfReserved1 ";
    cout<<header1->BITMAPFILEHEADER.bfReserved1
            <<"\n";
    cout<<"bfReserved2 ";
    cout<<header1->BITMAPFILEHEADER.bfReserved2
            <<"\n";
    cout<<"bfOffbits ";
    cout<<header1->BITMAPFILEHEADER.bfOffBits
            <<"\n\n";
    
    cout<<"biSize ";
    cout<<header1->BITMAPINFOHEADER.biSize
            <<"\n";
    cout<<"biWidth ";
    cout<<header1->BITMAPINFOHEADER.biWidth
            <<"\n";
    cout<<"biHeight ";
    cout<<header1->BITMAPINFOHEADER.biHeight
            <<"\n";
    cout<<"biPlanes ";
    cout<<header1->BITMAPINFOHEADER.biPlanes
            <<"\n";
    cout<<"biBitCount ";
    cout<<header1->BITMAPINFOHEADER.biBitCount
            <<"\n";
    cout<<"biCompression ";
    cout<<header1->BITMAPINFOHEADER.biCompression
            <<"\n";
    cout<<"biSizeImage ";
    cout<<header1->BITMAPINFOHEADER.biSizeImage
            <<"\n";
    cout<<"biXPelsPerMeter ";
    cout<<header1->BITMAPINFOHEADER.biXPelsPerMeter
            <<"\n";
    cout<<"biYPelsPerMeter ";
    cout<<header1->BITMAPINFOHEADER.biYPelsPerMeter
            <<"\n";
    cout<<"biClrUsed ";
    cout<<header1->BITMAPINFOHEADER.biClrUsed
            <<"\n";
    cout<<"biClrImportant ";
    cout<<header1->BITMAPINFOHEADER.biClrImportant
            <<"\n";
    
       return 0;
    }
    


  • Nur nochmal um das ganze hier zu vervollständigen:
    Die arrays lokal so zu erzeugen wie ich es gemacht hab ist nicht gut, da sie auf dem Stack abgelegt werden, der sehr schnell überlaufen kann, woarufhin dann gar nichts mehr funktionieren würde.
    Stattdessen sollte zum Erstellen jedes größeren Array unbedingt immer malloc benutzt werden, bzw. sofern die Arraygröße fest ist sollte man das Array global erstellen. In beiden Fällen wird der Speicherplatz dafür dann nicht auf dem Stack reserviert, sondern auf dem sogenannten Heap, einem gesonderten Speicherbereich, der extra für solche dynamischen Dinger gedacht ist und dessen Größe auch verändert werden kann, falls man mal mehr Platz braucht.



  • Fast richtig: statische Variablen liegen nicht im Heap, sondern im Daten-Segment. Und für die Speicherverwaltung würde ich lieber einen std::vector<> verwenden, anstatt manuell damit hantieren zu müssen 😉


Log in to reply