Aus Linux-Magazin 07/2005

Bitmaps mit Tcl erzeugen, bearbeiten und benutzen

Vor kaum zehn Jahren beherrschten graue Anwendungen den grauen Hintergrund des Unix-Desktops. Heute präsentieren sich KDE und Gnome mit moderner Oberfläche. Ihre Gestaltung verlangt ein geschultes Auge und guten Geschmack, beim Anzeigen und Erzeugen der Elemente hilft Tcls Werkzeugkasten.

Alte Unix-Hasen kennen sie noch aus ihrer Jugend, auch junge Linux-Freunde begegnen ihnen gelegentlich: klobige Anwendungen aus der X11-Steinzeit, mit kümmerlichen Toolkits ohne Rücksicht auf Bedienbarkeit und Aussehen entwickelt. Heute verdrängen aufgeputzte Applikationen diese Relikte vom Desktop und bringen frische Farben auf den Bildschirm. Wichtig für die Optik sind ansprechende Icons, die Knöpfe und Toolbars zieren. Gute Icons entwerfen ist eine Kunst; sie in Tk-Programmen zu verwenden dagegen leicht.

In den meisten Fällen gilt es, fertige Icons von der Festplatte zu laden und auf Labels und Buttons zu verwenden. Listing 1 zeigt alles Wesentliche in wenigen Zeilen, Abbildung 1 zeigt das Resultat. Zum Laden farbiger Bilder dient das »image«-Kommando:

image create photo Name -file Dateiname U
  -data Bildinhalt
Abbildung 1: Der Code in Listing 1 erzeugt drei Bilder, die in der ersten Zeile nebeneinander stehen. Darunter folgen zusammengesetzte Labels, die ein Bild mit Text kombinieren.

Abbildung 1: Der Code in Listing 1 erzeugt drei Bilder, die in der ersten Zeile nebeneinander stehen. Darunter folgen zusammengesetzte Labels, die ein Bild mit Text kombinieren.

Dieser Befehl lädt entweder ein Icon aus einer Datei (mit der Option »-file«) oder die Bilddaten stehen direkt Base-64-kodiert im Befehlsaufruf (nach »-data«). Für jedes Icon erzeugt Tk ein Kommando, ganz wie von den Widgets bekannt. Den Namen dieses Kommandos kann der Programmierer vorgeben; verzichtet er darauf, wählt »image« selbst eine Bezeichnung und übergibt sie an den Aufrufer. Letzteres hat den Vorteil, dass dieses Verfahren nicht versehentlich ein vorhandenes Kommando überschreibt. Die Zeilen 5 bis 10 in Listing 1 zeigen mehrere Aufrufvarianten: Die erste gibt den Namen vor, während die anderen beiden diese Aufgabe Tk überlassen. Die Namen speichern sie in den Variablen »rolle« und »ident«. Weitere Optionen fasst Tabelle 1 zusammen.

Bilder im Skript einbetten

In vielen Fällen genügt es, Icons – wie in Zeile 6 und 8 gezeigt – aus einer Datei zu laden. Um die Installation einer Anwendung zu erleichtern, empfiehlt es sich aber, den Bildinhalt passend kodiert im Skript abzulegen. Folgende Zeilen laden ein Gif-Bild und wandeln es in einen Base-64-kodierten String:

package require Base64
set fd [open "icons/gnome-whoami.gif"]
fconfigure $fd -translation binary
set bild [::base64::encode [read $fd]]
close $fd

Der String »$bild« enthält nun den Bildinhalt, den die Image-Option »-data« versteht. Einfach obige Befehle aufrufen, den String mit »puts $bild« ausgeben und den Zeichensalat in das Skript einfügen (vergleiche die gekürzte Zeile 10 in Listing 1). Diesen Trick nutzt auch Adrian Davis\’ Icons-Paket ([1] und Abbildung 2). Es verpackt Icons aus dem KDE-Projekt in einem großen Tcl-Skript. Wer dieses Skript in seine Tcl/Tk-Applikationen einbindet, kann bequem KDE-konforme Icons benutzen.

Das geladene Icon eignet sich für Labels, Buttons und Menü-Einträge sowie als eingebettetes Bild in Canvas- und Text-Widgets. Mit der Option »-image« zeigen Labels, Buttons und Menüfelder das gewünschte Icon, mit »-compound Anordnung« gleichzeitig Text und Icon. Mögliche Anordnungen sind »none« (nur Bild), »left« (Bild links des Textes), »right«, »bottom«, »top«, und »center« (Text und Bild zentriert übereinander). Die Zeilen 18 bis 22 (Listing 1) benutzen diese Option; in den unteren drei Vierteln von Abbildung 1 ist das Ergebnis zu sehen. Der Code darf ein geladenes Icon beliebig oft verwenden, auch das bestätigt sich in dem kleinen Programm.

Abbildung 2: Das Icons-Package von Adrian Davis enthält viele Symbolgrafiken aus dem KDE-Projekt. Das Paket bettet diese Bilder direkt in Tcl-Code ein.

Abbildung 2: Das Icons-Package von Adrian Davis enthält viele Symbolgrafiken aus dem KDE-Projekt. Das Paket bettet diese Bilder direkt in Tcl-Code ein.

Das Neueste

Für die Sprache Tcl gibt es mehrere Interpreter: Neben der bekannten »tclsh« existiert eine reine Java-Implementation namens Jacl [10]. Mit Jim [11] ist ein weiterer Interpreter in Entwicklung. Seine Ziele sind geringer Speicherbedarf – unter 100 KByte – und ein modularer Aufbau, um sich auch für sehr kleine Computer wie Handhelds zu eignen. Aus einer ganz anderen Ecke kommt Parrot [12], die Basis von Perl 6. Bei Parrot soll der Teil zum Lesen der Quellen und Interpretieren getrennt sein, als Beispiel gibt es einen Tcl-Interpreter auf Parrot-Basis. Einstiegshilfen für Tcl mit Parrot finden sich im Wiki [13].

Das Problem der fehlenden PNG-Unterstützung in Tk geht Michael Kirkham mit Tk PNG [14] an. Anders als die im Artikel benutzte Img-Erweiterung bindet Tk PNG keine weiteren Bibliotheken ein. Michael möchte seine Erweiterung langfristig in den normalen Sprachumfang von Tk bringen.

Wer sich mit VTK [9] zum Anzeigen von Daten aus Berechnungen und Messungen beschäftigen will, sollte Paraview [15] näher betrachten. Die leicht zu bedienende Oberfläche enthält viele VTK-Funktionen – das spart in vielen Fällen ein selbst geschriebenes Skript.

PostgreSQL ist eine der besten freien SQL-Datenbanken und ihr Tcl-Support ist exzellent. Mit »pgtcl1.5« [16] unterstützt die bewährte Tcl-Erweiterung nun auch die Features der neuen PostgreSQL-Release 8.0.

Formatwechsel

Dem normalen Image-Kommando fehlt leider die Unterstützung der verbreiteten Icon-Formate PNG und Jpeg, es liest nur Gif. Abhilfe bringt Jan Nijtmans\’ Img-Erweiterung [2]. Sie ist in den meisten Linux-Distributionen bereits enthalten; wer die Quellen selbst übersetzen will, findet die aktuelle Version 1.3 bei Sourceforge [3], dort heißt sie wegen eines Namenskonflikts Tkimg. Mit der Erweiterung zeigt Tk auch Icons und Grafiken in den Formaten Jpeg, PNG, Tiff, PPM, ICO, XPM, XBM oder PCX. Es genügt, in Zeile 3 von Listing 1 das Paket mit dem Kommando »package require Img« in den Interpreter zu laden.

Zudem fertigt Img auf Wunsch Screenshots von einzelnen Widgets an. Egal ob es auf ein einfaches Label oder eine komplexe Grafik im Canvas zielt, jedes GUI-Element findet damit seinen Weg in eine Bitmap-Datei. Besonders praktisch ist diese Technik, um dynamische Icons für HTML-Seiten zur Laufzeit zu erzeugen. Ein einfaches Beispiel ist in Listing 2 abgedruckt, es generiert ein PNG-Bild mit der aktuellen Uhrzeit.

Listing 1: Icons laden und
anzeigen

01 #!/usr/bin/tclsh
02 package require Tk
03 
04 # Bilder laden
05 image create photo password 
06     -file [file join icons change-password-48.gif]
07 set rolle [image create photo 
08     -file [file join icons lookandfeel-directory.gif] ]
09 set ident [image create photo 
10     -data "R0lGODlhMAAwAOf/AAABAAACAAEEAAIFAQQHAgUIBAIJDAcJBQg.....]
11 
12 # Bilder verwenden
13 label .password -image password
14 label .rolle    -image $rolle
15 label .ident    -image $ident
16 
17 # Bild mit Text
18 label .identO -text "Oben"   -image $ident -compound top
19 label .identL -text "Links"  -image $ident -compound left
20 label .identZ -text "Mitte"  -image $ident -compound center -fg white
21 label .identR -text "Rechts" -image $ident -compound right
22 label .identU -text "Unten"  -image $ident -compound bottom
23 
24 # Widgets platzieren
25 grid .rolle   .password .ident
26 grid    x     .identO
27 grid .identL  .identZ   .identR
28 grid    x     .identU

Warten vor dem Screenshot

Die Zeilen 6 bis 10 formen ein einfaches GUI mit einem Label und sorgen per »update idletasks« dafür, dass die Oberfläche am Bildschirm erscheint, bevor das Programm weiter abläuft. Ohne Zeile 10 würde Tk warten, bis das Programm in der Eventschleife landet – so vermeidet es, dass die Anzeige flackert, während das Programm Widgets einfügt – und der Aufruf in Zeile 13 würde scheitern. Die letzten beiden Zeilen schießen ein Bildschirmfoto des Labels und schreiben es mit »$image write -format Format Dateiname« auf die Festplatte.

Leider braucht Tk Verbindung zu einem X-Server, damit dieser Trick klappt. Auf einem Webserver läuft er allerdings meist nicht. Als einfacher Ausweg eignet sich ein virtueller X-Server mit VNC, der ohne Bildschirm und Grafikkarte auf jedem Server startet:

vncserver -name Hostname:42
wish listing2.tcl -display Hostname:42
vncserver -kill Hostname:42

Mit dem »image«-Kommando liefert Tk zwar keine komplette Bildbearbeitung, es eignet sich aber für viele Standardaufgaben. Beispielsweise ändert ein einfacher Aufruf die Farbe und Transparenz eines einzelnen Pixels. Das Tcl-Wiki enthält viele Beispiele [4] für Bildbearbeitungen, sie reichen vom einfachen Zusammenbau bestehender Icons bis zu umfangreichen Operationen wie Schärfen oder Farbmanipulation.

Listing 2: Bilder
erzeugen

01 #!/usr/bin/tclsh
02 package require Tk
03 package require Img
04 
05 # GUI erzeugen und auf den Bildschirm bringen
06 set uhrzeit [clock format [clock seconds] -format "%H:%M:%S"]
07 label .l -text $uhrzeit -font {Palatino 24 bold} -bg white
08 pack .l
09 wm geometry . +100+100
10 update idletasks
11 
12 # Bildschirmfoto schießen und speichern
13 set image [image create photo -format window -data .l]
14 $image write -format png "uhrzeit.png"

Montagearbeit

Viele Anwendungen montieren neue Icons aus mehreren bestehenden Bildern, zum Beispiel signalisieren verschiedenfarbige Flächen einen Status oder kleine Dreiecke kennzeichnen einen Verzeichnisknoten. Zeile 7 in Listing 3 lädt ein kleines Dreieck aus einem PNG-Bild, um es in ein anders Icon (Zeile 6) einzufügen: Das Image-Subkommando »copy« kopiert die Bilddaten eines Icons in ein anderes.

Listing 3:
Bildmontage

01 #!/usr/bin/tclsh
02 package require Tk
03 package require Img
04 
05 # Basis-Icons laden
06 image create photo basis   -file [file join icons emblem-people.png]
07 image create photo dreieck -file [file join icons dreieck.png]
08 
09 # Zusammenfügen durch Addieren
10 image create photo kombi
11 kombi copy basis   -to  0  0
12 kombi copy dreieck -to 15 15
13 
14 # Zusammenfügen durch Überschreiben
15 image create photo kombi2
16 kombi2 copy basis   -to  0  0
17 kombi2 copy dreieck -to 15 15 -compositingrule set
18 
19 # Statusanzeige
20 image create photo status
21 status put  red   -to 0 0 15 15
22 status copy basis -to 4 4
23 
24 # Darstellung
25 label .dreieck -image dreieck -text "Dreieck"  -compound top
26 label .basis   -image basis   -text "Basis"    -compound top
27 label .kombi   -image kombi   -text "Zusammen" -compound top
28 label .kombi2  -image kombi2  -text "Zusammen mit set" -compound top
29 label .status  -image status  -text "Statusanzeige" -compound top
30 grid .dreieck .basis .kombi .kombi2 .status -padx 10 -sticky s

Per Default überlagert das Kommando die vorhandenen Bilddaten mit den neuen (Zeilen 11, 12 und 16) und berücksichtigt dabei transparente Flächen. Mit der Option »-compositingrule set« (Zeile 17) überschreibt es vorhandene Bilddaten. Auch einfache Zeichenoperationen sind möglich; Zeile 21 färbt eine rechteckige Fläche rot ein. Das Ergebnis ist in Abbildung 3 zu sehen. Die Operationen laufen so schnell, dass sie problemlos zur Laufzeit erfolgen dürfen. Das reduziert oft die Anzahl der benötigten Icon-Dateien enorm.

Abbildung 3: Der Code in Listing 3 kombiniert neue Icons aus vorhandenen Bildern: Dreieck und Basis ergeben zusammen das dritte Icon. Nummer vier zeigt eine andere Kombinationstechnik. Das rote Rechteck im Icon rechts entsteht durch ein weiteres Image-Kommando.

Abbildung 3: Der Code in Listing 3 kombiniert neue Icons aus vorhandenen Bildern: Dreieck und Basis ergeben zusammen das dritte Icon. Nummer vier zeigt eine andere Kombinationstechnik. Das rote Rechteck im Icon rechts entsteht durch ein weiteres Image-Kommando.

Viele modern getrimmte Anwendungen sprengen den Rahmen des Windowmanagers und nehmen beliebige Formen an. Technische Basis sind die X-Shape-Extensions, sie erlauben unter X11 beliebige Fensterformen. Mit dem WMX-Paket von Rildo Pragana gelingt das auch mit Tk. Auf seiner Webseite [5] verteilt er ein fertiges Starkit [6], das neben einem Beispiel die Quellen sowie eine fertig kompilierte Linux-Version enthält. In den Download-Beispielen für diesen Artikel [17] ist es bereits enthalten.

Rahmenlos

Abbildung 4: Beliebig geformte Fenster sind dank WMX-Erweiterung auch mit Tcl/Tk möglich. Die Zeiger dieser realistisch wirkenden Uhr ticken im Zehntelsekundentakt.

Abbildung 4: Beliebig geformte Fenster sind dank WMX-Erweiterung auch mit Tcl/Tk möglich. Die Zeiger dieser realistisch wirkenden Uhr ticken im Zehntelsekundentakt.

Der Screenshot in Abbildung 4 zeigt das Ergebnis von Listing 4. Hierzu wurde eine Armbanduhr gescannt, mit Gimp das Armband und die Zeiger entfernt sowie die Uhr freigestellt, also alles außerhalb der Uhr als transparent definiert. Die Zeilen 8 bis 12 von Listing 4 produzieren ein gewöhnliches Fenster, in dem ein Canvas-Widget mit dem Uhrenbild steckt. Das Canvas nimmt später auch die Zeiger auf.

Listing 4: Krumme
Fenster

01 #!/usr/bin/tclsh
02 lappend auto_path wmx
03 package require Tk
04 package require wmx
05 package require Img
06 
07 # Bild im Fenster mit einem Canvas
08 image create photo uhr -file [file join icons uhr.png]
09 canvas .c
10 .c create image 0 0 -image uhr -anchor nw
11 pack .c -fill both -expand true
12 wm geometry . 273x250
13 setXwinshape . uhr
14 
15 # Fenster verschieben und schließen
16 bind . <1> {
17     set x [expr {[winfo rootx .] - %X}]
18     set y [expr {[winfo rooty .] - %Y}]
19 }
20 bind . <B1-Motion> {
21     wm geometry . +[expr {%X+$x}]+[expr {%Y+$y}]
22 }
23 bind . <Control-q> {
24     exit 0
25 }
26 
27 # Zeiger zeichnen
28 proc malZeiger {winkel radius dicke xoff yoff} {
29     set id [.c create line 0 0 
30         [expr {cos($winkel) * $radius}] 
31         [expr {sin($winkel) * $radius}] 
32         -fill black -width $dicke -tag zeiger]
33     .c move $id $xoff $yoff
34 }
35 
36 # Drei Zeiger zeichnen
37 proc malZeit {} {
38     set t [clock seconds]
39     scan [clock format $t -format %I] %d std
40     scan [clock format $t -format %M] %d min
41     scan [clock format $t -format %s] %d sec
42     set PI [expr {2*acos(0)}]
43 
44     .c delete zeiger
45 
46     set winkel [expr {($sec -15)/30.0 * $PI}]
47     malZeiger $winkel 27 2 127 171
48 
49     set winkel [expr {($min -15)/30.0 * $PI}]
50     malZeiger $winkel 100 2 127 125
51 
52     set winkel [expr {($std -2)/6.0 * $PI}]
53     malZeiger $winkel 80 3 127 125
54 
55     # In 100 Millisekunden neue Zeigerposition
56     after 1000 malZeit
57 }
59 malZeit

Damit nur die Uhr sichtbar ist und nicht ein normales rechteckiges Fenster, gibt »setXwinshape Fenster Bild« eine Maske an. Nur die nicht transparenten Bereiche der Maske gehören fortan zum sichtbaren Bereich des Fensters, die transparenten Stellen verbirgt X11. Zeile 13 verwendet das Uhrenbild als Maske.

Da der Windowmanager keine Fensterdekoration mehr anbringt, muss sich das Programm selbst um Funktionen wie Schließen und Verschieben kümmern. Dazu dienen drei »bind«-Aufrufe in den Zeilen 16 bis 25. Bei gedrückter linker Maustaste ist die Uhr auf dem Bildschirm verschiebbar, ein Druck auf [Strg]+[Q] beendet die Anwendung.

Die »malZeiger«-Prozedur ab Zeile 28 zeichnet einen Uhrzeiger mit den normalen Canvas-Befehlen. Spannend ist die »malZeit«-Funktion ab Zeile 37: Sie berechnet die Winkel aller Zeiger und sorgt per »after«-Aufruf (Zeile 56) dafür, dass der Chronograph alle 100 Millisekunden auf den aktuellen Stand kommt.

Die WMX-Erweiterung funktioniert leider nur unter X11. Wer zusätzlich für Windows programmiert, findet in der Shape-Extension [7] von Donal K. Fellows vergleichbare Features. Shape arbeitet unter X11 und Windows.

Grenzenlos

Dem Verwenden, Ändern oder Erzeugen von Icons setzt Tk kaum Grenzen. Braucht eine Webapplikation zur Laufzeit neue Icons, ist der VNC-Trick allerdings verpönt. Dann bietet sich die Tclgd-Erweiterung von Michael Schwartz an. Sie nutzt die bewährte GD-Bibliothek, um in Tcl-Programmen aufwändige Grafiken zu erstellen.

Wer bei Icons eher an hochauflösende Bilder aus Scanner oder der Radiologie denkt, ist bei VTK [9] gut aufgehoben. Es hat viele Methoden implementiert, um große Bilder zu ver- und bearbeiten (siehe auch Kasten “Das Neueste”).

Version 8.5

Ungefähr zum Erscheinen der nächsten Federlesen-Folge soll die neue Tcl-Version 8.5 fertig sein. Passend zu diesem Ereignis werden dann die neuen Möglichkeiten von Tcl und der Tile-Bibliothek Thema sein. (fjl)

Infos

[1] Icons-Paket mit eingebetteten Symbolen: [http://www.satisoft.com/tcltk/icons/]

[2] Jan Nijtmans Img-Erweiterung: [http://www.xs4all.nl/~nijtmans/img.html]

[3] Tkimg-Erweiterung auf Sourceforge: [http://sourceforge.net/projects/tkimg/]

[4] Suche nach Tcl-Wiki-Seiten zum Imagepaket: [http://wiki.tcl.tk/2?image]

[5] Rildo Pragana, “WMX – Shaped and managed tk toplevels”: [http://www.pragana.net/othersoft.html#wmx]

[6] Carsten Zerbst, “Stern-Gucker – Tcl-Module zu einer ausführbaren Datei verschnüren”: Linux-Magazin 01/04, S. 100

[7] Shape-Extension: [http://www.cs.man.ac.uk/~fellowsd/tcl/shapeidx.html]

[8] Tcl-GD: [http://www.du.edu/~mschwart/tclextensions.html#gdTbl]

[9] VTK, Visulization Toolkit: [http://public.kitware.com/VTK/]

[10] Jacl, ein Tcl-Interpreter nur in Java: [http://www.tcl.tk/software/java/]

[11] Jim: [http://jim.berlios.de]

[12] Parrot: [http://www.parrotcode.org]

[13] Parrot im Tcl-Wiki: [http://wiki.tcl.tk/7148]

[14] Tk PNG: [http://www.muonics.com/FreeStuff/TkPNG/]

[15] Paraview, GUI-Frontend für VTK: [http://www.paraview.org]

[16] Pg TCL, das Tcl-Interface für PostgreSQL: [http://pgfoundry.org/projects/pgtcl/]

[17] Dateien auf dem Linux-Magazin-FTP-Server: [ftp://ftp.linux-magazin.de/pub/magazin/2005/07/Federlesen]

LINUX-MAGAZIN KAUFEN
EINZELNE AUSGABE Print-Ausgaben Digitale Ausgaben
ABONNEMENTS Print-Abos Digitales Abo
TABLET & SMARTPHONE APPS Readly Logo
E-Mail Benachrichtigung
Benachrichtige mich zu:
0 Kommentare
Älteste
Neuste Beste Bewertung
Nach oben