1. Introduction
+ +Icons in AmigaOS and its derivatives (MorphOS, AROS), are basically the + same thing as on other operating systems – a small images identifying + files, directories, disks and so on. Except of image data, Amiga icons + contain some additional informations. File icons can contain a path to + an application used to open the project file when it is doubleclicked (the + default tool). They can also contain so-called tooltypes, which are just + strings used as program parameters. Dawer (folder) and disk icons contain + position, size and viewmode of a window opened on the desktop after + clicking the icon. All icons can store their position in parent drawer (or + desktop) window.
+ +I've decided to write this unofficial specification, after I've found + none on the Internet. While Amiga icons are not very popular, as AmigaOS + itself is rather a niche, hobby OS, someone may find this article useful. + Note that there are a few kinds of Amiga icons. This article describes an + old, bitplane based format. Later NewIcons and PNG icons (as used in AmigaOS + 4, MorphOS and AROS) are not described here.
+ +2. Real and default icons
+ +Icons in AmigaOS are separate files, with the same name as the 'main' + file, and '.info' extension at the end. Note that if a file has an extension + by itself (for example 'archive.lha'), the '.info' extension does not + replace file extension, but is appended at the end, so an icon for + 'archive.lha' has the name 'archive.lha.info'. It may look strange for a + Windows user, but comes from the fact, that Amiga system does not use + extensions for file type recognition at all. An executable file without an + '.exe' is perfectly OK for example. To say more, executable files on + Amiga have no extension at all usually.
+ +When a file has no icon associated, it is invisible in Workbench window + until "Show all files" viewmode is selected. Then a default icon for the + file is used. Older AmigaOS versions have stored default icons in + "ENVARC:sys/def_xxxx.info", where xxxx is 'drawer', 'project', 'tool' or + 'disk'. Some extensions to this system have been developed, which allowed + different icons for different file types. What is important here, default + icons have the same file format as real ones. One can easily create a real + icon from a default one, using system tools, or just by copying the icon and + changing its name.
+ +3. Amiga icon structure
+ +The icon file is composed directly of some system structures. It has an + advantage of fast icon loading and displaying, the file is just loaded to + memory, structures addresses are extracted and may be passed directly to + Intuition, the main Amiga UI library. On the other hand many fields of these + system structures are unused or redundant, making the icon file bigger. + Some data in these structures are referenced via pointers in memory, in an + icon file, the data are stored after structures in a defined order.
+ +The selected state of an Amiga icon is not generated programatically, but + is specified in the icon itself. Often the selected state is a second, separate + image, sometimes it is specified as palette entries swap.
+ +3.1. Format overview.
+ + The icon file starts from a DiskObject structure, which embeds Gadget + structure. Then there may be a DrawerData structure, followed by one or two + Image structures. After them raster image data for Image(s) follows. + Then there is a default tool string and tooltypes strings. DrawerData + contains a NewWindow structure. Here is a block diagram of an Amiga icon: ++
DiskObject | +DrawerData | +Image 1 | +raster data for Image 1 |
+ Image 2 | +raster data for Image 2 |
+ default tool | +tooltypes | +
Fig. 1. A block diagram of Amiga icon file structure (gray elements are optional). +
NOTE: All multi-byte fields of an Amiga icon are big-endian. x86 + programmers have to swap bytes.
+ +3.2. DiskObject structure
+ +0000 | uint16 | do_Magic | A file identifier. All + icons have 0xE310 here. | +
0002 | uint16 | do_Version | Icon version. The + current version is 1. | +
0004 | uint32 | do_Gadget.NextGadget | Unused. + Contains 0 usually. | +
0008 | int16 | do_Gadget.LeftEdge | Horizontal + position of the icon left edge relative to its parent window left + edge. This field is only used when an icon is loaded into memory. | +
0010 | int16 | do_Gadget.TopEdge | Vertical + position of the icon top edge relative to its parent window top + edge. This field is only used when an icon is loaded into memory. | +
0012 | uint16 | do_Gadget.Width | Icon width + in pixels. | +
0014 | uint16 | do_Gadget.Height | Icon height + in pixels. | +
0016 | uint16 | do_Gadget.Flags | Gadget flags. Used only by + Intuition, when the icon is loaded into memory. Usually set to 5. | +
0018 | uint16 | do_Gadget.Activation | Gadget activation flags. + The usual value is 3 here (both 'immediate' and 'relverify' activation methods set). | +
0020 | uint16 | do_Gadget.GadgetType | Gadget type. The usual value + is 1 here (means boolean gadget). | +
0022 | uint32 | do_Gadget.GadgetRender | In memory a pointer + to the first Image, used for not selected state. In file it should be any non-zero + value. Zero here should not happen. | +
0026 | uint32 | do_Gadget.SelectRender | In memory a pointer + to the second Image, used for selected state. In file non-zero value means that the + icon has the second Image and raster data. | +
0030 | uint32 | do_Gadget.GadgetText | Unused. Usually 0. | +
0034 | uint32 | do_Gadget.MutualExclude | Unused. Usually 0. | +
0038 | uint32 | do_Gadget.SpecialInfo | Unused. Usually 0. | +
0042 | uint16 | do_Gadget.GadgetID | Unused. Usually 0. | +
0044 | uint32 | do_Gadget.UserData | Used for icon revision. 0 for + OS 1.x icons. 1 for OS 2.x/3.x icons. | +
0048 | uint8 | do_Type | A type of icon:
+
|
+
0049 | uint8 | padding | Just padding byte. | +
0050 | uint32 | do_DefaultTool | In memory a pointer to a + default tool path string. In file should be interpreted as boolean field indicating + default tool presence. | +
0054 | uint32 | do_ToolTypes | In memory a pointer to a table + containing pointers to tooltype strings. In file should be interptered as boolean + field indicating tooltypes table presence. | +
0058 | int32 | do_CurrentX | Virtual horizontal position of + the icon in the drawer window. | +
0062 | int32 | do_CurrentY | Virtual vertical position of the + icon in the drawer window. | +
0066 | uint32 | do_DrawerData | In memory a pointer to + DrawerData structure. In file should be interpreted as a boolean field indicating + DrawerData presence. | +
0070 | uint32 | do_ToolWindow | Unused. | +
0074 | uint32 | do_StackSize | Task stack size for an application. + (in case of project file, this size is for default tool application). | +
Total size: 78 bytes. |
3.3. DrawerData structure
+ +The structure starts from a NewWindow structure. Note that DrawerData may be just skipped when + only icon image is to be decoded. I've put the information here just for completness.
+ +0000 | int16 | dd_NewWindow.LeftEdge | Drawer + window left edge relative to the Workbench screen. | +
0002 | int16 | dd_NewWindow.TopEdge | Drawer window top edge relative to the + Workbench screen. | +
0004 | int16 | dd_NewWindow.Width | Drawer window width. | +
0006 | int16 | dd_NewWindow.Height | Drawer window height. | +
0008 | uint8 | dd_NewWindow.DetailPen | Number of graphics pen used to render + window details. | +
0009 | uint8 | dd_NewWindow.BlockPen | Number of graphics pen used to + render window frame background. | +
0010 | uint32 | dd_NewWindow.IDCMPFlags | Kinds of IDCMP (GUI -> application) + events requested. | +
0014 | uint32 | dd_NewWindow.Flags | Various window flags (borders, system + gadgets etc.). | +
0018 | uint32 | dd_NewWindow.FirstGadget | In memory a pointer to the first + window gadget in a linked list. Unused in an icon file. | +
0022 | uint32 | dd_NewWindow.CheckMark | In memory a pointer to checkmark + imagery for the window. Unused in an icon file. | +
0026 | uint32 | dd_NewWindow.Title | In memory a pointer to the window title + string. Unused in an icon file. | +
0030 | uint32 | dd_NewWindow.Screen | In memory a pointer to system Screen + a window is to be opened on. Unused in an icon file. | +
0034 | uint32 | dd_NewWindow.BitMap | In memory points to a system BitMap + for the window. Unused in an icon file. | +
0038 | int16 | dd_NewWindow.MinWidth | Minimum width for the window. | +
0040 | int16 | dd_NewWindow.MinHeight | Minimum height for the window. | +
0042 | uint16 | dd_NewWindow.MaxWidth | Maximum width for the window. | +
0044 | uint16 | dd_NewWindow.MaxHeight | Maximum height for the window. | +
0046 | uint16 | dd_NewWindow.Type | Window type (public/custom screen). | +
0048 | int32 | dd_CurrentX | Horizontal position of originating icon. | +
0052 | int32 | dd_CurrentY | Vertical position of originating icon. | +
Total size: 56 bytes. |
3.4. Image structure
+ +0000 | int16 | LeftEdge | Image + left edge position relative to the icon left edge. Image clipping should be done for negative + values. | +
0002 | int16 | TopEdge | Image top edge position relative to + the icon top edge. Image clipping should be done for negative values. | +
0004 | uint16 | Width | Image width in pixels. May be less + than icon width (stored in DiskObject.Gadget), missing columns use color 0. If it is + bigger than icon width I recommend to clip the image. | +
0006 | uint16 | Height | Image height in pixels. May be less + than icon height (stored in DiskObject.Gadget), missing rows use color 0. If it is + bigger than icon height I recommend to clip the image. | +
0008 | uint16 | Depth | Number of image bitplanes (see chapter + 3.5.). | +
0010 | uint32 | ImageData | In memory it is a pointer to + bitplanes, in file it should be treated as a boolean value (if not zero, bitplane + data are stored as shown on fig. 1.). | +
0014 | uint8 | PlanePick | A bitfield controlling which + image bitplane is copied to which screen bitplane. Used only by classic Amiga + graphics chipset. Meaningless in a file, as it is interpreted in Amiga chipset + context displaying particular screen. | +
0015 | uint8 | PlaneOnOff | A bitfield controlling + screen bitplanes not fed with icon data. They may be either filled by zeros or + by ones. Used only by classic Amiga graphics chipset. Meaningless in a file, + as it is interpreted in Amiga chipset context displaying particular screen. | +
0016 | uint32 | NextImage | Unused. Usually 0. | +
Total size: 20 bytes. |
3.5. Image data and palette
+ +Icon image data are stored as bitplanes. While a bit cumbersome for nowadays display devices, + this format is a native one for Amiga graphics chipsets. The image data, once loaded into + graphics ("chip") memory, can be directly blitted to a screen. On bitplanes, every pixel + occupies one bit, regardless of number of palette colors. Palette size is determined by a + number of bitplanes, for N bitplanes there are 2N colors available. + To determine a pixel color, one has to gather this pixel bits from all bitplanes (bitplane 0, + which comes first in the data, is the most significant one) as shown on fig. 2, form a number + and use it as an index to the palette table.
+ ++
Fig. 2. Bitplaned image data. +
Amiga icon bitplanes are not interleaved, complete planes are stored one after one. Pixel + scanning order is usual left-to-right, top-to-bottom. Plane rows are padded to 16-bit words, + there is no vertical padding.
+ +In spite of image data are palette-based, there is no palette stored in + the icon, just some standard palette is assumed. Unfortunately there are a few + "standard" palettes used: +
- Standard AmigaOS 1.x palette, 4 colors.
+ + color 0, R=0, G=85, B=170 (0x0055AA)
+ + color 1, R=255, G=255, B=255 (0xFFFFFF)
+ + color 2, R=0, G=0, B=0 (0x000000)
+ + color 3, R=255, G=136, B=0 (0xFF8800) +
+ - Standard AmigaOS 2.x palette, 4 colors.
+ + color 0, R=149, G=149, B=149 (0x959595)
+ + color 1, R=0, G=0, B=0 (0x000000)
+ + color 2, R=255, G=255, B=255 (0xFFFFFF)
+ + color 3, R=59, G=103, B=162 (0x3B67A2) +
+ - MagicWB palette, 8 colors. It extends AmigaOS 2.x palette with 4 additional colors.
+ + color 4, R=123, G=123, B=123 (0x7B7B7B)
+ + color 5, R=175, G=175, B=175 (0xAFAFAF)
+ + color 6, R=170, G=144, B=124 (0xAA907C)
+ + color 7, R=255, G=169, B=151 (0xFFA997) +
There were some other palettes proposed, usually extending MagicWB with more colors, but + they have not gained popularity. NewIcons format solved the problem finally, storing a palette + inside an icon. Which palette one should use converting the icon image to RGB color space? + If we limit possibilities to palettes shown above, icon revision allows to choose between OS 1.x and OS 2.x + palette. Then if revision is 1 and number of bitplanes is 3, the icon is MagicWB one.
+ +4. Decoding icon images
+ +Usually you will be only interested in extracting images from an icon, and convert them to + the RGB color space (unless you are writing an Amiga Workbench replacement...). Here is a short guide + how to do it: + +
-
+
+
- + Take into account, that most of information in the icon is unused. All fields in DiskObject and Image + structures really needed to decode imagery are marked gray + in the above tables. White entries may be ignored. If you are on x86 or other little-endian platform, + do not forget about byte-swapping. + + +
- + Start from loading a fixed size DiskObject structure. Verify do_Magic and do_Version. Then + check for presence of DrawerData. Non zero do_DrawerData is the primary indicator, do_Type of + 1, 2 or 5 is the secondary one. Check for presence of the first image (do_Gadget.GadgetRender). The + second image primary indicator is do_Gadget.SelectRender, the secondary one is that gadget highlight + bits are set to 2 (do_Gadget.Flags & 0x0003 == 0x0002). + + +
- + If DrawerData is present, skip it. + + +
- + Read the first Image structure. Extract offsets, width, height and number of bitplanes. Calculate bitplane width + in bytes taking horizontal padding into account. It may be calculated as + ((Width + 15) >> 4) << 1. + + +
- + Check for ImageData. If it is 0, it may mean that the image is empty, or the file is damaged. If not, + load bitplanes to memory. + + +
- + If you've detected the second Image, repeat 4. and 5. Be prepared for different offsets and dimensions (may + happen often) or different bitplanes number (very unlikely, but who knows). + + +
- + Select the palette for every image, based on icon revision and number of bitplanes. Convert bitplanes to + a RGB pixelmap, using selected palette. Note that padding bits should be ignored even if non-zero. + + +
- + Create an empty rectangle of icon size (do_Gadget.Width × do_Gadget_Height). Fill it + with palette color 0. Then impose the normal or selected image on it using Image LeftEdge and + TopEdge as offsets. Perform clipping if neccesary. + + +