3 Byte Ausrichtung in eine Array ( TriByte / int24 )

Für Fragen zur Programmiersprache auf welcher Lazarus aufbaut
Antworten
Mathias
Beiträge: 7013
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunk)
CPU-Target: 64Bit
Wohnort: Schweiz

3 Byte Ausrichtung in eine Array ( TriByte / int24 )

Beitrag von Mathias »

Ist es mögliche eine 3 Byte Ausrichtung zu erstellen ?
Ich versuchte ein RGB-Wert, welcher aus 3 Byte besteht in einen 24Bit Integer zu packen.

Code: Alles auswählen

type
  TTriByte = 0..$FFFFFF;
const
  Data: packed array of TTriByte = ($000000, $FF0000, $00FF00, $0000FF);
begin
  WriteLn(SizeOf(TTriByte));   // -> 4
  WriteLn(PtrUInt(@Data[0]));
  WriteLn(PtrUInt(@Data[1]));
  WriteLn(PtrUInt(@Data[2]));
end.    
Es scheitert schon bei SizeOf, da sind es schon 4 anstelle 3 Byte.
Bei der Pointer Ausgabe ist der Abstand wie erwartet dann 4 Byte.

Ist sowas überhaupt möglich ?
Zuletzt geändert von Mathias am Sa 22. Jun 2024, 13:46, insgesamt 2-mal geändert.
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

Benutzeravatar
Jorg3000
Lazarusforum e. V.
Beiträge: 404
Registriert: So 10. Okt 2021, 10:24
OS, Lazarus, FPC: Win64
Wohnort: NRW

Re: 3 Byte Ausrichtung in eine Array

Beitrag von Jorg3000 »

Hi!
Ich vermute du möchtest soetwas machen wie: Data[0]:=$FF00FF; ... wobei nur 3 Bytes geschrieben werden sollen.
Das wird jedoch nie als 3-Byte-Operation funktionieren, weil es keine nativen 24-Bit-Integer gibt.
Das funktioniert nur mit 8-, 16-, 32- oder 64-Bit-Werten.

Man kann zwar ein Packed Array auf 3-Byte-Elemente zwingen, z.B. of Packed Record r, g, b: Byte; end;
aber dann müsste man die R/G/B-Bytes einzeln schreiben und nicht als ein 24-Bit-Wert.

Die Verarbeitungsgeschwindigkeit wird am höchsten sein, wenn du einfach mit 32-Bit-Werten (DWord oder Int32) arbeitest.
Grüße, Jörg

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

Re: 3 Byte Ausrichtung in eine Array

Beitrag von Mathias »

Danke, die habe ich fast vermutet.
Ich wollte etwas probieren.
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

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

Re: 3 Byte Ausrichtung in eine Array

Beitrag von Warf »

Was du machen kannst ist einen bitpacked record machen und dem ein Feld vom Typen 0..$FFFFFF geben und daraus einen Array machen.

Du kannst auch einfach einen 3 Byte großen record machen und den impliziten Cast Operator von und zu integer überladen, dann kannst du den record wie einen integer benutzen obwohl es ein record ist

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

Re: 3 Byte Ausrichtung in eine Array

Beitrag von Mathias »

Was du machen kannst ist einen bitpacked record machen und dem ein Feld vom Typen 0..$FFFFFF geben und daraus einen Array machen.
Dies würde schon mal funktionieren, nur die Konstanten Definition sieht recht mühsam aus,

Code: Alles auswählen

  type
    TTriByte = bitpacked record
    rgb: 0..$FFFFFF;
  end;
  const
    Data: array of TTriByte = (
      (rgb: $000000), (rgb: $FF0000), (rgb: $00FF00), (rgb: $0000FF));
Du kannst auch einfach einen 3 Byte großen record machen und den impliziten Cast Operator von und zu integer überladen, dann kannst du den record wie einen integer benutzen obwohl es ein record ist
Dies verstehe ich nicht, was du meinst.
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

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

Re: 3 Byte Ausrichtung in eine Array

Beitrag von Warf »

Bin unterwegs und nur am Handy, daher keine Garantie für funktionierenden code, aber sowas:

Code: Alles auswählen

TTriByte = bitpacked record
    rgb: 0..$FFFFFF;
  end;
  
operator :=(const AValue: Integer): TTriByte; inline;
begin
  Result.rgb := AValue;
end;
operator :=(const AValue: TTriByte): Integer; inline;
begin
  Result := AValue.rgb;
end;

var
  tb: TTriByte;
begin
  tb:=$FC00DA; // automatische Konvertierung von int
  WriteLn(IntToStr(tb)); //automatische Konvertierung nach int
end.
IntToStr als Beispiel hier, da das eine echte für integer überladene Funktion ist, WriteLn direkt geht nicht den WriteLn ist keine Funktion, daher greift der cast nicht

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

Re: 3 Byte Ausrichtung in eine Array

Beitrag von Mathias »

Danke.
Für eine Handy Tippung hast du dies sehr sauber hingekriegt.

Dies ist eine gute Lösung. Eine direkte Const-Zuweisung geht wie erwartet nicht.
Aber wenigstes geht folgendes:

Code: Alles auswählen

  var
    Data: array of TTriByte = nil;
  begin
    Data := [
      $000000, $FF0000, $00FF00, $0000FF,
      $444444, $FF4444, $44FF44, $4444FF,
      $888888, $FF8888, $88FF88, $8888FF,
      $AAAAAA, $FFAAAA, $AAFFAA, $AAAAAA]; 
      
  Result := SDL_CreateSurfaceFrom(PTriByte(Data), 4, 4, 12, SDL_PIXELFORMAT_RGB24);
An der SDL-Zeile sieht man an, das es einwandfrei funktioniert.

So würde das WriteLn auch gehen:

Code: Alles auswählen

WriteLn(Data[2].rgb);   
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

Antworten