Autor |
Beitrag |
Boom3
Hält's aus hier
Beiträge: 6
|
Verfasst: Mo 12.10.09 15:00
Hallo,
ich versuche gerade eine Bitmap einfach nur einzufärben..
leider bleibt die Bitmap immer weiß. Vill. kann mir einer von euch sagen, was ich vergessen habe zu beachten.. hier mal mein Code:
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22:
| procedure TDrawPainter.Paint(Background : TColor); type PixArray = array [0..2] of Byte; var p: PRGBQUAD; row,col: Integer; begin Bitmap := TBitmap.Create; Bitmap.PixelFormat:=pf32bit; Bitmap.Height := Paintbox.Height; Bitmap.Width := PaintBox.Width; for row:=0 to Bitmap.Height-1 do begin p:= Bitmap.ScanLine[row]; for col:=0 to Bitmap.Width-1 do begin p.rgbRed := 255; Inc(p); end; end; PaintBox.Canvas.Draw(0, 0, Bitmap); end; |
Schon mal danke!
|
|
Flamefire
      
Beiträge: 1207
Erhaltene Danke: 31
Win 10
Delphi 2009 Pro, C++ (Visual Studio)
|
Verfasst: Mo 12.10.09 15:04
versuchs mal so:
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24:
| procedure TDrawPainter.Paint(Background : TColor); type PixArray = array [0..2] of Byte; var p: PRGBQUAD; row,col: Integer; begin Bitmap := TBitmap.Create; Bitmap.PixelFormat:=pf32bit; Bitmap.Height := Paintbox.Height; Bitmap.Width := PaintBox.Width; for row:=0 to Bitmap.Height-1 do begin p:= Bitmap.ScanLine[row]; for col:=0 to Bitmap.Width-1 do begin p.rgbRed := 255; p.rgbBlue := 0; p.rgbGreen := 0; Inc(p); end; end; PaintBox.Canvas.Draw(0, 0, Bitmap); end; |
|
|
Gausi
      
Beiträge: 8548
Erhaltene Danke: 477
Windows 7, Windows 10
D7 PE, Delphi XE3 Prof, Delphi 10.3 CE
|
Verfasst: Mo 12.10.09 15:07
Wenn es einfach nur ums einfärben geht, dann ist Scanline etwas -ähm- ungut.
Delphi-Quelltext 1: 2:
| Bitmap.Canvas.Brush.Color := clRed; Bitmap.Canvas.FillRect(Rect(0,0, Bitmap.Width, Bitmap.Height)); |
... und fertig ist das einfarbige Bitmap. 
_________________ We are, we were and will not be.
|
|
Boom3 
Hält's aus hier
Beiträge: 6
|
Verfasst: Mo 12.10.09 15:07
ManManMan ...
Danke 
|
|
Boom3 
Hält's aus hier
Beiträge: 6
|
Verfasst: Di 13.10.09 09:08
Ne, geht nicht nur ums Einfärben .. schreib gerade ein Programm zum Zeichnen auf verschiedenen Ebenen.
Da ich intern gerne ohne Canvas auskommen möchte ist das mit scanline ganz ok so
Oder habt ihr spontan Ideen, die schneller sind als scanline?
Gruß
|
|
Lossy eX
      
Beiträge: 1048
Erhaltene Danke: 4
|
Verfasst: Di 13.10.09 09:59
Also wenn du direkten Speicherzugriff brauchst, dann ist Scanline schon ganz gut. Denn Scanline liefert einfach nur einen Pointer auf einen Speicherbereich. Was du damit anstellst ist dir überlassen. Und genau da dürfte meistens das Nadelöhr sein. Der Code zum Verrechnen der Daten. Wenn der komplex und nicht ganz optimal ist, dann kann da durchaus einiges an Zeit entstehen.
Allerdings solltest du bei massivem Gebrauch von Scanlines eher auf Scanline verzichten. Klingt etwas wirr ist aber einfach erklärt. Scanline ruft intern eine ganze Reihe von GDI Befehlen auf bzw berechnet verschiedene Dinge. Wenn ich die Scanlines häufiger benötige, dann cache ich die Rückgabepointer von Scanline meistens in einem dynamischen Array of Pointer. Denn ein einfacher Arrayzugriff ist immer deutlich schneller als Befehle aus der GDI egal wie klein sie sein mögen. Und sofern sich dein Bild nicht verändert hat, werden sich auch deine Pointer nicht verändern. Wenn sich das Bild verändert hat werden sich auch die Pointer verändern. Müssen also entsprechen neu ausgelesen werden. Das Auslesen könnte man auch beschleunigen in dem man sich den Startpointer (Kleinste Pointer aus der ersten oder letzten Scanline) holt und selber die Offset errechnet. Dann kommt man mit 2 Scanlineaufrufen aus. Die Bitmaps dürfen dafür aber nicht extrem flüchtig sein sondern müssen schon auch eine Weile halten.
Alternativ zu Scanlines kannst du dir auch mal die Graphics32 oder G32 anschauen. Die sind schon speziell optimiert und auch schon komplett auf Ebenen bzw Layer/Sprites ausgelegt. Schneller würde man es (ohne besondere Hardware) wohl nur hinbekommen, wenn man spezielle CPU Befehle (MMX, SSE) benutzt. Und der Aufwand dafür ich recht hoch.
Mit besonderer Hardware meine ich Grafikkarten. Du kannst dir natürlich auch deren Leistung zu Nutze machen. Mit der GDI Plus hast du auch so etwas wie die GDI nur deutlich erweitert und ich meine dabei werden mitunter auch mehr Befehle von der Grafikkarte beschleunigt. Die GDI Plus müsste auch so etwas wie Tranzparente Bilder sinnvoll unterstützen. Oder alternativ geht auch OpenGL. Dabei werden direkt die 3D Teile der Grafikkarte angesteuert und für die ist so was wie Transparenzen ein Klacks. Allerdings würde sich dadurch auch der Programmaufwand deutlich erhöhen. Besonders, wenn man noch nie etwas damit gemacht hat.
_________________ Nur die Menschheit ist arrogant genug, um zu glauben sie sei die einzige intelligente Lebensform im All. Wo nicht mal das nachhaltig bewiesen wurde.
|
|
Boom3 
Hält's aus hier
Beiträge: 6
|
Verfasst: Di 13.10.09 10:59
Hm.. ich würde schon gerne auf scanline verzichten
Intern ist eine Bitmap ja eine Art Array.. gibt es die Möglichkeit, die Adresse des 1. Pixels in der nächsten Zeile zu berechnen? So das man nur ein mal Scanline benutzen muss um die 1. Zeile auszulesen und die Adresse des 1. Pixel der restlichen Zeilen berechnet?
Theoretisch müsste das doch möglich sein oder?
inc(p) erhöt ja leider nur die "spalten"..
|
|
BenBE
      
Beiträge: 8721
Erhaltene Danke: 191
Win95, Win98SE, Win2K, WinXP
D1S, D3S, D4S, D5E, D6E, D7E, D9PE, D10E, D12P, DXEP, L0.9\FPC2.0
|
Verfasst: Di 13.10.09 11:16
Eine Bitmap-Zeile ist immer ein Vielfaches von 4 Byte lang. Ansonsten alle Pixel nebeneinander. Keine explizite weitere Lücke, außer Alignment.
Erstes Byte ist erster Pixel der letzten Zeile.
_________________ Anyone who is capable of being elected president should on no account be allowed to do the job.
Ich code EdgeMonkey - In dubio pro Setting.
|
|
Boom3 
Hält's aus hier
Beiträge: 6
|
Verfasst: Di 13.10.09 11:37
Wie kann ich denn auf die nächste Zeile zugreifen ohne Scanline zu benutzen?
Scanline liefert mir einen Pointer, der auf das 1. Byte der 1. Zeile zeigt.
Möchte ich nun aber, dass der Zeiger auf das 1. Byte der 2. Zeile zeigt.. ohne das ich Scanline benutze.. muss ich den Zeiger wie verbiegen?
Wenn ich inc(p) mache bekomm ich ja nur das 2. Byte der 1. Zeile..
|
|
BenBE
      
Beiträge: 8721
Erhaltene Danke: 191
Win95, Win98SE, Win2K, WinXP
D1S, D3S, D4S, D5E, D6E, D7E, D9PE, D10E, D12P, DXEP, L0.9\FPC2.0
|
Verfasst: Di 13.10.09 12:09
Boom3 hat folgendes geschrieben : | Wie kann ich denn auf die nächste Zeile zugreifen ohne Scanline zu benutzen? [...]
Möchte ich nun aber, dass der Zeiger auf das 1. Byte der 2. Zeile zeigt.. ohne das ich Scanline benutze.. muss ich den Zeiger wie verbiegen?
Wenn ich inc(p) mache bekomm ich ja nur das 2. Byte der 1. Zeile.. |
Wie du die Länge einer Zeile berechnest steht im vorigen Post: Anzahl der Bytes einer Zeile berechnen (BytesPerPixel*Breite) und dann auf's nächste Alignment runden.
_________________ Anyone who is capable of being elected president should on no account be allowed to do the job.
Ich code EdgeMonkey - In dubio pro Setting.
|
|
Boom3 
Hält's aus hier
Beiträge: 6
|
Verfasst: Di 13.10.09 12:27
Wie ich die Länge einer Zeile berechen ist mir schon klar, aber was meinst du mit "auf's nächste Alignment runden"?
|
|
Lossy eX
      
Beiträge: 1048
Erhaltene Danke: 4
|
Verfasst: Di 13.10.09 12:33
Die Zeilen in einem Bitmap befinden sich nacheinander im Speicher. Wenn dein Bitmap also 32 Bits Pro Pixel hast und du am Ende einer Zeile bist, dann wird durch ein Inc(P) das erste Pixel der nächsten Zeile adressiert. Hast du 24 Bits und eine Zeile mit 1 Pixel Breite, dann wäre eine Zeile normal 3 Bytes groß. Allerdings im Speicher von Windows würden sich trotzdem 4 Bytes befinden. Das ist das was mit Alignment gemeint ist. Wie Benbe schon sagte benutzen die Zeilen immer ein vielfaches von 4 Bytes.
In der Regel ist es wirklich so, dass die erste Zeile auch die erste Innerhalb des Speichers ist. ABER. Das muss nicht sein. Die Bitmaps im Windows können theoretisch auch BottomTop sein. Also die letzte Zeile des Bitmaps ist die Erste im Speicher. Deswegen würde ich empfehlen die letzte und die erste Zeile mittels Scanline auslesen und vergleichen welche die geringere Adresse haben.
_________________ Nur die Menschheit ist arrogant genug, um zu glauben sie sei die einzige intelligente Lebensform im All. Wo nicht mal das nachhaltig bewiesen wurde.
|
|
Waldheini
      
Beiträge: 32
Win 98SE, XP
D5 St., K3 Prof
|
Verfasst: So 18.10.09 22:07
Hallo,
der Fehler hier:
Delphi-Quelltext
damit erhöhst Du den Pointer nur um 1 Byte, dadurch wird alles weiß. Bei 32 Bit pro Pixel muß Du um 4 erhöhen:
Delphi-Quelltext
|
|
Flamefire
      
Beiträge: 1207
Erhaltene Danke: 31
Win 10
Delphi 2009 Pro, C++ (Visual Studio)
|
Verfasst: So 18.10.09 22:56
Waldheini hat folgendes geschrieben : | Hallo,
der Fehler hier:
Delphi-Quelltext
damit erhöhst Du den Pointer nur um 1 Byte, dadurch wird alles weiß. Bei 32 Bit pro Pixel muß Du um 4 erhöhen:
Delphi-Quelltext |
nur 1. post gelesen oder?
das war nicht der fehler.
P ist vom Typ PRGBSquad. Damit wird der automatisch um 4 erhöht...
ein PByte wäre um 1 erhöht. ein PWord um 2 und ein PInteger dann um 4 usw
|
|