Kompresja mapy bitowej.

Kompresja mapy bitowej.
SK
  • Rejestracja:prawie 12 lat
  • Ostatnio:około 10 lat
  • 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:około 20 lat
  • Ostatnio:około 15 godzin
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.


"Programs must be written for people to read, and only incidentally for machines to execute." - Abelson & Sussman, SICP, preface to the first edition
"Ci, co najbardziej pragną planować życie społeczne, gdyby im na to pozwolić, staliby się w najwyższym stopniu niebezpieczni i nietolerancyjni wobec planów życiowych innych ludzi. Często, tchnącego dobrocią i oddanego jakiejś sprawie idealistę, dzieli od fanatyka tylko mały krok."
Demokracja jest fajna, dopóki wygrywa twoja ulubiona partia.
SK
  • Rejestracja:prawie 12 lat
  • Ostatnio:około 10 lat
  • Postów:15
0

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

Wibowit
  • Rejestracja:około 20 lat
  • Ostatnio:około 15 godzin
0

Zrób diffa.


"Programs must be written for people to read, and only incidentally for machines to execute." - Abelson & Sussman, SICP, preface to the first edition
"Ci, co najbardziej pragną planować życie społeczne, gdyby im na to pozwolić, staliby się w najwyższym stopniu niebezpieczni i nietolerancyjni wobec planów życiowych innych ludzi. Często, tchnącego dobrocią i oddanego jakiejś sprawie idealistę, dzieli od fanatyka tylko mały krok."
Demokracja jest fajna, dopóki wygrywa twoja ulubiona partia.
SK
  • Rejestracja:prawie 12 lat
  • Ostatnio:około 10 lat
  • 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:około 20 lat
  • Ostatnio:około 15 godzin
0

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


"Programs must be written for people to read, and only incidentally for machines to execute." - Abelson & Sussman, SICP, preface to the first edition
"Ci, co najbardziej pragną planować życie społeczne, gdyby im na to pozwolić, staliby się w najwyższym stopniu niebezpieczni i nietolerancyjni wobec planów życiowych innych ludzi. Często, tchnącego dobrocią i oddanego jakiejś sprawie idealistę, dzieli od fanatyka tylko mały krok."
Demokracja jest fajna, dopóki wygrywa twoja ulubiona partia.
SK
  • Rejestracja:prawie 12 lat
  • Ostatnio:około 10 lat
  • Postów:15
0

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

Wibowit
  • Rejestracja:około 20 lat
  • Ostatnio:około 15 godzin
0

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


"Programs must be written for people to read, and only incidentally for machines to execute." - Abelson & Sussman, SICP, preface to the first edition
"Ci, co najbardziej pragną planować życie społeczne, gdyby im na to pozwolić, staliby się w najwyższym stopniu niebezpieczni i nietolerancyjni wobec planów życiowych innych ludzi. Często, tchnącego dobrocią i oddanego jakiejś sprawie idealistę, dzieli od fanatyka tylko mały krok."
Demokracja jest fajna, dopóki wygrywa twoja ulubiona partia.
edytowany 1x, ostatnio: Wibowit
SK
  • Rejestracja:prawie 12 lat
  • Ostatnio:około 10 lat
  • 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:około 20 lat
  • Ostatnio:około 15 godzin
0

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

Ewentualnie pobaw się debuggerem.


"Programs must be written for people to read, and only incidentally for machines to execute." - Abelson & Sussman, SICP, preface to the first edition
"Ci, co najbardziej pragną planować życie społeczne, gdyby im na to pozwolić, staliby się w najwyższym stopniu niebezpieczni i nietolerancyjni wobec planów życiowych innych ludzi. Często, tchnącego dobrocią i oddanego jakiejś sprawie idealistę, dzieli od fanatyka tylko mały krok."
Demokracja jest fajna, dopóki wygrywa twoja ulubiona partia.
SK
  • Rejestracja:prawie 12 lat
  • Ostatnio:około 10 lat
  • 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.