5.0 VisualClass Objekte

5.1 Die VisualClass

5.2 BitmapContent

5.2.1 Überblick

5.2.2 Grundlegende Funktionen

5.2.3 Erweitere Funktionen

5.2.4 Arbeit mit transparenten Bitmaps

5.2.4.1 Überblick

5.2.4.2 Beschreiben der Maske

5.2.4.3 Verwendung des MixMode MM_SET

5.2.4.4 Zeichnen einer maskierten Bitmap in eine andere

5.2.5 Arbeit mit Paletten

5.2.5.1 Überblick

5.2.5.2 Zugriff auf die Farbpalette

5.2.5.3 Beispiele

5.2.6 Direktzugriff auf die Bitmapdaten

^

5.1 Die VisualClass

Die VisualClass ist die Superclass für alle Visual Objekt Klassen. Visual Objekte werden innerhalb eines View-Objekts dargestellt. Sie dienen der komfortablen Ausgabe von Grafik bzw. Text und können auf Maus- und Tastaturereignisse reagieren. Dieser Abschnitt beschreibt die gemeinsamen Eigenschaften aller VisualClass Objekte. Ausnahmen sind explizit erwähnt.

In R-BASIC gibt es die folgenden VisualClass Objekte:

...

BitmapContent
Dieses Objekt verwaltet eine editierbare Bitmap und ist die erste Wahl, wenn es darum geht möglichst einfach Grafik auszugeben.

VisGroup
Die VisGroup Class ist die Superclass für VisContent und VisObj. Sie können in R-BASIC keine Objekte dieser Klasse anlegen.

VisContent
Objekte dieser Klasse können selbst Grafik ausgeben und sie können Children der Klassen VisObj und VisText haben, die ihrerseits Grafik bzw. Texte anzeigen können.

VisObj
Objekte dieser Klasse sind die Children eines VisContent Objekts und können selbst Children der Klasse VisObj haben. Sie ermöglichen es zum Beispiel, Grafiken so zu organisieren, dass einzelnen Teile mit der Maus angeklickt und separat bearbeitet werden können.

VisText
VisText-Objekte erlauben die Anzeige und Bearbeitung von Texten direkt in der Grafikebene. Sie müssen als Children eines VisContent eingebunden werden. VisText-Objekte werden ausführlich nicht hier, sondern im Kapitel 4.10 (Text-Objekte) besprochen.

LargeText
LargeText-Objekte ermöglichen die Anzeige und Bearbeitung von beliebig großen Textmengen (theoretisch bei zu 2 GByte). Sie müssen ebenfalls als Children eines VisContent eingebunden werden. LargeText-Objekte werden ausführlich nicht hier, sondern im Kapitel 4.10 (Text-Objekte) besprochen.
Die VisualClass stellt in R-BASIC keine eigenen Instance-Variablen oder Methoden bereit, erledigt im Hintergrund aber viele Dinge, die unverzichtbar und allen VisualClass Objekten gemeinsam sind. Dazu gehören insbesondere die folgenden Fähigkeiten:

Mausunterstützung

Alle VisualClass-Objekte unterstützten die Behandlung von Mausereignissen. Dazu werden von VisContent, VisObj und BitmapContent die folgende Instancevariablen und Methoden unterstützt. Die Text-Objekte behandeln die Mausereignisse komplett selbständig.

Actionhandler Instancevariablen Methoden
OnMouseButton
OnMouseMove
OnMouseOver
sendMouseEvents GrabMouse
ReleaseMouse
TestInside
TestInsideAC

Die Maus-Actionhandler müssen als MouseAction deklariert sein. Eine detaillierte Beschreibung der Arbeit mit der Maus finden Sie im Handbuch "Spezielle Themen", Kapitel 17.

Es ist sehr häufig, dass VisualClass-Objekte mit der Maus umgehen müssen. Sie können auch Text und Grafik innerhalb des Maushandlers auf den Schirm ausgeben. Allerdings speichert das VisContent und das VisObj Objekt diese Ausgaben nicht. Nur das BitmapContent Objekt speichert die Grafikausgaben gleichzeitig in der Bitmap.

Tastaturhandling

Sie können sich in das Tastaturhandling aller VisClass-Objekte, auch der Text-Objekte, einklinken, indem Sie einen Tastaturhandler schreiben. Dazu werden die folgenden Instancevariablen und Actionhandler unterstützt:

Actionhandler Instancevariablen Methoden
OnKeyPressed inputFlags --

Eine ausführliche Beschreibung, wie man einen Tastaturhandler schreibt und was es dabei zu beachten gilt, finden Sie im Handbuch "Spezielle Themen", Kapitel 14.

Focus und Target

Alle VisualClass Objekte interagieren mit der Focus- und Target-Hierarchie. Es ist möglich zu überwachen, ob ein VisualClass-Objekt den Focus oder das Target hat, indem man einen Focus- bzw. Target-Handler schreibt. Dazu werden die folgenden Actionhandler und Systemvariablen unterstützt.

Für VisObj-Objekte ist wichtig, dass die Tastatureingaben an das Focus-Objekt gehen. Das Beispiel "VisObj Keyboard Demo" verwendet die Focus-Hierarchie um dem Nutzer ein visuelles Feedback zu geben, welches Objekt als letztes angeklickt wurde.
Actionhandler Instancevariablen Systemvariable
OnFocusChanged
OnTargetChanged
-- Focus
Target

Die Arbeit mit Focus und Target ist etwas für erfahrene Programmierer und nur in wenigen Fällen notwendig. Die notwendigen Details dazu finden Sie in den Kapiteln 12 (Focus und Target) und 13 (Implementieren von Menüs: Bearbeiten, Textgröße und andere) des Handbuchs "Spezielle Themen".

Arbeit mit dem Clipboard

Alle VisualClass Objekte können mit der Zwischenablage (Clipboard) kommunizieren. Die Methoden ClpTestCopy, ClpTestPaste, ClpCopy und ClpPaste werden unterstützt. Eine detaillierte Beschreibung dieser Methoden finden Sie im Kapitel "Arbeit mit der Zwischenablage" (Kapitel 5 im Handbuch "Spezielle Themen"). Für BitmapContent-Objekte und die Text-Objekte gibt es dabei keine Einschränkungen, bei VisContent und VisObj-Objekten muss der gepufferte Modus aktiv sein (Instancevariable buffered = TRUE). Außerdem müssen Sie die Methode MarkInvalid aufrufen, nachdem Sie eine Grafik mit ClpPaste eingefügt haben, damit sich der visual Tree neu darstellt.

5.2 Das BitmapContent

^

5.2.1 Überblick

Objekte der Klasse BitmapContent verwalten eine editierbare Bitmap. Bitmaps sind digitalisierte Bilder. Sie bestehen aus einer rechteckigen Anordnung von einzelnen Bildpunkten (Picture Element: Pixel). Jedem Pixel kann eine eigene Farbe zugeordnet werden. In die Bitmaps der Klasse BitmapContent kann Text oder Grafik geschrieben werden. Das BitmapContent-Objekt legt die zugehörige Bitmap automatisch selbst an, so dass sie sofort benutzt werden kann.

Einen kompletten Überblick über die weitern Möglichkeiten von R-BASIC, Grafik auszugeben, finden Sie im Kapitel 2.2.

Abstammung:

...

Da BitmapContent Objekte von der VisualClass abstammen, kommen Sie nicht in den generic Tree des Programms. Stattdessen werden die über die Instance-Variable "Content" eines Views mit dem View verbunden. Das View muss aber in den generic Tree des Programms eingebunden werden.

Arbeit mit dem Clipboard

BitmapContent Objekte können mit der Zwischenablage (Clipboard) kommunizieren. Die Methoden (Objektanweisungen) ClpTestCopy, ClpTestPaste, ClpCopy und ClpPaste werden unterstützt. Eine detaillierte Beschreibung dieser Methoden finden Sie im Handbuch "Spezielle Themen", Kapitel 5, "Arbeit mit der Zwischenablage". Für BitmapContent Objekte gelten dabei folgende Besonderheiten:

  • Die Methode ClpCopy kopiert die Bitmap-Grafik sowohl als reine Bitmap als auch als Graphic String in die Zwischenablage. Damit können sowohl andere BitmapContent Objekte als auch andere GEOS Anwendungen wie GeoWrite oder GeoDraw die Grafik aus der Zwischenablage lesen.

  • Die Methode ClpPaste akzeptiert sowohl reine Bitmaps als auch als Graphic Strings, wobei Bitmaps bevorzugt werden. Wird ein Graphic String aus der Zwischenablage gelesen, so legt das Objekt eine transparente Bitmap an und kopiert den Graphic String in diese Bitmap.

  • Das Objekt passt seine Größe automatisch an das mit ClpPaste aus der Zwischenablage gelesene Bild an.

  • Die globale Variable clipboardError wird auf FALSE oder TRUE gesetzt, je nachdem ob ClpCopy bzw. ClpPaste erfolgreich waren oder nicht.


Mausunterstützung

Es ist sehr häufig, dass ein BitmapContent-Objekt mit der Maus umgehen muss. Da ein BitmapContent-Objekt in Normalfall keine Children hat muss es die Mausereignisse selbst behandeln. BitmapContent-Objekte erben die Fähigkeiten im Umgang mit der Maus vom der VisualClass. Eine detaillierte Beschreibung der Arbeit mit der Maus finden Sie im Handbuch "Spezielle Themen", Kapitel 17.

Tastaturhandling

BitmapContent-Objekte erben die Fähigkeiten im Umgang mit der Tastatur vom der VisualClass. Eine ausführliche Beschreibung, wie man einen Tastaturhandler schreibt und was es dabei zu beachten gilt, finden Sie im Handbuch "Spezielle Themen", Kapitel 14.

Focus und Target

BitmapContent Objekte erben die Fähigkeiten im Umgang mit der Focus- und der Traget-Hierarchie von der VisualClass. In den Kapiteln 12 und 13 des Handbuchs "Spezielle Themen" finden Sie eine detaillierte Darstellung des Umgangs mit Focus und Target. Spezielle Instance-Variablen:

Variable Syntax im UI-Code Im BASIC-Code
bitmapFormat bitmapFormat = x, y, n [, flags ] lesen, schreiben
defaultColor defaultColor = fg, bg lesen, schreiben
DefaultScreen DefaultScreen --
suspendDraw -- lesen, schreiben
editMask -- lesen, schreiben

Methoden:

Methode Aufgabe
Redraw Bitmap neu zeichnen
GetBitmapHandle Handle auf die Bitmap des Objekts holen
CopyBitmap Kopie der Bitmap des Objekts erstellen
NewBitmapFromHandle Bitmap aus Handle auslesen (ins Objekt kopieren)
GetPaletteEntry Einzelnen Paletteneintrag holen
SetPaletteEntry Einzelnen Paletteneintrag setzen
GetFullPalette Vollständige Palette holen
SetFullPalette Vollständige Palette setzen
PeekLine Einzelne Bitmapzeile aus dem RAM holen
PokeLine Einzelne Bitmapzeile in den RAM schreiben

^

5.2.2 Grundlegende Funktionen

Beispiel UI-Code:

Das View "MyView" enthält ein BitmapContent, das eine 320x256 Pixel große True-Color Bitmap darstellt. Es kommuniziert automatisch mit dem BitmapContent "MyBitmap" um seine Größe auf 320x256 Pixel zu setzen, so dass die ganze Bitmap sichtbar ist. "DefaultScreen" stellt das BitmapContent als "Standard-Ausgabe-Objekt" für Grafik- und Textausgaben ein.
View  MyView
  vControl = HVC_NO_LARGER_THAN_CONTENT + \
             HVC_NO_SMALLER_THAN_CONTENT 
  hControl = HVC_NO_LARGER_THAN_CONTENT + \
             HVC_NO_SMALLER_THAN_CONTENT 
  Content = MyBitmap
  END Object

BitmapContent  MyBitmap
  bitmapFormat = 320, 256, 24
  DefaultScreen
  defaultColor = BLACK, LIGHT_CYAN
  END Object
In vielen Fällen wird der im Code oben verwendete Fall (kein Scrolling der Bitmap, kein Zoom) ausreichend sein. Ein BitmapContent ist jedoch ein vollwertiges Content-Objekt und kann daher z.B. auch in einem scrollbaren View dargestellt werden:

...

View  MyView
  hControl = HVC_SCROLLABLE
  vControl = HVC_SCROLLABLE
  fixedSize = 200, 150
      ! Kleiner als das Content
  Content = MyBitmap
  END Object

BitmapContent  MyBitmap
  bitmapFormat = 320, 256, 24
  DefaultScreen
  defaultColor = BLACK, LIGHT_CYAN
  END Object


bitmapFormat

Die Instance-Variable bitmapFormat speichert die Größe, die Farbtiefe und weitere Eigenschaften der Bitmap. R-BASIC unterstützt die Farbtiefen 1 (schwarz/weiß), 8 (256 Farben) und 24 (True Color, 16 Mio. Farben). Die Farbtiefe 4 (16 Farben) wird von R-BASIC nicht unterstützt. Verwenden Sie stattdessen 8 Bit Farbtiefe. Über den Parameter flags können Sie einstellen, ob die Bitmap transparent sein soll ("maskierte" Bitmap) und/oder eine Palette verwenden soll. Masken und Paletten in den nächsten Abschnitten beschrieben.
Syntax UI-Code: bitmapFormat = x, y, n [, flags ]
             x: Breite der Bitmap
             y: Höhe der Bitmap
             n: Farbtiefe (zulässige Werte: 1, 8, 24)
         flags: Transparenz und Palette. Siehe Tabelle unten.
         Lesen: <numVar> = <obj>.bitmapFormat (0)   ' Breite
                <numVar> = <obj>.bitmapFormat (1)   ' Höhe
                <numVar> = <obj>.bitmapFormat (2)   ' Farbtiefe
                <numVar> = <obj>.bitmapFormat (3)   ' flags
     Schreiben: <obj>.bitmapFormat = x, y, n [, flags ]

 
Beispiel UI-Code: siehe oben

Für "flags" sind folgende Werte zugelassen:

Konstante Wert Bedeutung
BF_MASK 1 Transparente Bitmap
BF_PALETTE 2 Bitmap mit Palette
BF_MASK + BF_PALETTE Maske und Palette

Wenn Sie im BASIC-Code die Variable bitmapFormat belegen (schreiben), so wird die Bitmap neu angelegt. Alle vorhandenen Informationen (Grafik, Text..) gehen verloren. Die Bitmap darf dabei weiterhin als Content einen Views gesetzt sein, muss es aber nicht.

Beispiele BASIC-Code:

Lesen der Werte:
DIM  b, h, f  as WORD
  b = MyBitmap.bitmapFomat (0)  ' Breite
  h = MyBitmap.bitmapFomat (1)  ' Höhe
  f = MyBitmap.bitmapFomat (2)  ' Farbtiefe

  Print "Bitmapgröße:" b; "x"; h; "Pixel, "; f; "Bit pro Pixel"
    ! z.B.    320 x 256 Pixel,  24 Bit pro Pixel
Neu anlegen der Bitmap: 800 x 600 Pixel, 256 Farben
  MyBitmap.bitmapFormat = 800, 600, 8
Hinweis: Das Bitmapobjekt informiert sein View automatisch über seine neue Größe, so dass das View ggf. seine eigene Größe anpassen kann.

defaultColor

Die Instance-Variable defaultColor enthält die Farben, die beim Initialisieren der Bitmap (erstmaliges bzw. Neuanlegen der Bitmap) verwendet werden. Außerdem werden sie verwendet, wenn das Objekt zum "Screen" wird. Das tritt auf, wenn das Objekt die Anweisung DefaultScreen im UI-Code enthält oder wenn es der Systemvariablen Screen direkt zugewiesen wird (vergleiche Kapitel 2.3.1 "Die Screen-Variable").

BitmapContent-Objekte ohne die Anweisung defaultColor verwenden die Farben "schwarz auf weiß".


Syntax UI-Code: defaultColor = fg, bg  
            fg: Vordergrund (foreground)
            bg: Hintergrund (background)
                fg und bg müssen Indexfarben sein.
                RGB-Farben sind nicht zulässig.
         Lesen: <numVar> = <obj>.defaultColor (0)    ' fg
                <numVar> = <obj>.defaultColor (1)    ' bg
     Schreiben: <obj>.defaultColor = fg, bg  

 
Beim Anlegen der Bitmap löscht R-BASIC die Bitmap in der Hintergrundfarbe bg. Wird das zugehörige BitmapContent-Objekt zum Screen setzt R-BASIC die Farben folgendermaßen:
               Hintergrundfarbe: bg
Text-, Linien- und Flächenfarbe: fg
Das ist prinzipiell so, als würde automatisch die Anweisung "COLOR fg, bg" ausgeführt.

DefaultScreen

Diese Anweisung im UI-Code bewirkt, dass das entsprechende BitmapContent als "Standard-Ausgabe-Objekt" festgelegt wird. Es wird dazu automatisch in der Systemvariablen Screen gespeichert (vergleiche Kapitel 2.3.1 "Die Screen-Variable"). Alle Grafik- oder Textausgaben gehen damit automatisch auf dieses Objekt.
Syntax UI-Code: DefaultScreen

 
Beispiel UI-Code:
BitmapContent  MyBitmap
  bitmapFormat = 320, 256, 24
  DefaultScreen
  END Object

Hinweis für Profis BitmapContent-Objekte sind auch dann voll nutzbar, wenn sie nicht mit einem View verbunden sind, d.h. sie können zum "Screen" gemacht oder als "DefaultScreen" gesetzt werden. Natürlich werden sie dann nicht auf dem Bildschirm erscheinen. Grafik- und Textausgaben gehen dann "im Hintergrund" in die Bitmap und werden sichtbar, sobald das Objekt an ein View gekoppelt wird (z.B. mit der Zuweisung MyView.Content = MyBitmapContent). Insbesondere ist es möglich zwischen zwei BitmapContent Objekten hin- und herzuschalten. Sie können die eine Bitmap im Hintergrund ändern, während die andere sichtbar ist - und dann die Veränderungen mit der Zuweisung MyView.Content = .. auf "einen Schlag" sichtbar machen.

^

5.2.3 Erweitere Funktionen

suspendDraw

Parallel zur Bitmap gehen die Grafikausgaben gleichzeitig auf den Bildschirm. Dort wird aber weder das Vorhandensein einer Maske noch die Information, dass eventuell "nur" die Maske bearbeitet wird, berücksichtigt. Auch eine eventuell geänderte Farbpalette (siehe Kapitel 5.2.5) wird nicht berücksichtigt. Das führt zu einem zeitweisen Widerspruch zwischen Darstellung auf dem Bildschirm und der Grafik in der Bitmap. Deswegen sollten Sie, während Sie in eine maskierte Bitmap schreiben (egal ob Maske oder Bitmapdaten), die parallel dazu verlaufende Ausgabe auf den Monitor deaktivieren. Das Gleiche gilt für das Schreiben in eine Bitmap mit geänderter Farbpalette. Für diesen Zweck gibt es die Instancevariable suspendDraw.
Syntax UI-Code: nicht zulässig
         Lesen: <numVar> = <Bitmapobj>.suspendDraw
     Schreiben: <Bitmapobj>.suspendDraw =  TRUE | FALSE

 
SuspendDraw = TRUE deaktiviert die die gleichzeitige Ausgabe der Grafikbefehle auf den Bildschirm. Sobald suspendDraw wieder auf FALSE gesetzt wird zeichnet sich die Bitmap neu auf den Schirm, so dass die vorgenommenen Änderungen "auf einen Schlag" sichtbar werden.

SuspendDraw ist - unabhängig von der Existenz einer Maske oder einer Palette - ebenfalls nützlich, wenn Sie eine große Anzahl von Grafikbefehlen haben, die entweder zu "komischen" Zwischenresultaten führen oder sehr lange dauern. Das zeitweise Abschalten der Ausgabe auf den Schirm beschleunigt natürlich die Zeichenoperationen.

Verliert ein Objekt den "Screen" Status (d.h. belegen Sie die Systemvariable Screen neu), so wird die Suspendierung automatisch aufgehoben.

Redraw

Die Methode Redraw bewirkt, dass das Objekt die Bitmap neu auf den Bildschirm zeichnet. Der Aufruf der Methode ist notwendig, wenn Sie einen einzelnen Paletteneintrag geändert haben (Methode SetPaletteEntry, siehe Kapitel 5.2.5.2) oder eine Bitmapzeile manuell verändert haben (Methode PeekLine, siehe Kapitel 5.2.6).
        Syntax: <obj>.Redraw [drawBackground]
drawBackground: TRUE | FALSE (Default: FALSE)

 
Beispiel:
  DemoBitmap.Redraw
  DemoBitmap.Redraw TRUE
DrawBackground = TRUE bewirkt, dass sich das zum Objekt gehörende View neu zeichnet bevor das Objekt die Bitmap neu darstellt. Damit wird der Hintergrund gelöscht. DrawBackground = TRUE ist nur erforderlich, wenn die Bitmap eine Maske (Transparenzebene) hat und Sie mit der Methode PeekLine den von der Maske als durchsichtig markierten Bereich geändert haben.

GetBitmapHandle

Die Methode GetBitmapHandle liefert das Handle auf die vom BitmapContent verwaltete Bitmap. Das Handle kann zum Beispiel verwendet werden, um die Bitmap in ein anderes Objekt oder einen GString zu zeichnen. Im Kapitel 2.8.6.4 (Bitmaps und Bitmap Handles) des R-BASIC Programmierhandbuchs finden Sie eine Übersicht über die Möglichkeiten der Arbeit mit Bitmaphandles.
Syntax BASIC Code: <han> = <obj>.GetBitmapHandle
      <han>: Variable vom Typ Handle

 
Alle Änderungen, die an der Bitmap im BitmapContent-Objekt gemacht werden wirken sich auf das Handle aus. Insbesondere wird das Handle ungültig, wenn das Objekt seine Bitmap neu anlegt (z.B. die Größe oder die Farbtiefe ändert oder wenn einer der Methoden NewBitmapFromHandle oder ClpPaste aufgerufen werden).

Das folgende Codebeispiel zeigt wie man eine Bitmap in eine BMP-Datei schreibt.

SUB  WritToBMPFile( fileName$ as String )
DIM han as HANDLE
  han = MyBitmap.GetBitmapHandle
  WriteBitmapToFile(han, fileName$)
End SUB
 

CopyBitmap

Die Methode CopyBitmap fertigt eine Kopie des vom BitmapContent verwalteten Bitmap an und liefert das Handle der Kopie. Das Handle kann verwendet werden, um die kopierte Bitmap mit DrawBitmap() zu zeichnen. Im Kapitel 2.8.6.4 (Bitmaps und Bitmap Handles) des R-BASIC Programmierhandbuchs finden Sie eine Übersicht über die Möglichkeiten der Arbeit mit Bitmaphandles.

Die mit CopyBitmap erstellte Kopie muss mit FreeBitmap wieder freigegeben werden.


Syntax BASIC Code: <han> = <obj>.CopyBitmap
      <han>: Variable vom Typ Handle

 
Im Gegensatz zu GetBitmapHandle wirken sich Änderungen der Bitmap des Objekts nicht mehr auf die kopierte Bitmap und deren Handle aus.

NewBitmapFromHandle

Die Methode NewBitmapFromHandle kopiert eine durch ein Handle referenzierte Bitmap in das Objekt. Die alte vom Objekt gespeicherte Bitmap geht verloren. Das Objekt stellt sich anschließend neu dar. Es informiert auch sein View über die neue Größe der Bitmap.
Syntax BASIC Code: <obj>.NewBitmapFromHandle <han>  
      <han>: Referenz auf die zu kopierende Bitmap

 
Das folgende Codebeispiel kopiert eine Bitmap von einem Objekt in ein anderes.
SUB  CloneBitmap( )
DIM han as HANDLE
  han = MyBitmap.GetBitmapHandle
  MyOtherBitmap.NewBitmapFromHandle han
End SUB

^

5.2.4 Arbeit mit transparenten Bitmaps

5.2.4.1 Überblick

Der Begriff "transparente Bitmap" oder auch "maskierte Bitmap" beschreibt, dass Teile der Bitmap durchsichtig sind, also den Hintergrund nicht verdecken. Man muss sich das so vorstellen, dass die Bitmap außer der eigentlichen Grafik noch eine schwarz-weiß Bitmap gleicher Größe enthält. Diese heißt "Maske" und bestimmt die Transparenz. Weiße Pixel sind durchsichtig, schwarze nicht.

...         ...     ...

Um eine transparente Bitmap anzulegen muss das Bit 0 (zugehöriger Wert: 1, Konstante BF_MASK) im Parameter "flags" der Instancevariable bitmapFormat gesetzt sein. Der folgende UI-Code definiert eine transparente 8-Bit Bitmap:

BitmapContent DemoBitmap
    bitmapFormat = 300, 100, 8, BF_MASK
    DefaultScreen
    defaultColor = YELLOW, LIGHT_BLUE
END Object
Beim Anlegen einer transparenten Bitmap wird die Maske vollständig gefüllt, d.h. die Bitmap ist zunächst nicht durchsichtig.

editMask

Normalerweise gehen Grafik- und Textausgaben direkt in die Bitmap und parallel dazu auf den Bildschirm. Die Maske wird dabei nicht verändert. Um die Maske zu beschreiben müssen Sie die Instancevariable editMask auf TRUE setzen.
Syntax UI-Code: nicht zulässig
         Lesen: <numVar> = <Bitmapobj>.editMask
     Schreiben: <Bitmapobj>.editMask = TRUE | FALSE

 
Danach gehen alle Zeichenoperationen in die Maske und die "normalen" Bilddaten bleiben unberührt.

suspendDraw

Parallel zur Bitmap gehen die Grafikausgaben gleichzeitig auf den Bildschirm. Dort wird aber das Vorhandensein einer Maske nicht berücksichtigt. Deswegen sollten Sie, während Sie in eine maskierte Bitmap schreiben (egal ob Maske oder Bitmapdaten) die parallel dazu verlaufende Ausgabe auf den Monitor deaktivieren. Für diesen Zweck gibt es die Instancevariable suspendDraw. SuspendDraw = TRUE deaktiviert die die gleichzeitige Ausgabe der Grafikbefehle auf den Bildschirm. Sobald suspendDraw wieder auf FALSE gesetzt wird zeichnet sich die Bitmap neu auf den Schirm, so dass die vorgenommenen Änderungen "auf einen Schlag" sichtbar werden.

Wichtige Hinweise

  • Masken werden nicht gescrollt. Werden die Bitmapdaten nach einer Print-Anweisung automatisch nach oben verschoben (Scrolling), so bleibt die Maske davon unberührt. Unter Umständen kann es sinnvoll sein, in diesem Zusammenhang suspendDraw zu verwenden.

  • Bei der Ausgabe von Texten (Print-Befehl) wird der Hintergrund im Normalfall mit der Hintergrundfarbe gelöscht. Wenn dies stört setzen Sie die Hintergrundfarbe auf "transparent":
      Paper BG_TRANSPARENT
  • Wichtig! Das GEOS-System unterstützt transparente Bitmaps auch für 24-Bit Bitmaps, der Versuch, etwas in die Maske zu zeichnen führt jedoch zu einem Crash. Sie können die Methoden PeekLine und PokeLine verwenden, um die Maske von 24-Bit-Bitmap zu bearbeiten.

^

5.2.4.2 Beschreiben der Maske

Da es sich bei der Maske aus Sicht des Systems um eine schwarz-weiß-Bitmap handelt sollten Sie beim Zeichnen in die Maske (editMask = TRUE) nur die Farben Schwarz (macht den Bereich undurchsichtig) oder Weiß (macht den Bereich durchsichtig) verwenden. Flächen in anderer Farbe (nicht aber Linien und Texte) werden entsprechend der Helligkeit der Farbe gerastet.

Alternativ zu den Farben kann man das Feld "mixMode" der globalen Variablen "graphic" mit einem passenden Wert belegen. Mehr dazu im 2. Beispiel.

Die folgenden Beispiele verwenden die Kommandos ScreenSaveState (speichern aller Grafikdaten wie Farben, Font, mixMode usw.) und ScreenRestoreState (wiederherstellen der gespeicherten Werte). Außerdem wird die fertige Bitmap ins Clipboard kopiert (DemoBitmap.ClpCopy), von wo aus sie in z.B. GeoWrite für dieses Handbuch verwendet werden kann.

Der Befehl CLS wirkt - wie alle anderen Grafikbefehle - entweder auf die Bitmapdaten (editMask = FALSE) oder auf die Maske (editMask = TRUE). Ist editMask = TRUE löscht er die Maske immer (alles durchsichtig), egal welche Farbe Sie eingestellt haben.

Beispiel: Zeichenoperationen in die Maske

Sub InkDemo()

ScreenSaveState                 ' Grafikdaten sichern
DemoBitmap.suspendDraw = TRUE   ' Bildschirm tot legen

DemoBitmap.editMask = TRUE      ' Maske editieren
Cls
Ink BLACK
FillEllipse 0, 0, 150, 100
Ink WHITE
FillRect 50, 25, 100, 75 
DemoBitmap.editMask = FALSE     ' Maske ist fertig

ScreenRestoreState              ' Grafikeinstellungen
                                ' wiederherstellen
FillRect 0, 0, 75, 50, GREEN
FillRect 75, 0, 150, 50, RED
FillRect 0, 50, 150, 100, BLUE
FillRect 75, 50, 150, 100, CYAN  

DemoBitmap.suspendDraw = FALSE  ' alles neu zeichnen
DemoBitmap.ClpCopy  

END Sub
 
... Die vom Code oben erzeugte Bitmap vor einem Text:

Anmerkung: Da einige Druckertreiber (z.B. Postscript Color) transparente Bitmaps nicht korrekt drucken, wurden alle transparenten Bitmaps in diesem Handbuch zuvor in GeoDraw vor einen Text gelegt und diese Kombination in eine (druckbare) unmaskierte Bitmap konvertiert.

^

5.2.4.3 Verwendung des MixMode MM_SET

Nicht immer kann man sicherstellen, dass nur die Farben Schwarz und Weiß verwendet werden, z.B. wenn man einen GString (siehe R-BASIC Programmierhandbuch, Kapitel 2.8.5) in eine maskierte Bitmap schreiben will oder wenn die auszugebende Grafik in einer SUB steckt, die selbst Farben einstellt:
Sub PaintHouse()

ScreenSaveState
graphic.linewidth = 5
Ink LIGHT_BLUE
FillRect 10, 50, 100, 80    ' das Haus
Ink WHITE
FillRect 15, 55, 25, 65     ' ein Fenster
FillRect 35, 55, 45, 78     ' die Tür
FillRect 55, 55, 65, 65     ' ein Fenster
FillRect 75, 55, 85, 65     ' ein Fenster
Ink LIGHT_GREEN
Line 10, 50, 55, 10         ' das Dach
Line 55, 10, 100, 50
Ink LIGHT_RED
FillEllipse 90, 5, 110, 25  ' die Sonne
ScreenRestoreState

END Sub
 
... Um das Haus transparent in eine Bitmap zu zeichnen muss diese Sub sowohl für die Bitmapdaten als auch für die Maske gerufen werden. Dabei würden jedoch die farbigen Flächen gerastert (siehe Bild). Hier hilft das Einstellen des passenden "mixMode".

Dazu belegt man das Feld "mixMode" der globalen Variablen "graphic" mit dem passenden Wert. Für uns sind an dieser Stelle die Modes MM_SET, MM_CLEAR und MM_COPY interessant.

  • graphic.mixMode = MM_COPY ist der Normalfall.

  • graphic.mixMode = MM_SET bewirkt, dass die aktuelle Farbe ignoriert wird und alle Ausgaben in schwarz erfolgen. Bereiche der Maske, die in diesem Modus beschrieben werden, werden undurchsichtig.

  • graphic.mixMode = MM_CLEAR bewirkt, dass die aktuelle Farbe ignoriert wird und alle Ausgaben in weiß erfolgen. Bereiche der Maske, die in diesem Modus beschrieben werden, werden transparent. Der Befehl CLS nutzt diesen Modus automatisch um die Maske zu löschen (wenn editMask = TRUE ist).

    Achtung! MM_CLEAR wirkt nicht auf Textausgaben! Für transparente Buchstaben müssen Sie den "normalen" MixMode MM_COPY und die Farbe Weiß verwenden.

Beispiel: Verwendung des MixMode MM_SET. Beachten Sie, dass es egal ist, ob man erst die Maske oder erst die Bitmapdaten zeichnet.
Sub MixModeExample()
DIM mmSaved

DemoBitmap.suspendDraw = TRUE   ' Schirmausgabe abschalten
Cls                             ' Bitmapdaten löschen
PaintHouse                      ' Farbige Grafik zeichnen

DemoBitmap.editMask = TRUE      ' Maske editieren
mmSaved = graphic.mixMode
graphic.mixMode = MM_SET
Cls              ' Maske löschen
PaintHouse
graphic.mixMode = mmSaved       ' MixMode restaurieren

DemoBitmap.editMask = FALSE     ' Maske fertig
DemoBitmap.suspendDraw = FALSE  ' Alles neu zeichnen

DemoBitmap.ClpCopy
END Sub
 
... Der Code erzeugt nun wie gewünscht das rechts dargestellte Bild.

Beispiel: Das Resultat vom vorherigen Beispiel soll vollständig einfarbig gefärbt werden. Das ist sehr einfach. Wir löschen die Bitmapdaten ohne die Maske zu verändern.

DemoBitmap.suspendDraw = TRUE
Paper GREEN
CLS
DemoBitmap.suspendDraw = FALSE

^

5.2.4.4 Zeichnen einer maskierten Bitmap in eine andere

Wird eine maskierte Bitmap in eine andere Bitmap gezeichnet so werden die Masken natürlich berücksichtigt. Der folgende Code zeichnet eine Bitmap (aus dem Objekt DemoBitmap2) in den Screen DemoBitmap. Weil das Zielobjekt (DemoBitmap) ebenfalls eine maskierte Bitmap enthält setzen wir während der eigentlichen Zeichenanweisung die Instancevariable suspendDraw auf TRUE.
SUB DoDrawBitmap()
DIM h as Handle

  DemoBitmap.suspendDraw = TRUE
  h = DemoBitmap2.GetBitmapHandle
  DrawBitmap h, 0, 0
  DemoBitmap.suspendDraw = FALSE

End SUB

Das Ergebnis sieht so aus. Die Maske der Zielbitmap wurde nicht verändert.

...

DemoBitmap (Sreen)

...

DemoBitmap2

...

Nach DoDrawBitmap


... Wenn wir die Maske der Zielbitmap anpassen wollen (siehe Bild rechts) müssen wir explizit in die Maske der Zielbitmap schreiben. Dazu setzen wir editMask auf TRUE und stellen den MixMode MM_SET ein, sonst werden die roten Kreise gerastert. MixMode = MM_COPY stellt anschließend den Ausgangszustand wieder her.

Tipp: Wir brauchen in diesem speziellen Fall suspendDraw nicht auf TRUE zu setzen, weil wir den undurchsichtigen Teil der Maske ergänzen und genau diesen Bereich mit Grafik füllen, so dass der Bildschirm automatisch auf dem korrekten Stand ist.

SUB DoDrawBitmap()
DIM h as Handle

' hier nicht erforderlich: DemoBitmap.suspendDraw = TRUE
  h = DemoBitmap2.GetBitmapHandle
  Drawbitmap h, 0, 0
  
  DemoBitmap.editMask = TRUE
  graphic.mixMode = MM_SET
  DrawBitmap h, 0, 0
  graphic.mixMode = MM_COPY
  DemoBitmap.editMask = FALSE
  
' hier nicht erforderlich: DemoBitmap.suspendDraw = FALSE

End SUB

^

5.2.5 Arbeit mit Paletten

5.2.5.1 Überblick

Unter GEOS bzw. R-BASIC werden Bitmaps mit folgenden Farbtiefen unterstützt:

Bits pro Pixel Farben Anmerkung
1 2 Immer Schwarz/Weiß
4 16 Von R-BASIC nicht unterstützt
8 256 Palette möglich
24 True Color  

Eine Bitmap mit 24 Bit pro Pixel enthält für jedes Pixel 3 Byte, je eines für die Farben Rot, Grün und Blau. Da jedes Byte die Werte 0 bis 255 annehmen kann ergeben sich etwa 16,8 Millionen mögliche Farben.

Wenn eine Bitmap weniger als 3 Byte pro Pixel speichert muss das System entscheiden, welche der über 16 Millionen möglichen Farben dargestellt werden sollen. Das wird über eine sogenannte Farbpalette realisiert. Die Palette ist eine Liste von bis zu 256 Einträgen zu je drei Byte - jeweils eins für Rot, Grün und Blau. Der "Farbwert" des Pixels entspricht dann der Nummer (dem sogenannten Index) des Eintrags in der Liste. Die Zählung beginnt dabei immer mit Null.

Zur Verwaltung der Palette sind in R-BASIC die folgenden Strukturen definiert:

STRUCT PaletteEntry
  rt, gn, bl  as BYTE
  End Struct

STRUCT FullPalette  
  item[255] as PaletteEntry
  END Struct
PaletteEntry enthält einen einzelnen Paletteneintrag, FullPalette enthält die vollständige Palette einer 256-Farb-Bitmap. Erlaubte Werte für den Index sind 0 bis 255. Die Palettendaten werden in der GEOS-Bitmap selbst gespeichert. R-BASIC erlaubt den Zugriff auf die Palette und deren Änderung. Wenn die Bitmap keine eigene Palette hat nutzt das System die GEOS-Standard-Palette. Dann kann R-BASIC die Farben nicht ändern.

Um eine Bitmap mit Palette anzulegen muss im vierten Parameter (flags) der Instancevariablen bitmapFormat das Bit 1 (zugehöriger Wert: 2, Konstante BF_PALETTE) gesetzt sein. Das System belegt dann die Palettendaten der Bitmap mit der Standardpalette. Diese Daten können später von R-BASIC aus geändert werden. Das passiert individuell für jede Bitmap, so dass Sie in einem Programm mehrere Bitmaps mit verschiedenen Paletten gleichzeitig anzeigen können.

' Parameter flags: Transparenz und Palette
  bitmapFormat = 640, 480, 8                ' Keine eigene Palette,
                                            ' nutzt Standardpalette
  bitmapFormat = 640, 480, 8, BF_PALETTE    ' Palette 
  bitmapFormat = 640, 480, 8, BF_PALETTE + BF_MASK
                                            ' Palette + Transparenz
Die Verwendung einer Palette ist nur bei 8-Bit-Bitmaps sinnvoll. R-BASIC unterstützt zwar den Zugriff auf die Palette einer schwarz/weiß Bitmap, das System ignoriert die Palettendaten aber. Es zeichnet monochrome Bitmaps immer in schwarz/weiß.

^

5.2.5.2 Zugriff auf die Farbpalette

GetFullPalette

Die Methode GetFullPalette liest die Palette einer Bitmap aus. Enthält die Palette der Bitmap weniger als 256 Einträge werden die restlichen Einträge mit Null belegt. Enthält die Bitmap keine Palette kommt es zu einem Laufzeitfehler.
Syntax: <pal> = <obj>.GetFullPalette
 <pal>: Variable vom Typ FullPalette

 

SetFullPalette

Die Methode SetFullPalette belegt die Palette einer Bitmap. Das Objekt stellt sich automatisch neu dar. Enthält die Palette der Bitmap weniger als 256 Einträge werden die restlichen Einträge ignoriert. Enthält die Bitmap keine Palette kommt es zu einem Laufzeitfehler.
Syntax: <obj>.SetFullPalette <pal>
 <pal>: Variable oder Ausdruck vom Typ FullPalette

 

GetPaletteEntry

Die Methode GetPaletteEntry liest einen einzelnen Paletteneintrag einer Bitmap aus. Enthält die Bitmap keine Palette kommt es zu einem Laufzeitfehler.
 Syntax: <entry> = <obj>.GetPaletteEntry (index)
<entry>: Variable vom Typ PaletteEntry
  index: Index des auszulesenden Paletteneintrags. Es muss gelten
         0 <= index < Anzahl der Paletteneinträge der Bitmap,
         ansonsten kommt es zu einem Laufzeitfehler.

 

SetPaletteEntry

Die Methode GetPaletteEntry setzt einen einzelnen Paletteneintrag einer Bitmap aus. Das Objekt stellt sich aber nicht automatisch neu dar. Sie müssen dazu die Methode Redraw aufrufen. Enthält die Bitmap keine Palette kommt es zu einem Laufzeitfehler.
 Syntax: <obj>.SetPaletteEntry <entry>, index
<entry>: Variable oder Ausdruck vom Typ PaletteEntry
  index: Index des auszulesenden Paletteneintrags. Es muss gelten
         0 <= index < Anzahl der Paletteneinträge der Bitmap,
         ansonsten kommt es zu einem Laufzeitfehler.

 
Tipp: GetPaletteEntry und SetPaletteEntry laufen nur geringfügig schneller als SetFullPalette und GetFullPalette. Wenn Sie mehrere Paletteneinträge ändern wollen ist deshalb häufig effektiver, die komplette Palette zu holen, die zu ändern und sie dann komplett neu zu setzen.

Redraw

Die Methode Redraw (ausführliche Beschreibung siehe vorne) bewirkt, dass das Objekt die Bitmap neu auf den Bildschirm zeichnet. Der Aufruf der Methode ist notwendig, wenn Sie einen einzelnen Paletteneintrag geändert haben (Methode SetPaletteEntry).

^

5.2.5.3 Beispiele

Die Farbkonstanten von R-BASIC basieren auf der GEOS Standardpalette. Zum Beispiel hat BLACK den Wert Null, BLUE den Wert 1 und WHITE den Wert 15. Wenn Sie beispielsweise dem Palettenwert mit dem Index 1 die RGB-Werte der Farbe Weiß zuweisen, werden alle Pixel, die den Index 1 haben, nicht mehr blau, sondern weiß dargestellt. Auf diese Weise kann man die Farben einer Bitmap sehr schnell ändern.

Der folgende Code ersetzt den Paletteneintrag für die Farbe Schwarz (Index Null) durch einen Grauwert. Die erste Variante liest und setzt die vollständige Palette. Die Methode SetFullPalette zeichnet die Bitmap automatisch neu. In der zweiten Variante lesen und schreiben wir genau einen Paletteneintrag. Weil SetPaletteEntry die Bitmap nicht neu zeichnet müssen wir die Methode Redraw aufrufen.

SUB ModifyBlack()
DIM pal as FullPalette
  pal = DemoBitmap.GetFullPalette
  pal.item(0).rt = 120
  pal.item(0).gn = 120
  pal.item(0).bl = 120
  DemoBitmap.SetFullPalette pal
End SUB
SUB ModifyBlack2()
DIM pe as PaletteEntry
  pe = DemoBitmap.GetPaletteEntry (0)
  pe.rt = 120
  pe.gn = 120
  pe.bl = 120
  DemoBitmap.SetPaletteEntry pe, 0
  DemoBitmap.Redraw
End SUB
Der folgende Code senkt alle Farbwerte der Palette auf 80% ab. Dadurch wird das Bild deutlich dunkler.
SUB MakeDarker()
DIM pal AS FullPalette 
DIM n
  pal = DemoBitmap.GetFullPalette
  FOR n = 0 TO 255
    ' Rot, Grün und Blauwert verringern
    pal.item(n).rt = 0.8 * pal.item(n).rt
    pal.item(n).gn = 0.8 * pal.item(n).gn
    pal.item(n).bl = 0.8 * pal.item(n).bl
  NEXT n
  DemoBitmap.SetFullPalette pal
End Sub
Das folgende Beispiel tauscht die Palettenwerte für die Farben Blau und Weiß. Alles was bisher weiß war erscheint dann blau und umgekehrt. Die erste Variante verwendet die Methoden GetPaletteEntry und SetPaletteEntry. Deswegen ist der Aufruf der Methode Redraw erforderlich. Variante Zwei liest und schreibt die vollständige Palette. Der Aufruf von SetFullPalette stellt die Bitmap automatisch mit den geänderten Farben dar.
SUB SwitchColors()
DIM pe1, pe2 AS PaletteEntry

  ' originale Palettenwerte holen
  pe1 = DemoBitmap.GetPaletteEntry(WHITE)
  pe2 = DemoBitmap.GetPaletteEntry(LIGHT_BLUE)
  
  ' Jeweils dem anderen Farbwert zuweisen
  DemoBitmap.SetPaletteEntry(pe1, LIGHT_BLUE)
  DemoBitmap.SetPaletteEntry(pe2, WHITE)
  
  ' Objekt neu zeichnen. Das passiert nicht automatisch!
  DemoBitmap.Redraw
End SUB
SUB SwitchColors2()
DIM pal as FullPalette
DIM pe AS PaletteEntry

  pal = DemoBitmap.GetFullPalette
  pe = pal.item(WHITE)
  pal.item(WHITE) = pal.item(LIGHT_BLUE)
  pal.item(LIGHT_BLUE) = pe
  DemoBitmap.SetFullPalette pal
  
End SUB
Betrachten wir nun den folgenden Code. Wenn wir ihn ausführen nachdem wir die SUB SwitchColors aufgerufen haben, sollte eine weiße Line erscheinen, weil dem Index der Farbe Blau (LIGHT_BLUE) jetzt die RGB-Werte der Farbe Weiß zugeordnet sind.
Line 10, 10, 200, 200, LIGHT_BLUE
Wir sehen jedoch eine blaue Linie. Erst wenn wir das Fenster mit der Bitmap auf dem Schirm verschieben (und sich die Bitmap deswegen neu zeichnen muss) wird die Linie weiß. Warum? Jeder Grafikbefehl (auch Textausgaben) gehen nicht nur in die Bitmap, sondern parallel dazu auch direkt auf den Schirm. Bei der Ausgabe auf den Schirm wird die geänderte Palette aber nicht berücksichtigt, sie ist nur der Bitmap bekannt. Deswegen sollten sie während der Ausgabe von Grafik und Text in eine Bitmap mit geänderter Palette die parallele Ausgabe auf den Bildschirm abschalten. Für diesen Zweck gibt es die Instancevariable suspendDraw. Der folgende Code erzeugt sofort gewünschte weiße Linie:
DemoBitmap.suspendDraw = TRUE
Line 10, 10, 200, 200, LIGHT_BLUE
' <hier weitere Grafik- und Textausgaben>
DemoBitmap.suspendDraw = FALSE
DemoBitmap.suspendDraw = TRUE schaltet die parallele Ausgabe der Grafik auf den Schirm ab. Die Bitmap wird unsichtbar im Hintergrund beschrieben. DemoBitmap.suspendDraw = FALSE hebt die Suspendierung auf und zeichnet die Bitmap neu auf den Schirm, so dass alle Änderungen sichtbar werden.

Eine ähnliche Situation tritt auf, wenn wir eine Bitmap in eine andere Bitmap zeichnen, falls die Paletten nicht übereinstimmen. Oder wir zeichnen eine RGB-Grafik (Bitmap oder Grafikbefehl) in die 8-Bit Bitmap. Das System ersetzt dann die nicht in der Palette befindlichen Farben durch "ähnliche" Farben, die in der Palette der Zielbitmap vorhanden sind. Auf dem Schirm erscheinen jedoch die originalen Farben. Auch hier sollten wir suspendDraw einsetzen. Der folgende Code geht davon aus, dass DemoBitmap1 der Screen ist.

SUB CopyBitmap2ToScreen
DIM h as Handle
  DemoBitmap1.suspendDraw = TRUE
  h = DemoBitmap2.GetBitmapHandle
  DrawBitmap h, 10, 20            ' Handle, Koordinaten
  DemoBitmap1.suspendDraw = FALSE
End SUB

...

Bitmap mit geänderter Palette (DemoBitmap2)

...

Farben, nachdem die Bitmap links in die Bitmap
DemoBitmap1 mit Standardpalette gezeichnet wurde.



^

5.2.6 Direktzugriff auf die Bitmapdaten

Es ist möglich, auf die einzelnen Pixelzeilen einer Bitmapgrafik direkt zuzugreifen. Dazu kann man mit der Methode PokeLine eine komplette Grafikzeile in den virtuelle RAM schreiben, dort die einzelnen Pixel modifizieren und die Zeile dann mit der Methode PeekLine zurück in die Bitmap kopieren. Insbesondere ist es auf diese Weise möglich, die Maskendaten einer 24-bit Bitmap zu ändern. Man sollte sich jedoch der Tatsache bewusst sein, dass die Manipulation von einigen Tausend Pixeln sehr lange dauern kann.

PokeLine

Die Methode PokeLine kopiert eine komplette Pixelzeile aus der Bitmap in den virtuellen R-BASIC RAM. Falls die Bitmap eine Maske enthält werden die zur Zeile gehörenden Maskendaten ebenfalls kopiert.
Syntax: <obj>.PokeLine adr, line
   adr: Adresse im virtuellen RAM (0 ... 65535)
        Es werden so viele Bytes geschrieben wie die Zeile enthält
  line: Zeilennummer der in den RAM zu schreibenden Zeile
        Erlaubte Werte: 0 .. Höhe - 1

 

PeekLine

Die Methode PeekLine kopiert eine komplette Pixelzeile aus dem virtuellen R-BASIC-RAM in die Bitmap des Objekts. Falls die Bitmap eine Maske enthält werden die zur Zeile gehörenden Maskendaten ebenfalls überschrieben. Die Bitmap stellt sich nicht neu dar, Sie müssen dazu die Methode Redraw aufrufen.
Syntax: <obj>.PeekLine adr, line
   adr: Adresse im virtuellen RAM (0 ... 65535)
        Es werden so viele Bytes aus dem RAM gelesen,
        wie die Zeile fasst.
  line: Zeilennummer der zu beschreibenden Bitmap-Zeile
        Erlaubte Werte: 0 .. Höhe - 1

 
Beispiel: Der folgende Code kopiert die die ersten 50 Zeilen einer Bitmap in die Zeilen 100 bis 149. Die Adresse im virtuellen RAM ist egal, deswegen wählen wir Adresse 0.
DIM n
FOR n = 0 TO 49
  DemoBitmap.PokeLine 0, n
  DemoBitmap.PeekLine 0, 100+n
NEXT n
DemoBitmap.Redraw


Redraw

Die Methode Redraw (ausführliche Beschreibung siehe vorne) bewirkt, dass das Objekt die Bitmap neu auf den Bildschirm zeichnet. Der Aufruf der Methode ist notwendig, wenn Sie eine Bitmapzeile manuell verändert haben (Methode PeekLine). Falls die Bitmap eine Maske (Transparenzebene) hat und Sie mit der Methode PeekLine den von der Maske als durchsichtig markierten Bereich geändert haben müssen Sie Redraw mit dem Parameter TRUE aufrufen, damit der Hintergrund der Bitmap neu dargestellt wird und die geänderte Maske erkennbar wird.

Aufbau der Bitmapdaten

...

Um die Pixelzeilen bearbeiten zu können müssen Sie die Struktur der Bitmapdaten kennen. Wir nehmen zunächst an, dass die Bitmap keine Maske hat. Je nach Farbtiefe wird eine unterschiedliche Anzahl von Bits für ein Pixel benötigt. Daraus ergibt sich die Anzahl der Bytes für eine Pixelzeile.

Farbtiefe Bits pro Pixel Bytes pro Zeile
Monochrom 1 8 Pixel werden zu einem Byte zusammengefasst. Es wird auf ganze Bytes gerundet. anzahl = INT ( (breite+7) / 8 )
256 Farben 8 anzahl = breite
True Color 24 anzahl = 3 * breite

Grundsätzlich liegen die in der Zeile links liegenden Pixel auf den niedrigen Adressen im virtuellen RAM. Bei monochromen Bitmaps liegt das ganz linke Pixel auf dem höchstwertigen Bit des Bytes. True-Color Bitmaps speichern die Farbwerte in der Reihenfolge Rot-Grün-Blau. Daraus ergeben sich die folgenden Zusammenhänge. In den Bildern bezeichnet "adr" Adresse "adr", die an die Methoden PeekLine bzw. PokeLine übergeben wurde.

Monochrome Bitmap:

Bit 7 ist das höherwertigste Bit, Bit 0 ist das niederwertigste Bit.

...

256 Farben Bitmap:

...

True Color Bitmap:

...

Aufbau der Bitmapdaten mit Maske

Wenn die Bitmap eine Maske hat sind die Maskendaten für jede Zeile direkt vor den Grafikdaten der Zeile angeordnet. Der Aufbau der Maskendaten entspricht dem einer monochromen Bitmap. Ein gesetztes Bit bedeutet, dass die Grafikdaten des Pixels dargestellt werden sollen. Ist das Bit nicht gesetzt (also Null) ist das Pixel transparent. Die Größe der Maskendaten (Anzahl der Bytes) berechnet sich zu:
maskLen = INT ( (breite+7) / 8 )
Die Methoden PokeLine und PeekLine kopieren jeweils sowohl die Maskendaten als auch die Grafikdaten.

...

Das folgende Codefragment belegt die Maskendaten einer Bitmap mit dem Bitmuster 00001111 (= 15 dezimal). Dadurch erscheint die Grafik gestreift. Die Farbtiefe der Grafik spielt dabei keine Rolle, da sie die Größe der Maskendaten nicht beeinflusst.

... ... ...

Hinweis: Je nachdem, welche Grafikdaten die Maske vorher verdeckt hat kann das linke oder das rechte Bild entstehen.

DIM width, height, x, y, masklen

  width = DemoBitmap.bitmapformat(0)
  height = DemoBitmap.bitmapformat(1)
  maskLen = INT ( (width+7)/8)

  FOR y = 0 TO height-1
    DemoBitmap.PokeLine 0, y
    FOR x = 0 TO maskLen - 1
      Poke x, 15             ' &B00001111
    NEXT x
    DemoBitmap.PeekLine 0, y
  NEXT y 
  DemoBitmap.Redraw


Ein etwas komplexeres Beispiel

Die Tatsache, dass das Format der Maskendaten identisch mit dem einer monochromen Bitmap ist ermöglich es, auf relativ einfache Weise die Maske einer 24 Bit Bitmap zu bearbeiten. Das System unterstützt das leider nicht.

Nehmen wir an, wir haben eine 24 Bit Bitmap der Größe 256 x 192 Pixel, die eine Maske enthält (Objekt DemoBitmap). Die Idee hinter dem folgenden Code ist, eine ebenso große monochrome Bitmap ohne (!) Maske (DemoBitmap2) zu verwenden, diese mit Grafikbefehlen zu bearbeiten und dann die Daten der monochromen Bitmap in die Maske der 24 Bit Bitmap zu kopieren. Dieses Vorgehen setzt voraus, dass beide Bitmaps exakt die gleichen Abmessungen haben.

Der folgende Code bearbeitet zunächst die monochromen Bitmap. Weiße Pixel werden später transparent, schwarze Pixel werden undurchsichtig.

  Screen = DemoBitmap2
  Paper WHITE
  Cls                         ' komplett transparent
  FillEllipse 64, 32, 192, 160, Black
  FillRect 32, 64, 224, 128, Black
Nun holen wir uns jede einzelne Pixelzeile der 24 Bit Bitmap in den virtuellen RAM und kopieren die Daten der monochromen Bitmap an die gleiche Stelle. Weil beide Bitmaps die gleiche Größe haben werden damit nur die Maskendaten der 24 Bit Bitmap überschrieben. Dann kopieren wir die geänderte Pixelzeile zurück in die 24 Bit Bitmap. Abschießend rufen wir die Redraw-Methode mit dem Parameter TRUE auf um die Änderungen sichtbar zu machen.
DIM x, y, maskLen

  maskLen = INT ((256+7)/8)

  FOR y = 0 TO 191
    DemoBitmap.PokeLine 0, y
    DemoBitmap2.PokeLine 0, y
    DemoBitmap.PeekLine 0, y
  NEXT y

  DemoBitmap.Redraw TRUE
Dieser Code erzeugt aus dem linken das rechte Bild.

...       ...

Hinweis: Um Speicherplatz zu sparen wurden die Grafiken für dieses Handbuch auf 8 Bit heruntergerechnet und etwas verkleinert.

^

Weiter...