TBitmap und pf4bit

Rund um die LCL und andere Komponenten
Antworten
Mathias
Beiträge: 7315
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunk)
CPU-Target: 64Bit
Wohnort: Schweiz

TBitmap und pf4bit

Beitrag von Mathias »

Bei folgenden Code sollte man meinen, das jeder Pixel 4 Bit (16 Color)hat.
Bei folgen Code, werden die Pixel trotzdem mit 32bit Farbtiefe angezeigt.

Ersetzte ich aber diese Zeile: Bitmap.PixelFormat := pf4bit; mit pf1bit, dann kommt das Bild s/w.

Irgend wie sehe ich da nicht durch.

Code: Alles auswählen

procedure TForm1.Button2Click(Sender: TObject);
var
  Bitmap: TBitmap;
  x, y: integer;
const
  anz = 255;
begin
  Bitmap := TBitmap.Create;
  Bitmap.PixelFormat := pf4bit;
 
  Bitmap.Width := anz;
  Bitmap.Height := anz;
  for x := 0 to anz - 1 do begin
    for y := 0 to anz - 1 do begin
      Bitmap.Canvas.Pixels[x, y] := x + y * $100;
    end;
  end;
  Canvas.Draw(0, 0, Bitmap);
  Bitmap.Free;
end; 
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

soerensen3
Beiträge: 104
Registriert: Fr 22. Jun 2012, 01:51
OS, Lazarus, FPC: Fedora-Linux 23 (Korora) Lazarus 1.6 FPC 3.0
CPU-Target: 64Bit
Wohnort: Bonn

Re: TBitmap und pf4bit

Beitrag von soerensen3 »

Das sieht mir so aus als könnte das noch nicht fertig sein:
Zugegeben ein etwas älterer Thread: http://forum.lazarus.freepascal.org/ind ... ic=11839.0

Aber auch ein Blick in den Source Code erweckt den Eindruck das da noch was fehlt:

Code: Alles auswählen

 
procedure TCustomBitmap.SetPixelFormat(AValue: TPixelFormat);
begin
  if AValue = FPixelFormat then Exit;
  {$IFDEF VerboseLCLTodos}{$note todo copy image into new format }{$ENDIF}
  FreeImage;
  FPixelFormat := AValue;
end;
 
Zu TBitmap/FPImage gibt es aber zum Glück einige Alternativen.
Eine ist in dem Thread oben angegeben (Hab das allerdings noch nie verwendet).
Vielleicht kann BGRABitmap das auch.

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

Re: TBitmap und pf4bit

Beitrag von wp_xyz »

Bitmap.PixelFormat := pf4bit;
...
Bitmap.Canvas.Pixels[x, y] := x + y * $100;
Was willst du hier eigentlich erreichen? x und y laufen bis 255 (ich nehme an, du meinst "anz=256") und du multiplizierst y auch noch mit $100. Wenn x und y jeweils 255=$FF sind, ergibt sich ein Farbwert für das Pixel von $FFFF = 65535, das sind deutlich mehr als die 16 voreingestellten Farben! Das kann doch nicht funktionieren. Evtl. schaltet das Bitmap dann automatisch auf das höhere Pixelformat?

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

Re: TBitmap und pf4bit

Beitrag von Mathias »

Was willst du hier eigentlich erreichen?
Die for-Schleife ist nur ein Test, ob man eine Veränderung sieht.
Klar, ansonsten währe anz=256 besser.

Als Ausgabe hätte ich etwa so etwas erwartet, wie im Anhang.
Der Anhang habe ich mit XnView erzeugt.

Ich habe es noch rasch mit Delphi getestet, da kommt es etwa so wie im Anhang.
1.Anhang Delphi.
2.Anhang XnView
Dateianhänge
Zwischenablage-2.png
Zwischenablage-2.png (1.51 KiB) 2753 mal betrachtet
Zwischenablage-1.png
Zwischenablage-1.png (320 Bytes) 2753 mal betrachtet
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

Benutzeravatar
theo
Beiträge: 11327
Registriert: Mo 11. Sep 2006, 19:01

Re: TBitmap und pf4bit

Beitrag von theo »

Kommt drauf an, was das im Endeffekt werden soll.

OPBitmap kann Farbreduktion auf 8-,4-,1-bit mit Paletten und arbeitet nur mit dem Speicher, der wirklich benötigt wird.

http://www.theo.ch/lazarus/opbitmap64.zip

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

Re: TBitmap und pf4bit

Beitrag von Mathias »

Kommt drauf an, was das im Endeffekt werden soll.
Besseres Verständnis was intern in TBitmap passiert.
Schlusssendlich geht es mir drum, auf Rohdaten von TBitmap zuzugreifen für OpenGL-Texturen.
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

soerensen3
Beiträge: 104
Registriert: Fr 22. Jun 2012, 01:51
OS, Lazarus, FPC: Fedora-Linux 23 (Korora) Lazarus 1.6 FPC 3.0
CPU-Target: 64Bit
Wohnort: Bonn

Re: TBitmap und pf4bit

Beitrag von soerensen3 »

Für das Laden von Texturen für OpenGL gibt es aber bessere Möglichkeiten.
Ich verwende dazu SDL, außerdem kannst du auch glBitmap verwenden.
http://www.delphigl.com/forum/viewtopic.php?f=13&t=7458

Solange es dir nicht darum geht Daten von einem TBitmap ohne Umweg in OpenGL zu übertragen kannst du eine von den genannten Möglichkeiten verwenden.

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

Re: TBitmap und pf4bit

Beitrag von wp_xyz »

ich habe in diesem Zusammenhang eine Frage, weil ich seit Turbo-Pascal-Zeiten nie mehr mit 4-bit Graphik gearbeitet habe: Solche Bitmaps sind m.E. ja paletten-basiert. Wenn man jetzt mit "Bitmap.Canvas.Pixels[]" die Farbe eines Pixels setzt (so wie oben im ersten Posting) oder abfragt, ist dieser Wert nur der Palettenindex (also 0-15) oder schon in der Palette nachgeschlagen, also der "echte" RGB(A)-Wert? Wenn es der Palettenindex ist (was ich meine),wie definiert man dann die Palette?

Benutzeravatar
theo
Beiträge: 11327
Registriert: Mo 11. Sep 2006, 19:01

Re: TBitmap und pf4bit

Beitrag von theo »

wp_xyz hat geschrieben:ich habe in diesem Zusammenhang eine Frage, weil ich seit Turbo-Pascal-Zeiten nie mehr mit 4-bit Graphik gearbeitet habe: Solche Bitmaps sind m.E. ja paletten-basiert. Wenn man jetzt mit "Bitmap.Canvas.Pixels[]" die Farbe eines Pixels setzt (so wie oben im ersten Posting) oder abfragt, ist dieser Wert nur der Palettenindex (also 0-15) oder schon in der Palette nachgeschlagen, also der "echte" RGB(A)-Wert? Wenn es der Palettenindex ist (was ich meine),wie definiert man dann die Palette?
Ich glaube die LCL unterstützt das so gar nicht. Canvas.Pixels ist immer ein TColor.
Wie gesagt, wenn du wirklich mit Paletten und echten 4Bit Pixeln arbeiten willst, kannst du OPBitmap verwenden.
Dort kannst du sowohl die Paletteneinträge selbst bestimmen, wie auch eine optimierte Farbreduktion vornehmen lassen.

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

Re: TBitmap und pf4bit

Beitrag von Mathias »

Folgender Code zeigt wenigstens an, ob es eine 24 oder 32Bit Bitmap ist. Somot kann ichwenigsten ermitteln, ob ein Alpha-Kanal vorhanden ist,
Lade ich ein 4Bit Bitmap, dann wird pf24bit angezeigt.

Code: Alles auswählen

  if OpenDialog1.Execute then begin
    Image1.Picture.LoadFromFile(OpenDialog1.FileName);
    Writeln(Image1.Picture.Bitmap.PixelFormat);
  end; 
In den Quellen habe ich folgendes gefunden:

Code: Alles auswählen

  { For Delphi compatibility }
  TPixelFormat = (
    pfDevice,
    pf1bit,
    pf4bit,
    pf8bit,
    pf15bit,
    pf16bit,
    pf24bit,
    pf32bit,
    pfCustom
    );
 
const
  PIXELFORMAT_BPP: array[TPixelFormat] of Byte = (
    0, 1, 4, 8, 15, 16, 24, 32, 0
  );    
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

soerensen3
Beiträge: 104
Registriert: Fr 22. Jun 2012, 01:51
OS, Lazarus, FPC: Fedora-Linux 23 (Korora) Lazarus 1.6 FPC 3.0
CPU-Target: 64Bit
Wohnort: Bonn

Re: TBitmap und pf4bit

Beitrag von soerensen3 »

Falls du es unbedingt mit einem Bitmap machen willst, du aber nicht die restlichen Bytes verschwenden willst, benutze doch Bitmasken. Dann repräsentieren 32 Bits / 4 Bit pro Pixel = 8 Pixel, also sind die Bitmaps entweder nur 1/8 so breit oder du überlegst dir eine andere Aufteilung:

Code: Alles auswählen

 
var
  x,y: Integer; //gesuchter Punkt in deiner Karte
  px,py: Integer; //Pixel, in dem der Wert für diesen Punkt gespeichert ist
  spIdx: Integer; //Subpixel, welcher deinen 4 Bit entspricht (0-7)
   // Man kann wie gesagt 8 Werte pro Pixel speichern
  MeinWert: Byte; //Das ist der gespeicherte Wert, hier werden zwangsläufig 4 Bit verschwendet, da Byte der
                  //kleinste Wert ist. Hier noch zwei Pixel pro Wert zu komprimieren wäre glaube ich eher kontraproduktiv
begin
   py:= y; //Dieser Wert ist gleich
   px:= x div 8; //Nachkommastellen werden nach Division abgeschnitten
   spIdx:= x mod 8; //Rest der Division ist dein gesuchter Subpixel 
   MeinWert:= Byte(( Bitmap_32Bit.Pixels[ px, py ] shr spIdx * 4{du willst nur 4 bit auslesen}) and $F );
end;
 
Vielleicht hilft dir folgendes Programm das ganze zu verstehen

Code: Alles auswählen

 
program Project1;
{$IFDEF WINDOWS}
  {$APPYTYPE CONSOLE}
{$ENDIF}
uses
  sysutils;
 
var
  TestVal: Int32;
  spIdx: Integer;
 
  function IntToBit( int: Int32 ): String; //Quelle: http://www.entwickler-ecke.de/topic_bitdarstellung_103496,0.html
  var
    i: Integer;
  begin
    SetLength(result, 32);     //Länge festlegen (32 da Integer = 32Bit);
    for i := 0 to 31 do begin  //alle 32 Bits durchzählen
      if (int and 1) = 0 then  //wenn das letzte/niederwertigste Bit = 0 ist, dann
        result[32-i] := '0'    //0 in String schreiben
      else                     //sonst
        result[32-i] := '1';   //1 in String schreiben
      int := int shr 1;        //Int um 1 Bit nach rechts schieben
    end;
  end;
 
begin
  TestVal:= $00FAFF00;
  WriteLn( IntToBit( TestVal ));
  spx:= 4;
  WriteLn( 'Bitwert von ', spidx, '-', + spIdx + 4, ' ', IntToBit(( TestVal shr ( spIdx * 4 {du willst nur 4 bit} ) AND $F )));
end.
 
Falls du aber einfach 8 Bit (1 Byte) nehmen willst wäre auch folgendes möglich:

Code: Alles auswählen

 
type
  TPixelValues = packed record
     sp[ 0..3 ]: Byte; // Subpixel
  end;
var
  IntValue: Int32;
  SubPixelValue: Byte;
begin
  SubPixelValue:= TPixelValues( IntValue ).sp[ 2 ]; // Subpixel 3
end;
 

Antworten