Nadesłany przez Michał Knasiecki, 28 lipca 2005 01:00
Kod przedstawiony poniżej przedstawia główną część rozwiązania problemu.Pobierz pełne rozwiązanie.
Jeżeli nie odpowiada Ci sposób formatowania kodu przez autora skorzystaj z pretty printer'a i dostosuj go automatycznie do siebie.
BMP.cpp:
/******************************************************** * * * Ukrywanie pliku tekstowego w bitmapie * * Program został pobrany ze strony www.algorytm.org * * Znajdziesz na niej opis tego algorytmu i wielu innych * * * * Autor: Michał Knasiecki * * www.algorytm.org * * * *********************************************************/ #include <stdio.h> #include <stdlib.h> #include <conio.h> #include <string.h> //!Klasa służąca do konwersji liczb i manipulacji na najmłodszym bicie class Bajt{ public: int Wartosc; char Bity[100]; //!Ile bitow ma liczba int LiczbaBitow; //!Zamiana atrybutu na wartość binarną void Binarnie(void){ int W; int l=0; W=Wartosc; do{ if ((W % 2) == 0) Bity[LiczbaBitow-l-1]='0'; else Bity[LiczbaBitow-l-1]='1'; W/=2; l++; }while (l!=LiczbaBitow); } //!Zamiana wartości atrybutu na system dziesiętny void Dziesietnie(void){ unsigned long val = 1; Wartosc=0; for (int l=0;l<LiczbaBitow;l++) { if (Bity[LiczbaBitow-l-1]=='1') Wartosc+= val; val *= 2; } return; } //!Utworzenie 32-bitowej liczby z bajtow a,b,c i d void Zamien(Bajt a,Bajt b, Bajt c, Bajt d){ a.Binarnie(); b.Binarnie(); c.Binarnie(); d.Binarnie(); for (int i=0;i<8;i++) Bity[i]=d.Bity[i]; for (int i=0;i<8;i++) Bity[i+8]=c.Bity[i]; for (int i=0;i<8;i++) Bity[i+16]=b.Bity[i]; for (int i=0;i<8;i++) Bity[i+24]=a.Bity[i]; return; } //!Ustawia wartość najmniej znaczącego bitu na i (0 lub 1) void UstawBit(char i){ Binarnie(); Bity[LiczbaBitow-1]=i; return; } //!Konstruktor (n-liczba bitów na liczbę) Bajt(int n){ LiczbaBitow=n; } };//!Koniec klasy //!Klasa opisująca obrazek class BitMapa{ public: //!Plik wejściowy FILE *Plik; //!Plik z tekstem do ukrycia FILE *Tekst; //!Offset danych int AdresDanych; //!Liczba bajtów opisujących dane int RozmiarDanych; //!Szerokość obrazka w pikselach int Szerokosc; //Liczba bajtów tekstu int RozmiarTekstu; /*!Metoda wczytująca adres danych, liczbę bitów kolorów, i szerokość */ int WczytajPlik(char NazwaPliku[50]){ int Znak; //!Otwórz plik z bitmapą (w trybie binarnym) Plik=fopen(NazwaPliku,"rb"); if (Plik==NULL) return(0); //!Przejdź do 10 bajtu i odczytaj adres obszaru danych (4 bajty fseek(Plik,10,SEEK_SET); //Utworz 4 jednobajtowe liczby Bajt *word1=new Bajt(8); Bajt *word2=new Bajt(8); Bajt *word3=new Bajt(8); Bajt *word4=new Bajt(8); //!Wczytuj 4 kolejne bajty Znak=getc(Plik); word1->Wartosc=Znak; Znak=getc(Plik); word2->Wartosc=Znak; Znak=getc(Plik); word3->Wartosc=Znak; Znak=getc(Plik); word4->Wartosc=Znak; //!Utworz 32-bitową liczbę z powyższych bajtów Bajt *Dane=new Bajt(32); Dane->Zamien(*word1,*word2,*word3,*word4); Dane->Dziesietnie(); //!Przypisz otrzymaną wartość zmiennej adresu danych AdresDanych=Dane->Wartosc; //!Przejdz do 18 bajtu i odczytaj szerokosc fseek(Plik,18,SEEK_SET); Znak=getc(Plik); word1->Wartosc=Znak; Znak=getc(Plik); word2->Wartosc=Znak; Znak=getc(Plik); word3->Wartosc=Znak; Znak=getc(Plik); word4->Wartosc=Znak; Dane->Zamien(*word1,*word2,*word3,*word4); Dane->Dziesietnie(); //!Zapamiętaj wartość w atrybucie Szerokosc=Dane->Wartosc; //!Przejdz do 34 bajtu i odczytaj dlugosc obszaru danych (4 bajty) fseek(Plik,34,SEEK_SET); Znak=getc(Plik); word1->Wartosc=Znak; Znak=getc(Plik); word2->Wartosc=Znak; Znak=getc(Plik); word3->Wartosc=Znak; Znak=getc(Plik); word4->Wartosc=Znak; //!Utworz 32-bitowa liczbe Dane->Zamien(*word1,*word2,*word3,*word4); Dane->Dziesietnie(); //!Zapamiętaj rozmiar danych RozmiarDanych=Dane->Wartosc; //!Usuń niepotrzebne już obiekty delete word1; delete word2; delete word3; delete word4; delete Dane; return(1); } //!Koniec metody //!Destruktor zamyka otwarte pliki ~BitMapa(void){ fclose(Plik); fclose(Tekst); } //!Metoda odczytuje z bitmapy tekst i drukuje go na ekranie void Wypisz(char PlikTekstowy[10]){ int k=0; int Znak; int Przeczytane=0; //!Otwórz plik z tekstem (w trybie tekstowym) Tekst=fopen(PlikTekstowy,"wt+"); /*!Na końcu linii znajdują się zera nieznaczące. Może ich być 0, 1, 2 lub 3 jest to reszta z dzielenia szerokości przez 4 */ int ZeraNieznaczace = Szerokosc % 4; //!Na końcu tekstu znajduje się ciąg 8 wyzerowanych bitów int Koniec=0; Bajt *bajtZnaku=new Bajt(8); Bajt *bajtTMP=new Bajt(8); int licznikBitow=0; fseek(Plik,AdresDanych,SEEK_SET); while (k!=RozmiarDanych){ Znak=getc(Plik); Przeczytane++; if (Przeczytane<=Szerokosc) { bajtZnaku->Wartosc=Znak; bajtZnaku->Binarnie(); bajtTMP->Bity[licznikBitow]=bajtZnaku->Bity[7]; licznikBitow++; if (licznikBitow==8) { licznikBitow=0; bajtTMP->Dziesietnie(); //!Jeśli znalazłeś bajt 0 (ciąg 8 wyzerowanych bitów) to jest to koniec ukrytego tekstu if (bajtTMP->Wartosc==0) Koniec=1; if (Koniec==0) fprintf(Tekst,"%c",bajtTMP->Wartosc); } } if (Przeczytane==Szerokosc+ZeraNieznaczace) Przeczytane=0; k++; } //!Usuń obiekty delete bajtZnaku; delete bajtTMP; return; } //!Metoda tworzy bitmapę z ukrytym tekstem int Kopiuj(char NowaBitmapa[10],char PlikTekstowy[10]){ //!Bitmapa z ukrytym tekstem FILE *DrugiPlik; int znak; int Koniec=0; int k=0; int Znak; int Przeczytane=0; int BitZnaku=0; int ZnakTekstu; //!Zera nieznaczące, jak wyżej int ZeraNieznaczace= Szerokosc % 4; Bajt *bajt=new Bajt(8); Bajt *bajtZnaku=new Bajt(8); //!Otwórz plik z tekstem (w trybie tekstowym) Tekst=fopen(PlikTekstowy,"rt+"); //!Odczytaj jego rozmiar i wróć na początek pliku RozmiarTekstu=fseek(Tekst,0L,SEEK_END); RozmiarTekstu = ftell(Tekst); fseek(Tekst,0L,SEEK_SET); //!Czy wystarczy pikseli do ukrucia tekstu? if ((RozmiarTekstu+1)*8>RozmiarDanych) return(0); //!Utwórz drugą bitmapę w trybie binarnym do zapisu DrugiPlik=fopen(NowaBitmapa,"wb"); //!Wróć na początek pierwszej bitmapy fseek(Plik,0L,SEEK_SET); /*!Przepisz nagłówek oryginalnej bitmapy (aż do obszaru danych) niczego nie zmieniając */ do { znak=getc(Plik); if (k<AdresDanych) putc(znak,DrugiPlik); k++; } while (k<AdresDanych); /*!Przepisuj kolejne bajty obszaru danych zmieniając ostatni bit każdego koloru */ k=0; while (k!=RozmiarDanych){ if ((BitZnaku==0)) { if (Przeczytane<Szerokosc) ZnakTekstu=getc(Tekst); /*!Jeżeli skończył się plik z tekstem, wstaw do drugiej bitmapy 8 bajtów z wyzerowanym ostatnim bitem (znacznik końca tekstu) */ if (ZnakTekstu==-1) { //!Znacznik końca tekstu bajtZnaku->Wartosc=0; bajtZnaku->Binarnie(); } //!Jeżeli tekst się jeszcze nie skończył, pobierz następny bajt else{ bajtZnaku->Wartosc=ZnakTekstu; bajtZnaku->Binarnie(); } } //!Pobierz bajt z oryginalnej bitmapy znak=getc(Plik); Przeczytane++; //!Jeżeli nie wkroczyłeś w obszar zer nieznaczących i tekst się jeszcze nie skończył if ((Przeczytane<=Szerokosc)&&Koniec==0) { bajt->Wartosc=znak; bajt->Binarnie(); //!Zmień ostatni bit na kolejnt bit bajtu tekstu bajt->UstawBit(bajtZnaku->Bity[BitZnaku]); BitZnaku++; if (BitZnaku==8) { BitZnaku=0; if (bajtZnaku->Wartosc==0) Koniec=1; } bajt->Dziesietnie(); //!Zapisz zmodyfikowany bajt do nowej bitmapy znak=bajt->Wartosc; putc(znak,DrugiPlik); } else /*!Jeżeli tekst się już skończył lub wkroczyłeś w obszar zer nieznaczących to przepisz bajt nie zmieniając go */ putc(znak,DrugiPlik); if (Przeczytane==Szerokosc+ZeraNieznaczace) Przeczytane=0; k++; } //!Usuń obiekty i zamknij zmodyfikowaną bitmapę delete bajt; delete bajtZnaku; fclose(DrugiPlik); return 1; } }; //!Koniec klasy //----------------------------------------------- void main(void){ BitMapa BMP; int opcja; char BMP1[100]; char BMP2[100]; char TXT[100]; printf("Wybierz opcje\n"); printf("1- Ukrycie pliku\n2- Odzyskanie pliku\n3 - Koniec\n"); do scanf("%d",&opcja); while ((opcja!=1)&&(opcja!=2)&&(opcja!=3)); if (opcja==3) return; if (opcja==1){ printf("Nazwa pliku z wejsciowym obrazem: "); scanf("%s",BMP1); printf("Nazwa pliku z wejsciowym tekstem: "); scanf("%s",TXT); printf("Nazwa pliku z wyjsciowym obrazem: "); scanf("%s",BMP2); if (BMP.WczytajPlik(BMP1)==0){ printf("Plik %s nie istnieje\n",BMP1); getch(); exit(0); } if (BMP.Kopiuj(BMP2,TXT)==0) { printf("Plik z obrazkiem jest zbyt maly, zeby ukryc tekst\n"); getch(); exit(0); } else printf("Plik zostal ukryty...\n"); }else { printf("Nazwa pliku z wejsciowym obrazem: "); scanf("%s",BMP1); printf("Nazwa pliku z wyjsciowym tekstem: "); scanf("%s",TXT); if (BMP.WczytajPlik(BMP1)==0){ printf("Plik %s nie istnieje\n",BMP1); getch(); exit(0); } BMP.Wypisz(TXT); printf("Plik zostal odzyskany...\n"); } printf("\nDowolny klawisz...\n"); getch(); return; }