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;
}

