Buchempfehlung
Windows System Programming
Windows System Programming
Das Kompendium liefert viele interessante Informationen zur Windows-Programmierung auf Englisch. [Mehr Infos...]
FreeBASIC-Chat
Es sind Benutzer im FreeBASIC-Chat online.
(Stand:  )
FreeBASIC bei Twitter
Twitter FreeBASIC-Nachrichten jetzt auch über Twitter erhalten. Follow us!

Referenz - Interne Pixelformate

Referenz-Navigation

 

Die Darstellung von Grafiken im Speicher mit FreeBASIC lässt sich in mehrere Kapitel untergliedern:



Darstellung eines einzelnen Pixels
Die Gfxlib verwendet immer eines von drei Pixelformaten: indizierte 1-Byte-Pixel, Direct Color 2-Bytes-Pixel (Hicolor) und Direct Color 4-Bytes-Pixel (Truecolor). Diese Formate werden in den entsprechenden Modi verwendet:

Farbtiefe (bpp)Pixelelformat
11 Byte pro Pixel, indiziert, Index von 0 bis 1.
21 Byte pro Pixel, indiziert, Index von 0 bis 3.
41 Byte pro Pixel, indiziert, Index von 0 bis 15.
81 Byte pro Pixel, indiziert, Index von 0 bis 255.
15, 162 Bytes pro Pixel, Direct Color, Format &bRRRRRGGGGGGBBBBB.
24, 324 Bytes pro Pixel, Direct Color, Format &bAAAAAAAARRRRRRRRGGGGGGGGBBBBBBBB.

Indiziert bedeutet hierbei, dass jeder Zahl eine Farbe zugeordnet ist; beispielsweise kann ein Pixel mit dem Farbattribut 4 rot sein. Welche Farbe welcher Zahl zugeordnet ist, hängt vom Bildschirmmodus ab; siehe dazu die BefehlsreferenzeintragStandard-Paletten. Diese können mit BefehlsreferenzeintragPALETTE noch im Programmverlauf bearbeitet werden. Bei Direct-Color-Modi stellt die Zahl bereits die Farbe dar. Jeweils ein bestimmter Teil der Zahl stellt den Rot- Grün- und Blau-Anteil der Farbe dar. Bei der Angabe des Formats in obiger Tabelle steht jeweils ein Zeichen für ein Bit der Farbinformation. R symbolisiert jeweils den Rot-, G den Grün- und B den Blauanteil. Die Stellen A, die bei 24bpp und 32bpp aufgeführt sind, können tatsächlich nur in 32bpp-Modi genutzt werden. Sie stellen die Alpha- oder Transparenz-Komponente dar. In 24bpp-Modi sind diese Stellen jeweils mit null besetzt, sie werden lediglich zur leichteren Verwaltbarkeit beibehalten. Wie Sie sehen, verwenden der 15bpp- und der 16bpp-Modus dasselbe 16bpp-Format. Ähnliches gilt den 24bpp- und den 32bpp-Modus sagen: beide benutzen das 32bpp-Format. Das interne Format ist plattformunabhängig. Der Bildschirmspeicher wird in einem der drei Formate gehalten. Denken Sie daran, wenn Sie per BefehlsreferenzeintragSCREENPTR darauf zugreifen; dasselbe gilt für Daten, die in BefehlsreferenzeintragGET- und BefehlsreferenzeintragPUT-Feldern gespeichert sind. Mehr dazu unter Struktur eines Bildpuffers für die Drawing Primitives. In Modi mit mehr als einem Byte pro Pixel werden die Bytes in umgekehrter Reihenfolge im Speicher abgelegt; das obere Byte des Gesamtwertes ist also das zweite im Speicher, das untere Byte wird zuerst abgelegt. Befindet sich an der angenommenen Adresse 0 also eine 32bit-Pixelinformation, so werden ihre Komponenten folgendermaßen zerlegt:

ByteKomponente
0Blau
1Grün
2Rot
3Alpha

Transparenz - Maskenfarben und Alpha-Wert
Maskenfarbe
Die Maskenfarbe hängt von der aktuellen Farbtiefe ab; sie ist einer von diesen Werten:

FarbtiefeMaskenfarbnummer
1, 2, 4, 80
15, 16&hF81F
24, 32&hFF00FF


Indizierte Modi benutzen immer den Index 0 als Transparenzmaske, während Direct Color-Modi immer Pink verwenden.

Alphawert
FreeBASIC unterstützt Transparenzeffekte nach der BefehlsreferenzeintragALPHA-Methode. Dabei wird neben dem Farb-Tripplet (Rot, Grün, Blau) auch ein Transparenzgrad, der Alphawert angegeben. Ebenso wie die Werte des Farbtripplets liegt auch der Alphawert im Bereich von 0 bis 255; dabei entspricht Alpha=0 völliger Transparenz und Alpha=255 völliger Überdeckung. Für alle Werte dazwischen werden 'durchscheinende' Bilder erzeugt, d. h. ein Farbwert wird berechnet, der 'zwischen' überzeichnender und überzeichneter Farbe liegt. Dabei gibt der Alphawert an, welcher der beiden Werte den Farbeindruck dominiert. Berechnet wird die neue Farbe nach dieser Funktion:

Function custom_alpha(Byval src As ULong, Byval dst _
   As ULong, Byval param As Any Ptr ) As ULong
  Dim As Ubyte ptr color_src, color_dst
  Dim As Ubyte     r, g, b, a

  color_src = Cast(Ubyte ptr, @src)
  color_dst = Cast(Ubyte ptr, @dst)

  If param <> 0 Then
    a = *Cast(Ubyte ptr, param)
    ' ein Alphawert für alle Pixel
  Else
    a = color_src[3]
    ' aus jedem Pixel den Alphawert lesen
  End If

  r=(color_src[2]*a+color_dst[2]*(255-a))\255
  g=(color_src[1]*a+color_dst[1]*(255-a))\255
  b=(color_src[0]*a+color_dst[0]*(255-a))\255
  Return RGBA(r, g, b, 255)
End Function

Diese Funktion ist so gehalten, dass sie mit der Methode BefehlsreferenzeintragCUSTOM benutzt werden kann (siehe BefehlsreferenzeintragPUT (Grafik), BefehlsreferenzeintragDRAW STRING).



Struktur eines Bildpuffers für die Drawing Primitives
Ein Bildpuffer ist ein Speicherbereich, in dem größere Blocks von Pixeldaten - kurz Bildausschnitte - abgelegt werden können. Dies kann ein Array sein (siehe BefehlsreferenzeintragDIM, BefehlsreferenzeintragREDIM) oder ein mit BefehlsreferenzeintragALLOCATE, BefehlsreferenzeintragCALLOCATE oder (besonders zu empfehlen) BefehlsreferenzeintragIMAGECREATE reservierter Bereich. In FreeBASIC werden zwei verschiedene Formate für Bildpuffer verwendet; abhängig von der Version des Compilers und den Kommandozeilenoptionen verwendet FreeBASIC Version 1 oder Version 2 der verfügbaren Formate. Beide Formate sind mit allen Drawing Primitives (z. B. BefehlsreferenzeintragPSET, BefehlsreferenzeintragLINE (Grafik)) kompatibel. Siehe auch BefehlsreferenzeintragPUT (Grafik), BefehlsreferenzeintragGET (Grafik).

Version 2 (aktuell)
Version 2 des Bildpuffers ist seit v0.17 verfügbar; das Programm kann ohne Kommandozeilenoption oder mit Befehlsreferenzeintrag-lang fb compiliert werden. Ebenso wie in der weiter unten aufgeführten Version 1 lässt sich dieses Bildpuffer-Format in einen Header und die eigentlichen Pixeldaten zerlegen. Der Bildpuffer ist dabei so angelegt:

TYPE Image FIELD = 1
  UNION
    old             AS _OLD_HEADER
    type            AS ULONG
  END UNION
  bpp                AS LONG
  width              AS ULONG
  height             AS ULONG
  pitch              AS ULONG
  _reserved(1 to 12) AS UBYTE
END TYPE

Wie Sie sehen, enthält der Header noch die Informationen des alten Formates. Dadurch ist eine schnelle und einfache Prüfung der Pufferversion möglich, wodurch die Abwärtskompatibilität gewahrt wird. Die einzelnen Elemente bedeuten in der Deklaration bedeuten Folgendes:

Wie bei 'pitch' bereits angesprochen, sind im neuen Datenformat die Pixel nicht mehr direkt aneinander gereiht, sondern zeilenweise in Datenblocks zusammengefasst. Hinter jeder Zeile werden eine Reihe von Bytes reserviert, die nicht genutzt werden. Durch dieses 'Padding' können bestimmte Berechnungen schneller durchgeführt werden. Der Wert dieser Padding-Bytes ist abhängig von der Art der Erstellung des Puffers. Bei der Verwendung eines Arrays wird hier in den meisten Fällen null eingetragen, da mit DIM und REDIM initiierte Variablen i. d. R. mit null initialisiert werden. Eine Ausnahme sind Arrays, die durch Befehlsreferenzeintrag= ANY initialisiert wurden; da hier der Inhalt des Speicherbereichs nicht gelöscht wird, und nur die tatsächlich genutzen Bytes im Laufe der Bildbearbeitung überschrieben werden, findet man hier immer den 'Datenmüll', der sich vor der Reservierung des Speicherbereichs auf den entsprechenden Stellen angesammelt hat. Durch CALLOCATE wird immer ein null-initialisierter Speicherbereich reserviert.

Wie schon bei Arrays, die durch = ANY initialisiert wurden, findet man auch bei der Reservierung eines Speicherbereichs mittels ALLOCATE Datenmüll in den Padding-Bytes. IMAGECREATE arbeitet im Prinzip genauso wie ALLOCATE, berechnet jedoch selbständig den zu reservierenden Speicherplatz und legt außerdem bereits den Header an. Daher handelt es sich hier um die bevorzugte Vorgehensweise für Bildpuffer. Die Speicherbereiche, die mit IMAGECREATE reserviert wurden, werden vor Benutzung komplett mit einem Wert befüllt; dieser hängt von den Parametern, mit denen IMAGECREATE genutzt wird, und dem aktuellen Bildschirmmodus ab.

Um nun bei gegebener Startadresse des Bildpuffers die Adresse eines einzelnen Pixels zu ermitteln, bedient man sich dieser Formel:

p = buffer+32+(y*((w*bpp+15) AND -16)+(x*bpp)

Steht 'pitch' aus dem Bildheader zur Verfügung, so kann der Ausdruck auch vereinfacht werden:

p = buffer + 32 + (y * pitch) + (x * bpp)

Der Speicherbedarf berechnet sich also nach dieser Formel:

size = 32 + ( h * (( w * bpp + 15 ) AND -16 )

Beispiel: Ein Bildpuffer der Größe 2x2 Pixel in einem 32bpp-Modus, der einen roten, grünen, gelben und blauen Pixel enthält:

ByteBedeutungWert
0 bis 3Version des Bildpuffers - neuer Header7
4 bis 7Farbtiefe in bpp4
8 bis 11Breite des Bildpuffers in Pixeln2
12 bis 15Höhe des Bildpuffers in Pixeln2
16 bis 19Bytes pro Zeile in diesem Puffer16
20 bis 31zwölf reservierte Bytes, die in zukünftigen OpenGL-Anwendungen eine Bestimmung finden könnten0
32 bis 35Farbe des ersten Pixels (links oben) im Format &hAARRGGBB&h00FF0000
36 bis 39Farbe des zweiten Pixels (rechts oben) im Format &hAARRGGBB&h0000FF00
40 bis 43Padding-Stelle - ohne Bedeutung&hFFFF00FF
44 bis 47Padding-Stelle - ohne Bedeutung&hFFFF00FF
48 bis 51Farbe des dritten Pixels (links unten) im Format &hAARRGGBB&h00FFFF00
52 bis 55Farbe des vierten Pixels (rechts unten) im Format &hAARRGGBB&h000000FF
56 bis 59Padding-Stelle - ohne Bedeutung&hFFFF00FF
60 bis 63Padding-Stelle - ohne Bedeutung&hFFFF00FF

Beispiel 1:

#Include "fbgfx.bi"
Using FB

ScreenRes 400, 300, 32

Dim buffer As Any      Ptr
Dim header As Image    Ptr
Dim Pixels As UInteger Ptr
Dim Colors As UByte    Ptr
Dim i      As UInteger

buffer = ImageCreate(2, 2)
header = buffer
Pixels = buffer + 32
Colors = buffer + 32

Pset buffer, (0, 0), &hFF0000
Pset buffer, (1, 0), &h00FF00
Pset buffer, (0, 1), &hFFFF00
Pset buffer, (1, 1), &h0000FF

With *header
  PRINT "Header des Buffers:"
  PRINT "Version ID:       "; .type
  PRINT "Bytes pro Pixel: "; .bpp
  PRINT "Breite:           "; .width
  PRINT "Hoehe:            "; .height
  PRINT "Bytes pro Zeile:  "; .pitch
End With

Draw String (0, 100), "Die Grafik:"
Put (100, 100), buffer, PSET

Open Err For Output As #1
PRINT #1, "Pixeldaten:"
PRINT #1, ""
For i = 0 To 31
  PRINT #1, i, Hex(Colors[i], 2),
  If (i + 1) Mod 4 = 0 Then PRINT #1, ""
  If (i    ) Mod 4 = 0 Then
    PRINT #1, Hex(Pixels[i \ 4], 8)
  Else
    PRINT #1, ""
  End If
Next

ImageDestroy buffer
Close #1
Sleep

Beispiel 2:
Über das UDT Image kann auch direkt auf die Header-Daten zugegriffen werden:

#Include "fbgfx.bi"

ScreenRes 400, 300, 32

Dim As FB.Image Ptr img
Dim As UInteger Ptr Pixel
Dim As UInteger     x, y, pitch

img = ImageCreate(256, 256)
pitch = img->pitch

For y = 0 To 255
  For x = 0 To 255
     Pixel = Cast(Any Ptr, img) + 32 + (y * pitch) + (x * 4)
    *Pixel = RGB(x, y, 0)
  Next
Next

Put (0, 0), img
Sleep

Erkennen des Puffertyps und Bearbeitung
Je nach gewählten Ausgangsbedingungen wird FreeBASIC bei der Erstellung neuer Datenpuffer immer eine bestimmte Version des Puffers benutzen:

Dennoch ist es möglich, dass ein anderes Pufferformat behandelt werden soll als das unter gegebenen Bedingungen von FreeBASIC gewählte, z. B. wenn mittels BLOAD Daten in den Speicher geladen werden, die ein älteres Programm erstellt hat. Die Drawing Primitives ab FreeBASIC v0.17 können - bei jeder gewählten Kommandozeilenoption - mit beiden Pufferformaten umgehen; sie erkennen automatisch, welche Struktur angewandt werden muss. Die Drawing Primitives von FreeBASIC-Versionen vor v0.17 können nur mit Version 1 des Pufferformats umgehen; der Programierer muss selbständig Daten des jüngeren Formats umwandeln. Bei direkten Speicherzugriffen ohne die FB-eigenen Drawing Primitives kann anhand der ersten LONG-Stelle des Headers überprüft werden, ob es sich um das alte oder das neue Format handelt: Beim neuen Format beinhaltet diese immer den Wert 7; beim alten Format ist hier ein anderer Wert gespeichert, der sich aus Farbtiefe, Höhe und Breite des Bildpuffers zusammensetzt. Dieser Wert kann nie gleich sieben werden. Mit dem Headertyp ändert sich auch der Startpunkt der eigentlichen Pixeldaten. Diese Formel gibt unabhängig von Pointertyp und Pufferformat den richtigen Startpunkt aus:

start = buffer + IIF( PEEK(LONG, buffer) = 7, 32, 4 ) \ SIZEOF(buffer)

Beachten Sie hierbei, dass Sie separat prüfen müssen, ob die Zeilen gepaddet sind. Dies ist bei Version 2 IMMER der Fall, in Version 1 hingegen NIE.

Version 1 (veraltet)
Die alte Version des Bildpuffers entspricht dem Pufferformat von QB. Sie wurde bis FreeBASIC v0.16 benutzt; seit v0.17 ist sie nur noch dann verfügbar, wenn die Kommandozeilenoption -lang deprecated oder -lang qb eingesetzt wird. Der Bildpuffer besteht aus dem Header und den eigentlichen Pixelinformationen. Der Header ist ein Bitfeld (siehe BefehlsreferenzeintragTYPE (UDT) und BefehlsreferenzeintragBitfelder), das Angaben über Höhe, Breite und Farbtiefe des Bildes enthält; an ihn schließen sich die eigentlichen Pixeldaten im oben genannten Format an. Der Header besteht insgesamt aus 32bit, also vier Byte oder einer LONG-Stelle. Er ist folgendermaßen aufgebaut:

TYPE _OLD_HEADER FIELD = 1
  bpp     :  3 AS USHORT
  width   : 13 AS USHORT
  height       AS USHORT
END TYPE

Die einzelnen Elemente bedeuten dabei Folgendes:

Dem Header schließen sich die eigentlichen Pixeldaten an; für jeden Pixel werden dabei so viele Bytes verwendet, wie in 'bpp' angegeben ist. Die Pixeldaten sind von links nach rechts und von oben nach unten geordnet. Die Größe eines Puffers nach diesem Format lässt sich also folgendermaßen berechnen:

size = 4 + (w * h * b)

wobei 'w' die Breite, 'h' die Höhe und 'b' die Farbtiefe in Bytes pro Pixel ist.

Beispiel: Ein Bildpuffer der Größe 2x2 Pixel in einem 32bpp-Modus, der einen roten, grünen, gelben und blauen Pixel enthält:

ByteBedeutungWert
0 und 1(Breite SHL 3) OR bpp20
2 und 3Höhe2
4 bis 7Farbe des ersten Pixels (links oben) im Format &hAARRGGBB&h00FF0000
8 bis 11Farbe des zweiten Pixels (rechts oben) im Format &hAARRGGBB&h0000FF00
12 bis 15Farbe des dritten Pixels (links unten) im Format &hAARRGGBB&h00FFFF00
16 bis 19Farbe des vierten Pixels (rechts unten) im Format &hAARRGGBB&h000000FF

Dies verdeutlicht auch dieses Programm:

#lang "deprecated"
ScreenRes 400, 300, 32
Dim x As UByte    Ptr
Dim y As ULong Ptr
Dim i As Integer
x = ImageCreate(2, 2)
y = Cast(ULong Ptr, x)
Pset x, (0, 0), &hFF0000
Pset x, (1, 0), &h00FF00
Pset x, (0, 1), &h0000FF
Pset x, (1, 1), &hFFFF00
For i = 0 To 19
  Print i, x[i],
  If ( i      Mod 4) = 0 Then
    Print Hex(y[i \ 4], 8)
  Else
    Print
  End If
  If ((i + 1) Mod 4) = 0 Then Print
Next
ImageDestroy x
Sleep


Zusätzliche Informationen und Funktionen
  • Der Referenzeintrag wurde am 06.08.2007 von RedakteurJojo angelegt.
  • Die aktuellste Version wurde am 05.08.2020 von Redakteurnemored gespeichert.
  Versionen Versionen