Mehrere Trägerbilder

C# Quellcode - 19.5 Kb

Worum geht es?

Dieser Artikel erweitert die Anwendung aus Teil 1 um das Aufteilen der Nachricht auf mehrere Träger-Bitmaps.

Die Information über mehrere Bilder verteilen

Wenn Du richtig paranoid bist, wirst Du Deiner Mailbox nicht vertrauen. Natürlich wirst Du auch nicht dem Briefträger vertrauen. Das bedeutet, dass Du es nicht wagst, die Träger-Bitmap in einem Stück zu verschicken. Das ist kein Problem mehr, denn Du kannst eine Nachricht in mehreren Bitmaps verstecken, als würde man einen Text über mehrere Seiten schreiben. Auf diese Anwendung bezogen heisst es, die Pixel über mehrere Bilder zu verteilen.

So wie du einen Papierbrief zerschneiden und in mehrere hohle Baustämme stecken kannst…

multiple sheets of paper

… kannst du die Bits in mehreren Grafiken verstecken:

multiple images

Du kannst jedes Bild in einer separaten eMail verschicken, in verschiedenen Postfächern hinterlegen, oder auf verschiedenen Festplatten speichern. Die Oberfläche erlaubt es, mehrere Träger-Bitmaps genauso wie Schlüssel-Dateien auszuwählen. Die Auswahl wird in einem Array vom Typ CarrierImage gespeichert.

public struct CarrierImage{
        //Name des "sauberen" Bildes
        public String sourceFileName;
        //Dateiname für das neue Bild
        public String resultFileName;
        //Breite * Höhe
        public long countPixels;
        //Farbiges (false) oder monochromes (true) Rauschen in diesem Bild erzeugen
        public bool useGrayscale;
        //Anzahl der Bytes, die in diesem Bild versteckt werden - wird von HideOrExtract() gesetzt
        public long messageBytesToHide;

        public CarrierImage(String sourceFileName, String resultFileName, long countPixels, bool useGrayscale){
                this.sourceFileName = sourceFileName;
                this.resultFileName = resultFileName;
                this.countPixels = countPixels;
                this.useGrayscale = useGrayscale;
                this.messageBytesToHide = 0;
        }
}

Größere Bilder können mehr Bytes (in mehr Pixeln) fassen als kleinere Bilder. Diese Beispiel-Anwendung verwendet die einfachste mögliche Verteilung:

//Anzahl der Bytes berechnen, für die dieses Bild verwendet wird
for(int n=0; n<imageFiles.Length; n++){
        //pixels = Anzahl der Pixel im Bild / Anzahl verfügbarer Pixel insgesamt
        float pixels = (float)imageFiles[n].countPixels / (float)countPixels;
        //Das Bild wird (Länge der Nachricht * pixels) Bytes verstecken
        imageFiles[n].messageBytesToHide = (long)Math.Ceiling( (float)messageLength * pixels );
}

Jetzt beginnen wir mit der ersten Träger-Bitmap, laufen durch die Nachricht, verstecken eine bestimmte Anzahl an Bytes, wechseln zur zweiten Träger-Bitmap, und immer so weiter.

//Aktuelle Position im Träger-Bitmap
//Start bei 1, weil (0,0) die Länge der Nachricht enthält
Point pixelPosition = new Point(1,0);

//Anzahl der Bytes, die in diesem Bild bereits versteckt wurden
int countBytesInCurrentImage = 0;

//Index des aktuell verwendeten Bildes
int indexBitmaps = 0;

//Nachricht durchlaufen und jedes Byte verstecken
for(int messageIndex=0; messageIndex<messageLength; messageIndex++){
        //Position des nächsten Pixels berechnen
        //...

        //Weiter zur nächsten Bitmap
        if(countBytesInCurrentImage == imageFiles[indexBitmaps].messageBytesToHide){
                indexBitmaps++;
                pixelPosition.Y = 0;
                countBytesInCurrentImage = 0;
                bitmapWidth = bitmaps[indexBitmaps].Width-1;
                bitmapHeight = bitmaps[indexBitmaps].Height-1;
                if(pixelPosition.X > bitmapWidth){ pixelPosition.X = 0; }
        }

        //Ein Byte verstecken oder extrahieren
        //...

        countBytesInCurrentImage++;
}

Zum Schluss müssen wir die neuen Bilder speichern. Jedes Bild kann in einem anderen Format gespeichert werden (bmp, tif oder png). Das neue Format hat nichts mit dem Format der Original-Datei zu tun. Das heisst, Du kannst eine BMP-, zwei PNG und eine TIFF-Datei als Träger-Bilder auswählen, und die Ergebnisse in drei TIFF- und einer PNG-Datei speichern.

//...
        for(indexBitmaps=0; indexBitmaps<bitmaps.Length; indexBitmaps++){
                if( ! extract ){ //Extrations-Modus ändert keine Bilder
                        //Entstandenes Bild speichern und Original schließen
                        SaveBitmap( bitmaps[indexBitmaps], imageFiles[indexBitmaps].resultFileName );
                }
        }
//...

private static void SaveBitmap(Bitmap bitmap, String fileName){
        String fileNameLower = fileName.ToLower();

        //Format anhand der Erweiterung bestimmen
        System.Drawing.Imaging.ImageFormat format = System.Drawing.Imaging.ImageFormat.Bmp;
        if((fileNameLower.EndsWith("tif"))||(fileNameLower.EndsWith("tiff"))){
                format = System.Drawing.Imaging.ImageFormat.Tiff;
        }else if(fileNameLower.EndsWith("png")){
                format = System.Drawing.Imaging.ImageFormat.Png;
        }

        //Bitmap kopieren
        Image img = new Bitmap(bitmap);

        //Datei schließen
        bitmap.Dispose();
        //Neue Bitmap speichern
        img.Save(fileName, format);
        img.Dispose();
}