TIcon::SaveToFile - Error?



  • Die Betonung in TIcon lag auf T.



  • Würde sich das mit 256 Farbe über die WinAPI realisieren lassen?



  • Natürlich. Du kannst auch 2^16 Farben nehmen, wenn du lustig bist. Wäre aber etwas zu viel des guten Geschmacks. Ich habe mal etwas geschrieben, das die Anzahl der Farben in einem Icon ausliest und dann das Icon speichert. Willst du das haben?

    [EDIT]Blöde Frage. Natürlich willst du das haben. Hier die ganze Unit:

    Die Header-Datei:

    //---------------------------------------------------------------------------
    #ifndef IconHandlingH
    #define IconHandlingH
    //---------------------------------------------------------------------------
    #include <Graphics.hpp>
    //---------------------------------------------------------------------------
    //-----  Struktur - Definitionen  -------------------------------------------
    typedef struct
    {
        WORD             idReserved;
        WORD             idType;
        WORD             idCount;
    } ICONDIR, *LPICONDIR;
    
    typedef struct
    {
        BYTE             bWidth;
        BYTE             bHeight;
        BYTE             bColorCount;
        BYTE             bReserved;
        WORD             wPlanes;
        WORD             wBitCount;
        DWORD            dwBytesInRes;
        DWORD            dwImageOffset;
    } ICONDIRENTRY, *LPICONDIRENTRY;
    
    typedef struct
    {
        BITMAPINFOHEADER icHeader;
        RGBQUAD*         icColors;
        BYTE*            icXOR;
        BYTE*            icAND;
    } ICONIMAGE, *LPICONIMAGE;
    
    typedef struct
    {
        BYTE             rgbBlue;
        BYTE             rgbGreen;
        BYTE             rgbRed;
        BYTE             rgbOptional;
    } BGRCOLOR;
    
    typedef struct
    {
        int ColorCount;
        WORD TransparentNo;
    } COLORTABLEINFO;
    //---------------------------------------------------------------------------
    
    void PushLeft(char* byte, bool bit);
    BGRCOLOR MakeBGR(COLORREF color);
    bool IsEqual(BGRCOLOR bgr, COLORREF ref);
    COLORTABLEINFO CountColors(Graphics::TBitmap* bmp, BGRCOLOR* ColorTable, BYTE* PixelColorNo, COLORREF clTransparent);
    void MakeMask256(char* bytes, BYTE* PixelColorNo, WORD TransparentNo);
    void SaveIcon(TIcon* ico, char* fn);
    void SaveIcon(Graphics::TBitmap* bmp, COLORREF clTransparent, char* fn);
    void SaveIcon256Colors(BGRCOLOR* ColorTable, BYTE* PixelColorNo, WORD TransparentNo, char* fn);
    void SaveIcon16Colors(BGRCOLOR* ColorTable, BYTE* PixelColorNo, WORD TransparentNo, char* fn);
    void SaveIconTrueColor(Graphics::TBitmap* bmp, COLORREF clTransparent, char* fn);
    //---------------------------------------------------------------------------
    #endif
    

    Und hier die cpp-Datei:

    //---------------------------------------------------------------------------
    #include <vcl.h>
    #pragma hdrstop
    
    #include "IconHandling.h"
    //---------------------------------------------------------------------------
    
    void PushLeft(char* byte, bool bit)
    {
      byte[0] = byte[0] << 1;
      byte[0] = byte[0] + bit;
    }
    //---------------------------------------------------------------------------
    
    BGRCOLOR MakeBGR(COLORREF color)
    {
      BGRCOLOR retval;
      retval.rgbBlue     = LOBYTE(HIWORD(color));
      retval.rgbGreen    = HIBYTE(LOWORD(color));
      retval.rgbRed      = LOBYTE(LOWORD(color));
      retval.rgbOptional = HIBYTE(HIWORD(color));
      return retval;
    }
    //---------------------------------------------------------------------------
    
    bool IsEqual(BGRCOLOR bgr, COLORREF ref)
    {
      bool retval = false;
      if(bgr.rgbBlue  == LOBYTE(HIWORD(ref)))
        if(bgr.rgbGreen == HIBYTE(LOWORD(ref)))
          if(bgr.rgbRed   == LOBYTE(LOWORD(ref)))
            if(bgr.rgbOptional == HIBYTE(HIWORD(ref)))
              retval = true;
      return retval;
    }
    //---------------------------------------------------------------------------
    
    void MakeMask256(char* bytes, BYTE* PixelColorNo, WORD TransparentNo)
    {
      for(int i=0; i<1024; i++)
      {
        bool IsTransparent = (PixelColorNo[i]==TransparentNo);
        // Für AND-Maske
        int byte_number = i / 8;
        PushLeft(bytes + byte_number, IsTransparent);
        // Für XOR-Maske
        if(IsTransparent) PixelColorNo[i] = 0x00000000;
      }
    }
    //---------------------------------------------------------------------------
    
    void SaveIcon(TIcon* ico, char* fn)
    {
      // Vorläufige Version
      Graphics::TBitmap* bmp = new Graphics::TBitmap;
      bmp->Width = 32;
      bmp->Height = 32;
      bmp->Canvas->StretchDraw(Rect(0,0,32,32), ico);
      SaveIcon(bmp, (COLORREF)bmp->Canvas->Pixels[0][31], fn);
      delete bmp;
    }
    //---------------------------------------------------------------------------
    
    void SaveIcon(Graphics::TBitmap* bmp, COLORREF clTransparent, char* fn)
    {
      BGRCOLOR ColorTable[256]; // Palette
      BYTE PixelColorNo[1024];  // XOR-Maske
      COLORTABLEINFO TableInfo = CountColors(bmp, ColorTable, PixelColorNo, clTransparent);
      int ColorNumber = TableInfo.ColorCount;
      if(ColorNumber==0) SaveIconTrueColor(bmp, clTransparent, fn);
      else
        if(ColorNumber<=16)
        {
          // Den Rest der Farbenpalette mit weiß füllen
          for(int i=ColorNumber; i<16; i++) ColorTable[i] = MakeBGR(0x00FFFFFF);
          SaveIcon16Colors(ColorTable, PixelColorNo, TableInfo.TransparentNo, fn);
        }
        else
        {
          // Den Rest der Farbenpalette mit weiß füllen
          for(int i=ColorNumber; i<256; i++) ColorTable[i] = MakeBGR(0x00FFFFFF);
          SaveIcon256Colors(ColorTable, PixelColorNo, TableInfo.TransparentNo, fn);
        }
    }
    //---------------------------------------------------------------------------
    
    COLORTABLEINFO CountColors(Graphics::TBitmap* bmp, BGRCOLOR* ColorTable, BYTE* PixelColorNo, COLORREF clTransparent)
    {
      COLORTABLEINFO info;
      TCanvas* canvas = bmp->Canvas;
      // Schwarz ist erste Farbe - weiß zweite
        int counter = 2;
        ColorTable[0] = MakeBGR(0x00000000);
        ColorTable[1] = MakeBGR(0x00FFFFFF);
        info.TransparentNo = 257;
        if(clTransparent==0x00000000) info.TransparentNo = 0;
        if(clTransparent==0x00FFFFFF) info.TransparentNo = 1;
      for(int i=0; i<1024; i++)    // 1024 = 32 * 32
      {
        int column = i % 32;
        int row = 31 - i / 32;
        COLORREF PixelColor = (COLORREF)canvas->Pixels[column][row];
        int j = 0;
        while(j < counter && !IsEqual(ColorTable[j], PixelColor))
           j++;
        if(j==counter) // neue Farbe entdeckt
        {
          ColorTable[j] = MakeBGR(PixelColor);
          counter++;
          if(counter > 256)  // Mehr als 256 Farben in Bild
          {
            info.ColorCount = 0;
            return info;
          }
          if(info.TransparentNo==257)
            if(clTransparent==PixelColor)
              info.TransparentNo = j;
        }
        PixelColorNo[i] = j;
      }
      info.ColorCount = counter;
      return info;
    }
    //---------------------------------------------------------------------------
    
    void SaveIconTrueColor(Graphics::TBitmap* bmp, COLORREF clTransparent, char* fn)
    {
      ICONDIR IconDir;
      ICONDIRENTRY IconDirEntry;
      BITMAPINFOHEADER BmpInfoHeader;
      char bytes[128];        // AND-Maske
      BGRCOLOR pixels[1024];  // XOR-Maske
    
        IconDir.idReserved = 0;
        IconDir.idType     = 1;
        IconDir.idCount    = 1;
    
        IconDirEntry.bWidth        = 32;
        IconDirEntry.bHeight       = 32;
        IconDirEntry.bColorCount   = 0;
        IconDirEntry.bReserved     = 0;
        IconDirEntry.wPlanes       = 1;
        IconDirEntry.wBitCount     = 32;
        IconDirEntry.dwBytesInRes  = 4264;
        IconDirEntry.dwImageOffset = 22;
    
        BmpInfoHeader.biSize          = 40;
        BmpInfoHeader.biWidth         = 32;
        BmpInfoHeader.biHeight        = 64;
        BmpInfoHeader.biPlanes        = 1;
        BmpInfoHeader.biBitCount      = 32;
        BmpInfoHeader.biCompression   = 0;
        BmpInfoHeader.biSizeImage     = 0;
        BmpInfoHeader.biXPelsPerMeter = 0;
        BmpInfoHeader.biYPelsPerMeter = 0;
        BmpInfoHeader.biClrUsed       = 0;
        BmpInfoHeader.biClrImportant  = 0;
    
      TCanvas* canvas = bmp->Canvas;
      for(int i=0; i<1024; i++)
      {
        int column = i % 32;
        int row = 31 - i / 32;
        int byte_number = i / 8;    // bit_number = i % 8;
        COLORREF PixelColor = (COLORREF)canvas->Pixels[column][row];
    
        bool IsTransparent = (PixelColor==clTransparent);
        pixels[i] = MakeBGR(!IsTransparent * PixelColor);
        PushLeft(bytes + byte_number, IsTransparent);
      }
    
      TFileStream* Stream = new TFileStream((AnsiString)fn, fmCreate | fmOpenWrite);
      Stream->Write(&IconDir, sizeof(IconDir));
      Stream->Write(&IconDirEntry, sizeof(IconDirEntry));
      Stream->Write(&BmpInfoHeader, sizeof(BmpInfoHeader));
      Stream->Write(pixels, 1024 * sizeof(DWORD));
      Stream->Write(bytes, 128);
      delete Stream;
    }
    //---------------------------------------------------------------------------
    
    void  SaveIcon256Colors(BGRCOLOR* ColorTable, BYTE* PixelColorNo, WORD TransparentNo, char* fn)
    {
      ICONDIR IconDir;
      ICONDIRENTRY IconDirEntry;
      BITMAPINFOHEADER BmpInfoHeader;
      char bytes[128];
    
      MakeMask256(bytes, PixelColorNo, TransparentNo);
    
        IconDir.idReserved = 0;
        IconDir.idType     = 1;
        IconDir.idCount    = 1;
    
        IconDirEntry.bWidth        = 32;
        IconDirEntry.bHeight       = 32;
        IconDirEntry.bColorCount   = 0;
        IconDirEntry.bReserved     = 0;
        IconDirEntry.wPlanes       = 0;
        IconDirEntry.wBitCount     = 0;
        IconDirEntry.dwBytesInRes  = 2216;
        IconDirEntry.dwImageOffset = 22;
    
        BmpInfoHeader.biSize          = 40;
        BmpInfoHeader.biWidth         = 32;
        BmpInfoHeader.biHeight        = 64;
        BmpInfoHeader.biPlanes        = 1;
        BmpInfoHeader.biBitCount      = 8;
        BmpInfoHeader.biCompression   = 0;
        BmpInfoHeader.biSizeImage     = 0;
        BmpInfoHeader.biXPelsPerMeter = 0;
        BmpInfoHeader.biYPelsPerMeter = 0;
        BmpInfoHeader.biClrUsed       = 0;
        BmpInfoHeader.biClrImportant  = 0;
    
      TFileStream* Stream = new TFileStream((AnsiString)fn, fmCreate | fmOpenWrite);
      Stream->Write(&IconDir, sizeof(IconDir));
      Stream->Write(&IconDirEntry, sizeof(IconDirEntry));
      Stream->Write(&BmpInfoHeader, sizeof(BmpInfoHeader));
      Stream->Write(ColorTable, 256 * sizeof(DWORD));
      Stream->Write(PixelColorNo, 1024 * sizeof(BYTE));
      Stream->Write(bytes, 128);
      delete Stream;
    }
    //---------------------------------------------------------------------------
    
    void  SaveIcon16Colors(BGRCOLOR* ColorTable, BYTE* PixelColorNo, WORD TransparentNo, char* fn)
    {
      ICONDIR IconDir;
      ICONDIRENTRY IconDirEntry;
      BITMAPINFOHEADER BmpInfoHeader;
      char bytes[128];
    
      for(int i=0; i<1024; i++)
      {
        bool IsTransparent = (PixelColorNo[i]==TransparentNo);
        // AND-Maske
        int byte_number = i / 8;
        PushLeft(bytes + byte_number, IsTransparent);
        // Für XOR-Maske
        if(IsTransparent) PixelColorNo[i] = 0x00000000;
      }
      // XOR-Maske (wird in halben Bytes gespeichert)
      for(int i=0; i<512; i++)
         PixelColorNo[i] = (PixelColorNo[2*i] << 4) + PixelColorNo[2*i+1];
    
        IconDir.idReserved = 0;
        IconDir.idType     = 1;
        IconDir.idCount    = 1;
    
        IconDirEntry.bWidth        = 32;
        IconDirEntry.bHeight       = 32;
        IconDirEntry.bColorCount   = 16;
        IconDirEntry.bReserved     = 0;
        IconDirEntry.wPlanes       = 0;
        IconDirEntry.wBitCount     = 0;
        IconDirEntry.dwBytesInRes  = 744;
        IconDirEntry.dwImageOffset = 22;
    
        BmpInfoHeader.biSize          = 40;
        BmpInfoHeader.biWidth         = 32;
        BmpInfoHeader.biHeight        = 64;
        BmpInfoHeader.biPlanes        = 1;
        BmpInfoHeader.biBitCount      = 4;
        BmpInfoHeader.biCompression   = 0;
        BmpInfoHeader.biSizeImage     = 0;
        BmpInfoHeader.biXPelsPerMeter = 0;
        BmpInfoHeader.biYPelsPerMeter = 0;
        BmpInfoHeader.biClrUsed       = 0;
        BmpInfoHeader.biClrImportant  = 0;
    
      TFileStream* Stream = new TFileStream((AnsiString)fn, fmCreate | fmOpenWrite);
      Stream->Write(&IconDir, sizeof(IconDir));
      Stream->Write(&IconDirEntry, sizeof(IconDirEntry));
      Stream->Write(&BmpInfoHeader, sizeof(BmpInfoHeader));
      Stream->Write(ColorTable, 16 * sizeof(DWORD));
      Stream->Write(PixelColorNo, 512 * sizeof(BYTE));
      Stream->Write(bytes, 128);
      delete Stream;
    }
    //---------------------------------------------------------------------------
    

    Sorry wegen der wenigen Kommentare. Das ist schon eine Weile her, dass ich das geschrieben hatte. Damals habe ich noch nicht so viel Wert auf Kommentare gelegt.[/EDIT]



  • Jo das wär super! 👍
    DaKinel(AT)gmx(DOT)de oder in meinem Profil.

    Danke!

    [EDIT] Okay, aht sich dann wohl erledigt! Danke nochmal.



  • Ach ja, ganz vergessen: Mit diesem Code lassen sich nur 32x32-Icons abspeichern. Aber wer trotz Kommentarmangel dahintersteigt, kann das auch leicht für 16x16- oder 48x48-Icons implementieren.



  • Genial Webfritzi, einfach genial. Der Beitrag gehört in die FAQ, unter der Rubrik "Icons in mehr als 16 Farben abspeichern"... *fg*



  • Nene, lass mal mit den FAQs. Sooo dolle ist der Code nun auch wieder nicht...
    Gründe: schlecht kommentiert, nur 32x32-Icons, nur ein Icon pro Datei und und und...
    Müsste mal jemand eine Klasse erstellen. Vielleicht gibt's das ja unter torry, oder so.



  • @WebFritzi:

    Ich muss nochmal nerven 😃

    Hab grad ein bissel mit deinem Code rumgespielert und es funktioniert auch soweit ganz gut, ABER...

    ...wieso wird bei dem speichern als TrueColor-Icon keine Information bezüglich der Anzahl der Farbe mit gespeichert? Bei 16 und 256 iss dem aber so.
    Mir ist das aufgefallen, weil ich ein Bitmap mit der Funktion SaveIconTrueColor als Icon gespeichert hab. Das Icon wurde auch erzeugt, nur ,als ich es in einem Programm geöffnet habe mit dem man Icons erstellen kann (Micoangelo), wurde nix angezeigt. Hab mich erst gewundert, da ja das Icon richtig erstellt wurde und hab dann gesucht woran es liegen könnte.
    Kann es sein das da die Farbinformationen fehlen, denn mit 256 Farbe klappt alles wunderbar?



  • Hatte das Icon denn auch mehr als 256 Farben?



  • Wäre das denn von Wichtigkeit?
    Ich hatte ein Bitmap (24 Bit, Windows) in ein TImage geladen und dieses dann als Icon gespeichert. Eigentlich sollte das schon mehr als 256 Farben gehabt haben.



  • Mit Vermutungen hilfst du mir (und dir) auch nicht weiter! Außerdem sollst du natürlich nicht die einzelnen SaveIcon[...]-Funktionen verwenden sondern nur die beiden SaveIcon-Funktionen. Benutze CountColors(), um herauszubekommen, wie viele Farben das Bitmap hat.



  • Ich werd mal noch ein bissel probieren und sehen was es bringt.
    Was mich aber verwundert hatte war, das du im Code, in der Funktion für die 256 Farben, eine Information über die Anzahl der Farben mit in die Datei geschrieben hast und bei der TrueColor Funktion nicht.
    Ich will ja den Code nicht einfach 1:1 übernehmen, sonder eher erst mal durchsteigen und verstehen wieviele und was für Daten in eine Icon-Datei geschrieben werden müssen.



  • Ah, verstehe. Die Infos dazu habe ich von www.wotsit.org. Da solltest du auf jeden Fall mal nachschauen, wenn dich das interessiert. Dann wirst du auch meinen Code besser verstehen.



  • @WebFritzi:

    Aha. Ich hab mir grad dein IconStudio von deiner Website runtergeladen. Dort benutzt du doch die Funktionen die du gepostet hast, oder?
    Hab damit mal ein bissel rumgespielert und festgestellt, das der selbe Fehler auftritt.
    Ich hab einfach mal ein *.ico mit mehr als 256 Farben in dem IconStudio geöffnet und wieder gespeichert. Beim Öffnen in Microangelo hat er dann auch nischt angezeigt. Man sollte wohl doch noch mal die Funktion CoutColor (oder so?) anwenden, um die Anzahl der Farben zu ermitteln, oder?



  • Hi,
    wie muss ich das eigentlich machen, wenn ich mehrere Icons in eine Datei speichern will?


Anmelden zum Antworten