Mehr Icons für das Desktop

Hat es Sie auch schon einmal gestört, daß eine Resource-Datei nur maximal 64 Kilobyte groß sein darf und man deshalb ,nur‘ 207 Icons in die DESKICON.RSC-Datei des neuen Desktops von STE und TT bekommen kann? Wie man trotzdem auf bis zu 255 Icons zugreifen und dabei auch noch Speicherplatz sparen kann, zeigt dieser Artikel.

Normalerweise wird die DESKICON.RSC-Datei mit einem Resource-Construction-Set erzeugt oder verändert, z. B. um weitere Icons hinzuzufügen. Ein RCS geht aber bei der Speicherung einer Resource-Datei nicht so vor, wie es für das Desktop optimal wäre. Es ist zwar zugegebenermaßen einfacher, schneller und für einige Anwendungen auch ratsamer, den .normalen1 Aufbau einer Resource zu benutzen, aber für den Spezialfall der DESKICON.RSC-Datei geht es auch anders. Wie diese Alternative funktioniert, soll nach einer kurzen Erklärung "normaler" Resource-Dateien erläutert werden.

Bild 1: Aufbau der Resource-Datei

Eine Resource besteht aus mehreren Blöcken, die unterschiedliche Bedeutungen haben (siehe unter [1] und [3]). Für das Desktop sind dabei nur Informationen über das Aussehen von Icons wichtig, weshalb auch auf alle anderen Daten verzichtet werden kann. Darum beschränke ich mich auf die Erläuterung der Blöcke, in denen Daten über die Icons enthalten sind.

Der erste Block von Interesse ist der Header, der aus 36 Byte besteht. In ihm sind die Pointer auf die folgenden Blöcke und Angaben über die Anzahl ihrer Elemente enthalten. Außerdem ist am Ende des Headers die Länge der Resource zu finden. Die Reihenfolge der weiteren Blöcke ist nicht wichtig, da auf sie über Pointer zugegriffen wird. In den je 24 Byte großen Objektblöcken sind die Pointer auf die jeweiligen Icon-Blöcke enthalten sowie die Position des Icons auf dem Objekt, in dem es sich befindet.

In den Icon-Blöcken von je 34 Byte sind die Pointer auf Image, Masken und Text untergebracht. Der ,Text‘-Pointer zeigt hierbei auf eine Zeichenfolge im String-Block. Der String-Block wiederum besteht aus einer Anzahl von Zeichenketten, welche nach C-Konvention durch Bytes mit dem Wert Null getrennt sind. Des weiteren sind in den Icon-Blöcken die Farben von Image und Maske, der Buchstabe im Icon und dessen Lage sowie die Größe des Icons in Pixeln zu finden.

Unentbehrlich zur Darstellung eines Icons ist noch der Imageblock, in dem die Bit-Muster der Icons, aufgeteilt in Image und Maske, gespeichert sind. Das Desktop erwartet Icons mit einer Größe von 32 mal 32 Pixeln. Daraus folgt eine Länge von 128 Byte sowohl für das Image als auch für die Maske eines Icons. Im Image-Block werden die Icons normalerweise nacheinander untergebracht.

Als letzter Block ist der Tree-Index-Block zu nennen, der vier Byte große Pointer auf die Objektbäume enthält. Bei nur einem Objektbaum, wie im Fall der DESKICON.RSC-Datei, zeigt der Tree-Index einfach auf das erste Objekt.

Die Idee

Bild 2: Aufbau des Image-Blocks

Es gibt viele Icons, bei denen sich zwar die Images unterscheiden, aber die Masken identisch sind. Ein Beispiel hierfür sind Programm-Icons, die alle den gleichen Umriß haben und sich nur im Innern unterscheiden. Ein RCS speichert aber alle Masken separat ab, auch wenn sie gleich sind, also z.B. für 11 Icons sind dies 11 Images und 11 Masken. Durch die Verwendung von Pointern auf die Daten für Image und Maske in der Icon-Block-Struktur ist es aber durchaus möglich, vollständig gleiche Masken wegzulassen. Kommen z.B. in einer Resource 3 Icons vor, die die gleiche Maske besitzen, so soll diese Maske nur einmal gespeichert werden. Die Pointer dieser 3 Icons zeigen dann zwar auf verschiedene Image-Daten, aber auf dieselbe Maske. Mit diesem Verfahren kann man genügend Platz in einer Resource-Datei sparen, um mehr Icons darin unterzubringen. Bei Verwendung von nur einer Maske könnte man so 351 Icons in eine Resource-Datei packen.

Um die erstellten Icons auch benutzen zu können, muß das Desktop wissen, welche Icons für welchen Zweck gebraucht werden, z.B. welches Icon für einen Ordner verwendet wird. Diese Zuordnung ist unter anderem in der NEWDESK.INF-Datei enthalten. Leider werden in dieser Datei für die Numerierung der Icons nur zwei Zeichen verwendet, wobei die Zeichenfolge ,FF‘ (dezimal: 255) als ,Icon nicht vorhanden* gedeutet wird (siehe unter [4]). Daher kann man insgesamt nur 255 Icons (Nummer 0 bis 254) für das Desktop benutzen.

Der Entwurf

Was muß nun ein Programm tun, mit dem es möglich sein soll, eine Resource-Datei zu erzeugen, die bis zu 255 Icons enthalt? (Mehr Icons wären möglich, sind aber durch die NEWDESK.INF-Datei nicht sinnvoll.) Das einfachste ist es, die Icons mehrerer Resourcen aneinanderzuhängen und sie in einer Resource-Datei zu speichern. Dadurch kann man die Icons mit einem RCS bearbeiten und dann, packen ‘. Allerdings sollte das Programm auch in der Lage sein, eine gepackte Datei zu entpacken. Falls diese mehr Icons enthält als aus Speicherplatzgründen in eine ,normale* Resource-Datei passen, müssen auch zwei ungepackte Dateien erzeugt werden können.

Das Programm

Alle diese Punkte werden von dem Icon-Packer erfüllt. Das Programm ist allerdings nur für den Spezialfall der DESKICON.RSC-Datei geschrieben. Deswegen berücksichtigt es nur Icons und keine anderen Objekte. Auch derText des Icons ist hierbei nicht relevant und würde nur unnötig Platz in Anspruch nehmen. Daher zeigen alle ,Text‘-Pointer auf ein Byte mit dem Wert 0, was nach C-Konvention einem String mit der Länge Null entspricht.

Zum Ablauf des Programms: Es lädt eine oder mehrere RSC-Dateien und entnimmt ihnen jene Icons, die 32 mal 32 Pixel groß sind, bis entweder 255 Icons geladen sind (mit der Variablen max_icon=255) oder bei der Aufforderung zum Laden einer weiteren Resource-Datei .Abbruch* angeklickt wird. Danach fragt das Programm ab, ob die Daten gepackt werden sollen. Wurde ,packen* angewählt, werden die Masken auf Gleichheit untersucht und in der Liste ,info* als gleich markiert. Nun wird die Resource berechnet, gegebenenfalls gepackt und gespeichert. Das Programm erzeugt natürlich keine Dateien, die länger als 64 KByte sind, es bringt aber die maximale Anzahl von Icons in der Resource-Datei unter. Um 255 Icons in eine Resource zu packen, muß man mindestens 46 Masken doppelt verwenden, was bei Benutzung derselben Icon-Umrisse für Programme, Ordner und Dateien kein Problem sein sollte.

Bild 3: Icons mit gleichen Masken

Ein Feature

Haben Sie gewußt, daß es möglich ist, Icons auch farbig auf das Desktop zu bringen? In der Resource-Datei werden nämlich auch die Farben der Icons untergebracht. Da für den ASCII-Wert des im Icon angezeigten Buchstabens nur ein Byte gebraucht wird und Pointer auf Wortgrenzen liegen müssen, wird das andere Byte für die Speicherung der Farben genutzt. Dieses Byte ist in zwei mal vier Bit unterteilt, von denen die vorderen für die Farbe des Images (normal ist 1 für Schwarz, farbig wären die Werte 2 bis 15, nicht 0 -sonst ist das Icon nicht sichtbar) und die hinteren für die Farbe der Maske (immer 0) verantwortlich sind.

Durch Änderung der ersten vier Bit kann so die Farbigkeit des Icons und damit die des Desktops erhöht werden. Leider hat der Text unter dem Icon, z.B. der Dateiname, dieselbe Farbe wie das Icon. Wünschenswert wäre es, der besseren Lesbarkeit wegen, den Text immer in Schwarz darzustellen. Übrigens wird in einer monochromen Auflösung auch ein farbiges .Icon schwarzweiß dargestellt. Wer einmal farbige Icons bei sich ausprobieren will, kann dies durch Änderung der Variablen color tun. Hat color einen Wert, der von Null abweicht, wird dieser als Farbe aller Icons eingetragen. Wer seine Icons einzeln einfärben möchte, sollte hierzu ein Resource-Construction-Set verwenden. Ein dafür verwendbares RCS findet sich z.B. auf der Sonderdisk Nr. 2 von MAXON Computer.

Bild 4: Speicherung der Farben

Eine Anmerkung

Sowohl im Profibuch [1] als auch im GFA-BASIC-Handbuch [2] ist der Icon-Block mit einer Länge von 36 Byte angegeben. Eine Untersuchung einiger Resource-Construction-Sets hat aber ergeben, daß keines der getesteten den Icon-Block wirklich mit 36 Byte speichert. Vielmehr gehen alle von 34 Byte dafür aus. Normalerweise sollte es keine Rolle spielen, ob nun 34 oder 36 Byte, aber ein Versuch, die DESKICON.RSC-Datei mit 36 Byte langen Icon-Blocks zu verwenden, hat gezeigt, daß etwas im neuen TOS mit der Auswertung dieser Datei nicht ganz stimmen kann. Entweder werden die meisten Icons als, Pixel-Müll* dargestellt, oder der Rechner wirft gleich mit Bomben um sich. Durch eine Änderung der Variablen icb auf 36 kann jeder den Effekt einmal ausprobieren.

Literatur:

[1] ATARI ST/STE/TT-Profibuch, Sybex Verlag

[2] GFA-BASIC 3.5 Handbuch, GFA-Systemtechnik

[3] "Resource-Formate", Stefan Höhn,
ST-Computer Juli/August 90', Seite 97 ff.

[4] "Dem Desktop auf der Spur" (3), Klaus Eisbernd,
ST-Computer November 90,Seite 101 ff.

' *******************************************
' *                                         *
' *        Icon-Packer in GFA-BASIC 3.x     *
' *           Autor : K.-L. Dietsch         *
' *                                         *
' *          (c) 1992 MAXON Computer        *
' *******************************************
'
max_icon%=255   ! maximale Anzahl der Icons 
icb%=34         ! Länge des ICONBLOCKs 34/3 
color%=0        ! 1 bis 15 = Farbe ändern nach
'
DIM infoo%(max_icon%, 5)
' ,0 = welche Maske
' ,1 = anzahl der Daten für eine Maske 
' ,2 = Farben + Buchstabe des Icons 
' ,3 = x-position des Buchstaben 
' ,4 = y-position des Buchstaben 
' ,5 = test auf Gleichheit
'
DIM rsc|(64*1024)
DIM daten%(32*max_icon%-1)
DIM maske%(32*max_icon%-1) 
rsc%=VARPTR(rsc1(0)) 
daten%=VARPTR(daten%(0)) 
maske%=VARPTR(maske%(0))
'
pfad$=CHR$(65+GEMDOS(25))+":\*.RSC"
filename$=""
n_anz%=0
'
REPEAT
    x%=@load_rsc(rsc%,pfad$,filename$)
    IF x%=2 ! laden erfolgreich
        PRINT AT(1,1);"Icons entnehmen",, 
        i%=@take_icons(rsc%,daten%,maske%, n_anz%,info%())
    ENDIF
UNTIL x%=0 OR i%=0 ! Abbruch oder genug Icons
'
IF n_anz%=0
    PRINT AT(1,1);"Kein Icon geladen !!!!!!!"
    END
ENDIF
'
ALERT 2,"Soll gepackt werden ?",2," Nein | Ja ",pac% 
DEC pac% ! 0 = nicht ... , 1 = packen
IF pac%=1
    PRINT AT(1,1);"gleich Icons suchen",
    GOSUB suche_gleiche_masken(pac%,rsc%,n_anz%,maske%,info%())
ELSE
    GOSUB init_info(n_anz%,info%())
ENDIF
'
i%=1
REPEAT
    PRINT AT(1,1);"RSC berechnen",, 
    s_anz%=@make_resource (pac%, rsc%, daten%, maske%, icb%, color%, n_anz%, size%, info%()) 
    IF pac%=1
        filename$ = "ICON_PAC.RSC"
    ELSE
        filename$ = "ICON_N_"+STR$(i%)+".RSC""
    ENDIF
    '
    REPEAT
        x%=@save_rsc(rsc%,size%,pfad$,filename$)
    UNTIL x%=1
    '
    INC i%
    SUB n_anz%, s_anz%
    IF n_anz%>0 AND pac%=0 
        FOR x%=0 TO n_anz%-1 
            FOR a%=0 TO 4
                info%(x%,a%)=info%(x%+s_anz%,a%)
            NEXT a%
        NEXT x%
        BMOVE daten%+s_anz%*128,daten%,n_anz%*128 
        BMOVE maske%+s_anz%*128,maske%,n_anz%*128 
    ENDIF
UNTIL n_anz%=0 OR pac%=1 END
'
FUNCTION load_rsc(rsc%,VAR pfad$,filename$)
    LOCAL x%, i.%,dummy$
    '
    dummy$=fi1ename$
    PRINT AT(1,1);"Icons laden",, 
    x%=FSEL_INPUT(pfad$,dummy$,i%)
    IF x% AND i%=1
        x%=RINSTR(pfad$,"\") 
        fi1ename$=dummy$
        dummy$=LEFT$(pfad$,x%)+filename$
        IF EXIST(dummy$)=FALSE 
            IF dummy$<>""
                ALERT 1,"Nicht vorhanden !",1," OK ",i%
            ENDIF
        ELSE
            OPEN "I",#1,dummy$ 
            i%=LOF(#1)
            BGET #1,rsc%,i%
            CLOSE #1 
            RETURN 2 
        ENDIF 
    ELSE
        IF i%=0 
            RETURN 0 
        ENDIF 
    ENDIF
    '
    RETURN 1
ENDFUNC
'
FUNCTION save_rsc(rsc%,size%,VAR pfad$,filename$) 
    LOCAL x%,i%,dummy$
    '
    dummy$=fi1ename$
    PRINT AT(1,1);"Icons speichern",, 
    x%=FSEL_INPUT(pfad$,dummy$,i%)
    IF x% AND i%=1
        x%=RINSTR(pfad$,"\") 
        filename$=dummy$
        dummy$=LEFT$(pfad$,x%)+filename$
        IF dummy$<>"" 
            i%=1
            IF EXIST(dummy$)=TRUE
                ALERT 0,"Datei ist schon vorhanden !| Überschreiben ?" ,2," JA |NEIN",i%
            ENDIF 
            IF i%=1
                OPEN "O",#1,dummy$
                BPUT #1,rsc%,size%
                CLOSE #1
                RETURN 1 
            ENDIF 
        ENDIF 
    ELSE
        IF i%=0 
            RETURN 1 
        ENDIF 
    ENDIF
    '
    RETURN 0 
ENDFUNC
'
FUNCTION take_icons(rsc%,daten%,maske%,VAR anz%,info%())
    LOCAL i.%
    LOCAL anz_obj%,obj_start%, obj_adr%, icon_adr%
    anz_obj%=CARD{rsc%+20} 
    obj_start%=rsc%+CARD{rsc%+2}
    ' alle Objekte untersuchen 
    FOR i%=0 TO anz_obj%-1
        obj_adr%=obj_start%+24*i%
        ' Icon ?
        IF CARD{obj_adr%+6}= 31
            icon_adr%=rsc%+LONG{obj_adr%+12}
            IF CARD{icon_adr%+22} = 32 AND CARD{icon_adr%+24} = 32 
                BMOVE rsc%+LONG{icon_adr%},maske%+anz%*128,128 
                BMOVE rsc%+LONG{icon_adr%+4},daten%+anz%*128,128 
                info%(anz%,2)=CARD{icon_adr%+12} 
                info%(anz%,3)=CARD{icon_adr%+14} 
                info%(anz%,4)=CARD{icon_adr%+16}
                INC anz%
                IF anz%=max_icon%
                    RETURN 0 
                ENDIF 
            ENDIF
        ENDIF
    NEXT i%
    '
    RETURN 1 
ENDFUNC
'
PROCEDURE init_info(anz%,VAR info%())
    LOCAL i%
    '
    FOR i%=0 TO anz%-1
        info%(i%,0)= i% 
        info%(i%,1)= -1 
    NEXT i%
RETURN
'
PROCEDURE suche_gleiche_masken(pac%,rsc%,anz%,maske%,VAR info%()) 
    LOCAL i%,y%,a%,test%,gleich!
    '
    FOR ±%=0 TO anz%-1 
        test%=0
        FOR y%=0 TO 63
            ADD test%, CARD{maske%+128*i%+2*y%}
        NEXT y%
        info%(i%,5)=test% 
        info%(i%,0)=-1 
        info%(i%,1)=-1
    NEXT i%
    FOR i%=0 TO anz%-2 
        IF info%(i%,1) =-1 
            info%(i%, 0) =i% 
            info%(i%, 1) =1 
            FOR a%=i%+1 TO anz%-1
                IF info%(i%, 5)=info%(a%,5) 
                    gleich!=TRUE 
                    FOR y%=0 TO 31
                        IF LONG{maske%+128*i%+4*y%}<>LONG{maske%+128*a%+4*y%) 
                            gleich!=FALSE 
                        ENDIF 
                    NEXT y%
                    IF gleich!
                        info%(a%,0)=i% 
                        info%(a%,1)=0 
                        INC info%(i%,1)
                    ENDIF 
                ENDIF 
            NEXT a%
        ENDIF 
    NEXT i% 
    i%=anz%-1 
    IF info%(i%,1)=-1 
        info%(i%,0)=i% 
        info%(i%,1)=1 
    ENDIF 
RETURN
'
FUNCTION make_resource(pac%,rsc%,daten%,maske%,icb%,color%,anz%,VAR size%,info%()) 
    LOCAL i%,x%,y%, a%, icon%, obj%
    '
    CARD{rsc%}=1        !   Version
    CARD{rsc%+10}=0     !   Freestring-Index-Tabelle
    CARD{rsc%+12}=36    !   String-Adresse
    IF pac%=1
        CARD{rsc%+CARD{rsc%+12}}=0  ! Strings
        CARD{rsc%+14}=CARD{rsc%+12}+2   ! Images
        x%=64+2 
    ELSE
        y%=MIN(anz%,208)
        ADD y%,MOD(y%,2)
        FOR i%=0 TO y%-1
            BYTE{rsc%+CARD{rsc%+12}+i%}=0 ! Strings 
        NEXT i% 
        x%=64+y%
        CARD{rsc%+14}=CARD{rsc%+12}+y%  ! Images
    ENDIF
    CARD{rsc%+16}=0 !   Free-Images
    CARD{rsc%+22}=1 !   Anzahl der Bäume
    CARD{rsc%+24}=0 !   Anzahl der Tedinfos
    CARD{rsc%+28}=0 !   Anzahl der Bitblks
    CARD{rsc%+30}=0 !   Anzahl der Strings
    CARD{rsc%+32}=0 !   Anzahl der Bilder
    CARD{rsc%+36}=0 !   Strings
    '
    y%=24+icb%+128 
    a%=CARD{rsc%+14} 
    i%=0 
    REPEAT
        IF info%(i%,1)=0 AND pac%=1 
            EXIT IF x%+y%>64*1024
            info%(i%,1)=info%(info%(i%,0),1)
        ELSE
            EXIT IF x%+y%+128>64*1024 
            BMOVE maske%+128*i%,rsc%+a%,128 
            info%(i%,1)=a%
            ADD a%,128 
            ADD x%,128 
        ENDIF
        BMOVE daten%+128*i%,rsc%+a%,128 
        info%(i%,0)=a%
        ADD a%,128 
        ADD x%,y%
        INC i%
    UNTIL i%=anz% 
    anz%=i%
    '
    CARD{rsc%+20}=anz%+1    ! Anzahl der Objekte 
    CARD{rsc%+6}=a%         ! Iconblock
    CARD{rsc%+2}=CARD{rsc%+6}+icb%*anz% ! Objekt 
    CARD{rsc%+18}=CARD{rsc%+2}+24*(anz%+1) ! Tree 
    CARD{rsc%+26}=anz% ! Anzahl der Iconblocks 
    CARD{rsc%+4}=CARD{rsc%+2} ! TEDINFO 
    CARD{rsc%+8}=CARD{rsc%+6} ! Bitblock 
    LONG{rsc%+CARD{rsc%+18}}=CARD{rsc%+2} ! Tree 
    CARD{rsc%+34}=CARD{rsc%+18}+4 ! Länge
    '
    obj%=CARD{rsc%+2}
    CARD{rsc%+obj%}=&HFFFF 
    CARD{rsc%+obj&+2}=1 
    CARD{rsc%+obj%+4}=anz%
    CARD{rsc%+obj%+6}=20 
    CARD{rsc%+obj%+8}=0 
    CARD{rsc%+obj%+10}=16 
    LONG{rsc%+obj%+12}=135424 
    CARD{rsc%+obj%+16}=0 
    CARD{rsc%+obj%+18}=0 
    CARD{rsc%+obj%+20}=79 
    CARD{rsc%+obj%+22}=1+3*(DIV(anz%,15)+SGN(MOD(anz%,15)))
    '
    FOR i%=0 TO anz%-1
        obj%=CARD{rsc%+2}+(i%+1)*24 
        icon%=CARD{rsc%+6}+i%*icb%
        ' object 
        IF i%=anz%-1
            CARD{rsc%+obj%} = 0 
        ELSE
            CARD{rsc%+obj%}=i%+2
        ENDIF
        CARD{rsc%+obj%+2}=&HFFFF 
        CARD{rsc%+obj%+4}=&HFFFF 
        CARD{rsc%+obj%+6}=31 
        CARD{rsc%+obj%+8}=0 
        CARD{rsc%+obj%+10}=0 
        LONG{rsc%+obj%+12}=icon%
        CARD{rsc%+obj%+16}= 2 + 5 *MOD (i%, 15) 
        CARD{rsc%+obj%+18} = 1+3*DIV (i%, 15) 
        CARD{rsc%+obj%+20}=9 
        CARD{rsc%+obj%+22}=2050 
        ' iconblk
        LONG{rsc%+icon%}=info%(i%,1) 
        LONG{rsc%+icon%+4}=info%(i%, 0)
        LONG{rsc%+icon%+8}=CARD{rsc%+12}+i%*(1-pac%)
        ' Farbe + Buchstabe 
        IF color%=0 ! alles so lassen 
            CARD{rsc%+icon%+12}=info%(i%,2)
        ELSE
            BYTE{rsc%+icon%+12}=SHL(color%,4)
            BYTE{rsc%+icon%+13}=BYTE(info%(i%,2))
        ENDIF
        CARD{rsc%+icon%+14}=info%(i%,3)
        CARD{rsc%+icon%+16}=info%(i%,4)
        CARD{rsc%+icon%+18}=20
        CARD{rsc%+icon%+20}=0
        CARD{rsc%+icon%+22}=32
        CARD{rsc%+icon%+24}=32
        CARD{rsc%+icon%+26}= 0
        CARD{rsc%+icon%+28}=32
        CARD{rsc%+icon%+30}=72
        CARD{rsc%+icon%+32}=8
        IF icb%=36
            CARD{rsc%+icon%+34} =0 
        ENDIF 
    NEXT i%
    size%=CARD{rsc%+34}
    RETURN anz%
ENDFUNC


Karl-Ludwig Dietsch



Links

Copyright-Bestimmungen: siehe Über diese Seite
Classic Computer Magazines
[ Join Now | Ring Hub | Random | << Prev | Next >> ]