跳转到内容

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) 
华夏公益教科书