School-Coding-Cpp/sfusi/es04_zoli_filebmp.cpp

474 lines
12 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
Nome: Mario
Cognome: Montanari
Classe: 3AIN
Data: 09/05/2025
1) Leggere il primo pixel (BGR);
2) Modificarlo;
3) Elaborare unimmagine (crearla con paint con dimensioni in pixel multiple di 4):
- Rendendo i pixel casuali;
- Generando blocchi uniformi di colore;
4) Inventare un banale algoritmo di compressione e decompressione:
- stessi header poi … i prossimi 50 px sono verdi, i prossimi 20 px sono blu, …
5) Steganografia:
- Nascondere i byte corrispondenti ai caratteri di una parola sparpagliandoli
nei pixel secondo una mappa prestabilita;
- Nascondere i bit corrispondenti al byte di una o più lettere mascherandoli
come lsbit dei pixel secondo una mappa prestabilita;
- Decomprimere un file bmp compresso secondo un algoritmo banale (vedi es 4.e).
*/
#include <iostream>
#include <cstdlib>
#include <ctime>
using namespace std;
#pragma pack(1)
typedef struct {
char bfType[2];
int bfSize;
int bfReserved;
int bfOffBits;
} BITMAPFILEHEADER;
typedef struct {
unsigned char b;
unsigned char g;
unsigned char r;
} BGR;
void compressioneBMP(const char * inputFilename, const char * outputFilename, int lunghezza, int altezza, int offset);
void decompressioneBMP(const char * inputFilename, const char * outputFilename, int lunghezza, int altezza, int offset);
void nascondiByteNeiPixel(const char * inputFile, const char * outputFile, const char * messaggio, int offset);
void estraiByteDaiPixel(const char * filename, int offset, int intervallo, int lunghezzaMessaggio);
void nascondiBitNeiPixel(const char * inputFilename, const char * outputFilename, const char * messaggio, int offset);
void estraiBitDaiPixel(const char * filename, int offset, int lunghezzaMessaggio);
int main(void) {
cout << "sizeof(BITMAPFILEHEADER): " << sizeof(BITMAPFILEHEADER) << endl;
FILE * file = fopen("tuttaBianca.bmp", "rb");
if (file != NULL) {
srand(time(NULL));
int bfOffBits;
BITMAPFILEHEADER bf;
// Scrivo l'header del file .bmp
fseek(file, 0, SEEK_SET);
fread(&bf, sizeof(bf), 1, file);
cout << "bfType: " << bf.bfType[0] << bf.bfType[1] << endl;
fseek(file, 2, SEEK_CUR);
cout << "bfSize: " << bf.bfSize << endl;
fseek(file, 10, SEEK_CUR);
cout << "bfOffBits: " << bf.bfOffBits << endl;
fseek(file, bf.bfOffBits, SEEK_SET);
// --------------------------------------------------------------------
// 1. Copiare il file BMP originale in modificato.bmp
// --------------------------------------------------------------------
rewind(file);
FILE * file_mod = fopen("modificato.bmp", "wb");
if (file_mod != NULL) {
char buffer[1024];
int byte;
while ((byte = fread(buffer, 1, sizeof(buffer), file)) > 0) {
fwrite(buffer, 1, byte, file_mod);
}
fclose(file_mod);
} else {
perror("Error");
}
// --------------------------------------------------------------------
// 2. Modificare il primo pixel in rosso nel file modificato.bmp
// --------------------------------------------------------------------
file_mod = fopen("modificato.bmp", "r+b");
if (file_mod != NULL) {
fseek(file_mod, bf.bfOffBits, SEEK_SET);
BGR bgr;
bgr.b = 255;
bgr.g = 0;
bgr.r = 0;
fwrite(&bgr, sizeof(BGR), 1, file_mod);
fclose(file_mod);
} else {
perror("Error");
}
// --------------------------------------------------------------------
// 3. Creare il file modificato2.bmp e riempire con pixel casuali
// --------------------------------------------------------------------
rewind(file);
FILE * file_mod2 = fopen("modificato2.bmp", "wb");
if (file_mod2 != NULL) {
char buffer[1024];
int byte;
while ((byte = fread(buffer, 1, sizeof(buffer), file)) > 0) {
fwrite(buffer, 1, byte, file_mod2);
}
fclose(file_mod2);
} else {
perror("Error");
}
// --------------------------------------------------------------------
// Sovrascrivere i pixel con valori casuali in modificato2.bmp
// --------------------------------------------------------------------
file_mod2 = fopen("modificato2.bmp", "r+b");
if (file_mod2 != NULL) {
fseek(file_mod2, bf.bfOffBits, SEEK_SET);
int lunghezza = 400;
int altezza = 400;
int padding = (4 - (lunghezza * 3) % 4) % 4;
fseek(file_mod2, bf.bfOffBits, SEEK_SET);
for (int y = 0; y < altezza; y++) {
for (int x = 0; x < lunghezza; x++) {
BGR pixel;
pixel.b = rand() % 256;
pixel.g = rand() % 256;
pixel.r = rand() % 256;
fwrite(&pixel, sizeof(BGR), 1, file_mod2);
}
// Scrivi il padding se necassario
for (int p = 0; p < padding; p++) {
fputc(0x00, file_mod2);
}
}
fclose(file_mod2);
} else {
perror("Error");
}
cout << endl;
// --------------------------------------------------------------------
// 4A. Compressione del file modificato2.bmp
// --------------------------------------------------------------------
compressioneBMP("modificato2.bmp", "compresso.bmpc", 400, 400, bf.bfOffBits);
// --------------------------------------------------------------------
// 4B. Decompressione del file compresso.bmp
// --------------------------------------------------------------------
decompressioneBMP("compresso.bmpc", "decompresso.bmp", 400, 400, bf.bfOffBits);
cout << endl;
// Steganografia dei byte interi
nascondiByteNeiPixel("tuttaBianca.bmp", "conMessaggio_byte.bmp", "MONTANARI", bf.bfOffBits);
estraiByteDaiPixel("conMessaggio_byte.bmp", bf.bfOffBits, 50, 9);
cout << endl;
// Steganografia dei bit
nascondiBitNeiPixel("tuttaBianca.bmp", "conMessaggio_bit.bmp", "MONTANARI", bf.bfOffBits);
estraiBitDaiPixel("conMessaggio_bit.bmp", bf.bfOffBits, 9);
fclose(file);
} else {
perror("Error (source)");
}
return 0;
}
void compressioneBMP(const char * inputFilename, const char * outputFilename, int lunghezza, int altezza, int offset) {
FILE * inputFile = fopen(inputFilename, "rb");
FILE * outputFile = fopen(outputFilename, "wb");
if (inputFile != NULL && outputFile != NULL) {
// Copia l'header
char header[1024];
fread(header, 1, offset, inputFile);
fwrite(header, 1, offset, outputFile);
int padding = (4 - (lunghezza * 3) % 4) % 4;
BGR pixel;
BGR precedente;
int count = 0;
bool primo = true;
// Legge i pixel uno a uno e li comprime
for (int y = 0; y < altezza; y++) {
for (int x = 0; x < lunghezza; x++) {
fread(&pixel, sizeof(BGR), 1, inputFile);
if (primo) {
precedente = pixel;
count = 1;
primo = false;
} else if (
pixel.b == precedente.b &&
pixel.g == precedente.g &&
pixel.r == precedente.r &&
count < 255
) {
count++;
} else {
// Scrive [numero_pixel_uguali][colore]
fputc(count, outputFile);
fwrite(&precedente, sizeof(BGR), 1, outputFile);
precedente = pixel;
count = 1;
}
}
fseek(inputFile, padding, SEEK_CUR);
}
// Scrive l'ultimo blocco
if (count > 0) {
fputc(count, outputFile);
fwrite(&precedente, sizeof(BGR), 1, outputFile);
}
cout << "Compressione completata in: " << outputFilename << endl;
fclose(inputFile);
fclose(outputFile);
} else {
perror("Error");
}
}
void decompressioneBMP(const char * inputFilename, const char * outputFilename, int lunghezza, int altezza, int offset) {
FILE * inputFile = fopen(inputFilename, "rb");
FILE * outputFile = fopen(outputFilename, "wb");
if (inputFile != NULL && outputFile != NULL) {
// Leggi e scrivi l'header BMP
char header[1024];
fread(header, 1, offset, inputFile);
fwrite(header, 1, offset, outputFile);
int padding = (4 - (lunghezza * 3) % 4) % 4;
int totalPixels = lunghezza * altezza;
int writtenPixels = 0;
while (writtenPixels < totalPixels) {
int count = fgetc(inputFile);
BGR pixel;
fread(&pixel, sizeof(BGR), 1, inputFile);
for (int i = 0; i < count; i++) {
fwrite(&pixel, sizeof(BGR), 1, outputFile);
writtenPixels++;
// Dopo ogni riga, aggiungi un padding
if (writtenPixels % lunghezza == 0) {
for (int p = 0; p < padding; p++) {
fputc(0x00, outputFile);
}
}
}
}
fclose(inputFile);
fclose(outputFile);
cout << "Decompressione completata in: " << outputFilename << endl;
} else {
perror("Error");
}
}
// Nasconde ogni byte di un messaggio nei colori di pixel a intervalli
void nascondiByteNeiPixel(const char * inputFilename, const char * outputFilename, const char * messaggio, int offset) {
FILE * inputFile = fopen(inputFilename, "rb");
FILE * outputFile = fopen(outputFilename, "wb");
if (inputFile != NULL && outputFile != NULL) {
char header[1024];
fread(header, 1, offset, inputFile);
fwrite(header, 1, offset, outputFile);
BGR pixel;
int i = 0;
int intervallo = 50;
int posizionePixel = 0;
int lunghezza = strlen(messaggio);
while (fread(&pixel, sizeof(BGR), 1, inputFile) == 1) {
if (posizionePixel % intervallo == 0 && i < lunghezza) {
pixel.r = messaggio[i++];
}
fwrite(&pixel, sizeof(BGR), 1, outputFile);
posizionePixel++;
}
fclose(inputFile);
fclose(outputFile);
cout << "Byte nascosti in: " << outputFilename << endl;
} else {
perror("Error");
}
}
// Recupera il messaggio nascosto
void estraiByteDaiPixel(const char * filename, int offset, int intervallo, int lunghezzaMessaggio) {
FILE * file = fopen(filename, "rb");
if (file != NULL) {
fseek(file, offset, SEEK_SET);
BGR pixel;
int posizionePixel = 0;
int letti = 0;
cout << "Messaggio estratto: ";
while (fread(&pixel, sizeof(BGR), 1, file) == 1 && letti < lunghezzaMessaggio) {
if (posizionePixel % intervallo == 0) {
cout << (char)pixel.r;
letti++;
}
posizionePixel++;
}
cout << endl;
fclose(file);
} else {
perror("Error");
}
}
// Nasconde bit a bit un messaggio nei pixel
void nascondiBitNeiPixel(const char * inputFilename, const char * outputFilename, const char * messaggio, int offset) {
FILE * inputFile = fopen(inputFilename, "rb");
FILE * outputFile = fopen(outputFilename, "wb");
if (inputFile != NULL && outputFile != NULL) {
char header[1024];
fread(header, 1, offset, inputFile);
fwrite(header, 1, offset, outputFile);
int posizioneBit = 0;
int posizioneChr = 0;
BGR pixel;
int len = strlen(messaggio);
while (fread(&pixel, sizeof(BGR), 1, inputFile) == 1) {
if (posizioneChr < len) {
char chr = messaggio[posizioneChr];
int bit = (chr >> (7 - posizioneBit)) & 1;
pixel.b = (pixel.b & 0xFE) | bit;
posizioneBit++;
if (posizioneBit == 8) {
posizioneBit = 0;
posizioneChr++;
}
}
fwrite(&pixel, sizeof(BGR), 1, outputFile);
}
fclose(inputFile);
fclose(outputFile);
cout << "Bit nascosti in: " << outputFilename << endl;
} else {
perror("Error");
}
}
// Recupera i bit nascosti nei pixel
void estraiBitDaiPixel(const char * filename, int offset, int lunghezzaMessaggio) {
FILE * file = fopen(filename, "rb");
if (file != NULL) {
fseek(file, offset, SEEK_SET);
BGR pixel;
int posizioneBit = 0;
int chr = 0;
int estratti = 0;
cout << "Messaggio estratto: ";
while (fread(&pixel, sizeof(BGR), 1, file) == 1 && estratti < lunghezzaMessaggio) {
int bit = pixel.b & 1;
chr = (chr << 1) | bit;
posizioneBit++;
if (posizioneBit == 8) {
cout << (char)chr;
posizioneBit = 0;
chr = 0;
estratti++;
}
}
cout << endl;
fclose(file);
} else {
perror("Error");
}
}