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.
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.
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.
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.
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.
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.
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