Dateiformat: ICO und CUR

 Navigation
· Beschreibung
· Dateiformat
   · Dateiheader
   · Verzeichnis der Einzelbilder
   · Bilddaten
· Ausblick
· Weiterführende Informationen
Stand: 20.11.2005

15.08.2005: Durch einen Beitrag im Delphi-PRAXiS Forum bin ich letztens wieder dazu gekommen, mich mit dem Format von Windows Icons und Cursorn zu befassen. Die meisten Dokumente, die man im Internet dazu findet, stammen aus der Zeit, als Icons noch maximal 256 Farben hatten (oder davor). Darum hier eine kleine Formatbeschreibung.

20.11.2005: Endlich bin ich dazu gekommen, etwas weiter zu arbeiten. Es fehlen aber immer noch viele Dinge und das ganze Dokument ist eher noch eine Fakten- und Gedankensammlung. Die Gliederung der Informationen werde ich noch überarbeiten.

Beschreibung

Anders als Bitmaps oder viele andere Grafikdateiformate können Icons und Cursor mehrere Einzelbilder beinhalten, die das System je nach benötigter Auflösung und Farbtiefe benutzt. So können in einer einzigen ICO-Datei z.B. Bilder für die Größen 16x16, 32x32, 48x48 und die Farben 16, 256 und Truecolor enthalten sein.

Außerdem können Icons und Cursor transparent dargestellt werden und auch eine das ursprüngliche Bild invertierende Wirkung haben, weshalb zusätzlich zu den eigentlichen Bilddaten noch eine Maske in der Größe des Icons bzw. Cursors abgespeichert wird.

Original Hintergrund (rot)
Original Hintergrund (grün)
-> UND-Maske -> Zwischenergebnis (rot)
Zwischenergebnis (grün)
-> XOR-Bild -> Resultat (rot)
Resultat (grün)
Original
Hintergrund
  UND-Maske   Zwischen-
ergebnis
  XOR-Bild   Resultat

Zur Darstellung des Icons bzw. des Cursors wird das ursprüngliche Bildschirminhalt zunächst über AND mit der Maske verknüpft und danach über XOR mit dem Bild.

Insgesamt lassen sich mit der Kombination von Maske und Bild drei Effekte erzielen. Diese werden deutlich, wenn wir uns eines der Ergebnisbilder noch einmal genauer ansehen:

Maske
UND-Maske
 
Effekte
Resultat
 
Bild
XOR-Bild

Die drei markierten Bereiche auf den Bildern zeigen die unterschiedlichen Effekte:

  1. Links oben: wo die Maske 0 ist (schwarz), ist das Bild deckend — der Hintergrund wird vollständig übermalt.

  2. Links unten: wo die Maske 1 ist (weiß) und das Bild schwarz, ist das Bild transparent — der Hintergrund bleibt vollständig erhalten.

  3. Rechts: wo die Maske 1 ist (weiß) und das Bild nicht schwarz, werden die Pixel von Hintergrund und Bild per XOR kombiniert.

    Ja, natürlich geschieht dies natürlich auch bei (2), aber "A xor 0" ist wieder A, und so bleibt der Hintergrund vollständig erhalten.

Fehlt: Windows-XP-Icons (alphablending)

Dateiformat

Eine ICO- oder CUR-Datei besteht aus dem Dateiheader, dem Verzeichnis der Einzelbilder für den schnellen Zugriff und den einzelnen Daten für jedes Einzelbild. Da Icons und Cursor bis auf kleine Unterschiede dasselbe Dateiformat benutzen, werde ich sie hier auch zusammen beschreiben.

Dateiheader

Die Datei besitzt zunächst einen kleinen Header von 6 Byte Größe, der den Dateityp und die Anzahl der enthaltenen Teilbilder angibt:

Offset  Größe  Typ  Name  Inhalt
0000h0002hWORDidReservedImmer 0.
0002h0002hWORDidTypeImmer 1 für Icons und 2 für Cursor.
0004h0002hWORDidCountAnzahl der Einzelbilder in der Datei.

Oder als Typdeklaration für C/C++ bzw. Pascal:

// Werte für idType

#define IMAGE_ICON 1
#define IMAGE_CURSOR 2


typedef struct _ICONDIRHDR {
  unsigned short idReserved;
  unsigned short idType;
  unsigned short idCount;
} ICONDIRHDR;
   
// Werte für idType
const
  IMAGE_ICON = 1;
  IMAGE_CURSOR = 2;

type
  TIconDirHdr = packed record
    idReserved: Word;
    idType: Word;
    idCount: Word;
  end;

Hinweis: Für C/C++ müsste noch etwas wie "#pragma packed(1)" hinzugefügt werden.

Verzeichnis der Einzelbilder

Auf diesen Header folgt das Verzeichnis der Einzelbilder, also idCount Datenblöcke mit der folgenden Struktur, die jeweils 16 Byte groß sind:

Offset  Größe  Typ  Name  Inhalt
0000h0001hBYTEbWidthBreite des Icons, z.B. 16, 32, 48, 64, 128.
0001h0001hBYTEbHeightHöhe des Icons, z.B. 16, 32, 48, 64, 128.
0002h0001hBYTEbColorCountAnzahl der Farben im Bild (2 oder 16, bzw. 0 falls mehr als 256 Farben).
0003h0001hBYTEbReservedImmer 0.
0004h0002hWORDwPlanesFür Icons: Anzahl der Farbebenen.
Für Cursor: X-Position des Hotspots.
0006h0002hWORDwBitCountFür Icons: Anzahl der Bits/Pixel.
Für Cursor: Y-Position des Hotspots.
0008h0004hLONGdwBytesInResGröße des Einzelbildes in Byte.
000Ch0004hLONGdwImageOffsetDateioffset des Einzelbildes in Byte, relativ zum Dateianfang.

Oder auch dies als Typdeklaration für C/C++ bzw. Pascal:

typedef struct _ICONFILEDIRENTRY {
  unsigned char  bWidth;
  unsigned char  bHeight;
  unsigned char  bColorCount;
  unsigned char  bReserved;
  unsigned short wPlanes;
  unsigned short wBitCount;
  unsigned long  dwBytesInRes;
  unsigned long  dwImageOffset;
} ICONFILEDIRENTRY;
   
type
  TIconFileDirEntry = packed record
    bWidth: Byte;
    bHeight: Byte;
    bColorCount: Byte;
    bReserved: Byte;
    wPlanes: Word;
    wBitCount: Word;
    dwBytesInRes: Longint;
    dwImageOffset: Longint;
  end;

Im Falle eines Icons können die Werte für wPlanes und wBitCount auch 0 sein, da sie ohne Probleme aus dem Bitmapinfo-Header des Einzelbildes ermittelt werden können und für die Auswahl des Bildes zunächst irrelevant sind; wichtig sind die Breite, die Höhe und die Anzahl der Farben.

Für Cursor werden diese Felder sowieso »missbraucht« und dort werden die X- und Y-Koordinaten des Hotspots gespeichert. Der Hotspot ist der Punkt des Bildes - von links oben gerechnet - der die Spitze des Mauszeiger repräsentiert. Dies muss nicht immer die linke obere Ecke sein, wie man sich leicht am Beispiel eines Fadenkreuzes deutlich machen kann.

Bilddaten

Die eigentlichen Bilddaten findet man für jedes Einzelbild in der Datei ab Offset dwImageOffset mit einer Größe von dwBytesInRes Bytes.

Die Bilddaten sind — wohl aus historischen Gründen — etwas unglücklich gespeichert.

An sich geht es ganz normal los mit einer BITMAPINFOHEADER Struktur wie sich auch am Anfang von BMP-Dateien gespeichert wird. Diese Struktur besteht aus den folgenden Feldern:

Offset  Größe  Typ  Name  Inhalt
0000h0004hDWORDbiSizeGröße der Struktur in Bytes.
0004h0004hLONGbiWidthBreite des Bildes in Pixeln.
0008h0004hLONGbiHeightDie doppelte Höhe des Bildes in Pixeln.
000Ch0002hWORDbiPlanesAnzahl der Farbebenen (immer 1).
000Eh0002hWORDbiBitCountAnzahl der Bits/Pixel: 0, 1, 4, 8, 16, 24, 32.
0010h0004hDWORDbiCompressionKompressionsverfahren für das Bild.
0014h0004hDWORDbiSizeImageGröße der Bilddaten in Bytes.
0018h0004hLONGbiXPelsPerMeterHorizontale Auflösung des Bildes in Pixel/Meter.
001Ch0004hLONGbiYPelsPerMeterVertikale Auflösung des Bildes in Pixel/Meter.
0020h0004hDWORDbiClrUsedAnzahl der benutzten Farbeinträge in der Palette. Kann 0 sein, in diesem Fall werden alle Farbeinträge benutzt.
0024h0004hDWORDbiClrImportantAnahl der wichtigen Farbeinträge in der Palette. Hier bedeutet 0, dass alle Farben wichtig sind.

Die Typdeklaration für BITMAPINFOHEADER steht in den Windows API Deklarationsdateien. Die wirkliche Größe der Struktur ist nicht fest, sondern steht im Feld biSize.

Auf die Angabe im Feld biSizeImage kann man sich nicht verlassen; manche Anwendung speichern hier Größe der Pixeldaten für beide Bitmaps und manche nur für die erste.

Sofern das Bild eine Palette hat, also wenn biClrUsed größer als 0 ist oder wenn biBitCount kleiner oder gleich 8 ist, dann folgt auf diese Struktur ein Array mit ebensovielen RGBQUAD Farbeinträgen.

Danach folgen die wirklichen Pixeldaten des Bildes, deren Format abhängig von den Angaben im BITMAPINFOHEADER sind.

Für die Verarbeitung der Pixeldaten ist es wichtig zu beachten, dass der BITMAPINFOHEADER, die Palette und die eben beschriebenen Pixeldaten zusammen exakt das Format einer geräteunabhängigen Windows-Bitmap haben, mit der einzigen Ausnahme, dass das Feld biHeight falsch ist und eben die doppelte Höhe der Bitmap angibt.

Direkt im Anschluss an die Pixeldaten des Bildes kommen die der monochromen Maske des Icons. Zu diesen Pixeldaten könnte man sich den folgenden BITMAPINFOHEADER erzeugen:

Feld  Inhalt
biSize40
biWidthbihFile.biWidth
biHeightbihFile.biHeight / 2
biPlanes1
biBitCount1
biCompressionBI_RGB
biSizeImage((biWidth + 31) / 32) * 4 * biHeight
biXPelsPerMeterbihFile.biXPelsPerMeter
biYPelsPerMeterbihFile.biYPelsPerMeter
biClrUsed0
biClrImportant0

Hinweis: biSizeImage wird hier einfach aus der Größe der Bitmap berechnet unter der Vorgabe, dass jede Scanzeile der Bitmap auf einer 4-Byte-Grenze liegen muss (32 Bits).

Dazu gehört dann noch eine Farbpalette mit zwei Einträge: Schwarz (Index 0) und Weiß (Index 1).

Ausblick

Hier schließe ich für heute, bald gibt's mehr Infos zusammen mit einigen Beispielprogrammen.

Weiterführende Informationen

  • MSDN Artikel Icons in Win32 von John Hornick (englisch).
    Die darin angesprochenen Artikel aus der Knowledge Base findet man unter Q81498 und Q94326.

Flocke's Garage
Valid HTML 4.01 Transitional Valid CSS!
(C) 2005-2013 Volker Siebert.
Creative Commons-LizenzvertragDer gesamte Inhalt dieser Webseite steht unter einer Creative Commons-Lizenz (sofern nicht anders angegeben).