Bitmaps

Attraktive Bilder, mit Lichteffekten, Texturen und vielen Details, lassen sich mit vertretbarem Aufwand (falls man nicht gerade einen 3D Renderer zur Hand hat) in der Regel nur mit sogenannter Rastergrafik (Pixelgrafik) darstellen. Das Gleiche gilt für Fotografien. Auch diese werden als Rastergrafik gespeichert und dargestellt.

Was die Rastergrafik betrifft, ähneln Bitmaps durchaus den Icons. Der wesentliche Unterschied besteht in der Farbtiefe und der Pixelanzahl (Bildgröße). Icons verwendetet lediglich eine Auswahl von Farben aus einer Palette, während Bitmaps die Farbe jedes einzelnen Bildpunktes im RGB-Farbmodell abbildet. Bitmaps verbrauchen somit wesentlich mehr Speicher.

Aufgabe

Es ist ein Bitmap mit einer Größe von 240×320 Pixeln auf dem Display darzustellen.

Vorbereitung

Falls Sie nicht in der Vorgehensmodell-Ebene sind, navigieren Sie diese bitte an (nach oben). Falls das Projekt nicht mehr geöffnet ist, öffnen sie das SiSy UML-Projekt wieder. Legen Sie ein neues Klassendiagramm an und wählen Sie die Sprache ARM C++. Beachten Sie die Einstellungen für die Zielplattform STM32F4-Discovery. Beim Öffnen des Diagramms (rechte Maustaste, nach unten) laden Sie die Diagrammvorlage für eine ARM C++ Applikation mit Grafikdisplay ohne µGL.

(Mit installiertem Flash kann man an dieser Stelle ein Video in dieser Web-Seite ansehen.)

Selektieren Sie die Operation onStart der Klasse Application.

Ersetzen Sie möglicherweise vorhandenen Beispielquelltext durch folgenden Code.

onStart()
display.clearScreen();

Erstellen und übertragen Sie die Anwendung auf den Mikrocontroller.

Grundlagen zu Bitmaps

Bitmaps können prinzipiell auch von einem Speichermedium gelesen werden. Dazu benötigt man ein Dateisystem und einen Decoder für das entsprechende Format der Datei (BMP, JPG, PNG, …). Steht kein Speichermedium, wie zum Beispiel eine SD-Karte, zur Verfügung, können die Bitmaps ähnlich wie die Icons im Programm selbst abgelegt werden. Die folgenden Ausführungen beziehen sich darauf, dass die Bitmaps im Flash abgelegt und in C++ codiert werden.

Als Erstes soll der µGL-Bitmap-Header besprochen werden. Diese Struktur wird jedem Bitmap vorangestellt. Das Strukturelement Typ enthält ein 'b' für die Kennzeichnung eines Bitmaps.

struct BitmapHeader{
	char 	type;			// 	='b' ... Bitmap
	uint8_t framesCount;	
	uint16_t width;			
	uint16_t height;		 
	const color_t** frameList;		
	};

Ein Bitmap-Header kann auf eine oder mehrere Bitmaps gleicher Größe verweisen. Dazu wird die Anzahl und die Größe der Frames angegeben. Als letztes Element folgt ein Zeiger auf die Bitmap-Daten des ersten Frames. Sollten mehrere Frames vorhanden sein, folgt eine entsprechende Anzahl von Verweisen. Ein einfaches Bitmap besitzt ein Frame.

Bitmapdaten:
const color_t _bmp_data_demoPicture[] = {
	0xFF30, 0xFFDF, 
	...
	0xDD30, 0xFFDF 
};
der dazugehörige BitmapHader:
BitmapHeader _bmp_demoPicture = { 'b', 1, 240, 320 , _bmp_frames_demoPicture };

Das RGB Farbmodell wird in den meisten Fällen mit einer Farbtiefe von 24 Bit abgebildet. Das entspricht 8 Bit je Farbe ( RGB-8-8-8, True Color, 16.777.216 Farben ). Sind die Ressourcen des Systems knapp, kann die Farbtiefe reduziert werden ohne dass es dem menschlichen Auge groß auffällt. Die in diesem Tutorial verwendeten Boards verfügen über eine maximale Farbtiefe von 16 Bit ( RGB-5-6-5, Heigh Color, 65.536 Farben). Die nächstkleinere akzeptable Farbtiefe ist Real Color mit 15 Bit und 32.768 Farben. Daraus ergibt sich ein RGB-5-5-5 und es wird in einem 16-Bit-Farbword ein Bit frei ;-)

[ R R R R R G G G | G G x B B B B B ]
  16                    ^         0  
                        |
                  Die Bitstelle 5 kennzeichnet eine Metainformation
                      0 = RGB-5-5-5
                      1 = Metainformation = 0b0000000000100000 = 0x0020

Die Metainformationen sollen zusätzlich zu normalen Farbinformationen, zum Beispiel Transparenz, Hintergrund- oder Vordergrundfarben und was besonders interessant ist Komprimierungsinformationen, codieren. Im Folgenden die entsprechenden Deklarationen:

	typedef unsigned short color_t; // = uint16_t
	// RGB to 5-5(6)-5
	#define RGB(r,g,b)		( (((r)&0xF8)<<8) | (((g)&0xF8)<<3) | ((b)>>3) )
	#define ColorTransparent	0x0020
	#define ColorForeground		0x0021
	#define ColorBackground		0x0022
	#define ColorHalfTransparent	0x0023
	#define ColorInvalid		0x002F
	#define ColorCompressed		0x0030
	...

Sehen wir uns den Codeabschnitt 0xFF30, 0xFFDF, aus den Bitmapdaten näher an:

Die Codierung von Farben wird vom Anwendungsentwickler im Quelltext als 24 Bit Farbe notiert. Das RGB-Makro konvertiert die Farbangabe in die vom Displaytreiber verwendete 16Bit Farbtiefe. Ein Bitmap mit 240 x 320 Pixeln codiert kein Anwednungsentwickler von Hand. Das gäbe eine ordentliche Sehnenscheidenentzündung. Dafür bedient man sich Werkzeugen wie dem Icon-Desinger und Bitmap-Konverter. Aus diesem Werkzeug wurde auch der Inhalt für die Datei Bitmapdaten.h generiert.

Entwurf der Bitmap-Anwendung

Die Programmschritte zum darstellen eines Bitmaps sind denkbar einfach:

  1. Bildschirm löschen, Funktion clearScreen
  2. Bitmap darstellen, Funktion drawBitmap

Da das Bitmap recht groß ist, soll es nicht innerhalb einer Operation oder Klasse abgelegt werden, sondern eine eigene Datei bekommen. Dazu benutzt man in der UML das Artefakt.

Die eigentlichen Bitmapdaten lassen wir uns entweder vom Icon- und Bitmap-Konverter generieren oder nehmen die vorbereiteten Bitmapdaten zur Hand.

Realisierung der Bitmap-Anwendung

Sie haben in der Vorbereitung ein Grundgerüst für eine einfache Grafikanwendung geladen und den Quellcode der Operation onStart mit einem display.clearScreen() erstellt.

Ziehen Sie aus der Objektbibliothek ein Element vom Typ Artefakt in das Klassendiagramm. Geben Sie dem Artefakt den Namen Bitmapdaten. Das Artefakt soll generiert und in die Anwendung eingebunden werden. Der Dateiname soll bitmapdaten.h lauten. Vergleichen Sie die Einstellungen mit dem folgenden Dialog:

Verbinden Sie das Artefakt mit der Klasse Application als Abhängigkeit mit dem Stereotyp «include».

Kopieren Sie den Inhalt der Bitmapdaten in das Artefakt.

Ergänzen Sie den Quellcode der Operation onStart wie folgt:

onStart:
// Bildschirm aufräumen
display.clearScreen();
// Bitmap darstellen
display.drawBitmap( 0, 0, bmpDemoPicture );

Erstellen und übertragen Sie das Programm auf den Mikrocontroller. Vergleichen Sie die Anzeige mit dem Quellcode.

Videozusammenfassung

(Mit installiertem Flash kann man an dieser Stelle ein Video in dieser Web-Seite ansehen.)

Nächstes Thema