2016-03-28 8 views
2

Ich versuche, eine BMP-Datei in C zu bearbeiten. Mein Code funktioniert für BMP-Dateien ohne Padding, aber ich habe Probleme mit Padding.Umgang mit Padding in einer BMP-Datei in C

Es gibt ein paar andere Fragen zu BMP-Dateien, die ich gelesen habe, aber die meisten von ihnen verwenden andere Sprachen wie C# und Java, also fand ich sie nicht sehr nützlich.

Hier ist, was die Pixel-Array aussieht, aber viel größer ist:

char bmpArray[MAX] = {B,G,R,B,G,R,B,G,R,0,0,0, 
         B,G,R,B,G,R,B,G,R,0,0,0, 
         B,G,R,B,G,R,B,G,R,0,0,0} 

Die Nullen sind für Füllbytes durch 4 teilbar jede Zeile zu machen, es hängt von der Pixelbreite des Bildes. Was ich versuche zu tun, ist diese Padding-Bytes so zu belassen, wie sie in der gleichen Position sind und nur mit den Bytes B, G, R umzugehen. Wenn ich Änderungen an den Füllwerten anwende, wird das resultierende Bild verzerrt.

Ich machte eine Funktion, die die Menge der Füllbytes basierend auf der Breite generiert. Es verwendet diese Formel 4 - ((width * 3) % 4) und es funktioniert, wie ich es mit Bildern mit unterschiedlicher Breite getestet habe.

Ich extrahierte erfolgreich die B, G, R Daten der BMP Datei und legte sie in ein Array, so dass ich nur den Teil des Codes veröffentlichen werde, mit dem ich Probleme habe.

int c = 0; 
for (int a = 0; a < height; a++) { 
    for (int b = 0; b < width*3; b++) { 
     if (bmpArray[a*(width*3)+b] < 127) { 
      bmpArray[a*(width*3)+b] = 0; 
     } else { 
      bmpArray[a*(width*3)+b] = 255; 
     } 
     c++; 
    } 
    for (int pad = 0; pad < padding; pad++) { 
     bmpArray[c++] = 0x00; 
    } 
} 

Was ich versuche, jede Zeile der Ausgabe BMP-Datei zu tun ist, „ziehen“ und dann unterbrochen werden, sobald ich das Ende der Reihe erreicht, dh Breite * 3, dann, dass nach der Polsterung ziehen vor dem Wechsel zur nächsten Pixelzeile.

Oder gibt es eine Möglichkeit, die Padding-Pixel mit einer einzigen for-Schleife zu identifizieren und dann eine if-Anweisung zu verwenden, um die Padding-Pixel nicht zu ändern? Zum Beispiel:

for (int a = 0; a < bmpArraySize; a++) { 
    paddingBytes = ??? //for example for the first row 
         // paddingBytes are i + width*3 + 1 
         // and i + width*3 + 2 and i + width*3 + 3 if padding = 3 
    if (a = paddingBytes) { 
     bmpArray[a] = 0x00; 
    } 
    else if (bmpArray[a] < 127) { 
     bmpArray[a] = 0; 
    } 
    else { 
     bmpArray[a] = 255; 
    } 
} 
+0

was die Verwendung von imgArray? –

+0

Ich habe das behoben. Ich habe diesen Teil des Codes von einer anderen Stapelüberlauffrage kopiert und vergessen, den Namen des Arrays zu ändern. – user6005857

+0

Beim Durchlaufen von Spalten sollten Sie "c" erhöhen. –

Antwort

3

Das Problem in diesem Teil ist:

int c = 0; 
for (int a = 0; a < height; a++) { 
    for (int b = 0; b < width*3; b++) { 
     if (bmpArray[a*(width*3)+b] < 127) { 
      bmpArray[a*(width*3)+b] = 0; 
     } else { 
      bmpArray[a*(width*3)+b] = 255; 
     } 
    } 
    for (int pad = 0; pad < padding; pad++) { 
     bmpArray[c++] = 0x00; /* ONLY HERE is 'c' updated! */ 
    } 
} 

Am Ende jeder Zeile, füllen Sie die Polsterung an c anfangen, die bei 0 beginnt und überschreibt so die erste einige Bytes der ersten Zeile. Dann wird jede nächste Zeile kopiert, aber Sie überschreiben von Anfang an (wo c anfänglich gezeigt).

Die Polsterung sollte in jeder Zeile hinzugefügt werden. In den Loops passen Sie a und b aber Sie vergessen, für die Polsterung anzupassen.

schlage ich vor, den einfachen Code (ungetestet!):

for (int a = 0; a < height; a++) { 
    for (int b = 0; b < width*3; b++) { 
     if (bmpArray[a*(width*3 + padding)+b] < 127) { 
      bmpArray[a*(width*3 + padding)+b] = 0; 
     } else { 
      bmpArray[a*(width*3 + padding)+b] = 255; 
     } 
    } 
    for (int pad = 0; pad < padding; pad++) { 
     bmpArray[a*(width*3 + padding) + 3*width + pad] = 0x00; 
    } 
} 

ist es eine Möglichkeit, die Polsterung Pixel erkennen kann ..

Ja - meine Schleife oben mit Anpassungen Beim Auffüllen überspringt es automatisch das Padding selbst. Sie können die explizite 'set padding to 0' Schleife am Ende entfernen.

+0

Ausgezeichnet! Denken Sie, dass es mit der zweiten Methode machbar ist (1 Schleife)? – user6005857

+0

@ user6005857: es ist, aber ich würde davon abraten, es so zu tun. Sie können eine einzelne Schleife über 'height * (Breite * 3 + Padding) machen, aber dann wird der innere Ausdruck, der Pixel und Padding unterscheiden muss, ziemlich kompliziert. – usr2564301

3

Etwas wie:

... 

int originalLineSize = width * 3; 
int workLineSize = originalLineSize + 4 - originalLineSize % 4; 

for (int a = 0; a < bmpArraySize; ++a) { 
    if ((a % workLineSize) >= originalLineSize) 
     bmpArray[a] = 0x00; 
    } 
    else if (bmpArray[a] < 127) { 
     bmpArray[a] = 0; 
    ... 
} 
+0

Sehr schlau. Dies ist eine hervorragende Möglichkeit, es zu tun! – user6005857

1

Die "Füllbytes" werden die Bytes im Anschluss an die Pixel einer Scanzeile. Sie sind nicht so interessiert an der Polsterung wie in der Abtastzeile Größe und Pixelgröße:

iScanlineSize = ((width * bitsperpixel) + 31)/32 * 4; 
iBytesperPixel = bitsperpixel/8; 

Jetzt können Sie eine Schleife über Abtastlinien und Adresse Pixel und Pixelteile (Farben) wie folgt:

for (int a = 0; a < height; a++) { 
    for (int b = 0; b < width; b++) { 
     for (int c = 0; c < iBytesperPixel; c++) { 
      pixelPart= bmpArray[a*iScanlineSize + b*iBytesperPixel + c]; 
     } 
    ] 
}