Problem z odczytanie bitmapy za pomocą ifstream.

0

Witam.
Chciałbym napisać program który za pomocą ifstream odczyta bitmapę monochromatyczna i zapisze dane o niej do pliku txt.
Jak dotąd napisałem program który odczytuje nagłówek bitmapy ale źle odczytuje właściwy obrazek.

#include <iostream>
#include <fstream>

using namespace std;

int main()
{    
    
 ifstream plik("trk2.bmp", ios::binary);
 ofstream save("trk2.txt");
 if(!plik){
    cout <<"Nie mozna otworzyc pliku. \n";
    return -1;
    }
        
 short bfType;
 int bfSize;
 short bfReserved1;
 short bfReserved2;
 int bfOffBits;
 int biSize;
 int biWidth;
 int biHeight;
 short biPlanes;
 short biBitCount;
 int biCompression;
 int biSizeImage;
 int biXPelsPerMeter;
 int biYPelsPerMeter;
 int biClrUsed;
 char biClrImportant[1];
 char biClrRotation[1];
 short biReserved;
        
 plik.read((char*)&bfType, sizeof(short));
 plik.read((char*)&bfSize, sizeof(int));
 plik.read((char*)&bfReserved1, sizeof(short));
 plik.read((char*)&bfReserved2, sizeof(short));
 plik.read((char*)&bfOffBits, sizeof(int));
 plik.read((char*)&biSize, sizeof(int));
 plik.read((char*)&biWidth, sizeof(int));
 plik.read((char*)&biHeight, sizeof(int));
 plik.read((char*)&biPlanes, sizeof(short));
 plik.read((char*)&biBitCount, sizeof(short));
 plik.read((char*)&biCompression, sizeof(int));
 plik.read((char*)&biSizeImage, sizeof(int));
 plik.read((char*)&biXPelsPerMeter, sizeof(int));
 plik.read((char*)&biYPelsPerMeter, sizeof(int));
 plik.read((char*)&biClrUsed, sizeof(int));
 plik.read(biClrImportant,1);
 plik.read(biClrRotation,1);
 plik.read((char*)&biReserved, sizeof(short));
 int a=biWidth*biHeight*2;
 int pi[a];
 plik.read((char*)pi, sizeof(a));
    
 save<<"bfType: "<<bfType<<endl;
 save<<"bfSize: "<<bfSize<<endl;
 save<<"bfReserved1: "<<bfReserved1<<endl;
 save<<"bfReserved2: "<<bfReserved2<<endl;    
 save<<"bfOffBits: "<<bfOffBits<<endl;
 save<<"biSize: "<<biSize<<endl;
 save<<"biWidth: "<<biWidth<<endl;
 save<<"biHeight: "<<biHeight<<endl;
 save<<"biPlanes: "<<biPlanes<<endl;
 save<<"biBitCount: "<<biBitCount<<endl;
 save<<"biCompression: "<<biCompression<<endl;
 save<<"biSizeImage: "<<biSizeImage<<endl;
 save<<"biXPelsPerMeter: "<<biXPelsPerMeter<<endl;
 save<<"biYPelsPerMeter: "<<biYPelsPerMeter<<endl;
 save<<"biClrUsed: "<<biClrUsed<<endl;
 save<<"biClrImportant: "<<biClrImportant<<endl;
 save<<"biClrRotation: "<<biClrRotation<<endl;
 save<<"biReserved: "<<biReserved<<endl;
    
 for (int x=0; x<a; x++)
    save<<pi[x]<<endl;
    
 system("PAUSE");
 return 0;
}

Przykładowe odczytanie bitmapy monochromatycznej za pomocą tego programu o wielkości 2x2, z czego są 4 białe piksele:
bfType: 19778
bfSize: 70
bfReserved1: 0
bfReserved2: 0
bfOffBits: 62
biSize: 40
biWidth: 2
biHeight: 2
biPlanes: 1
biBitCount: 1
biCompression: 0
biSizeImage: 8
biXPelsPerMeter: 0
biYPelsPerMeter: 0
biClrUsed: 0
biClrImportant:
biClrRotation:
biReserved: 0
0
4248912
2292888
16384
2088763392
2088810217
0
4200280

Proszę o pomoc i z góry dziękuję.

0

Jednobitowe bitmapy to bitmapy z paletą, zatem następne po nagłówkach 8 bajtów (struktura RGBQUAD) to dwa kolory, które odpowiadają wartości piskela.

*linia 53: źle liczysz rozmiar tablicy. Na jeden piksel przypada jeden bit, a nie int. Każdy wiersz bitmapy jest wielokrotnością 4 bajtów. W przypadku bitmapy 2x2 na wiersz przypadają 4 bajty (dla jasności, dla bitmapy 3x3 też).
*linia 54: definicja niezgodna ze standardem.
*linia 55: niezależnie od wartości a, zawsze czytasz sizeof(int) bajtów.

0

Mógłbyś podpowiedziec/podać przykład wczytania tej palety ?

0

Wywal linie 51 i 52. Nie wiem, skąd je wziąłeś, ale nie pasują mi tu.

unsigned int biClrImportant;

...

plik.read((char*)&biClrImportant, sizeof(int));

vector<RGBQUAD> clr_table(biClrUsed);

for(int i = 0; i < clr_table.size(); ++i)
{
	plik.read((char*)&clr_table[i], sizeof(RGBQUAD));
}

plik.seekg(bfOffBits); // tak na dobrą sprawę to ta linia wystarczy, jeśli paleta Cię nie interesuje

/* tu czytasz zawartość bitmapy */

0

A jeśli chciałbym odczytać bmp 24-bitową to czy mogę po offbits wczytywać po jednym bajcie (3bajty na piksel, 1baj 1 kolor) ?

0

Tak, tylko pamiętaj, że każdy wiersz wyrównany jest do wielokrotności 4 bajtów.

0
 short bfType;
 int bfSize;
 short bfReserved1;
 short bfReserved2;

etc, etc...

weź utwórz strukturę, np. struct bmpheader {, a nie tak sypiesz tysiącem zmiennych...

0

Jeśli są wyrównywane do 4bajtów to jak po przeczytaniu 3bajtów przeskoczę do nowej linijki to poprawnie odczyta zawartość ?
Dzięki za radę, zrobię strukturę.

0

Dziwne pytanie. Nie wiem, o co Ci chodzi.

0

Przepraszam za głupie pytanie wynikające z mojej niewiedzy. Poczytałem trochę o wyrównywaniu i czy poprawnie wczytam dane za pomocą struktury

 struct {
     byte R;
     byte G;
     byte B;
} RGB;
0

Tak, tylko kolory odwróć, bo jeśli dobrze pamiętam, w bitmapie są w odwrotnej kolejności.

p.s. typedef zjadłeś.

0

Zrobiłem strukturę (nie wiem dlaczego nie mogłem dać typu byte):

 struct kolory {
       int R;
       int G;
       int B;
       int a1;
       int a2;
     };
     kolory Rgb;

I wczytuje w taki sposób:

do {
   save<<f<<"         ";
   plik.read((char*)&Rgb.B, sizeof(char));
   save<<Rgb.B<<" ";
   plik.read((char*)&Rgb.G, sizeof(char));
   save<<Rgb.G<<" ";
   plik.read((char*)&Rgb.R, sizeof(char));
   save<<Rgb.R<<endl;
   f++;
 }while (!plik.eof()); 

Działa ale tylko dla pierwszych pięciu pikseli (w przypadku bmp 5x5 dla 10 w przypadlu 10x10) potem odczytuje w złej kolejności. Wynik działania powyższego kodu dla 25 czerwonych pikseli.
1 0 0 255
2 0 0 255
3 0 0 255
4 0 0 255
5 0 0 255
6 0 0 0
7 255 0 0
8 255 0 0
9 255 0 0
10 255 0 0
11 255 0 0
12 0 255 0
13 0 255 0
14 0 255 0
15 0 255 0
16 0 255 0
17 0 0 255
18 0 0 255
19 0 0 255
20 0 0 255
21 0 0 255
22 0 0 0
23 255 0 0
24 255 0 0
25 255 0 0
26 255 0 0
27 255 0 0

Proszę o rady ( w c++ jestem początkującym).

0

nie wiem dlaczego nie mogłem dać typu byte

Nie mogłeś, bo w C++ typ byte nie istnieje. Daj unsigned char.

Działa ale tylko dla pierwszych pięciu pikseli (w przypadku bmp 5x5 dla 10 w przypadlu 10x10) potem odczytuje w złej kolejności.

Pisałem o wyrównaniu wierszy do wielokrotności 4. Wiersz w bitmapie 5x5 ma szerokość 16 bajtów, a nie 15. Dla bitmapy o szerokości 10 pikseli wiersz będzie miał nie 30 a 32 bajty. To dopełnienie widać w odczytach, które podałeś:

1 0 0 255
2 0 0 255
3 0 0 255
4 0 0 255
5 0 0 255
6 0 0 0
7 255 0 0
8 255 0 0
9 255 0 0
10 255 0 0
11 255 0 0
12 0 255 0
...

Podsumowując: po odczytaniu wszystkich pikseli w wierszu musisz przeskoczyć n bajtów dopełnienia.

0

Teraz wszystko działa jak powinno :)
Dziękuje za pomoc i cierpliwość.

1 użytkowników online, w tym zalogowanych: 0, gości: 1