Example #1
0
        /// <summary>
        /// Erstellt eine neue Farbtabelle aus einen angegebenen JASCPalette-Objekt. <param name="pal">Die zu ladende JASC-Palette.</param>
        /// </summary>
        public ColorTable(JASCPalette pal)
        {
            // Anzahl der Farben in pal verwenden, aber maximal 256
            int count = Math.Min(pal._farben.GetLength(0), 256);

            // Alle Farben der Palette durchlaufen
            for(int i = 0; i < count; i++)
            {
                // Farbeintrag erstellen
                _colors[i] = Color.FromArgb(pal._farben[i, 0], pal._farben[i, 1], pal._farben[i, 2]);
            }
        }
Example #2
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);
                }
            }
        }