RGB Hex-Farbwerte

Für Probleme bezüglich Grafik, Audio, GL, ACS, ...
Antworten
wennerer
Beiträge: 507
Registriert: Di 19. Mai 2015, 20:05
OS, Lazarus, FPC: Linux Mint 20 Cinnamon,Lazarus 2.2.6 (rev lazarus_2_2_6) FPC 3.2.2 x86_64-linux-
CPU-Target: x86_64-linux-gtk2

RGB Hex-Farbwerte

Beitrag von wennerer »

Hallo,
ich bin auf folgende Merkwürdigkeit gestoßen: In der Unit Graphics sind die Farbkonstanten definiert. Ebenso kann man im Colordialog den Hexwert einer Farbe sehen. Wenn ich die Werte vergleiche sind die vertauscht rgb - bgr.

RGB_BGR.png
RGB_BGR.png (100.33 KiB) 4052 mal betrachtet
Wenn ich in einer Procedure eine TColor Variable übergebe kommt mit clYellow und dem ColorDialog Gelb als Ergebnis heraus. Setze ich aber den angezeigten Farbnamen $FFFF00 ein kommt Aqua raus. Gibts da eine Erklärung dafür oder wurde da nur einfach was vertauscht?

Viele Grüße
Bernd

Code: Alles auswählen

unit Unit1;

{$mode objfpc}{$H+}

interface

uses
  Classes, SysUtils, Forms, Controls, Graphics, Dialogs, StdCtrls, ExtCtrls,
  LCLIntf;

type

  { TForm1 }

  TForm1 = class(TForm)
    Button1: TButton;
    Button2: TButton;
    Button3: TButton;
    ColorDialog1: TColorDialog;
    Panel1: TPanel;
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
    procedure Button3Click(Sender: TObject);
    procedure SetaColor(aColor : TColor);
  private

  public

  end;

var
  Form1: TForm1;

implementation

{$R *.lfm}

{ TForm1 }

procedure TForm1.Button1Click(Sender: TObject);
begin
 setaColor(clYellow);
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
 setaColor($FFFF00);
end;

procedure TForm1.Button3Click(Sender: TObject);
var col : TColor;
begin
 if ColorDialog1.Execute then
 col := ColorDialog1.Color;
 setaColor(col);
end;

procedure TForm1.SetaColor(aColor: TColor);
var valR,valG,valB       : integer;
begin
 valR:=getRvalue(aColor);
 valG:=getGvalue(aColor);
 valB:=getBvalue(aColor);
 Panel1.Color:= rgb(valR,valG,valB);
end;

end.


wp_xyz
Beiträge: 4869
Registriert: Fr 8. Apr 2011, 09:01

Re: RGB Hex-Farbwerte

Beitrag von wp_xyz »

Das ist nun mal so. Die Deklarationen in der Unit Graphics sind die Zahlenwerte mit dem Rot-Wert im Low-byte (am weitesten rechts) und dem Blau-Wert im High-Byte (am weitesten links), und Gelb dazwischen. Bei HTML schreibt man die Werte wie als String in der Reihenfolge RRGGBB, also von links nach rechts.

Da der ColorDialog aus dem Widgetset kommt, kannst du nicht erwarten, dass die Konvention der Unit Graphics verwendet wird.

Benutzeravatar
Winni
Beiträge: 1577
Registriert: Mo 2. Mär 2009, 16:45
OS, Lazarus, FPC: Laz2.2.2, fpc 3.2.2
CPU-Target: 64Bit
Wohnort: Fast Dänemark

Re: RGB Hex-Farbwerte

Beitrag von Winni »

Hi!

Endlich gehts mal um Sex. In diesem Fall um Byte-Sex.

Die Farbwerte in HTML sind im Motorola-Format.
Wir arbeiten aber meistenteils auf Intel-Maschinen (oder Artverwandtem).

Motorola speichert die bytes so, wie wir gelernt haben, Zahlen zu schreiben (Big Endian)
Intels vertauscht die bytes, so dass erstmal das kleine Ende kommt (Little Endian)

Den Ärger hast Du nun gerade geschildert:
Um von der HTML Darstellung zur Delphi-/Lazarus-Darstellung zu kommen musst Du nun rot und blau vertauschen.

Die BGRAbitmap hat aufrund des byte-sex Problems dschon mal gleich die function SwapRedBlue.

Kann man sich aber auch gleich selber bauen:

Code: Alles auswählen

function HTML2Color (HexString: string) : TColor;
var s : string;
begin
HexString := UpperCase(HexString);
if NOT (hexString[1] in ['0'..'9', 'A'..'F'] ) then delete (HexString,1,1);
s := '$'+copy(HexString,5,2)+   copy(HexString, 3,2)+    copy(HexString,1,2);
result := strToInt(s);
end;
Hier gibtst Du den HTML-string wie #F8A1B9 ein und bekommst den richtigen TColor Wert zurück.

Winni
Zuletzt geändert von Winni am Mi 21. Okt 2020, 22:49, insgesamt 1-mal geändert.

Timm Thaler
Beiträge: 1224
Registriert: So 20. Mär 2016, 22:14
OS, Lazarus, FPC: Win7-64bit Laz1.9.0 FPC3.1.1 für Win, RPi, AVR embedded
CPU-Target: Raspberry Pi 3

Re: RGB Hex-Farbwerte

Beitrag von Timm Thaler »

Ja, ist so. TColor ist BGR definiert.

An die einzelnen Farben kommst Du mit Red(color), Green(color), Blue(color) oder color.Red... ran. Umgekehrt mit RGBToColor().

wennerer
Beiträge: 507
Registriert: Di 19. Mai 2015, 20:05
OS, Lazarus, FPC: Linux Mint 20 Cinnamon,Lazarus 2.2.6 (rev lazarus_2_2_6) FPC 3.2.2 x86_64-linux-
CPU-Target: x86_64-linux-gtk2

Re: RGB Hex-Farbwerte

Beitrag von wennerer »

Vielen Dank für eure Erklärungen!

Viele Grüße
Bernd

Mathias
Beiträge: 6162
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunk)
CPU-Target: 64Bit
Wohnort: Schweiz

Re: RGB Hex-Farbwerte

Beitrag von Mathias »

Timm Thaler hat geschrieben:
Mi 21. Okt 2020, 22:48
Ja, ist so. TColor ist BGR definiert.

An die einzelnen Farben kommst Du mit Red(color), Green(color), Blue(color) oder color.Red... ran. Umgekehrt mit RGBToColor().
Gar nicht gewusst, das dies so einfach geht. Ich habe dies immer mit shiften und and gemacht.
Sind diese Funktionen relativ neu ?
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

Warf
Beiträge: 1908
Registriert: Di 23. Sep 2014, 17:46
OS, Lazarus, FPC: Win10 | Linux
CPU-Target: x86_64

Re: RGB Hex-Farbwerte

Beitrag von Warf »

Ich benutz am liebsten records dafür:

Code: Alles auswählen

type
  TColorRec = record
    case Boolean of
    True: (R, G, B, A: Byte);
    False: (Color: TColor);
  end;
Aus portabilitätsgründen mit conditionals:

Code: Alles auswählen

type
  TColorRec = record
    case Boolean of
    {$IFDEF ENDIAN_LITTLE}
    True: (R, G, B, Special: Byte);
    {$ELSE}
    True: (Special, B, G, R: Byte);
    {$ENDIF}
    False: (Color: TColor);
  end;
Dann kann man einfach sowas machen:

Code: Alles auswählen

var
  col: TColorRec;
begin
  col.R :=255;
  col.B := 0;
  col.G := 0;
  col.Special := 0;
  if col.Color = clRed then WriteLn('Working as expected');
Mit ein paar operatoren und funktionen:

Code: Alles auswählen

operator :=(const AColor: TColor): TColorRec; inline;
begin
  Result.Color := AColor;
end;

operator := (const AColorRec: TColorRec): TColor; inline;
begin
  Result := AColorRec.Color;
end;

function RGBColor(const R: Byte; const G: Byte; const B: Byte): TColorRec; inline;
begin
  Result.R := R;
  Result.G := G;
  Result.B := b;
  Result.Special := 0;
end;
Und schon kann man viele tolle sachen machen:

Code: Alles auswählen

function RBSwap(const color: TColor): TColor;
var
  col: TColorRec;
begin
  col := color;
  Result := RGBColor(col.B, col.G, col.R);
end;
Wenn ich grafische anwendungen schreibe arbeite ich für gewöhnlich ausschließlich in meinem eigenen color type (der hat dann noch andere funktionen wie grayscale oder hsv konvertierung) und benutz dann die impliziete convertierung um das einfach von und zu TColor zu casten und es so einfach in der LCL benutzen zu können

wennerer
Beiträge: 507
Registriert: Di 19. Mai 2015, 20:05
OS, Lazarus, FPC: Linux Mint 20 Cinnamon,Lazarus 2.2.6 (rev lazarus_2_2_6) FPC 3.2.2 x86_64-linux-
CPU-Target: x86_64-linux-gtk2

Re: RGB Hex-Farbwerte

Beitrag von wennerer »

@Warf: Vielen Dank für deinen, für mich sehr interessanten Code. Leider reicht mein Wissenshorizont nicht aus um alles zu verstehen. Aber vielleicht kannst du ihn ja etwas Erweitern :D

So wohl Records mit einem varianten Teil wie auch Operator overloading kannte ich gar nicht, deshalb habe ich mich da jetzt mal eingelesen. Bin mir aber noch nicht sicher ob ich es richtig verstanden habe.

Den Record hast du folgendermaßen deklariert:

Code: Alles auswählen

type
  TColorRec = record
    case Boolean of
    {$IFDEF ENDIAN_LITTLE}
    True: (R, G, B, Special: Byte);
    {$ELSE}
    True: (Special, B, G, R: Byte);
    {$ENDIF}
    False: (Color: TColor);
  end;
Sehe ich es richtig dass das "case of Boolean" verwendet wird damit weniger Speicherplatz bereit gestellt werden muss?
Wann würde der Compiler in die {$ELSE} Anweisung springen? Ist das vom Betriebssystem oder von der Hardware abhängig?
Wenn ich die Antwort von Winni richtig verstehe wäre das ja von der Hardware abhängig?

Zum den Operatoren:

Code: Alles auswählen

operator :=(const AColor: TColor): TColorRec; inline;
Hier werden den Typ TColorRec die Eigenschaften von TColor zugewiesen? Wie eine Art TypeCast? Wann wird der operator aufgerufen?

Viele Grüße
Bernd

Warf
Beiträge: 1908
Registriert: Di 23. Sep 2014, 17:46
OS, Lazarus, FPC: Win10 | Linux
CPU-Target: x86_64

Re: RGB Hex-Farbwerte

Beitrag von Warf »

Zu dem record, das mit dem case ist ein varianter record, das ist ein record der erlaubt die selbe speicherregion verschieden aufzufassen. In diesem fall ist die Speicherregion 4 byte groß, die entweder als 4 Byte Felder oder als ein 32 Bit integer aufgefasst wird.
Das ENDIAN_LITTLE is ein vordefinierter Compilerswitch der Wahr ist wenn man sich auf einer Little endian architektur befindet. Auf einer Little endian ist das ende einer zahl auf der kleinsten addresse (daher little endian). Die zahl $AABBCCDD besteht ja aus den bytes $AA, $BB, $CC und $DD. Little endian ist das ende auf der niedrigsten addresse, also zu erst kommt $DD (das ende) dann $CC dann $BB und dann $AA.
In unserem varianten record heißt das das $DD in R steht, $CC in G und $BB, etc.
Bei big endian ist das genau anders rum, da ist das ende der zahl ($DD) auf der größten addresse.

Zum operator, das ist der Implicit cast operator, wenn man den überlädt wird der autmatisch zur impliziten umwandlung von typen aufgerufen, z.b.

Code: Alles auswählen

col: TColorRec;
col := TColor($FF); // Impliziete konvertierung von TColor zu TColorRec über den definierten operator

procedure foo(const col: TColorRec);
...
foo(TColor($FF)); // parameter vom typ TColorRec erwartet daher impliziete konvertierung
Es gibt auch noch den Operator Explicit für explizite casts, wenn der nicht überladen wird, wird der impliziete auch für explizite casts verwendet

Code: Alles auswählen

col := TColorRec(TColor($FF));
Das erlaubt halt einfach den typen "transparent" zu benutzen, sodass du überall wo TColor erwartet wirst TColorRec benutzen kannst

wennerer
Beiträge: 507
Registriert: Di 19. Mai 2015, 20:05
OS, Lazarus, FPC: Linux Mint 20 Cinnamon,Lazarus 2.2.6 (rev lazarus_2_2_6) FPC 3.2.2 x86_64-linux-
CPU-Target: x86_64-linux-gtk2

Re: RGB Hex-Farbwerte

Beitrag von wennerer »

Vielen Dank für deine ausführliche Antwort!!!
Viele Grüße
Bernd

Antworten