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
Aus: ST-Computer 10 / 1992, Seite 106

Links

Copyright-Bestimmungen: siehe Über diese Seite