Kompresja mapy bitowej.

0

Kompresuję mapę bitową (24 bity) metodą RLE. Plik zajmujący ok. 4MB przed kompresją po kompresji zajmuje o. 1MB, natomiast gdy chcę go zdekompresować by móc go otworzyć plik po dekompresji zajmuje ok. 3,98MB i nie można go otworzyć.
Może ktoś z Was będzie w stanie mi pomóc.
Kompresja:

 
void kompresja (string sciezka)
{
	ifstream otworz(sciezka, ios::binary);
	int rozmiar;
	otworz.seekg(0, ios::end);
	rozmiar=otworz.tellg();
	otworz.seekg(0, ios::beg);
	
	int i=0;
	ofstream kompresja("skompresowany.bmp", ios::binary);
	for(i=0; i<54; i++)						
	{
		char znak=otworz.get();
		kompresja<<znak;
	}
	char TempA1, TempA2, TempA3, TempB1, TempB2, TempB3;
	int licznik=1;
	while(!otworz.eof())
	{
		int poz=otworz.tellg();
		if(otworz.tellg()>56) otworz.seekg(poz-3, ios::beg); //Powrót o 3 pozycje, aby  piksel TempA był pikselem TempB z wcześniejszego przebiegu
		TempA1=otworz.get(); //Pixel1 R
		TempA2=otworz.get(); //Pixel1 G
		TempA3=otworz.get(); //Pixel1 B

		TempB1=otworz.get(); //Pixel2 R
		TempB2=otworz.get(); //Pixel2 B
		TempB3=otworz.get(); //Pixel2 G

		if((TempA1==TempB1)&&(TempA2==TempB2)&&(TempA3==TempB3)) licznik++;
		else if(((TempA1!=TempB1)||(TempA2!=TempB2)||(TempA3!=TempB3)) && (licznik==1))
		{
			kompresja<<TempA1<<TempA2<<TempA3<<" ";
		}
		else if(((TempA1!=TempB1)||(TempA2!=TempB2)||(TempA3!=TempB3)) && (licznik>1))
		{
			kompresja<<TempA1<<TempA2<<TempA3<<"x"<<licznik<<" ";
			licznik=1;
		}
	}

Dekompresja:

ifstream otworz(sciezka_wej, ios::binary);
	ofstream dekompresowany(sciezka_wyj, ios::binary);
	for(int i=0; i<54; i++) 
	{
		char znak=otworz.get();
		dekompresowany<<znak; //Nagłówek bitmapy
	}
	otworz.seekg(54, ios::beg);
	char WartoscR, WartoscB, WartoscG,znak;
	int ilosc, suma=0;
	do
	{
		otworz>>WartoscR;
		otworz>>WartoscG; 
		otworz>>WartoscB;
		znak=otworz.get();
		
		if(znak=='x')
		{
			otworz>>ilosc;
			suma+=ilosc;
			for(int i=0; i<ilosc; i++) dekompresowany<<WartoscR<<WartoscG<<WartoscB;
		}
		else {dekompresowany<<WartoscR<<WartoscG<<WartoscB; suma++;}
	}while(!otworz.eof());
0
  1. Jeśli licznik != 0 po zakończeniu pętli w kompresji, to musisz go zgrać do pliku razem z pikselem, który się powtarza.
  2. Zabawy z seekg są bardzo nieeleganckie i generalnie niepotrzebne. Skoro już masz zmienne na 2 piksele, to wystarczy, że po każdym obiegu zrobisz coś a'la:
tempA1 = tempB1;
tempA2 = tempB2;
tempA3 = tempB3;

a nie jakieś seekg czy inne kombinacje alpejskie.

0

Niestety nie rozwiązało to problemu. W pliku po dekompresji nadal czegoś brakuje.

0

Zrób diffa.

0

Po porównaniu plików przed kompresją i po dekompresji wychodzi na to, że ilość zliczonych powtórzeń pikseli jest za mała. Nie wiem z czego może to wynikać.

0

Zaimplementowałeś punkt 2? Upewniłeś się, że (rozmiar pliku - 54) jest podzielne przez 3?

0

Zaimplementowałem.
Rozmiar pliku jest na pewno podzielny przez 3.

0

To wrzuć nowy kod (taki, który się kompiluje) i jakąś bitmapę testową.

0

Teraz natrafiłem na nieco inny problem. Podczas dekompresji pętla się nie chce skończyć. Jeśli zamknę program "z buta" podczas działania tej pętli to bitmapę będzie można otworzyć i wygląda tak jak powinna, z tym że im dłużej działa pętla tym większy rozmiar bitmapy.
Kod do dekompresji:

void dekompresja(string sciezka_wej, string sciezka_wyj)
{
	ifstream otworz(sciezka_wej, ios::binary);
	ofstream dekompresowany(sciezka_wyj, ios::binary);
	for(int i=0; i<54; i++) 
	{
		char znak=otworz.get();
		dekompresowany<<znak;
	}
	otworz.seekg(54, ios::beg);
	char WartoscR, WartoscB, WartoscG,znak;
	int ilosc, suma=0;
	while(!otworz.eof())
	{
		otworz>>WartoscR;
		otworz>>WartoscB; 
		otworz>>WartoscG;
		znak=otworz.get();
	
		
		if(znak=='x')
		{
			otworz>>ilosc;
			for(int i=0; i<ilosc; i++) dekompresowany<<WartoscR<<WartoscB<<WartoscG;
		}
		else dekompresowany<<WartoscR<<WartoscB<<WartoscG; 
		
	}
}
0

Zobacz na końcówkę skompresowanego pliku, może jest tam coś nieprawidłowego.

Ewentualnie pobaw się debuggerem.

0

Dokonałem pewnych zmian w tej kompresji. Nie porównuję ze sobą bloku po 3 znaki (RGB), tylko pojedyncze znaki. Program dzięki temu działa zdecydowanie szybciej.
Jest jednak problem z wyglądem bitmapy po dekompresji, a mianowicie 99% bitmapy to kolor biały. Jedynie cienki pasek na dole jest taki jak powinien być.

Kod:

void kompresja (string sciezka)
{
	ifstream otworz(sciezka, ios::binary);
	int rozmiar;
	otworz.seekg(0, ios::end);
	rozmiar=otworz.tellg();
	otworz.seekg(0, ios::beg);
	
	int i=0;
	ofstream kompresja("skompresowany.bmp", ios::binary);

	kompresja<<rozmiar<<" ";
	char TempA1, TempB1;
	int licznik=1, licznik_globalny=0, a=0;
	while(!otworz.eof())
	{
		if(a==0)
		{
			TempA1=otworz.get(); //Pixel1 R
			a++;
		}
		TempB1=otworz.get(); //Pixel2 R

		if(TempA1==TempB1) licznik++;
		else if((TempA1!=TempB1) && (licznik<=3))
		{
			for(int i=0; i<licznik; i++)	kompresja<<TempA1;
			licznik=1;
		}
		else if((TempA1!=TempB1) && (licznik>3))
		{
			kompresja<<TempA1<<"x"<<licznik<<"_";
			licznik=1;
		}
		TempA1=TempB1;
	}
}

void dekompresja(string sciezka_wej, string sciezka_wyj)
{
	ifstream otworz(sciezka_wej, ios::binary);
	ofstream dekompresowany(sciezka_wyj, ios::binary);

	char WartoscR, WartoscB, WartoscG,znak;
	int ilosc, suma=0, rozmiar;
	otworz>>rozmiar;
	otworz.seekg(1, ios::cur);
	while((!otworz.eof()) && (suma<rozmiar))
	{
		WartoscR=otworz.get();
		znak=otworz.get();
	
		if(znak=='x')
		{
			otworz>>ilosc;
			for(int i=0; i<ilosc; i++) dekompresowany<<WartoscR;
			otworz.seekg(1, ios::cur);
			suma=suma+ ilosc;
		}
		else {dekompresowany<<WartoscR; otworz.seekg(-1, ios::cur); suma++;}
		
	}
}

int _tmain(int argc, _TCHAR* argv[])
{
	kompresja("bitmapa.bmp");
	dekompresja("skompresowany.bmp","bitmapa_wyj.bmp");


	//_getch();
	return 0;
}

Bitmapa poddawana kompresji: http://skeetch.pl/bitmapa.bmp

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