Exemplo n.º 1
0
        /// <summary>
        /// Erstellt eine neue Farbtabelle aus derm Bitmap-Puffer (d.h. aus einer binären Bitmap-Tabelle).
        /// </summary>
        /// <param name="buffer">Der Bitmap-Puffer mit einem Zeiger am Beginn der Farbtabelle.</param>
        /// <param name="count">Die Anzahl der in der Tabelle definierten Farben.</param>
        public ColorTable(ref RAMBuffer buffer, uint count)
        {
            // Einträge einzeln einlesen
            for(int i = 0; i < count; ++i)
            {
                // 4 Bytes lesen
                byte[] b = buffer.ReadByteArray(4);

                // Farbeintrag erstellen
                _colors[i] = Color.FromArgb(b[2], b[1], b[0]);
            }

            // Fehlende Einträge mit 255er-Weiß initialisieren
            for(int i = (int)count; i < 256; ++i)
            {
                // Weiß einfügen
                _colors[i] = Color.FromArgb(255, 255, 255);
            }
        }
Exemplo n.º 2
0
		/// <summary>
		/// Lädt die SLP-Daten.
		/// </summary>
		/// <param name="buffer">Ein Puffer mit den SLP-Daten. Die Leseposition wird entsprechend der Datenlänge erhöht.</param>
		/// <remarks></remarks>
		private void loadData(RAMBuffer buffer)
		{
			// Header

			#region SLP-Header

			_headers.Version = buffer.ReadString(4);
			_headers.FrameCount = buffer.ReadUInteger();
			_headers.Comment = buffer.ReadString(24);

			#endregion SLP-Header

			// Frame-Informationen: Header

			#region Frame-Header

			for(int i = 0; i < _headers.FrameCount; i++)
			{
				// Neues Frame-Header-Objekt erstellen
				FrameInformationHeader aktFIH = new FrameInformationHeader();

				// Der Zeichenindex in der SLP-Datei, an dem die Kommandotabelle des Frames beginnt
				aktFIH.FrameCommandsOffset = buffer.ReadUInteger();

				// Der Zeichenindex in der SLP-Datei, an dem die Umrissdaten (RowEdge) des Frames gespeichert sind
				aktFIH.FrameOutlineOffset = buffer.ReadUInteger();

				// Der Zeichenindex in der SLP-Datei, an dem die Farbpalette des Frames definiert ist; Genaueres ist nicht bekannt
				aktFIH.PaletteOffset = buffer.ReadUInteger();

				// Die Frame-Eigenschaften; die Bedeutung dieses Werts ist unbekannt
				aktFIH.Properties = buffer.ReadUInteger();

				// Die Abmessungen des Frames
				aktFIH.Width = buffer.ReadUInteger();
				aktFIH.Height = buffer.ReadUInteger();

				// Die Anker (Mittelpunkt) des Frames
				aktFIH.AnchorX = buffer.ReadInteger();
				aktFIH.AnchorY = buffer.ReadInteger();

				// Frame-Header in die zentrale Liste schreiben
				_frameInformationHeaders.Add(aktFIH);
			}

			#endregion Frame-Header

			// Frameinformationen: Daten

			#region Frame-Daten (RowEdge und Kommandotabelle)

			// Gefundene Einstellungen merken
			bool useTransp = false;
			bool useOutline1 = false;
			bool useOutline2 = false;
			bool usePlayerColor = false;
			bool useShadow = false;

			// Frames einzeln durchgehen
			for(int i = 0; i < _headers.FrameCount; i++)
			{
				// Spielernummer einer ggf. ausgegebenen Einheit
				const byte Spielernummer = 0; // Spieler 1 => Blau

				// Frame-Header-Daten abrufen
				FrameInformationHeader aktFIH = _frameInformationHeaders[i];

				// Neues Frame-Daten-Objekt erstellen
				FrameInformationData aktFID = new FrameInformationData();

				// RowEdge (leere Fläche [=> Transparenz, ohne Kommandos], von den Bildrändern ausgehend)

				#region RowEdge-Daten

				// Arrays initialisieren: Das RowEdge-Array und das BinaryRowEdge-Array, um bei unveränderten Frames dieses nicht neu berechnen zu müssen und direkt schreiben zu können
				aktFID.RowEdge = new ushort[aktFIH.Height, 2];
				aktFID.BinaryRowEdge = new BinaryRowedge[aktFIH.Height];
				for(int j = 0; j < aktFIH.Height; j++)
				{
					// Werte einlesen
					ushort left = buffer.ReadUShort(); // Links
					ushort right = buffer.ReadUShort(); // Rechts

					// Evtl. falsche Werte korrigieren
					{
						// Links
						if(left > aktFIH.Width)
						{
							left = (ushort)aktFIH.Width;
						}

						// Rechts
						if(right > aktFIH.Width)
						{
							right = (ushort)aktFIH.Width;
						}
					}

					// Werte speichern
					aktFID.RowEdge[j, 0] = left;
					aktFID.RowEdge[j, 1] = right;

					// Binäres RowEdge mitschreiben
					aktFID.BinaryRowEdge[j] = new BinaryRowedge(left, right);
				}

				#endregion RowEdge-Daten

				// Kommandotabellen-Offsets abrufen

				#region Kommandotabellen-Offsets

				aktFID.CommandTableOffsets = new uint[aktFIH.Height];
				for(int j = 0; j < aktFIH.Height; j++)
				{
					aktFID.CommandTableOffsets[j] = buffer.ReadUInteger();
				}

				#endregion Kommandotabellen-Offsets

				// Kommandotabelle zeilenweise auslesen und umgewandelte Kommandotabelle erzeugen

				#region Kommandotabelle

				// Gleichzeitig wird die binaryCommands-Variable miterzeugt, um unveränderte Frames ggf. ohne Umweg über eine Neuerstellung der Kommandos wieder in die *.slp schreiben zu können
				aktFID.CommandTable = new int[aktFIH.Height, aktFIH.Width];
				aktFID.BinaryCommandTable = new List<BinaryCommand>();
				for(int j = 0; j < aktFIH.Height; j++)
				{
					// Gibt die aktuelle X-Position innerhalb des generierten Bildes (in Pixeln) an
					int aktPtr = 0;

					// Linker RowEdge-Bereich ist leer => transparent, also -1
					for(int k = 0; k < aktFID.RowEdge[j, 0]; k++)
					{
						aktFID.CommandTable[j, aktPtr + k] = -1;
					}

					// Linker RowEdge-Bereich ist komplett in das Bild geschrieben worden
					aktPtr += aktFID.RowEdge[j, 0];

					// Wird false, wenn ein Zeilenumbruch erreicht wurde
					bool Weiter = true;

					// Kommando für Kommando lesen
					while(Weiter)
					{
						// Das aktuelle Kommandobyte
						byte aktKommandoByte = buffer.ReadByte();

						// Das aktuelle Kommando (die ersten vier Bits des Kommandobytes) Wird berechnet, um das oft mit der Datenlänge korrelierte Kommandobyte bestimmen zu können (es müssen nur die Werte 0 bis 15 abgefragt werden, statt eigentlich 0 bis 255; weiterhin geben immer die ersten 2 oder 4 Bits das Kommando an, die anderen 4 oder 6 meist nur die jeweilige Länge)
						byte aktKommando = (byte)(aktKommandoByte & 0x0F);

						// Das Kommando auswerten
						switch(aktKommando)
						{
							// Farbblock (klein)
							case 0x00:
							case 0x04:
							case 0x08:
							case 0x0C:
								{
									// Länge ermitteln
									int len = aktKommandoByte >> 2;

									// Daten einlesen
									byte[] dat = buffer.ReadByteArray(len);

									// Daten in die Kommandotabelle schreiben
									for(int k = 0; k < len; k++)
									{
										aktFID.CommandTable[j, aktPtr + k] = dat[k];
									}

									// Es wurden len Pixel eingelesen
									aktPtr += len;

									// Binary-Wert erstellen
									cmdColor(ref aktFID, dat);

									break;
								}

							// Transparenz (klein)
							case 0x01:
							case 0x05:
							case 0x09:
							case 0x0D:
								{
									// Länge ermitteln
									int len = aktKommandoByte >> 2;

									// Transparenz in die Kommandotabelle schreiben
									for(int k = 0; k < len; k++)
									{
										aktFID.CommandTable[j, aktPtr + k] = -1;
									}

									// Es wurden len Pixel eingelesen
									aktPtr += len;

									// Binary-Wert erstellen
									cmdTransp(ref aktFID, len);

									// Transparenz wurde gefunden
									useTransp = true;

									break;
								}

							// Großer Farbblock
							case 0x02:
								{
									// Hilfs-Kommandobyte auslesen
									byte byte2 = buffer.ReadByte();

									// Länge ermitteln
									int len = ((aktKommandoByte & 0xF0) << 4) + byte2;

									// Daten einlesen
									byte[] dat = buffer.ReadByteArray(len);

									// Daten in die Kommandotabelle schreiben
									for(int k = 0; k < len; k++)
									{
										aktFID.CommandTable[j, aktPtr + k] = dat[k];
									}

									// Es wurden len Pixel eingelesen
									aktPtr += len;

									// Binary-Wert erstellen
									cmdColor(ref aktFID, dat);

									break;
								}

							// Großer Transparenzblock
							case 0x03:
								{
									// Hilfs-Kommandobyte auslesen
									byte byte2 = buffer.ReadByte();

									// Länge ermitteln
									int len = ((aktKommandoByte & 0xF0) << 4) + byte2;

									// Transparenz in die Kommandotabelle schreiben
									for(int k = 0; k < len; k++)
									{
										aktFID.CommandTable[j, aktPtr + k] = -1;
									}

									// Es wurden len Pixel eingelesen
									aktPtr += len;

									// Binary-Wert erstellen
									cmdTransp(ref aktFID, len);

									// Transparenz wurde gefunden
									useTransp = true;

									break;
								}

							// Spielerfarbenblock
							case 0x06:
								{
									// Die oberen 4 Bits bestimmen
									byte next4Bits = (byte)(aktKommandoByte & 0xF0);

									// Die Länge der Daten
									int len = 0;

									// Die oberen 4 Bits sind 0, wenn die Länge im nächsten Byte angegeben ist; ansonsten werden diese um 4 nach rechts verschoben und sind somit als Längenangabe verwendbar
									if(next4Bits == 0)
									{
										len = buffer.ReadByte();
									}
									else
									{
										len = next4Bits >> 4;
									}

									// Daten auslesen
									byte[] dat = buffer.ReadByteArray(len);

									// Daten durchgehen
									for(int k = 0; k < len; k++)
									{
										// Das aktuelle Byte
										byte aktVal = dat[k];

										// Farbindex berechnen: Die Spielerfarben liegen zwischen 16 und 13. Beim SLP-Schreiben wurde von allen Werten 16 subtrahiert => aktVal liegt zwischen 0 und 7. Zwischen den Spielerfarben auf der Palette liegen immer 16 Einheiten. Angegeben wird die Spielerfarbe durch: 16 + (Spielernummer - 1) * 16, wobei die Spielernummer zwischen 1 und 8 liegt.
										aktVal = (byte)(aktVal + 16 + 16 * Spielernummer);

										// Wert in das Bild schreiben
										aktFID.CommandTable[j, aktPtr + k] = aktVal;

										// Wert zurück in Array schreiben, um das Schreiben der Binary-Daten zu erleichtern
										dat[k] += 16;
									}

									// Es wurden len Pixel eingelesen
									aktPtr += len;

									// Binary-Wert erstellen
									cmdPlayerColor(ref aktFID, dat);

									// Spielerfarben wurden gefunden
									usePlayerColor = true;

									break;
								}

							// Einfarbiger Block
							case 0x07:
								{
									// Die oberen 4 Bits bestimmen
									byte next4Bits = (byte)(aktKommandoByte & 0xF0);

									// Die Länge der Daten
									int len = 0;

									// Die oberen 4 Bits sind 0, wenn die Länge im nächsten Byte angegeben ist; ansonsten werden diese um 4 nach rechts verschoben und sind somit als Längenangabe verwendbar
									if(next4Bits == 0)
									{
										len = buffer.ReadByte();
									}
									else
									{
										len = next4Bits >> 4;
									}

									// Das nächste Byte gibt die Farbe an
									byte farbe = buffer.ReadByte();

									// Hilfsvariable für das Binary-Schreiben
									byte[] dat = new byte[len];

									// Betroffene Pixel durchgehen
									for(int k = 0; k < len; k++)
									{
										// Farbe in das Bild schreiben
										aktFID.CommandTable[j, aktPtr + k] = farbe;

										// Farbe in das Array übernehmen
										dat[k] = farbe;
									}

									// Es wurden len Pixel eingelesen
									aktPtr += len;

									// Binary-Wert erstellen
									cmdColor(ref aktFID, dat);

									break;
								}

							// Einfarbiger Spielerfarben-Block
							case 0x0A:
								{
									// Die oberen 4 Bits bestimmen
									byte next4Bits = (byte)(aktKommandoByte & 0xF0);

									// Die Länge der Daten
									int len = 0;

									// Die oberen 4 Bits sind 0, wenn die Länge im nächsten Byte angegeben ist; ansonsten werden diese um 4 nach rechts verschoben und sind somit als Längenangabe verwendbar
									if(next4Bits == 0)
									{
										len = buffer.ReadByte();
									}
									else
									{
										len = next4Bits >> 4;
									}

									// Das nächste Byte gibt die Grundfarbe an
									byte farbe = buffer.ReadByte();

									// Hilfsvariable für das Binary-Schreiben
									byte[] dat = new byte[len];

									// Daten durchgehen
									for(int k = 0; k < len; k++)
									{
										// Das aktuelle Byte
										byte aktVal = farbe;

										// Farbindex berechnen: Die Spielerfarben liegen zwischen 16 und 13. Beim SLP-Schreiben wurde von allen Werten 16 subtrahiert => aktVal liegt zwischen 0 und 7. Zwischen den Spielerfarben auf der Palette liegen immer 16 Einheiten. Angegeben wird die Spielerfarbe durch: 16 + (Spielernummer - 1) * 16, wobei die Spielernummer zwischen 1 und 8 liegt.
										aktVal = (byte)(aktVal + 16 + 16 * Spielernummer);

										// Wert in das Bild schreiben
										aktFID.CommandTable[j, aktPtr + k] = aktVal;

										// Wert zurück in Array schreiben, um das Schreiben der Binary-Daten zu erleichtern
										dat[k] = (byte)(farbe + 16);
									}

									// Es wurden len Pixel eingelesen
									aktPtr += len;

									// Binary-Wert erstellen
									cmdPlayerColor(ref aktFID, dat);

									// Spielerfarben wurden gefunden
									usePlayerColor = true;

									break;
								}

							// Schattenblock
							case 0x0B:
								{
									// Die oberen 4 Bits bestimmen
									byte next4Bits = (byte)(aktKommandoByte & 0xF0);

									// Die Länge der Daten
									int len = 0;

									// Die oberen 4 Bits sind 0, wenn die Länge im nächsten Byte angegeben ist; ansonsten werden diese um 4 nach rechts verschoben und sind somit als Längenangabe verwendbar
									if(next4Bits == 0)
									{
										len = buffer.ReadByte();
									}
									else
									{
										len = next4Bits >> 4;
									}

									// Schattenpixel einzeln durchgehen
									for(int k = 0; k < len; k++)
									{
										// Schatten in Bild schreiben
										aktFID.CommandTable[j, aktPtr + k] = -4;
									}

									// Es wurden len Pixel eingelesen
									aktPtr += len;

									// Binary-Wert erstellen
									cmdShadow(ref aktFID, len);

									// Schatten wurde gefunden
									useShadow = true;

									break;
								}

							// Outline-Kommandos: Hängen von Kommandobyte ab ("E" am Ende bei allen gemeinsam)
							case 0x0E:
								{
									switch(aktKommandoByte)
									{
										// Outline1-Pixel
										case 0x4E:
											{
												// Outline auf Bild schreiben
												aktFID.CommandTable[j, aktPtr] = -2;

												// Es wurde ein Pixel eingelesen
												aktPtr += 1;

												// Binary-Wert erstellen
												cmdOutline1(ref aktFID, 1);

												// Outline1 wurde gefunden
												useOutline1 = true;

												break;
											}

										// Outline2-Pixel
										case 0x6E:
											{
												// Outline auf Bild schreiben
												aktFID.CommandTable[j, aktPtr] = -3;

												// Es wurde ein Pixel eingelesen
												aktPtr += 1;

												// Binary-Wert erstellen
												cmdOutline2(ref aktFID, 1);

												// Outline2 wurde gefunden
												useOutline2 = true;

												break;
											}

										// Outline1-Block
										case 0x5E:
											{
												// Blocklänge abrufen
												int len = buffer.ReadByte();

												// Outlinepixel in der angegebenen Anzahl auf das Bild schreiben
												for(int k = 0; k < len; k++)
												{
													aktFID.CommandTable[j, aktPtr + k] = -2;
												}

												// Es wurden len Pixel eingelesen
												aktPtr += len;

												// Binary-Wert erstellen
												cmdOutline1(ref aktFID, len);

												// Outline1 wurde gefunden
												useOutline1 = true;

												break;
											}

										// Outline2-Block
										case 0x7E:
											{
												// Blocklänge abrufen
												int len = buffer.ReadByte();

												// Outlinepixel in der angegebenen Anzahl auf das Bild schreiben
												for(int k = 0; k < len; k++)
												{
													aktFID.CommandTable[j, aktPtr + k] = -3;
												}

												// Es wurden len Pixel eingelesen
												aktPtr += len;

												// Binary-Wert erstellen
												cmdOutline2(ref aktFID, len);

												// Outline2 wurde gefunden
												useOutline2 = true;

												break;
											}
									}
									break;
								}

							// Zeilenende
							case 0x0F:
								{
									// Kein weiterer while-Schleifen-Durchlauf => nächste Zeile (for-Schleife)
									Weiter = false;

									// Binary-Wert erstellen
									cmdEOL(ref aktFID);

									break;
								}
						} // Ende switch: Kommando auswerten
					} // Ende while: Kommando für Kommando

					// Rechtes RowEdge einfügen (leere Bereiche) Leere Bereiche sind transparent, also erstmal -1 als Palettenindex schreiben
					for(int k = 0; k < aktFID.RowEdge[j, 1]; k++)
					{
						aktFID.CommandTable[j, aktPtr + k] = -1;
					}
					aktPtr += aktFID.RowEdge[j, 1];
				} // Ende for: Zeile für Zeile

				#endregion Kommandotabelle

				// Framedaten zur zentralen Liste hinzufügen
				_frameInformationData.Add(aktFID);
			} // Ende for: Frame für Frame

			// Einstellungen speichern
			_settings = (useTransp ? Settings.UseTransparency : 0)
				| (useOutline1 ? Settings.UseOutline1 : 0)
				| (useOutline2 ? Settings.UseOutline2 : 0)
				| (usePlayerColor ? Settings.UsePlayerColor : 0)
				| (useShadow ? Settings.UseShadow : 0);

			#endregion Frame-Daten (RowEdge und Kommandotabelle)
		}
Exemplo n.º 3
0
            /// <summary>
            /// Erstellt aus der angegebenen Binär-Datei eine neue External-File-Struktur.
            /// </summary>
            /// <param name="data">Die auszulesende Binär-Datei.</param>
            /// <returns></returns>
            /// <remarks></remarks>
            public static ExternalFile FromBinary(RAMBuffer data)
            {
                // An den Anfang springen
                data.Position = 0;

                // Der Rückgabewert
                ExternalFile ret = new ExternalFile();

                // Ausnahmen abfangen für ungültige Dateien
                try
                {
                    // DRS-Dateiname
                    uint drsNameLen = data.ReadUInteger();
                    ret.DRSFile = System.Text.Encoding.ASCII.GetString(data.ReadByteArray((int)drsNameLen));

                    // Datei-ID
                    ret.FileID = data.ReadUInteger();

                    // Ressourcen-Typ
                    uint resTypeLen = data.ReadUInteger();
                    ret.ResourceType = System.Text.Encoding.ASCII.GetString(data.ReadByteArray((int)resTypeLen));

                    // Data
                    uint dataLen = data.ReadUInteger();
                    ret.Data = data.ReadByteArray((int)dataLen);
                }
                catch
                {
                    // Fehler
                    MessageBox.Show("Fehler: Das Datenobjekt konnte nicht fehlerfrei in ein ExternalFile-Objekt umgewandelt werden!", "Fehler", MessageBoxButtons.OK, MessageBoxIcon.Error);
                }

                // Fertig
                return ret;
            }
Exemplo n.º 4
0
        /// <summary>
        /// Fügt eine Ressource hinzu oder ersetzt diese.
        /// </summary>
        /// <param name="data">Die hinzuzufügende / zu ersetzende Ressource.</param>
        /// <param name="resourceID">Die ID der hinzuzufügenden / zu ersetzenden Ressource.</param>
        /// <param name="resourceType">Der Typ der Ressource, rückwärts geschrieben und drei Zeichen lang.</param>
        /// <remarks></remarks>
        public void AddReplaceRessource(RAMBuffer data, ushort resourceID, string resourceType)
        {
            // Neue Ressource?
            if(!_files.ContainsKey(resourceID))
            {
                // Die zu ermittelnden Tabelleninfos
                TableInfo myTI = new TableInfo();
                Table myT = new Table();

                // Suchen der Tabelle mit dem passenden Ressourcen-Typen
                int i;
                bool found = false;
                for(i = 0; i < _tableInfos.Count; ++i)
                {
                    // Passender Ressourcen-Typ?
                    if(_tableInfos[i].ResourceType == resourceType)
                    {
                        // Tabelleninfos merken
                        myTI = _tableInfos[i];
                        myT = _tables[i];
                        found = true;
                        break;
                    }
                }

                // Neue Tabelle erforderlich?
                if(!found)
                {
                    // Tabelleninfo anlegen
                    myTI.Unknown1 = (byte)'a';
                    myTI.TableOffset = 0;
                    myTI.ResourceType = resourceType;
                    myTI.FileCount = 0;
                    _tableInfos.Add(myTI);

                    // Neue Tabelle ist der einzige Eintrag
                    myT.Entries = new List<TableEntry>();
                    _tables.Add(myT);
                }

                // Eine Datei mehr
                myTI.FileCount += 1;

                // Tabelleneintrag für die Datei erstellen
                TableEntry eintr = new TableEntry();
                eintr.FileSize = (uint)data.Length;
                eintr.FileID = resourceID;
                myT.Entries.Add(eintr);

                // Datei speichern
                data.Position = 0;
                _files.Add(resourceID, data.ReadByteArray(data.Length));

                // Tabelleninfos speichern
                _tableInfos[i] = myTI;
                _tables[i] = myT;
            }
            else
            {
                // Ressource ersetzen
                data.Position = 0;
                _files[resourceID] = data.ReadByteArray(data.Length);

                // Tabellen durchlaufen und passende Datei-ID suchen
                Table currTable;
                TableEntry currEntry;
                for(int i = 0; i < _tables.Count; ++i)
                {
                    // Aktuelle Tabelle abrufen
                    currTable = _tables[i];

                    // Eintrag mit passender Datei-ID suchen
                    for(int j = 0; j < currTable.Entries.Count; ++j)
                    {
                        // Eintrg abrufen
                        currEntry = currTable.Entries[j];

                        // Passende ID?
                        if(currEntry.FileID == resourceID)
                        {
                            // Dateigröße ersetzen
                            currEntry.FileSize = (uint)data.Length;
                            _tables[i].Entries[j] = currEntry;

                            // Fertig
                            return;
                        }
                    }
                }
            }
        }
Exemplo n.º 5
0
        /// <summary>
        /// Lädt die angegebene Bitmap-Datei.
        /// </summary>
        /// <param name="filename">Der Pfad zur zu ladenden Bitmap-Datei.</param>
        /// <param name="pal">Optional. Gibt die zu verwendende 256er-Farbtabelle an. Sonst wird die entweder die im Bitmap angegebene oder die 50500er-Farbtabelle verwendet.</param>
        public BitmapLoader(string filename, JASCPalette pal = null)
        {
            // Datei laden
            _buffer = new RAMBuffer(filename);

            // Header laden
            _header = new Header();
            _header.type = ReadUShort();
            _header.fileSize = ReadUInteger();
            _header.reserved = ReadUInteger();
            _header.offsetData = ReadUInteger();
            _header.imageHeaderSize = ReadUInteger();
            _header.width = ReadInteger();
            _header.height = ReadInteger();
            _header.layerCount = ReadUShort();
            _header.bitsPerPixel = ReadUShort();
            _header.compression = ReadUInteger();
            _header.size = ReadUInteger();
            _header.xDPI = ReadInteger();
            _header.yDPI = ReadInteger();
            _header.colorCount = ReadUInteger();
            _header.colorImportantCount = ReadUInteger();

            // Farbtabellenanzahl nachjustieren
            if(_header.colorCount == 0 && _header.bitsPerPixel == 8)
                _header.colorCount = 256;

            // Farbtabelle laden
            bool needAdjustColorTable = false;
            if(_header.colorCount > 0)
            {
                // Bildfarbtabelle laden
                _colorTable = new ColorTable(ref _buffer, _header.colorCount);

                // Falls eine Palette übergeben wurde, diese mit der Bildtabelle vergleichen
                if(pal == null || pal._farben.GetLength(0) != 256)
                    needAdjustColorTable = true;
                else
                    for(int i = 0; i < 256; ++i)
                    {
                        // Farben vergleichen
                        Color aktF = _colorTable[i];
                        if(pal._farben[i, 0] != aktF.R || pal._farben[i, 1] != aktF.G || pal._farben[i, 2] != aktF.B)
                        {
                            // Farbtabellen unterscheiden sich
                            needAdjustColorTable = true;
                            break;
                        }
                    }
            }
            else
            {
                // Bei 24-Bit-Bitmaps wird die Farbtabelle später geladen
                _colorTable = null;
            }

            // Nach Bitzahl unterscheiden
            if(_header.bitsPerPixel == 8)
            {
                // Bilddatenbreite ggf. auf ein Vielfaches von 4 Bytes erhöhen
                int width = _header.width; // Hilfsvariable zur Performanceerhöhung (immer gleichwertig mit _header.width)
                int width2 = width;
                while(width2 % 4 != 0)
                {
                    width2++;
                }

                // Binäre Original-Bilddaten einlesen
                _imageDataBin = _buffer.ReadByteArray(width2 * Math.Abs(_header.height));

                // Neues Bilddaten-Array anlegen (ohne Füllbytes)
                _imageData = new byte[width * Math.Abs(_header.height)];

                // Richtung bestimmen
                bool dirTopDown = (_header.height < 0);

                // Der bisher nächste Farbindex
                byte nearestIndex = 0;

                // Der Abstand zum bisher nächsten Farbindex
                double nearestDistance;

                // Der aktuelle Farbabstand
                double tempDistance = 0.0;

                // Bilddaten abrufen
                int height2 = Math.Abs(_header.height);
                for(int x = 0; x < width2; x++)
                {
                    for(int y = 0; y < height2; y++)
                    {
                        // Wenn es sich bei dem aktuellen Pixel um kein Füllbyte handelt, diesen übernehmen
                        if(x < width)
                        {
                            // Pixel abrufen
                            byte aktCol = _imageDataBin[y * width2 + x];

                            // TODO: 0-Indizes in 255 umwandeln??

                            // Falls nötig, Farben vergleichen
                            if(needAdjustColorTable)
                            {
                                // Alle Farbwerte abrufen
                                byte aktB = _colorTable[aktCol].B;
                                byte aktG = _colorTable[aktCol].G;
                                byte aktR = _colorTable[aktCol].R;

                                // Die zur Pixelfarbe nächste Palettenfarbe suchen
                                {
                                    // Werte zurücksetzen
                                    nearestIndex = 0;
                                    nearestDistance = 441.673; // Anfangswert: maximaler möglicher Abstand

                                    // Alle Einträge durchgehen
                                    for(int i = 0; i < 256; i++)
                                    {
                                        // Aktuelle Paletten-RGB-Werte abrufen
                                        byte pR = pal._farben[i, 0];
                                        byte pG = pal._farben[i, 1];
                                        byte pB = pal._farben[i, 2];

                                        // Gleiche Einträge sofort filtern
                                        if(aktR == pR && aktB == pB && aktG == pG)
                                        {
                                            // Paletten-Index überschreiben
                                            nearestIndex = (byte)i;

                                            // Fertig
                                            break;
                                        }

                                        // Abstand berechnen (Vektorlänge im dreidimensionalen RGB-Farbraum)
                                        tempDistance = Math.Sqrt(Math.Pow(aktR - pR, 2) + Math.Pow(aktG - pG, 2) + Math.Pow(aktB - pB, 2));

                                        // Vergleichen
                                        if(tempDistance < nearestDistance)
                                        {
                                            // Index merken
                                            nearestDistance = tempDistance;
                                            nearestIndex = (byte)i;
                                        }
                                    }

                                    // Paletten-Index überschreiben
                                    aktCol = nearestIndex;
                                }
                            } // Ende Adjust-ColorTable

                            // Pixel zum Hauptbildarray hinzufügen und dabei nach Top-Down / Bottom-Up unterscheiden
                            _imageData[(dirTopDown ? y : height2 - y - 1) * width + x] = aktCol;
                        }
                    }
                }
            }
            else if(_header.bitsPerPixel == 24)
            {
                // Es handelt sich um ein 24-Bit-Bitmap, somit muss eine Farbtabelle eingeführt werden
                {
                    // Farbpalettenreader abrufen
                    JASCPalette tempPal;
                    if(pal == null)
                        tempPal = new JASCPalette(new RAMBuffer(BitmapLibrary.Properties.Resources.pal50500));
                    else
                        tempPal = pal;

                    // Farbpaletteninhalt in eigene Farbtabelle schreiben
                    _colorTable = new ColorTable();
                    for(int i = 0; i < tempPal._farben.GetLength(0); i++)
                    {
                        // Eintrag in Tabelle einfügen
                        _colorTable[i] = Color.FromArgb(tempPal._farben[i, 0], tempPal._farben[i, 1], tempPal._farben[i, 2]);

                        // Sicherheitshalber bei i = 255 abbrechen (falls Palette zu groß sein sollte)
                        if(i == 255)
                            break;
                    }
                }

                // Bilddatenbreite ggf. auf ein Vielfaches von 4 Bytes erhöhen
                int width = _header.width; // Hilfsvariable zur Performanceerhöhung (immer gleichwertig mit _header.width)
                int fillBytes = 0;
                while(((width * 3) + fillBytes) % 4 != 0)
                {
                    fillBytes++;
                }

                // Binäre Original-Bilddaten einlesen
                _imageDataBin = _buffer.ReadByteArray((3 * width + fillBytes) * Math.Abs(_header.height));

                // Neues Bilddaten-Array anlegen (ohne Füllbytes)
                _imageData = new byte[width * Math.Abs(_header.height)];

                // Richtung bestimmen
                bool dirTopDown = (_header.height < 0);

                // Der bisher nächste Farbindex
                byte nearestIndex = 0;

                // Der Abstand zum bisher nächsten Farbindex
                double nearestDistance;

                // Der aktuelle Farbabstand
                double tempDistance = 0.0;

                // Bilddaten abrufen
                int height2 = Math.Abs(_header.height);
                for(int x = 0; x < width; x++)
                {
                    for(int y = 0; y < height2; y++)
                    {
                        // Pixel abrufen
                        byte aktB = _imageDataBin[y * (3 * width + fillBytes) + 3 * x];
                        byte aktG = _imageDataBin[y * (3 * width + fillBytes) + 3 * x + 1];
                        byte aktR = _imageDataBin[y * (3 * width + fillBytes) + 3 * x + 2];

                        // Die zur Pixelfarbe nächste Palettenfarbe suchen
                        {
                            // Werte zurücksetzen
                            nearestIndex = 0;
                            nearestDistance = 441.673; // Anfangswert: maximaler möglicher Abstand

                            // Alle Einträge durchgehen
                            for(int i = 0; i < 256; i++)
                            {
                                // Aktuelle Paletten-RGB-Werte abrufen
                                byte pR = _colorTable[i].R;
                                byte pG = _colorTable[i].G;
                                byte pB = _colorTable[i].B;

                                // Gleiche Einträge sofort filtern
                                if(aktR == pR && aktB == pB && aktG == pG)
                                {
                                    // Pixel zum Hauptbildarray hinzufügen und dabei nach Top-Down / Bottom-Up unterscheiden
                                    _imageData[(dirTopDown ? y : height2 - y - 1) * width + x] = (byte)i;

                                    // Fertig
                                    break;
                                }

                                // Abstand berechnen (Vektorlänge im dreidimensionalen RGB-Farbraum)
                                tempDistance = Math.Sqrt(Math.Pow(aktR - pR, 2) + Math.Pow(aktG - pG, 2) + Math.Pow(aktB - pB, 2));

                                // Vergleichen
                                if(tempDistance < nearestDistance)
                                {
                                    // Index merken
                                    nearestDistance = tempDistance;
                                    nearestIndex = (byte)i;
                                }
                            }

                            // Pixel zum Hauptbildarray hinzufügen und dabei nach Top-Down / Bottom-Up unterscheiden
                            _imageData[(dirTopDown ? y : height2 - y - 1) * width + x] = nearestIndex;
                        }
                    }

                    // Ggf. Füllbytes überspringen (bei Dateiende nicht)
                    if(_buffer.Position < _buffer.Length - fillBytes)
                        _buffer.Position = (_buffer.Position + fillBytes);
                }
            }
        }