![]() |
Re: Bitmap als Pointer auf einem Display ausgeben
Also, Windows bietet auch die GetDiBits-Funktion und hier wird darauf verwiesen, dass nur ein mehrfaches Scanline durchgeführt wird. Das gleiche kannst du natürlich auch mit einem TBitmap machen.
Dazu legst du einfach ein Array an, dass die Bilddaten aufnehmen kann ((Breite * Höhe) / 8) wobei du darauf achten musst, dass deine Breite und Höhe auch vielfache von 8 sind (wegen der Organisation in Bytes). Nun kannst du über die Höhe der Bitmap iterieren, eine Zeile mittels Scanline in den Speicher laden und in dein Array kopieren, fertig.
Delphi-Quellcode:
Das sollte es schon sein.
var row : Integer;
bits : TByteDynArray; buffer : PByteArray; begin // wegen 1 Bit / pixel setLength(bits, (Bitmap.Height * Bitmap.Width) div 8); for row := 0 to Bitmap.Height - 1 do begin buffer := Bitmap.Scanline[row]; CopyMemory(@bits[row * (Bitmap.Width div 8), buffer, (Bitmap.Width div 8)]; end; // for row := 0 to Bitmap.Height - 1 end; |
Re: Bitmap als Pointer auf einem Display ausgeben
Delphi-Quellcode:
Ist undefiniert...
bits : TByteDynArray;
Delphi-Quellcode:
Muss ich mir das darunter vorstellen?
type Name = array of {array of ...} Base type; // Dynamic array
Wie gesagt habe weder bisher mit Pointern noch mit Arrays gearbeitet, ehrlich gesagt habe ich sie bisher auch nie gebraucht. Habe auch einen Auszug gefunden der wohl das gleiche macht, aber da taucht genau sowas wieder auf.
Delphi-Quellcode:
Als ich dort nachfragte kam nur "Das brauch Dich nicht zu interessieren, das kommt aus dem Programm!"
procedure LCD_SendToGfxMemory(Pixels : TArrayType; X1,Y1,X2,Y2 : Word; inverted : boolean);
Vllt. stell ich mich in den Fall aber auch nur zu blöd an... War ja schon verdamt froh das es mit der Procedure im ersten Post funktionierte. [E]
Delphi-Quellcode:
Er meckert bei "buffer"
CopyMemory(@bits[row * (Width div 8), buffer, (Width div 8)];
[Fehler] LUI.pas(193): Array-Typ erforderlich [Fehler] LUI.pas(193): Nicht genügend wirkliche Parameter[/E] |
Re: Bitmap als Pointer auf einem Display ausgeben
Sorry, ist natürlich ein dummer Fehler, die eckigen Klammern stimmen so natürlich nicht, korrekt ist :
Delphi-Quellcode:
Was TByteDynArray angeht, es ist einfach nur ein dynamisches Array vom Typ Byte und in der Unit Types deklariert (die musst du nur einbinden).
CopyMemory(@bits[row * (Width div 8)], buffer, (Width div 8));
An sich sind Arrays sehr einfach (und praktisch). Wenn du sehr viele Variablen vom gleichen Typ hast, dann kannst du die sehr einfach in ein Feld (ein so genantes Array) schreiben. Dynamische Arrays sind dabei nicht auf eine Größe festgelegt (so wie statische). An sich gibt es sehr viele Bereiche, in denen man dann mit Arrays arbeitet. Insbesondere in diesem Fall, die Bits einer Bitmap (oder Maps an sich) zahlen sich Arrays aus. Möchtest du etwa auf eine Zeile zugreifen, so liefert dir Scanline einen Zeiger auf ein Array, dass die Werte enthält. Dabei kannst du dir ein Array als einen Speicherabschnitt vorstellen, der groß genug ist x-mal einen Datentyp zu speichern. Hättest du ein Array[0..9] of Integer, so hieße es, dass du 10 Felder vom Typ Integer (10 * 4 Byte) reservierst. Über einen Index kannst du dann auf einen einzelnen Wert zugreifen (deinArray[3] := ...). Ein Zeiger auf die erste Zelle reicht dabei aus. Möchtest du wie hier auf die 4te zugreifen, so weißt du dass diese (bei angenommener linearer Anordnung im Speicher) bei Adresse von deinArray[0] + (3 * 4 Byte) liegen muss. Das schöne ist, dass du nur den Index hinschreibst, Delphi kümmert sich schon drum. Hättest du kein Array, hättest du halt das Problem, dass du für jedes Pixel der Bitmap eine eigene Variable bräuchtest. Das würde natürlich einen riesigen Overhead bedeuten (zu jedem Pixel hättest du eine 4 Byte Adresse und damit mehr Speicher verbraucht als die zugehörige Information). Zudem ermöglichen dir Arrays einen eher anonymen Zugriff, du gibst natürlich nur dem gesamten Feld einen Namen und greifst dann auf eine Bestimmte Zelle des Feldes zu (statt zig Variablen zu unterscheiden). |
Re: Bitmap als Pointer auf einem Display ausgeben
Hey danke nun funktioniert es und ich muss bei BMPdataWidth auch nix mehr zu addieren :)
Jetzt noch eine kleine Frage...
Code:
Bei meiner Ausgangsfunktion habe ich zu dem Wert BMPdataWidth was zu addieren müssen bei der jetzigen muss ich dies nun nicht mehr... Woran liegt das nun? Genau wie das das Bild nun nicht mehr auf dem Kopf steht...
ErrorCode LUI_Bitmap (int DevNum, unsigned char ScreenNr, int ScreenPosX,
int ScreenPosY, int BMPoffsetX, int BMPoffsetY, int BMPWidth, int BMPHight, int BMPdataWidth, int BMPdataHight, unsigned char *Bitmap) |
Re: Bitmap als Pointer auf einem Display ausgeben
Also dass du nichts addieren musst liegt daran, dass jetzt nichts falsch gemacht wird ;-)
Wo genau der Fehler liegt, kann ich dir nicht sagen. Ich weiß nicht wie du InfoSize berechnet hast. Dass was du jetzt machst basiert zu großen Teilen auf fast direkten Speicherzugriffen. In einer Bitmap (als Datei) stecken zwei Dinge, ein Bitmapheader (der enthält alle Metainfos wie Größe, Komprimierung, Farbtiefe,...) und der eigentlichen Bitmap (also wirklich die rohe Tabelle der kodierten Pixel). Windows arbeitet auch direkt mit DIBs (dass ermöglicht, da Geräteunabhängig die ausgabe auf beliebigen Geräten). Wenn du dir die GetDiBits der WindowsApi anschaust, so steht dort Zitat:
Der Scanline Befehl (von der Delphi TBitmap) hingegen greift wieder direkt auf die Daten der zugrunde liegenden DIB zu. DIBs werden dabei von unten nach ob abgetastet (ScanLine[0] = unterste Zeile). Da du so also nichts anderes tust als der Windowsbefehl GetDiBits, sollte es also auch korrekt funktionieren. Du kannst natürlich auch die Windowsfunktion verwenden, nur müsstest du erst das BitmapInfo aus der TBitmap extrahieren um es dann wieder zu verwenden. Da Delphi seine eigene Struktur natürlich kennt, umgehst du so die Redundanz. Was ich natürlich vergessen habe hinzuschreiben ist, dass du das dynamische Array wieder freigeben solltest, wenn du fertig mit der Benutzung bist. Jeder Aufruf von setLength alloziert sonst nur unnötig neuen Speicher ohne den alten frei zu geben (und das kann dir schnell deinen Speicher bis zum Prog.ende zu Müllen). Einfach nach der Benutzung mit
Delphi-Quellcode:
wieder frei geben.
finalize(bits);
setLength(bits, 0); Gruß Der Unwissende |
Alle Zeitangaben in WEZ +1. Es ist jetzt 12:47 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz