/* Nome: Mario Cognome: Montanari Classe: 3AIN Data: 09/05/2025 1) Leggere il primo pixel (BGR); 2) Modificarlo; 3) Elaborare un’immagine (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 #include #include 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"); } }