Kompresja mapy bitowej.

Kompresja mapy bitowej.
SK
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 15
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:

Kopiuj
 
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:

Kopiuj
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());
Wibowit
  • Rejestracja: dni
  • Ostatnio: dni
  • Lokalizacja: XML Hills
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:
Kopiuj
tempA1 = tempB1;
tempA2 = tempB2;
tempA3 = tempB3;

a nie jakieś seekg czy inne kombinacje alpejskie.

SK
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 15
0

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

Wibowit
  • Rejestracja: dni
  • Ostatnio: dni
  • Lokalizacja: XML Hills
0

Zrób diffa.

SK
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 15
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ć.

Wibowit
  • Rejestracja: dni
  • Ostatnio: dni
  • Lokalizacja: XML Hills
0

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

SK
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 15
0

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

Wibowit
  • Rejestracja: dni
  • Ostatnio: dni
  • Lokalizacja: XML Hills
0

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

SK
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 15
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:

Kopiuj
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; 
		
	}
}
Wibowit
  • Rejestracja: dni
  • Ostatnio: dni
  • Lokalizacja: XML Hills
0

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

Ewentualnie pobaw się debuggerem.

SK
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 15
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:

Kopiuj
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

Zarejestruj się i dołącz do największej społeczności programistów w Polsce.

Otrzymaj wsparcie, dziel się wiedzą i rozwijaj swoje umiejętności z najlepszymi.