跳轉到內容

Aros/開發者/文件/庫/圖示

來自華夏公益教科書,開放的世界,開放的書籍
用於 Aros 華夏公益教科書的導航欄
Aros 使用者
Aros 使用者文件
Aros 使用者常見問題解答
Aros 使用者應用程式
Aros 使用者 DOS Shell
Aros/使用者/AmigaLegacy
Aros 開發者文件
Aros 開發者文件
從 AmigaOS/SDL 移植軟體
適用於 Zune 初學者
Zune .MUI 類
適用於 SDL 初學者
Aros 開發者構建系統
特定平臺
Aros x86 完整系統 HCL
Aros x86 音訊/影片支援
Aros x86 網路支援
Aros 英特爾 AMD x86 安裝
Aros 儲存支援 IDE SATA 等
Aros Poseidon USB 支援
x86-64 支援
摩托羅拉 68k Amiga 支援
Linux 和 FreeBSD 支援
Windows Mingw 和 MacOSX 支援
Android 支援
Arm Raspberry Pi 支援
PPC Power 架構
其他
Aros 公共許可證
  • 舊 - OS1.x (4 色) - OS 2/3 (4 色)
  • 新 - NewIcons (大小 36x40 x 32 色) - GlowIcons (大小 46x46 x 256 色) - PowerIcons (24 位)
  • AROS - 24 位 png 雙重

未來可能性

  • SVG 或 SVGZ - Haiku HVIF 採用了一種簡化的格式。

這種格式由 Amiga 計算機使用,用於顯示每個程式的圖示,以便您從圖形使用者介面工作臺訪問這些程式。

在 AROS 上,不同大小的圖示會導致圖示之間出現錯位和雜亂,即使是相同大小的方形圖示和圓形圖示,也會顯得很大。此外,具有邊緣或突起(例如手柄)的資料夾會顯得更小,這就是我使用不同大小的圖示集的原因。最好注意圖示錯位的問題。大多數圖示為 46x46。資料夾影像區域為 42x42,但常規圖示影像區域與其他 AROS Glow 圖示相同,為 38x38。

最初,有 3 種不同的格式。

1) The OS1.x/OS2.x icons.
2) The NewIcon icon extension.
3) The OS3.5 icon extension.

關於所用資料描述符的說明。所有元素均採用摩托羅拉位元組順序(最高位元組優先)。

APTR  - a memory pointer (usually this gets a boolean meaning on disk)
BYTE  - a single byte                   -128..127
UBYTE - an unsigned byte                   0..255
WORD  - a signed 16 bit value         -32768..32767
UWORD - an unsigned 16 bit value           0..65535
LONG  - a signed 32 bit value    -2147483648..2147483647
ULONG - a unsigned 32 bit value            0..4294967295

有很多元素標記為 ???。這些通常填充有值,但這些值根本沒有效果。因此,通常可以忽略它們。對於某些值,描述了其通常內容。


OS1.x/OS2.x 格式

[編輯 | 編輯原始碼]

OS1.x/OS2.x 格式主要是將記憶體中的結構儲存在磁碟上。本文試圖說明哪些值很重要,哪些值不重要。

0x00 UWORD ic_Magic          always 0xE310
0x00 UWORD ic_Version        always 1
0x04 struct Gadget           (described below)
0x30 UBYTE ic_Type
     1 DISK                  a disk
     2 DRAWER                a directory
     3 TOOL                  a program
     4 PROJECT               a project file with defined program to start
     5 GARBAGE               the trashcan
     6 DEVICE                should never appear
     7 KICK                  a kickstart disk
     8 APPICON               should never appear
0x31 UBYTE ic_Pad            <undefined>
0x32 APTR  ic_DefaultTool    <boolean>
0x36 APTR  ic_ToolTypes      <boolean>
0x3A LONG  ic_CurrentX       X position of icon in drawer/on WorkBench
0x3E LONG  ic_CurrentY       Y position of icon in drawer/on WorkBench
0x42 APTR  ic_DrawerData     <boolean>
0x46 APTR  ic_ToolWindow     <boolean>
0x4A LONG  ic_StackSize      the stack size for program execution
                             (values < 4096 mean 4096 is used)

接著是某些其他資料結構

struct DrawerData            if ic_DrawerData is not zero (see below)
struct Image                 first image
struct Image                 second image if ga_SelectRender not zero
                             (see below) in gadget structure
DefaultTool text             if ic_DefaultTool not zero (format see below)
ToolTypes texts              if ic_ToolTypes not zero (format see below)
ToolWindow text              if ic_ToolWindow not zero (format see below)
                             this is an extension, which was never implemented
struct DrawerData2           if ic_DrawerData is not zero and ga_UserData
                             is 1 (see below)

現在描述子格式

a) 文字儲存方法(DefaultTool、ToolWindow 和 ToolTypes)

0x00 ULONG tx_Size           the size of tx_Text including zero byte (tx_Zero)
0x04 ...   tx_Text           the plain text
.... UBYTE tx_Zero           the finishing zero byte

這意味著文字“Hallo”將被編碼為 \00\00\00\06Hallo\00。

由於 ToolTypes 是一個文字陣列,因此編碼之前會新增另一個 ULONG 值,該值包含條目數。但為了使解析更有趣,它不是預期的條目數,而是條目數加 1 再乘以 4。因此,10 個條目將具有 44 個計數。

b) Gadget 結構

0x00 APTR  ga_Next           <undefined> always 0
0x04 WORD  ga_LeftEdge       unused ???
0x06 WORD  ga_TopEdge        unused ???
0x08 WORD  ga_Width          the width of the gadget
0x0A WORD  ga_Height         the height of the gadget
0x0C UWORD ga_Flags          gadget flags
     bit 2                   always set (image 1 is an image ;-)
     bit 1                   if set, we use 2 image-mode
     bit 0                   if set we use backfill mode, else complement mode
                             complement mode: gadget colors are inverted
                             backfill mode: like complement, but region
                             outside (color 0) of image is not inverted
     As you see, it makes no sense having bit 0 and 1 set.
0x0E UWORD ga_Activation     <undefined>
0x10 UWORD ga_GadgetType     <undefined>
0x12 APTR  ga_GadgetRender   <boolean> unused??? always true
0x16 APTR  ga_SelectRender   <boolean> (true if second image present)
0x1A APTR  ga_GadgetText     <undefined> always 0 ???
0x1E LONG  ga_MutualExclude  <undefined>
0x22 APTR  ga_SpecialInfo    <undefined>
0x26 UWORD ga_GadgetID       <undefined>
0x28 APTR  ga_UserData       lower 8 bits:  0 for old, 1 for icons >= OS2.x
			     upper 24 bits: undefined

c) DrawerData 結構:此結構對於抽屜和磁碟很有用(但仍有一些其他型別的圖示具有這些過時的條目)。

0x00 struct NewWindow        (see below)
0x30 LONG  dd_CurrentX       the current X position of the drawer window
                             contents (this is the relative offset of the
                             drawer drawmap)
0x34 LONG  dd_CurrentY       the current Y position of the drawer window contents

d) DrawerData 使用的 NewWindow 結構

0x00 WORD  nw_LeftEdge       left edge distance of window
0x02 WORD  nw_TopEdge        top edge distance of window
0x04 WORD  nw_Width          the width of the window (outer width)
0x06 WORD  nw_Height         the height of the window (outer height)
0x08 UBYTE nw_DetailPen      always 255 ???
0x09 UBYTE nw_BlockPen       always 255 ???
0x0A ULONG nw_IDCMPFlags     <undefined>
0x0E ULONG nw_Flags          <undefined>
0x12 APTR  nw_FirstGadget    <undefined>
0x16 APTR  nw_CheckMark      <undefined>
0x1A APTR  nw_Title          <undefined>
0x1E APTR  nw_Screen         <undefined>
0x22 APTR  nw_BitMap         <undefined>
0x26 WORD  nw_MinWidth       <undefined> often 94, minimum window width
0x28 WORD  nw_MinHeight      <undefined> often 65, minimum window height
0x2A UWORD nw_MaxWidth       <undefined> often 0xFFFF, maximum window width
0x2C UWORD nw_MaxHeight      <undefined> often 0xFFFF, maximum window width
0x2E UWORD nw_Type           <undefined>

e) OS2.x 抽屜的 DrawerData2 結構

0x00 ULONG dd_Flags          flags for drawer display
     value 0                 handle viewmode like parent drawer current
                             setting (OS1.x compatibility mode)
     bit 0                   view icons
     bit 1                   view all files (bit 0 maybe set or unset
                             with this)
0x04 UWORD dd_ViewModes      viewmodes of drawer display
     value 0                 show icons (OS1.x compatibility mode)
     value 1                 show icons
     value 2                 show sorted by name
     value 3                 show sorted by date
     value 4                 show sorted by size
     value 5                 show sorted by type

f) 現在是最後一個元素,Image 結構

0x00 WORD  im_LeftEdge       always 0 ???
0x00 WORD  im_TopEdge        always 0 ???
0x04 WORD  im_Width          the width of the image
0x06 WORD  im_Height         the height of the image
0x08 WORD  im_Depth          the image bitmap depth
0x0A APTR  im_ImageData      <boolean> always true ???
0x0E UBYTE im_PlanePick      foreground color register index
0x0F UBYTE im_PlaneOnOff     background color register index
0x10 APTR  im_Next           always 0 ???

接著是平面模式的影像資料。影像寬度始終四捨五入到下一個 16 位邊界。


NewIcon 擴充套件

[編輯 | 編輯原始碼]

由於原始圖示格式在使用超過 4 或 8 種預設顏色時以及使用與預設值不同的調色盤集時非常有限,因此人們想出瞭如何規避這種情況。一位共享軟體作者發明了 NewIcons 格式,該格式使用 ToolTypes 來儲存影像資料,因為擴充套件原始格式無疑會導致相容性問題。

NewIcons 內容通常從以下 2 個 ToolTypes 文字(僅文字在 "" 中)開始

"*** 請勿編輯以下行!***"

之後,影像資料將以 ASCII 格式編碼。第一張影像的行始終以“IM1=”開頭。如果存在,第二張影像將以“IM2=”開頭。

每個影像集的第一行包含影像資訊和調色盤。

0x00 UBYTE ni_Transparency
     "B"                     transparency on
     "C"                     transparency off
0x01 UBYTE ni_Width          image width + 0x21  - "}" means width 92
0x02 UBYTE ni_Height         image height + 0x21 - "}" means height 92
0x03 UWORD ni_Colors         ASCII coded number of palette entries:
     entries are: ((buf[3]-0x21)<<6)+(buf[4]-0x21)
     "!'" means 6 entries

之後,編碼後的調色盤將被儲存。每個元素具有 8 位,顏色按紅色、綠色、藍色的順序儲存。編碼格式將在下面描述。ni_Width 和 ni_Height 的最大值為 93。理論上,最大顏色值為 255。我見過至少儲存了 257 種顏色(但使用了不到 256 種)的影像。

以下行包含使用與調色盤相同系統編碼的影像資料。用於編碼條目的位數取決於顏色數(例如,6 種顏色需要 3 位)。這些行的最大長度為 127 位元組,包括“IM1=”或“IM2=”標題。因此,包括零位元組,字串將為 128 位元組。

編碼/解碼演算法

Each byte encodes 7bit (except the RLE bytes)
Bytes 0x20 to 0x6F represent 7bit value 0x00 to 0x4F
Bytes 0xA1 to 0xD0 represent 7bit value 0x50 to 0x7F
Bytes 0xD1 to 0xFF are RLE bytes:
  0xD1 represents  1*7 zero bits,
  0xD2 represents  2*7 zero bits and the last value
  0xFF represents 47*7 zero bits.

與原始圖示格式相反,NewIcons 格式使用塊狀模式來儲存影像資料。

影像和調色盤的編碼在字串邊界(127 位元組)處停止,並使用緩衝區重新整理(並新增填充位),並在下一行重新開始。


OS3.5 擴充套件

[編輯 | 編輯原始碼]

NewIcon 格式的最初發明者是 Phil Vedovatti。負責設計 Amiga OS 3.5/3.9 使用的 Glow Icons 的是 Mat Chaput。

OS3.5 格式引入了與 NewIcons 幾乎相同的資訊,但格式更易用。工具型別不再被誤用,而是將一個新的資料塊附加到圖示檔案的末尾。此資料塊採用 IFF 格式。

這些檔案包含一個經典的資訊磁碟結構(可能包含或可能不包含工具型別中的 newicon 結構),後面跟著一個 IFF 圖示結構(實際的 glowicon 位)。

因此,GlowIcon 是一個具有 ICON 識別符號的 IFF 結構,其中可以包含(新新增的)FACE 和 IMAG 塊。該檔案可能包含或可能不包含多個 IMAG 塊(儘管在這種情況下,至少包含 1 個,最多包含 2 個是合理的)。

它包含標準標題

0x00 UBYTE[4] ic_Header      set to "FORM"
0x04 ULONG    ic_Size        size [excluding the first 8 bytes!]
0x08 UBYTE[4] ic_Identifier  set to "ICON"

現在,各種資料的塊將依次出現。每個塊包含 8 個標題位元組和資料位元組。如果標題中的大小不均勻,則會在末尾自動填充 1 個位元組。

目前,使用了 3 個塊,並使用以下資料。請注意,IFF 通常允許擴充套件和塊重新排序,因此不要依賴任何當前大小資訊或塊順序,而是根據儲存在檔案中的大小資訊跳過未知資料。

1)

0x00 UBYTE[4] fc_Header      set to "FACE"
0x04 ULONG    fc_Size        size [excluding the first 8 bytes!]
0x08 UBYTE    fc_Width       icon width subtracted by 1
0x09 UBYTE    fc_Height      icon height subtracted by 1
0x0A UBYTE    fc_Flags       flags
     bit 0                   icon is frameless
0x0B UBYTE    fc_Aspect      image aspect ratio:
     upper 4 bits            x aspect
     lower 4 bits            y aspect
0x0C UWORD    fc_MaxPalBytes maximum number of bytes used in image palettes
                             subtracted by 1 (i.e. if palette 1 has 17 and
                             palette 2 has 45 entries, then this is 45)

2) 現在可以出現 2 個這種型別的塊,其中第一個塊是影像 1,第二個塊是影像 2。

 
0x00 UBYTE[4] im_Header      set to "IMAG"
0x04 ULONG    im_Size        size [excluding the first 8 bytes!]
0x08 UBYTE    im_Transparent number of the transparent color
0x09 UBYTE    im_NumColors   number of colors subtracted by 1
0x0A UBYTE    im_Flags
     bit 0                   there exists a transparent color
     bit 1                   a palette data is attached (NOTE, that first
                             image always needs palette data, whereas the
                             second one can reuse the first palette.)
0x0B UBYTE    im_ImageFormat storage format of image data
     value 0                 uncompressed
     value 1                 run-length compressed
0x0C UBYTE    im_PalFormat   storage format of palette data (same as above)
0x0D UBYTE    im_Depth       the number of bits used to store a pixel
0x0E UWORD    im_ImageSize   number of bytes used to store image (subtracted
                             by 1)
0x10 UWORD    im_PalSize     number of bytes used to store palette
                             (subtracted by 1)
0x12 UBYTE[...]              the image data
.... UBYTE[...]              the palette data (if existing)

現在談談執行長度壓縮。這與 IFF-ILBM 格式中的執行長度方法相同:輸入資料被視為一個位流,其中每個條目對於影像具有 im_Depth 位,對於調色盤具有 8 位。首先是一個 8 位 RLE 塊,其含義如下

 
0x00 .. 0x7F copy the next n entries as they are, where n is "RLE-value"+1
0x80         ignore this, do nothing
0x81 .. 0xFF produce the next entry n times, where n is 256-"RLE-value"+1
             (if using signed chars n is "RLE-value"+1)

在非壓縮模式下,每個位元組表示一個畫素(即使使用較低的深度)。

在儲存經典圖示時,我們只關心 IFF 圖示影像。IFF 資料以“FORM....ICONFACE”開頭。根據圖示資料中的實際位平面數、索引值和顏色表儲存 ILBM 檔案。一旦提取了影像和顏色表,就很容易編寫 ILBM。為了簡化操作,ILBM 可以是非壓縮的平面圖像和顏色表。如果您搜尋 IFF85,可以找到有關 ILBM 格式的資訊。

有時,經典 Amiga 圖示包含 OS3.5 IFF 資料和 ARGB 資料塊,這些塊附加到檔案的末尾。請參閱圖示庫瞭解如何讀取 zlib 壓縮的 32 位資料。

IFF 資料應包含兩個用於影像的 IMAG 塊,但它可能包含一個或沒有。如果它只包含一個影像,我們只匯出一個影像。如果它不包含用於影像的 IMAG 塊,但包含一個或兩個附加到 IFF 資料末尾的 ARGB 塊,那麼它是一個 OS4 圖示,它是一個具有 OS3.5 擴充套件的經典 Amiga 圖示,沒有 IMAG,但有 ARGB。如果它包含一個或兩個 IMAG 塊和一個或兩個 ARGB 塊,那麼它就是一個 AROS ARGB 圖示格式。

要解碼用於 Glow 圖示格式的 IMAG 塊的影像資料。影像資料解碼器和 RLE 解碼器正在執行

追蹤過 CybergraphX ReadRGBPixel 函式。它使用 DoPixelFunct,然後恢復到 do_pixel_funct,它是 Rom/Graphics 的一部分。ReadPixel 僅使用 RGB 值。

如果一個樣本畫素為 (255,46,58,78)。它是一個 ARGB 32 位畫素。但 ReadRGBPixel 返回 3029582,即 2E3A4E,或者以十進位制表示為 46,58,78。因此,alpha 值丟失了。它只有 RGB。這是有道理的,因為它使用與 ReadPixel 相同的函式。

讀取 alpha 畫素(小於 255)時會發生一些奇怪的事情。顏色 (12,0,0,0) 的 alpha 值為 12,但 ReadRGBPixel 返回 (146,146,146)。所以,似乎 ReadRGBPixel 使用了預乘 alpha 與背景顏色 (在本例中為 153) 進行混合。謎團的一部分已經解開。現在可以提供一個 WriteRGBPixel 的示例值,然後從那裡開始。

在評估了原始影像中的幾個 alpha 畫素並比較了 ReadRGBPixel 的結果值之後,我已經推算出 Alpha 混合公式。

如果背景顏色為 (153,153,153) 並且 ARGB 畫素為 (13,0,0,0),那麼公式如下:

//Alpha Blending
//alpha=13
//factor= 1-[(roundup(alpha/3))/100] =
(1 - 0.05) = 0.95
//value = (int)153*(factor) = (145,145,145).

這是迄今為止的 DrawLargeImage 函式。在螢幕截圖中,“畫素緩衝區”是包含來自原始影像(即小影像)的畫素資料的位元組緩衝區。原始影像中的每個 ARGB 畫素都被對映到一個畫素區域,在本例中為 2x2,因為 pixelateSize=2。


PowerIcons PNG

[edit | edit source]

Workbench (Wanderer) 本身不直接讀取任何內容——它依賴於 icon.library 來處理“檔案”。PNG 圖示的載入不是使用 *system* 資料型別完成的。它是透過 libpng 函式完成的。為了避免 icon.library 和 png.datatype 都靜態連結 libpng(檔案/記憶體使用量加倍),這僅對其中之一完成:png.datatype。png.datatype 公開了一些額外的函式 PNG_#?。請參閱 workbench/classes/datatypes/png/png.conf 和同一目錄下的 directaccess.c。

在 workbench/libs/icon/diskobjPNGio.c 中,您可以看到如何使用 PNG_ 函式讀取 PNG 圖示。在那裡您還會看到一個名為 MakePlanarImage() 的函式。它是一個函式,它肯定會使事情稍微慢一些。它所做的(以一種非常沒有最佳化的方式)是建立一個非常簡單的 PNG 影像的即時重新對映平面版本,用於低色 (LUT) 螢幕。

In libpng 1.5, png_ptr and info_ptr are opaque data types, and can't be dereferenced.

Replace that code with the following (which works in both libpng 1.2 and 1.5)

...
   Write(png_get_io_ptr(png_ptr), data, length);
...

The reason is that in a (near!) future version of libpng, the details of the png_ptr and info_ptr data structures may change dramatically.

Changes are trivial, just grep for the old field name (ie 'io_ptr') in png.h, and use the appropriate accessor function. 

合併 icon35 和 png 圖示

  • png 資料將位於 icon35 格式的 IFF 流中(IFF 型別為 'PNG ')
  • 4 色和 icon35 影像格式將由 ilbmtoicon 工具預先計算。
  • AOS 應該能夠讀取並理解這種格式。

拆分 PNG 圖示並保留 icOn 塊的最簡單方法是找到第一個 'IEND' 和第二個 'IEND'(如果有的話),然後計算 filesize1 和 filesize2,然後讀寫二進位制檔案。您可以使用另一種方法來獲取影像,但是 icOn 塊可能會丟失,除非您在 'IEND' 之前找到它,然後將其儲存到 .bin 檔案中或以其他方式儲存它,以便以後寫入檔案。至於經典圖示,您可以按順序讀取它們。對於 AROS,我們可以直接使用 IconControl 函式,但對於 Windows 或 AROS 以外的作業系統,您需要使用另一種方法來讀取圖示資料。

OS4 和 MorphOS 使用與我們相同的 PNG 圖示型別,還是不同的變體?它們使用相同的格式(PowerIcons 的起源),即一個名為“*.info”的普通 PNG 檔案,其中包含一些額外的 PNG 塊來儲存一些圖示資料。(PNG 在這種情況下類似於 IFF)。

擴充套件圖示 3.5 以包含 PNG 資料,以便 (a) 我們生成的 ICON 可以工作在任何 Amiga 系統上,包括 OS 1.x 到 3.x,以及 (b) 我可憐的 68000 可以從圖示檔案中選擇一個平面圖像,而不是每張圖示花費大約 7 秒將 ARGB 轉換為 4 色平面。

現有的 PNG 支援 *不會* 被更改——因此我們應該能夠繼續在更快的處理器上享受 AmigaOS4 和 Morphos 圖示集。

帶有特殊 ic0n 塊嵌入到 png 中的 png 影像可以是 1 或 2 張 png 影像。

ic0n 塊儲存填充 f.e. drawerdata 結構所需的“舊”資料。

它是一個標籤列表,可以包含來自以下列表的零個或多個標籤。

ATTR_DRAWERX,
ATTR_DRAWERY,
ATTR_DRAWERWIDTH,
ATTR_DRAWERHEIGHT,
ATTR_DRAWERFLAGS,
ATTR_DRAWERFLAGS2,
ATTR_DRAWERFLAGS3,
ATTR_VIEWMODES,
ATTR_VIEWMODES2,
ATTR_DD_CURRENTX,
ATTR_DD_CURRENTY :
ATTR_ICONX,
ATTR_ICONY,
ATTR_STACKSIZE,
ATTR_TYPE,
ATTR_FRAMELESS:
ATTR_DEFAULTTOOL,
ATTR_TOOLTYPE:

當然,每個標籤後面都跟著它對應的值。

void List_Icontype(char *name)
{    
    LONG length = 0;
    struct DiskObject *icon = NULL;
    Printf("Reading icOn chunk values...\n");    
    Printf("Icon Filename: %s\n", name);

    char *iconfile = RemoveFileExtension(name);
    icon = GetDiskObjectNew(iconfile);
    if (icon != NULL)
    {        
        if (icon->do_Type)
        {
           LONG type = icon->do_Type;
           Printf("Icontype: %ld\n", type); 
        }
    }
    FreeDiskObject(icon);        
}

LONG List_Icon_Chunk_Deftool(char *name)
{    
    LONG length = 0;
    struct DiskObject *icon = NULL;
    Printf("Reading icOn chunk values...\n");    
    Printf("Icon Filename: %s\n", name);

    char *iconfile = RemoveFileExtension(name);
    icon = GetDiskObjectNew(iconfile);
    if (icon != NULL)
    {                
        if (icon->do_DefaultTool) 
        {
            Printf("Deftool: %s\n", icon->do_DefaultTool);
            length = strlen(icon->do_DefaultTool) + 1;
        }
    }
    FreeDiskObject(icon);

    return length;    
}

LONG List_Icon_Chunk_Tooltype(char *name)
{
    LONG length = 0;
    struct DiskObject *icon = NULL;
    Printf("Reading icOn chunk values...\n");    
    Printf("Icon Filename: %s\n", name);

    char *iconfile = RemoveFileExtension(name);
    icon = GetDiskObjectNew(iconfile);
    if (icon != NULL)
    {        
        if (icon->do_ToolTypes)
        {
            int i = 0;
            char *tt = NULL;
            while ((tt = icon->do_ToolTypes[i]) != NULL)
            {
                Printf("Tooltype: %s\n", tt);
                length += strlen(icon->do_ToolTypes[i]) + 1;
                i++;
            }
        }
    }
    FreeDiskObject(icon);

    return length;
}

void List_Icon_Chunk_Tags(char *name, BPTR file, int curPos, LONG pSize)
{    
    ULONG attr;
	IPTR val = 0;     
    UBYTE *chunkdata;
	UBYTE Buffer32[4];           

    LONG len = 0;
    LONG chunksize = pSize;
    LONG pOffset = (LONG)curPos;

    Printf("Reading icOn chunk tags...\n");
    Printf("icOn chunk Size: %ld\n", pSize);
    Printf("icOn chunk Offset: %ld\n", pOffset);

    //#define ATTR_ICONX   	    0x80001001
    //#define ATTR_ICONY   	    0x80001002
    //#define ATTR_DRAWERX 	    0x80001003
    //#define ATTR_DRAWERY 	    0x80001004
    //#define ATTR_DRAWERWIDTH    0x80001005
    //#define ATTR_DRAWERHEIGHT   0x80001006
    //#define ATTR_DRAWERFLAGS    0x80001007
    //#define ATTR_TOOLWINDOW     0x80001008  //OS4: STRPTR, tool window string, length including the tag, multiple of 8
    //#define ATTR_STACKSIZE	    0x80001009
    //#define ATTR_DEFAULTTOOL    0x8000100a
    //#define ATTR_TOOLTYPE	    0x8000100b
    //#define ATTR_VIEWMODES      0x8000100c  //OS4 PNG use that
    //#define ATTR_DD_CURRENTX    0x8000100d  //OS4 ULONG, drawer view X offset
    //#define ATTR_DD_CURRENTY    0x8000100e  //OS4 ULONG, drawer view Y offset
    //#define ATTR_TYPE           0x8000100f  //OS4 icon type (WBDISK...WBKICK)
    //#define ATTR_FRAMELESS      0x80001010  //OS4 ULONG, frameless property
    //#define ATTR_DRAWERFLAGS3   0x80001011  //OS4 ULONG, drawer flags
    //#define ATTR_VIEWMODES2     0x80001012  //OS4 ULONG, drawer view modes
    //#define ATTR_DRAWERFLAGS2   0x80001107  //written from AFA to store needed dopus Magellan settings       

    while(pSize >= 4) //(pOffset < chunksize)
    {   
        /* Read icOn chunk attribute tag */
        Seek(file,pOffset,OFFSET_BEGINNING);
		Read(file,Buffer32, 4); //length = 4;        
        attr = (Buffer32[0] << 24) | (Buffer32[1] << 16) | (Buffer32[2] << 8) | Buffer32[3];                

        pOffset += 4; //offset + 4
        pSize -=4; //size - 4

        /* Read icOn chunk value tag */
        Seek(file,pOffset,OFFSET_BEGINNING);
		Read(file,Buffer32, 4); //length = 4;        
        val = (Buffer32[0] << 24) | (Buffer32[1] << 16) | (Buffer32[2] << 8) | Buffer32[3];

        pOffset += 4; //offset + 4
        pSize -=4; //size - 4

        /* Compare icOn chunk attribute tags */
        if(attr == 0x80001001) Printf("IconX: %ld\n", val);
        if(attr == 0x80001002) Printf("IconY: %ld\n", val); 
        if(attr == 0x80001003) Printf("DrawerX: %ld\n", val); 
        if(attr == 0x80001004) Printf("DrawerY: %ld\n", val);
        if(attr == 0x80001005) Printf("Drawerwidth: %ld\n", val); 
        if(attr == 0x80001006) Printf("Drawerheight: %ld\n", val);
        if(attr == 0x80001007) Printf("Drawerflag: %ld\n", val);
        if(attr == 0x80001008) Printf("Toolwin: %ld\n", val);      
        if(attr == 0x80001009) Printf("Stacksize: %ld\n", val);
        if(attr == 0x80001010) Printf("Frameless: %ld\n", val);
        if(attr == 0x8000100f) Printf("Icontype: %ld\n", val);
        //if(attr == 0x8000100a) Printf("Deftool found.\n");
        //if(attr == 0x8000100b) Printf("Tooltype found.\n");

        if(attr == 0x8000100a)
        { 
            Printf("Deftool found.\n");
            len = List_Icon_Chunk_Deftool(name);
            pOffset += len;
        }

        if(attr == 0x8000100b)
        {
            Printf("Tooltype found.\n");
            len = List_Icon_Chunk_Tooltype(name);            
            pOffset += len;
        }
    } /* while(chunksize >= 4) */    
}


處理

[edit | edit source]

應用程式視窗/選單/圖示的圖示處理。這就是從 Kickstart 2.04 開始,以圖形方式處理來自已執行應用程式的檔案(表示為圖示物件)的概念的實現方式。因此,選擇圖示對於任何應用程式來說是不夠的:使用者必須執行一個額外的操作(即拖動選定的圖示到應用程式視窗/圖示,或選擇應用程式選單)。

Wanderer 目前只允許使用應用程式視窗。因此,將您的視窗提升為應用程式視窗,然後監聽應用程式訊息並採取相應操作。

如果您想要一次對多個圖示採取操作,則需要調整程式碼以瀏覽 AppMessage->am_ArgList 的次數,與 AppMessage->am_NumArgs 一致...

我們“DefaultIcon”的實現更好(更像是原始實現)——新增使用模式匹配而不是效率較低的資料型別匹配的預設圖示很容易。

如果圖示與目錄關聯(WBDISK、WBDRAWER、WBGARBAGE),則需要一個 DrawerData 結構來與其一起使用。此結構包含一個 Intuition NewWindow 結構 [...] Workbench 使用它來儲存視窗的當前視窗位置和大小,以便它將在相同的位置重新開啟。

對於目錄,圖示儲存在與目錄名稱出現位置相同的級別的 .info 檔案中(不在目錄本身內)。圖示型別應設定為 DRAWER。磁碟的圖示應始終儲存在磁碟根級目錄下的名為 disk.info 的檔案中。圖示型別應設定為 DISK。(圖示型別可以使用 IconEdit 程式設定,並且圖示影像可以使用該程式編輯)。

因此很清楚,名為“foo”的 Amiga 磁碟在根目錄下包含一個名為“disk.info”的檔案:這是磁碟圖示的影像(在主 Workbench 視窗中看到,並與名稱“foo”關聯),以及使用者雙擊它時要開啟的視窗的座標。如果磁碟包含一個名為“bar”的帶有圖示的抽屜,您可以使用“C:List foo:”來讀取內容,這些內容至少應包括“bar”(即抽屜本身)和“bar.info”(包含抽屜圖示影像(在 Workbench 螢幕上的 foo 視窗中看到)_和_ 使用者雙擊此 bar 圖示時要開啟的視窗的座標)。當然,磁碟可以沒有圖示,抽屜也可以沒有圖示:在這種情況下,Workbench 可以提供預設圖示(並且始終為磁碟提供預設圖示)。

據我所知,Amiga 圖示的處理方式是這樣的。

透過執行類似於以下操作來開啟它們。

struct DiskObject *icon = GetIconTags(PUT_YOUR_TAGS_HERE);

然後,例如,您可以透過以下方式讀取圖示的座標。

printf("Icon X coord. in drawer/on WorkBench: %ldn",icon->do_CurrentX); 
printf("Icon Y coord. in drawer/on WorkBench: %ldn",icon->do_CurrentY);

如果它是抽屜或磁碟的圖示(那麼 info 檔案包含一個 DrawerData 結構),您可以讀取雙擊圖示時要開啟的視窗的座標。

printf("Left Edge position of drawer's window: %dn",icon->do_DrawerData->dd_NewWindow.LeftEdge); 
printf("Top Edge position of drawer's window:  %dn",icon->do_DrawerData->dd_NewWindow.TopEdge); 
printf("Drawer's window Width:                 %dn",icon->do_DrawerData->dd_NewWindow.Width); 
printf("Drawer's window Height:                %dn",icon->do_DrawerData->dd_NewWindow.Height);

如果它是為 OS2+ 設計的抽屜(或磁碟)圖示,它會在 DrawerData 結構中包含 Flags 和 ViewModes,它們儲存抽屜視窗中圖示的顯示方式:您可以透過類似於以下操作來讀取它們。

switch(icon->do_DrawerData->dd_Flags) 
{ 
    case 0: 
        printf("Default"); 
        break; 
    case 1: 
        printf("Show only icons"); 
        break; 
    case 2: 
        printf("Show all files"); 
        break; 
    case 3: 
        printf("Show all files"); 
        break; 
    default: 
        printf("Only values between 0 an 3 should be found here"); 
} 
switch(icon->do_DrawerData->dd_ViewModes) 
{ 
    case 0: 
        printf("Default (inherit from parent)"); 
        break; 
    case 1: 
        printf("View as icons"); 
        break; 
    case 2: 
        printf("View as text, sorted by name"); 
        break; 
    case 3: 
        printf("View as text, sorted by date"); 
        break; 
    case 4: 
        printf("View as text, sorted by size"); 
        break; 
    case 5: 
        printf("View as text, sorted by type"); 
        break; 
    default: 
        printf("Only values between 0 an 5 should be found here"); 
}

預設圖示透過預設圖示工具型別指定圖示(因此是檔案型別)的可能操作。正常的圖示行為仍然用於其預設操作,但它也可以公開該檔案型別的特定操作,例如。

ICON_ACTION="Preview","SYS:Utiltieis/MultiView"
ICON_ACTION="Edit","Extras:Gfx/LunaPaint"


工具型別

[edit | edit source]

來自 http://utilitybase.com/forum/index.php?action=vthread&forum=2&topic=1252

修改圖示中的 tooltypeslist 時要非常小心。

  1. 讀取一個圖示 (Icon->GetdiskObject())
  2. 構建一個新的 tooltypeslist
  3. 將當前 tooltypelist 的地址複製到安全的地方
  4. 將 NEW tooltypeslist 的地址複製到圖示
  5. 重寫圖示 (Icon->PutDiskObject())
  1. 將舊 tooltypeslist 的地址從安全的地方複製回圖示
  2. 釋放磁碟物件 (Icon->FreeDiskObject())

6 和 7 實際上並不必要。icon.library 透過附加到 'struct DiskObject' 本身的機制來跟蹤與載入的圖示關聯的所有資料,該機制位於結構的私有未記錄部分。它不會跟蹤指標,也不會假設它們指向有意義的地方。

從本質上講,這意味著您可以修改 'struct DiskObject' 文件部分的每個位資訊,而不會產生不良影響。但是您必須小心,確保資訊本身在您要將其寫回磁碟時是一致的。雖然 icon.library 會執行一些健全性檢查,尤其是 icon.library V44 及更高版本,但您所能做的有限。

應用程式通常希望呼叫 GetDiskObjectNew()——而不是 GetDiskObject()——來獲取放入視窗的圖示的磁碟物件。

#include <workbench/workbench.h>
#include <workbench/icon.h>

#include <proto/icon.h>

#include <stdio.h>

int main(int argc, char **argv)
{
    STRPTR newToolTypes[] =
    {
        "AROS=RULES",
        "Tooltypes are actually free-form text",
        "Ain't that neat?",
        NULL
    };
    
    struct DiskObject *icon = GetIconTags
    (
        "writetooltypes", ICONGETA_FailIfUnavailable, FALSE, TAG_DONE
    );
    
    if (icon != NULL)
    {
        STRPTR *oldToolTypes = icon->do_ToolTypes;
        
        icon->do_ToolTypes = newToolTypes;
        if (!PutIconTags("writetooltypes", icon, TAG_DONE))
        {
            printf("ERROR: Failed to write icon.\n");
        }
        icon->do_ToolTypes = oldToolTypes;
        
        FreeDiskObject(icon);
    }
    else
    {
        printf("ERROR: Failed to open icon for file\n");
        return 20;
    }

    return 0;
}


LayoutIcon

[edit | edit source]

目前,LayoutIcon 尚未實現,這是一種想法,可以為 PNG 影像節省大量 RAM,當它們在低色螢幕上渲染時。思路是使用 LayoutIcon() 將圖示渲染到螢幕的點陣圖佈局中,並將其用作圖示的工具影像,然後使用 FreeMem() 釋放 PNG 或其他高色圖示影像。

這類似於 AOS 的處理方式,但有一個技巧——我“記住”原始影像的格式(以及 .icon 檔案中的偏移量和大小),並在呼叫 PutDiskObject() 時,我會小心地避免在影像資料上亂塗亂畫,從而保留原始影像。

但是,當用戶更改螢幕深度時,您需要更新影像。在 AFA 中,layoutIcon 還沒有實現,我在函式被呼叫時,在偵錯程式命令中的跳轉前添加了一些時間來進行測試。如果一個程式使用此函式,我會看到 Workbench 沒有使用此函式。其他程式也沒有使用。但是,當您建立一個快取,以便所有預設圖示只加載一次時,可以加快 AROS iconlib 的速度,並減少記憶體使用量。getdiskobject 然後只提供指向現有預設圖示的指標。

AROS 上的問題是,它每次都會載入圖示並使用新的記憶體。例如,如果您顯示 100 個 jpg 檔案,那麼會載入 100 * icon def_jpg.info。因此會使用 100 * 記憶體和載入時間。由於 wanderer 始終載入所有圖示,即使只有圖示檢視被選中也是如此。

透明 PNG

[edit | edit source]

graphics.lbrary BltMaskBitMapRastPort 很有用

static void Change_State(int Reset)
{
    int x;

    for(x=Levels_Struct[CurrentLevel].Beginning; x<IconCounter; x++)
    {
        if(Icons_Struct[x].Icon_OK)
        {
            if(Icons_Struct[x].Icon_Status != 0)
            {
                if(Reset == 0)
                {
                    if((Icons_Struct[x].Icon_Status & ICON_ACTIVE) == 0 && Icons_Struct[x].Icon_Status < 4)
                    {
                        // 11000111b
                        Icons_Struct[x].Icon_Status = (Icons_Struct[x].Icon_Status - 1) & 0xC7;
                    }
                    else
                    {
                        Icons_Struct[x].Icon_Status = (Icons_Struct[x].Icon_Status + 1) & 0xC7;
                    }
                }
                else
                {
                    Icons_Struct[x].Icon_Status = 0;
                }

                Insert_Icon((Icons_Struct[x].Icon_Status & SELECTED_ICON) ? IDS_SELECTED : IDS_NORMAL, x);
            }
        }
    }
}

static void Insert_Icon(int Tryb, int IconNumber)
{
    BltBitMapRastPort(BMP_Buffer,
        Icons_Struct[IconNumber].Icon_PositionX,
        0,
        &RP_DoubleBuffer, //Window_struct->RPort,
        0, //Icons_Struct[IconNumber].Icon_PositionX,
        0,
        Icons_Struct[IconNumber].Icon_Width + 1,
        WindowHeight,
        0xC0);

    DrawIconState(&RP_DoubleBuffer, //Window_struct->RPort,
        Icon[IconNumber],
        NULL,
        0, //Icons_Struct[IconNumber].Icon_PositionX,
        Icons_Struct[IconNumber].Icon_PositionY - MovingTable[(Icons_Struct[IconNumber].Icon_Status & 0x07)],
        Tryb,
        ICONDRAWA_Frameless, TRUE,
        ICONDRAWA_EraseBackground, FALSE,
        TAG_DONE);

    BltBitMapRastPort(BMP_DoubleBuffer,
        0,
        0,
        Window_struct->RPort,
        Icons_Struct[IconNumber].Icon_PositionX,
        0,
        Icons_Struct[IconNumber].Icon_Width + 1,
        WindowHeight,
        0xC0);
}

static void Blink_Icon(int IconNumber)
{
    int x, Tryb=IDS_SELECTED;

    for(x=0; x<8; x++)
    {
        Insert_Icon(Tryb, IconNumber);
        Delay(3);

        if(Tryb == IDS_NORMAL) Tryb = IDS_SELECTED;
        else Tryb = IDS_NORMAL;
    }
}

資料型別檢測

[編輯 | 編輯原始碼]

icon.library 使用 sys:devs/datatypes 中的資料型別描述符來識別檔案型別。然後使用一個名為 def_NAME.info 的預設圖示來表示型別為 NAME 的檔案。AROS 構建系統使用名為 createdtdesc 的工具從簡單的文字檔案建立資料型別描述符。

在圖示可以移動後,能夠對它們的位置進行快照將是一件好事。

以及抽屜圖示中視窗的位置。但是需要注意的是,據我所知,在某個地方(可能是 icon.library 中)存在一個錯誤/未實現的功能,它阻止了在所有情況下正確儲存 DrawerData 結構(dd_Flags 和 dd_NewWindow 成員)。因此 Wanderer 目前也遇到了這個問題,你無法同時儲存“檢視所有檔案”狀態以及抽屜視窗的位置快照。

  1. 在包含對映關係的目錄中使用資料庫,在處理單個檔案時效率也不高——可能比使用 deficons/datatypes(通常只掃描檔案的頭幾個位元組)匹配效率更低。當在一個大型目錄中,你要查詢的檔案位於資料庫的深處時會發生什麼?效能會更慢..
  1. 現代檔案系統可以在檔案中儲存額外的元資料——例如,在 NTFS 中,幾乎所有東西都是某種形式的屬性,只要稍微修改一下,就能讓大多數 AmigaOS 程式碼的 exall/exnext 目錄掃描迴圈能夠查詢/設定這些屬性。

一種情況是結合使用檔案系統元資料和預設圖示。

應用程式使用普通的 AmigaOS 例程掃描一個包含檔案的目錄。我們提供了一個新的例程 (*) 來查詢檔案/鎖的屬性(它使用資料包與檔案系統處理程式通訊並查詢元資料),我們用它來請求資料格式屬性。這不會造成任何/大量的 IO 負擔,因為元資料很可能已經被快取作為掃描目錄的一部分。如果屬性不可用,我們可以使用預設圖示模式/資料匹配來識別檔案——並且可選地設定屬性,如果檔案系統支援元資料。

(*) 或許這個呼叫可以在 deficon 程式碼中處理,這樣現有的使用 icon.library 等的 AmigaOS 程式碼就可以從中受益,而無需進行更改。

function readIFFICON(file){
		
		var index = file.index;
		var img = {states:[]};
		
		function readChunk(){
			var chunk = {};
			chunk.name = file.readString(4);
			chunk.size = file.readDWord();
			return chunk;
		}

		while (index<file.length-4){
			file.goto(index);
			var chunk = readChunk();
			index += chunk.size + 8;
			if (chunk.size%2 === 1) index++;
			
			switch (chunk.name){
				case "FACE":
					img.width = file.readUbyte() + 1;
					img.height = file.readUbyte() + 1;
					img.flags = file.readUbyte();
					img.aspectRatio = file.readUbyte(); //upper 4 bits:x aspect, lower 4 bits: y aspect
					img.MaxPaletteSize = file.readWord();
                    console.log("Icon is " + img.width + "x" + img.height);
					break;
				case "IMAG":
					var endIndex = file.index + chunk.size;

					var state = {};
					state.transparentIndex = file.readUbyte();
					state.NumColors = file.readUbyte() + 1;
					state.flags = file.readUbyte();
					state.imageCompression = file.readUbyte();
					state.paletteCompression = file.readUbyte();
					state.depth = file.readUbyte();
					state.imageSize = file.readWord() + 1;
					state.paletteSize = file.readWord() + 1;

					state.pixels = [];
					state.palette = [];

					var imageDataOffset = file.index;
					var paletteDataOffset = imageDataOffset + state.imageSize;

                    if (state.imageCompression){
						// note: this is BIT aligned, not byte aligned ...
						// -> RLE control chars are 8 bits, but the data elements are n bits, determined by state.depth

						var max = (state.imageSize-1) * 8;
						var bitIndex = 0;

						while (bitIndex < max) {
							var b = file.readBits(8,bitIndex,imageDataOffset);
                            bitIndex += 8;
							
							if (b > 128) {
								var b2 = file.readBits(state.depth,bitIndex,imageDataOffset);
                                bitIndex += state.depth;
								for (var k = 0; k < 257 - b; k++) state.pixels.push(b2);
							}
							if (b < 128) {
								for (k = 0; k <= b; k++){
									state.pixels.push(file.readBits(state.depth,bitIndex,imageDataOffset));
                                    bitIndex += state.depth;
                                }
							}
						}
					}else{
                        // note: uncompressed data is BYTE aligned, even if state.depth < 8
						for (var i = 0; i < state.imageSize; i++){
							state.pixels.push(file.readUbyte())
						}
					}

					if (state.paletteSize){
                        file.goto(paletteDataOffset);
                        var rgb = [];

                        var bitsPerColorByte = 8;

                        if (state.paletteCompression){
                            var max = (state.paletteSize-1) * 8;
                            var bitIndex = 0;

                            while (bitIndex < max) {
                                var b = file.readBits(8,bitIndex,paletteDataOffset);
                                bitIndex += 8;

                                if (b > 128) {
                                    var b2 = file.readBits(bitsPerColorByte,bitIndex,paletteDataOffset);
                                    bitIndex += bitsPerColorByte;
                                    for (var k = 0; k < 257 - b; k++) rgb.push(b2);
                                }
                                if (b < 128) {
                                    for (k = 0; k <= b; k++){
                                        rgb.push(file.readBits(bitsPerColorByte,bitIndex,paletteDataOffset));
                                        bitIndex += bitsPerColorByte;
                                    }
                                }
                            }
                        }else{
                            for (i = 0; i < state.paletteSize; i++){
                                rgb.push(file.readUbyte())
                            }
                        }

                        if (rgb.length>2){
                        	for (i = 0, max = rgb.length; i<max; i+=3){
                        		state.palette.push([rgb[i],rgb[i+1],rgb[i+2]])
							}
						}
					}
					
					img.states.push(state);


					break;
				case "ARGB":
					// zlib compressed
					// found some info/structure on https://amigaworld.net//modules/newbb/viewtopic.php?viewmode=flat&order=0&topic_id=34625&forum=15&post_id=639101#639062

					console.log("decoding ARGB data");
					
					var state = {};

					state.rgba = true;
					state.pixels = [];
					state.palette = [];
					
					
					for (var offset = 0; offset<10;offset++){
						// no idea what this data structure is ...
						// first DWORD always seem to be 1?
						state.dummy = file.readUbyte();
						//console.log(state.dummy);
					}
					
					var size = chunk.size-offset;
					var data = new Uint8Array(size);
					for (var i = 0; i<size; i++){
						data[i] = file.readUbyte();
					}

					try{
						var a;
						if (typeof Zlib !== "undefined"){
							// running in browser
							a = new Zlib.Inflate(data).decompress();
						}else{
							// running in node
							var zlib = require('zlib');
							a = zlib.inflateSync(data);
						}
						
						for (var y = 0; y<img.height; y++){
							for (var x = 0; x<img.width; x++){
								var pixelIndex = (y*img.width + x) * 4;
								var color = [a[pixelIndex+1]||0,a[pixelIndex+2]||0,a[pixelIndex+3]||0,(a[pixelIndex]||0)/255];
								state.pixels.push(color);
							}
						}
						
						img.states.push(state);
						
						
					}catch (e) {
						console.log("invalid zlib structure");
					}
					
					break;
				default:
					console.log("unhandled IFF chunk: " + chunk.name);
					break;
			}
		}
		
		return img;
	}

/**************************************************************************************************/

static char *DecodeOS35(unsigned char *buffer, LONG numbytes, LONG bits, struct IconImage *im, enum DecodeType type, LONG mode)
{
  int cop = 0, loop = 0, entries, numbits = 0, mask, curentry = 0;
  ULONG bitbuf = 0;
  ULONG byte;

  //DecodeNew(buffer+10, numi, imf ? dep : 8, im, DECODE_IMAGE, imf)
  //DecodeNew(buffer+10+numi, nump, 8, im, DECODE_PALETTE, palf)

  Printf ("DecodeOS35 - mode: %ld\n", mode);
  Printf ("DecodeOS35 - bits: %ld\n", bits);
  Printf ("DecodeOS35 - bytes: %ld\n", numbytes);
  Printf ("DecodeOS35 - colors: %ld\n", im->NumColors);

  Printf ("Icon Image Dimensions: %ld, %ld\n", im->Width, im->Height);

  if(type == DECODE_IMAGE) Printf ("DECODE_IMAGE\n");
  if(type == DECODE_PALETTE) Printf ("DECODE_PALETTE\n");

  //WriteData("Ram Disk:imgdata1.bin", buffer, numbytes);

  if(!mode) /* no RLE */
    cop = numbytes*8/bits; //planar Size
  if(type == DECODE_PALETTE)
    entries = im->NumColors*3;
  else
    entries = im->Width*im->Height;

  mask = (1<<bits)-1;

  /* UnpackByteRun RLE */
  while((numbytes || (cop && numbits >= bits)) && (curentry < entries))
  {
    if(!cop) /* RLE */
    {
      if(numbits < 8)
      {
        bitbuf = (bitbuf<<8)|*(buffer++); --numbytes;
        numbits += 8;
      }
      byte = (bitbuf>>(numbits-8))&0xFF;
      numbits -= 8;
      if(byte <= 127)     cop = byte+1;
      else if(byte > 128) loop = 256-byte+1;
      else                continue;
    }
    if(cop) ++loop;

    if(numbits < bits)
    {
      bitbuf = (bitbuf<<8)|*(buffer++); --numbytes;
      numbits += 8;
    }
    byte = (bitbuf>>(numbits-bits))&mask;
    
    while(loop && (curentry < entries))
    {
      if(type == DECODE_PALETTE)
      { /* NOTE: This may not be very fast, but for sure portable */
        switch(curentry%3)
        {
        case 0: im->Palette[curentry/3].Red = byte; break;
        case 1: im->Palette[curentry/3].Green = byte; break;
        case 2: im->Palette[curentry/3].Blue = byte; break;
        }
      }
      else
        im->ImageData[curentry] = byte;
      ++curentry;
      --loop;
    }
    if(cop) --cop;
    numbits -= bits;
  }  
  //return "DecodeOS35 completed successfully";
  return curentry != entries ? "error decoding icon data" : 0;
}

/**************************************************************************************************/
/*
    Example for changing icon tooltypes.
*/

#include <proto/exec.h>
#include <proto/dos.h>
#include <proto/icon.h>

#include <workbench/startup.h>

#include <stdlib.h>
#include <stdio.h>
#include <string.h>

static STRPTR conwinname   = "CON:30/50/500/400/Tooltype parsing/AUTO/CLOSE/WAIT";
static BPTR conwin;
static BPTR olddir = (BPTR)-1;
static struct DiskObject *dobj;
static STRPTR *oldtoolarray, *newtoolarray;

static void clean_exit(CONST_STRPTR s);

int main(int argc, char **argv)
{
    if (argc)
    {
        clean_exit("Application must be started from Wanderer.");
        /* See dos_readargs.c for start from Shell. */
    }
    else
    {
        struct WBStartup *wbmsg = (struct WBStartup *)argv;
        struct WBArg *wbarg = wbmsg->sm_ArgList;
        STRPTR *toolarray;
        LONG toolcnt = 0;
        LONG idx;
        
        /*
            An application started from Wanderer doesn't have a console window
            for output. We have to open our own con: window or all output will
            go to Nirwana.
        */
        conwin = fopen(conwinname, "w");
        if (!conwin)
        {
            clean_exit("Can't open console window");
        }
        
        if ( (wbarg->wa_Lock) && (*wbarg->wa_Name) )
        {
            fprintf(conwin, "Trying to open %s\n", wbarg->wa_Name);
            
            /* We must enter the directory of the icon */
            olddir = CurrentDir(wbarg->wa_Lock);

            dobj = GetDiskObject(wbarg->wa_Name);
            if (dobj)
            {
                /*
                    Remember the old toolarray, so that we can put it back later.
                */
                oldtoolarray = dobj->do_ToolTypes;
            
                /* Count entries */
                if (oldtoolarray)
                {
                    toolarray = oldtoolarray;
                    while (*toolarray)
                    {
                        toolcnt++;
                        toolarray++;
                    }
                }
                fprintf(conwin, "Old icon has %d tooltype entries\n", toolcnt);
                
                /* Create new toolarray */
                newtoolarray = AllocVec(sizeof(STRPTR) * (toolcnt + 3), MEMF_ANY);
                if (!newtoolarray)
                {
                    clean_exit("Can't allocate memory for new toolarray");
                }
                /*
                    Add two new entries and copy the pointers to the
                    old values. If w'd want to change the strings we'd
                    have to work with copies of the strings.
                */
                newtoolarray[0] = "START";
                for (idx = 0 ; idx < toolcnt; idx++)
                {
                    newtoolarray[idx+1] = oldtoolarray[idx];
                }
                newtoolarray[toolcnt + 1] = "END";
                newtoolarray[toolcnt + 2] = NULL;
                
                /* Change toolarray pointer and save icon. */
                dobj->do_ToolTypes = newtoolarray;
                if (!PutDiskObject(wbarg->wa_Name, dobj))
                {
                    clean_exit("Can't write Diskobject");
                }
            }
            else
            {
                clean_exit("Can't open DiskObjekt");
            }
        }
    }

    clean_exit(NULL);

    return 0;
}

static void clean_exit(CONST_STRPTR s)
{
    if (s)
    {
        if (conwin)
        {
            fprintf(conwin, "%s\n", s);
        }
        else
        {
            printf("%s\n", s);
        }
    }
    
    /* Give back allocated resourses */
    if (conwin) fclose(conwin);

    /*
        Free DiskObject. We have to set back the pointer to the toolarray or
        we'll get memory corruption.
    */
    if (dobj)
    {
        dobj->do_ToolTypes = oldtoolarray;
        FreeDiskObject(dobj);
    }
    
    FreeVec(newtoolarray);
    
    /*
        Switch back to old directory. It's important that the directory which
        was active at program start is set when the application is quit.
    */
    if (olddir != (BPTR)-1)
    {
        CurrentDir(olddir);
        olddir = (BPTR)-1;
    }
    
    exit(0);
}


基於 SVG 的圖示的問題是,沒有地方儲存圖示資料本身。PNG 圖示使用 icOn 塊。經典圖示將圖示屬性儲存在磁碟物件資料中,等等。但 SVG 必須是一個混合圖示。經典 Amiga 圖示檔案在開頭。通常 Glow 圖示的 IFF 資料所在的位置是 SVG 資料的開頭。它可以儲存多少影像?

SVG 是一種非常靈活的格式,因為它允許嵌入向量、點陣圖和文字內容,以及轉換/過濾器/動畫,因此你甚至不需要定義像雙 PNG 這樣的東西(一個 SVG 就足以模擬它)。SVG 允許定義任何型別的元資料,這些元資料可用於儲存圖示屬性(以及更多)。你可以將這些標籤新增到任何地方(據我所知),因此即使在 XML 資料 的開頭(如果需要,可以將其“強制”為對這些新圖示的要求)。


struct DiskObject *NewDiskObject(ULONG type) 
struct DiskObject *GetIconTagList(CONST_STRPTR name, const struct TagItem *tags)

struct DiskObject *GetDiskObject(CONST_STRPTR name) 
BOOL PutDiskObject(CONST_STRPTR name, struct DiskObject *icon) 
void FreeDiskObject(struct DiskObject *diskobj)

BOOL AddFreeList(struct FreeList *freelist, APTR mem, unsigned long size) 
void FreeFreeList(struct FreeList *freelist)

UBYTE *FindToolType(const STRPTR *toolTypeArray, const STRPTR typeName) 
BOOL MatchToolValue(UBYTE *typeString, UBYTE *value) 
UBYTE *BumpRevision(UBYTE *newname, UBYTE *oldname)

struct DiskObject *GetDefDiskObject(LONG type) 
BOOL PutDefDiskObject(struct DiskObject *icon) 
struct DiskObject *GetDiskObjectNew(CONST_STRPTR name) 
BOOL DeleteDiskObject(UBYTE *name)

struct DiskObject *DupDiskObjectA(struct DiskObject *icon, struct TagItem *tags)

ULONG IconControlA(struct DiskObject *icon, struct TagItem *tags) 
void DrawIconStateA(struct RastPort *rp, struct DiskObject *icon, STRPTR label, LONG leftEdge, LONG topEdge, ULONG state, struct TagItem *tags)

BOOL GetIconRectangleA(struct RastPort *rp, struct DiskObject *icon, STRPTR label, struct Rectangle *rectangle, struct TagItem *tags)

BOOL PutIconTagList(CONST_STRPTR name, struct DiskObject *icon, struct TagItem *tags) 
BOOL LayoutIconA(struct DiskObject *icon, struct Screen *screen, struct TagItem *tags) 
void ChangeToSelectedIconColor(struct ColorRegister *cr) 
華夏公益教科書