Problem beim Ermitteln von Pixeldaten einer Bitmap



  • Hallo,

    möchte eine etwas größere Bitmap verarbeiten. Im ersten Schritt geht es darum die Pixel des Bitmaps in eine Textdatei zu schreiben. Prinzipiell funktioniert dies auch, allerdings ist meine Verarbeitung fehlerhaft.

    #include <stdio.h>
    #include <stdlib.h>
    #include <math.h>
    
    typedef unsigned short WORD;
    typedef unsigned long DWORD;
    typedef long LONG;
    
    #pragma pack(2)
    typedef struct bmpFileHeader
    {
       WORD   typ;             /*  Magic Numbers ('BM' => 0x4D42) Offset =  0;  */
       DWORD  groesse;         /*  Dateigröße                     Offset =  2;  */
       WORD   res1;            /*  Reseviert                      Offset =  6;  */
       WORD   res2;            /*  Reseviert                      Offset = 10;  */
       DWORD  startPixeldaten; /*  Beginn der Pixeldaten          Offset = 14;  */
    
    } bmpfh; 
    #pragma pack()
    
    typedef struct bmpInfoHeader
    {
       DWORD groesse;          /* Größe bmpInfoHeader */      
       LONG  breite;           /* Breite der Bitmap (Pixel) */       
       LONG  hoehe;            /* Höhe der Bitmap (Pixel) */  
       WORD  farbebenen;       /* Immer = 1 */
       WORD  farbtiefe;        /* Bitmap-Farbtiefe in bpp */
       DWORD kompression;      /* Angabe über eventuell verwendete Kompression */
       DWORD bildGroesseByte;  /* Größe der Bilddatei in Byte */
       LONG  pixelProMeterX;   /* Pixel pro Meter (X) auf Ausgabegerät */   
       LONG  pixelProMeterY;   /* Pixel pro Meter (Y) auf Ausgabegerät */   
       DWORD farbtabelle;      /* Anzahl der Einträge in Farbtabelle */
       DWORD verwendeteFarben; /* Anzahl der im Bild verwendeten Farben */        
    
    } bmpih; 
    
    int main()
    {
       FILE *eingabedatei = NULL;
       FILE *ausgabedatei = NULL;   
       bmpFileHeader bmpfh;
       bmpInfoHeader bmpih;
       unsigned char R, G, B;
       int zeilen;
       int spalten;
       int i;
       int j;
    
       eingabedatei = fopen("TEST.bmp", "rb");
    
       if (eingabedatei == NULL)
          return printf("Eingabedatei konnte nicht geoeffnet werden\n");
    
       ausgabedatei = fopen("daten.txt", "w");
    
       if (ausgabedatei == NULL)
          return printf("Ausgabedatei konnte nicht geoeffnet werden\n");
    
       fseek(eingabedatei, 0, SEEK_SET);   
       fread(&bmpfh, sizeof(bmpFileHeader), 1, eingabedatei);
    
       if (bmpfh.typ != 0x4D42)
          return printf("Es handelt sich um keine Bitmap\n");
    
       fseek(eingabedatei, 0, SEEK_CUR);
       fread(&bmpih, sizeof(bmpInfoHeader), 1, eingabedatei);
    
       printf("Dateigroesse (Bytes) : %ld\n", bmpfh.groesse);
       printf("Beginn der Pixeldaten: %ld\n", bmpfh.startPixeldaten);
       printf("Bildgroesse (Pixel)  : %ld x %ld\n", bmpih.breite, bmpih.hoehe);
       printf("Farbpalette (Bit)    : %ld\n", bmpih.farbtiefe);
       printf("Farbanzahl           : %2.0f\n", pow(2.0, (double)bmpih.farbtiefe));   
    
       fseek(eingabedatei, 54, SEEK_SET);   
    
       zeilen  = bmpih.hoehe;
       spalten = bmpih.breite;
    
       for (i = 0; i < zeilen ; i++) {
          for (j = 0; j < spalten ; j++) {
    
             fread(&B, sizeof(unsigned char), 1, eingabedatei);         
             fread(&G, sizeof(unsigned char), 1, eingabedatei);         
             fread(&R, sizeof(unsigned char), 1, eingabedatei);
    
             fprintf(ausgabedatei, "R = %3d | G = %3d | B = %3d\n", R, G, B);
    
          }
       }
    
       fclose(eingabedatei);
       fclose(ausgabedatei);
    
       return 0;
    }
    

    Hier die Ausgabe:

    R = 255 | G =   0 | B =   0
    R = 255 | G = 255 | B = 255
    R = 255 | G =   0 | B =   0
    R =   0 | G =   0 | B =   0
    

    Verwendet habe ich folgendes (hier stark vergrößertes) Bild:

    http://upload.wikimedia.org/wikipedia/en/0/0d/Bmp_format.png

    Nach dem BMP-Format müsste die Reihenfolge eigentlich so aussehen:

    R = 255 | G =   0 | B =   0
    R = 255 | G = 255 | B = 255
    R =   0 | G =   0 | B = 255
    R =   0 | G = 255 | B =   0
    

    Danke im Voraus!



  • Nachtrag: Mit "eine etwas größere Bitmap" ist natürlich eine andere Bitmap als die hier (beispielhaft) verwendete Bitmap gemeint. 😉



  • hi,
    da ich genau das gebraucht habe was du da geschrieben hast, warst du mir erst einmal eine große Hilfe 😉
    aber du hast Recht, du hast einen kleinen Fehler eingebaut... hast du mal bei Wikipedia geschaut? nach jeder Pixelzeile sind 2 zusätzliche Bytes gespeichert mit irgendwelchen infos über die row... diese musst du natürlich nach jeder Zeile überspringen... ich habe das elegant mit einer Variable gelöst schau:
    erstmal die Variable deklarieren

    int offset;
    

    dann schreibst du for deine doppelforschleife

    seeker = 54;
    fseek(eingabedatei, seeker, SEEK_SET);
    

    nach der ersten for-schleife dann die 2 bytes überspringen:

    seeker += j*3 + 2;
    fseek(eingabedatei, seeker, SEEK_SET);
    

    und schon klappts prima 😉



  • sry hatte murks geschrieben da ich kurzfristig den namen der variablen geändert hatte : hier nochmal alles komplett:
    erst offset deklarieren

    int offset;
    

    dann

    // offset auf Beginn der Pixel einstellen
       offset = 54;
       fseek(eingabedatei, offset, SEEK_SET);
    
       zeilen  = bmpih.hoehe;
       spalten = bmpih.breite;
       printf("%d Zeile(n), %d Spalte(n)\n", zeilen, spalten);
    
       for (i = 0; i < zeilen ; i++) {
          for (j = 0; j < spalten ; j++) {
             fread(&B, sizeof(unsigned char), 1, eingabedatei);
             fread(&G, sizeof(unsigned char), 1, eingabedatei);
             fread(&R, sizeof(unsigned char), 1, eingabedatei);
    
             fprintf(ausgabedatei, "R = %3d | G = %3d | B = %3d\n", R, G, B);
    
          }
          // nach jeder row 2 bytes vorspulen
          offset += j*3 + 2;
          fseek(eingabedatei, offset, SEEK_SET);
       }
    

Anmelden zum Antworten