using System.Diagnostics; using System.Drawing.Imaging; namespace IFF___Anzeige { public partial class IFFAnzeige : Form { private string? fileIFF; private string? openFileName; private string? openFileOrdner; private int formIndex; private int ilbmIndex; private int bmhdIndex; private int bodyIndex; private string? formType; private string datenGrosseAlsString; private string? ilbmType; private string? bmhdType; // Varaiblen für BMHD private int bildBreite; private int bildHoehe; private int xVersatz; private int yVersatz; private int bildTiefe; private int intMaske; private int transparent; private int kompresion; private int xAspekt; private int yAspekt; private int xScreen; private int yScreen; // Variablen für das auslesen aus IFF Body private byte[] pixelRGB = new byte[24]; // Auslesen der Byte aus dem IFF Body private byte[] RotByte = new byte[8]; // zuweisen der Bite für Rot aus pixelRGB[] private byte[] GruenByte = new byte[8]; // zuweisen der Bite für Grün aus pixelRGB[] private byte[] BlauByte = new byte[8]; // zuweisen der Bite für Blau aus pixelRGB[] // Interner Schleifenzähler -- Sprung zum nächsten Farbwerte private int rotByteIndex = 0; // Zähler für Rot zum auslesen aus dem IFF Body private int gruenByteIndex = 0; // Zähler für Grün zum auslesen aus dem IFF Body private int blauByteIndex = 0; // Zähler für Blau zum auslesen aus dem IFF Body private int rotByteArray = 0; // Startwert für die Farbe Rot in IFF Body private int gruenByteArray = 0; // Startwert für die Farbe Grün in IFF Body private int blauByteArray = 0; // Startwert für die Farbe blau in IFF Body private int bytezaehler; // Sprung Adresse zum nächsten Farbwert in IFF Body private int farbzaehler; // Farbe für nächstes Pixel private int blockZaehler; // Blockzähler für Rot-, Grün- und Blaublock private int bz = 0; // Zähler für Zeilenzaehler private int blocksprung; private int zeile; // Zähler für Farbe in der Zeile // Zähler zum zuweisen der von RotByte[], GruenByte[] und BlauByte in der Bitmap private int bitmapZaehlerHoehe; private int bitmapZaehlerBreite; private int headerSize; public IFFAnzeige() { InitializeComponent(); } // Datei öffnen private void buttonOeffnen_Click_1(object sender, EventArgs e) { OpenFileDialog openFileDialog = new OpenFileDialog(); // Filter für IFF Dateien openFileDialog.Filter = "IFF Image |*.iff"; if (openFileDialog.ShowDialog() == DialogResult.OK) { fileIFF = openFileDialog.FileName; // Überprüfen Sie, ob die Datei existiert if (File.Exists(fileIFF)) { labeloeffnen.Text = fileIFF; openFileName = System.IO.Path.GetFileNameWithoutExtension(fileIFF); // FileName aus QuellVideo auslesen openFileOrdner = Path.GetDirectoryName(openFileDialog.FileName); // QuellOrdner speichern check_Chunks(sender, e); } else { MessageBox.Show("Datei konnte nicht geöffnet werden"); } } } // ********** Chunks suchen und auslesen ********** private void check_Chunks(object sender, EventArgs e) { byte[] fileContent = File.ReadAllBytes(fileIFF); // FORM suchen // FORM Hexodezimal = 46, 4F, 52, 4D byte[] formTag = new byte[] { 0x46, 0x4F, 0x52, 0x4D }; formIndex = FindPattern(fileContent, formTag); if (formIndex != -1) { lies_Form(sender, e); formType = "FORM"; } else { MessageBox.Show("'FORM' nicht gefunden"); return; } // ILBM suchen // ILMB Hexodezimal = 49, 4C, 42, 4D byte[] ilbmTag = new byte[] { 0x49, 0x4C, 0x42, 0x4D }; ilbmIndex = FindPattern(fileContent, ilbmTag); if (ilbmIndex != -1) { ilbmType = "ILBM"; labelDatenType.Text = (formType + "=" + ilbmType); labelgroesse.Text = (datenGrosseAlsString + " Byte"); } else { MessageBox.Show("Die Datei ist nicht vom Type ILBM"); return; } // BMHD suchen // BMHD Hexodezimal = 42, 4D, 48, 44 byte[] bmhdTag = new byte[] { 0x42, 0x4D, 0x48, 0x44 }; bmhdIndex = FindPattern(fileContent, bmhdTag); // Wert ausgeben if (bmhdIndex != -1) { lies_Bmhd(sender, e); tbBildbreite.Text = (bildBreite.ToString()); tbBildhoehe.Text = (bildHoehe.ToString()); labelInfo.Text = ("Bildbreite: " + bildBreite + "\nBildhöhe: " + bildHoehe + "\n\nX Versatz: " + xVersatz + "\nY Versatz: " + yVersatz + "\n\nBildtiefe: " + bildTiefe + "\n\nMaske: " + intMaske + "\n\nTransparents: " + transparent + "\n\nKompreion: " + kompresion + "\n\nX Aspekt: " + xAspekt + "\nY Aspekt: " + yAspekt + "\n\nScreenbreite: " + xScreen + "\nScreenhöhe: " + yScreen); } else { MessageBox.Show("BMHD wurde nicht gefunden! Auslesen der Bildinfo nicht möglich"); } // BODY suchen // BODY Hexodezimal = 42, 4F, 44, 59 byte[] bodyTag = new byte[] { 0x42, 0x4F, 0x44, 0x59 }; bodyIndex = FindPattern(fileContent, bodyTag); if (bodyIndex != -1) { if (bildTiefe == 24) { bitmap_Erstellen(sender, e); } } else { MessageBox.Show("Zur Zeit können nur Bilder mit 24 Bit Farbtiefe angezeigt werden!"); return; } } //********* FORM und größe der Datei lesen ********** private void lies_Form(object sender, EventArgs e) { /* formIndex Byte 0 - 3 Hex 0 - 3: Blocktyp(FORM) formIndex Byte 4 - 7 Hex 4 - 7: Dateigröße */ using (FileStream fs = new FileStream(fileIFF, FileMode.Open, FileAccess.Read)) { headerSize = formIndex + 8; byte[] header = new byte[headerSize]; fs.Read(header, 0, header.Length); formType = System.Text.Encoding.ASCII.GetString(header, formIndex, 4); // Größe der Datei auf FORM lesen uint datenGrosse = BitConverter.ToUInt32(header, formIndex + 4); // Überprüfen der Endianness, Byte umkehren if (BitConverter.IsLittleEndian) { datenGrosse = UintBytes(datenGrosse); } datenGrosseAlsString = datenGrosse.ToString(); } } // ********** BMHD Block lesen ********** private void lies_Bmhd(object sender, EventArgs e) { /* BMHD-Blockstruktur laut Dokumentation: Blocktyp (BMHD) bmhdIndex Byte 0-4 Unbenutzt (2 Bytes) bmhdIndex Byte 5-7 Bildbreite (2 Bytes) bmhdIndex Byte 8-9 Bildhöhe (2 Bytes) bmhdIndex Byte 10-11 X-Versatz (2 Bytes) bmhdIndex Byte 12-13 Y-Versatz (2 Bytes) bmhdIndex Byte 14-15 Anzahl der Bitplanes (1 Byte) bmhdIndex Byte 16 Maskierungstechnik (1 Byte) bmhdIndex Byte 17 Komprimierungstechnik (1 Byte) bmhdIndex Byte 18 Padbyte (1 Byte, ungenutzt bmhdIndex Byte 19 Transparentfarbe (2 Bytes) bmhdIndex Byte 20-21 X-Aspektverhältnis (1 Byte) bmhdIndex Byte 22 Y-Aspektverhältnis (1 Byte) bmhdIndex Byte 23 Bildschirmbreite (2 Bytes) bmhdIndex Byte 24-25 Bildschirmhöhe (2 Bytes) bmhdIndex Byte 26-27 */ using (FileStream fs = new FileStream(fileIFF, FileMode.Open, FileAccess.Read)) { BinaryReader br = new BinaryReader(fs); // Strung zu BMHD Block headerSize = bmhdIndex; br.BaseStream.Seek(headerSize, SeekOrigin.Begin); // nächsten 28 Byte lesen byte[] dataBytes = br.ReadBytes(28); bmhdType = System.Text.Encoding.ASCII.GetString(dataBytes, 0, 4); if (bmhdType == "BMHD") { // Bild Breit ushort uWordBreite = BitConverter.ToUInt16(dataBytes, 8); // Bild Höhe ushort uWordHoehe = BitConverter.ToUInt16(dataBytes, 10); // X-Versatz der Grafik ushort wordX = BitConverter.ToUInt16(dataBytes, 12); // Y-Versatz der Grafik ushort wordY = BitConverter.ToUInt16(dataBytes, 14); // Bitplanes byte tiefe = dataBytes[16]; // Maskiertechnik byte maske = dataBytes[17]; // Komprimiertechnik byte komorimiert = dataBytes[18]; // Transparent-Bitplanes ushort transcolor = BitConverter.ToUInt16(dataBytes, 20); // X-Ansicht byte xAspect = dataBytes[22]; // Y-Ansicht byte yAspect = dataBytes[23]; // Screenweite ushort wordBreite = BitConverter.ToUInt16(dataBytes, 24); // Screenbreite ushort wordHoehe = BitConverter.ToUInt16(dataBytes, 26); // Überprüfen der Endianness, Byte umkehren if (BitConverter.IsLittleEndian) { uWordBreite = ReverseBytes(uWordBreite); uWordHoehe = ReverseBytes(uWordHoehe); wordX = ReverseBytes(wordX); wordY = ReverseBytes(wordY); transcolor = ReverseBytes(transcolor); wordBreite = ReverseBytes(wordBreite); wordHoehe = ReverseBytes(wordHoehe); } bildBreite = Int32.Parse(uWordBreite.ToString()); bildHoehe = Int32.Parse(uWordHoehe.ToString()); xVersatz = Int32.Parse(wordX.ToString()); yVersatz = Int32.Parse(wordY.ToString()); bildTiefe = Int32.Parse(tiefe.ToString()); intMaske = Int32.Parse(maske.ToString()); transparent = Int32.Parse(transcolor.ToString()); kompresion = Int32.Parse(komorimiert.ToString()); xAspekt = Int32.Parse(xAspect.ToString()); yAspekt = Int32.Parse(yAspect.ToString()); xScreen = Int32.Parse(wordBreite.ToString()); yScreen = Int32.Parse(wordHoehe.ToString()); } } } // ********** IFF ILBM in Bitmap erstellen ********** private void bitmap_Erstellen(System.Object sender, EventArgs e) { if (intMaske != 0 || kompresion != 0) { MessageBox.Show("Zur Zeit konnen nur Bilder ohne Maske und Kompresion angezeigt werden!"); return; } // Bitmap erstellen Bitmap flag = new Bitmap(bildBreite, bildHoehe, PixelFormat.Format32bppArgb); using (FileStream fs = new FileStream(fileIFF, FileMode.Open, FileAccess.Read)) { BinaryReader br = new BinaryReader(fs); // Zu Bodydaten springen br.BaseStream.Seek(bodyIndex + 8, SeekOrigin.Begin); int byteBody = (bildBreite * bildHoehe * 3); byte[] bodyData = br.ReadBytes(byteBody); // Überprüfen, ob bodyData korrekt gelesen wurde if (bodyData == null || bodyData.Length == 0) { MessageBox.Show("Body-Daten konnten nicht gelesen werden."); return; } // Zähler für Sprunge berechenen blockZaehler = bildHoehe; bz = 0; bytezaehler = bildBreite / 8; // Zähler für Farbe blocksprung = (bildBreite * 24) / 8; // Zähler für Frabblock rotByteArray = 0; gruenByteArray = bytezaehler * 8; blauByteArray = bytezaehler * 16; rotByteIndex = rotByteArray; gruenByteIndex = gruenByteArray; blauByteIndex = blauByteArray; byte[] RotByte = new byte[8]; byte[] GruenByte = new byte[8]; byte[] BlauByte = new byte[8]; Debug.WriteLine($"\n\nBlockzähler: {blockZaehler}\nBlocksprung: {blocksprung}\nBytesprung: {bytezaehler}\n"); Debug.WriteLine($"RotByteArray: {rotByteArray} GrüneByteArray: {gruenByteArray} BlauByteArray: {blauByteArray}\n"); // Hautschleife für den Durchlaufen der Scannzeilen while (bz < blockZaehler) { // Schleife für Scannzeile for (zeile = 0; zeile < bildBreite / 8; zeile++) { // Arrays zurücksetzen Array.Clear(RotByte, 0, RotByte.Length); Array.Clear(GruenByte, 0, GruenByte.Length); Array.Clear(BlauByte, 0, BlauByte.Length); rotByteIndex = rotByteArray + zeile; gruenByteIndex = gruenByteArray + zeile; blauByteIndex = blauByteArray + zeile; // Rot auslesen für 8 Pixel for (int pixelPosRot = 0; pixelPosRot < 8; pixelPosRot++) { byte originalByte = bodyData[rotByteIndex]; byte reversedByte = ReverseBits(originalByte); pixelRGB[pixelPosRot] = reversedByte; Debug.WriteLine($"pixelPosRot: {pixelPosRot}, rotByteIndex: {rotByteIndex} - pixelRGB Rot: {pixelRGB[pixelPosRot]:X2}\n\n"); rotByteIndex = rotByteIndex + bytezaehler; } // Grün auslesen für 8 Pixel for (int pixelPosGruen = 8; pixelPosGruen < 16; pixelPosGruen++) { byte originalByte = bodyData[gruenByteIndex]; byte reversedByte = ReverseBits(originalByte); pixelRGB[pixelPosGruen] = reversedByte; Debug.WriteLine($"pixelPosGruen: {pixelPosGruen}, gruenByteIndex: {gruenByteIndex} - pixelRGB Grün: {pixelRGB[pixelPosGruen]:X2}\n\n"); gruenByteIndex = gruenByteIndex + bytezaehler; } // Blau auslesen für 8 Pixel for (int pixelPosBlau = 16; pixelPosBlau < 24; pixelPosBlau++) { byte originalByte = bodyData[blauByteIndex]; byte reversedByte = ReverseBits(originalByte); pixelRGB[pixelPosBlau] = reversedByte; Debug.WriteLine($"pixelPosBlau: {pixelPosBlau}, blauByteIndex: {blauByteIndex} - pixelRGB Blau: {pixelRGB[pixelPosBlau]:X2}\n\n"); blauByteIndex = blauByteIndex + bytezaehler; } // Bit Zuweissen for (int i = 0; i < 8; i++) { for (int bit = 0; bit < 8; bit++) { // RotByte RotByte[bit] |= (byte)((pixelRGB[i] & (1 << bit)) != 0 ? (1 << i) : 0); // GruenByte GruenByte[bit] |= (byte)((pixelRGB[i + 8] & (1 << bit)) != 0 ? (1 << i) : 0); // BlauByte BlauByte[bit] |= (byte)((pixelRGB[i + 16] & (1 << bit)) != 0 ? (1 << i) : 0); //Debug.WriteLine($"RotByte: {RotByte[bit]} GrüneByte: {GruenByte[bit]} BlauByte: {BlauByte[bit]}\n\n"); } } // Farben der Bitmap zuweisen for (int za = 0; za < 8; za++) { flag.SetPixel(bitmapZaehlerBreite, bitmapZaehlerHoehe, Color.FromArgb(255, RotByte[za], GruenByte[za], BlauByte[za])); Debug.WriteLine($"Breite: {bitmapZaehlerBreite} - Hoehe: {bitmapZaehlerHoehe}\n"); if (bitmapZaehlerBreite < bildBreite - 1) { bitmapZaehlerBreite += 1; } else { bitmapZaehlerBreite = 0; bitmapZaehlerHoehe++; } } } bz++; // Neuen Einsprung in Farbblock berechnen. rotByteArray = blocksprung * bz; gruenByteArray = rotByteArray + (bytezaehler * 8); blauByteArray = rotByteArray + (bytezaehler * 16); rotByteIndex = rotByteArray; gruenByteIndex = gruenByteArray; blauByteIndex = blauByteArray; Debug.WriteLine($"bz: {bz}\n"); Debug.WriteLine($"Einsprung Farbblock -> Rot Index: {rotByteIndex} Grün Index: {gruenByteIndex} Blau Index: {blauByteIndex}\n"); Debug.WriteLine("---------------------------------------------\n\n"); } } // Überprüfen, ob das Bitmap korrekt erstellt wurde if (flag != null) { pictureBox1.Image = flag; // In einer PictureBox anzeigen Debug.WriteLine("Bild erfolgreich der PictureBox zugewiesen."); } else { Debug.WriteLine("Fehler beim Erstellen des Bildes."); } } // ---------- Funktzionsrotinen ---------- // *************************************** // ********** Methode zum Finden eines Byte-Musters in einem Byte-Array ********** private int FindPattern(byte[] data, byte[] pattern) { for (int i = 0; i <= data.Length - pattern.Length; i++) { bool found = true; for (int j = 0; j < pattern.Length; j++) { if (data[i + j] != pattern[j]) { found = false; break; } } if (found) { return i; } } return -1; } // ********** uint Umkehren ********** private uint UintBytes(uint value) { return (value & 0x000000FFU) << 24 | (value & 0x0000FF00U) << 8 | (value & 0x00FF0000U) >> 8 | (value & 0xFF000000U) >> 24; } // ********** Byte umkehren ********** private ushort ReverseBytes(ushort value) { return (ushort)((value >> 8) | (value << 8)); } // Methode zum Umkehren der Bits eines Bytes public static byte ReverseBits(byte b) { byte result = 0; for (int i = 0; i < 8; i++) { result = (byte)((result << 1) | (b & 1)); b >>= 1; } return result; } } }