AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Programmierung allgemein Multimedia Delphi Bitmap als Pointer auf einem Display ausgeben
Thema durchsuchen
Ansicht
Themen-Optionen

Bitmap als Pointer auf einem Display ausgeben

Ein Thema von Cyberaxx · begonnen am 30. Mär 2006 · letzter Beitrag vom 2. Apr 2006
Antwort Antwort
Seite 2 von 2     12   
Der_Unwissende

Registriert seit: 13. Dez 2003
Ort: Berlin
1.756 Beiträge
 
#11

Re: Bitmap als Pointer auf einem Display ausgeben

  Alt 1. Apr 2006, 20:18
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:
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;
Das sollte es schon sein.
  Mit Zitat antworten Zitat
Benutzerbild von Cyberaxx
Cyberaxx

Registriert seit: 15. Jul 2005
311 Beiträge
 
Delphi XE5 Professional
 
#12

Re: Bitmap als Pointer auf einem Display ausgeben

  Alt 1. Apr 2006, 20:44
bits : TByteDynArray; Ist undefiniert...

type Name = array of {array of ...} Base type; // Dynamic array Muss ich mir das darunter vorstellen?

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.

procedure LCD_SendToGfxMemory(Pixels : TArrayType; X1,Y1,X2,Y2 : Word; inverted : boolean); Als ich dort nachfragte kam nur "Das brauch Dich nicht zu interessieren, das kommt aus dem Programm!"

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] CopyMemory(@bits[row * (Width div 8), buffer, (Width div 8)]; Er meckert bei "buffer"

[Fehler] LUI.pas(193): Array-Typ erforderlich
[Fehler] LUI.pas(193): Nicht genügend wirkliche Parameter[/E]
Daniel
  Mit Zitat antworten Zitat
Der_Unwissende

Registriert seit: 13. Dez 2003
Ort: Berlin
1.756 Beiträge
 
#13

Re: Bitmap als Pointer auf einem Display ausgeben

  Alt 1. Apr 2006, 22:04
Sorry, ist natürlich ein dummer Fehler, die eckigen Klammern stimmen so natürlich nicht, korrekt ist :
  CopyMemory(@bits[row * (Width div 8)], buffer, (Width div 8)); Was TByteDynArray angeht, es ist einfach nur ein dynamisches Array vom Typ Byte und in der Unit Types deklariert (die musst du nur einbinden).

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).
  Mit Zitat antworten Zitat
Benutzerbild von Cyberaxx
Cyberaxx

Registriert seit: 15. Jul 2005
311 Beiträge
 
Delphi XE5 Professional
 
#14

Re: Bitmap als Pointer auf einem Display ausgeben

  Alt 1. Apr 2006, 22:22
Hey danke nun funktioniert es und ich muss bei BMPdataWidth auch nix mehr zu addieren

Jetzt noch eine kleine Frage...

Code:
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)
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...
Daniel
  Mit Zitat antworten Zitat
Der_Unwissende

Registriert seit: 13. Dez 2003
Ort: Berlin
1.756 Beiträge
 
#15

Re: Bitmap als Pointer auf einem Display ausgeben

  Alt 2. Apr 2006, 11:28
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:
The GetDIBits function retrieves the bits of the specified bitmap and copies them into a buffer using the specified format.

int GetDIBits(

HDC hdc, // handle of device context
HBITMAP hbmp, // handle of bitmap
UINT uStartScan, // first scan line to set in destination bitmap
UINT cScanLines, // number of scan lines to copy
LPVOID lpvBits, // address of array for bitmap bits
LPBITMAPINFO lpbi, // address of structure with bitmap data
UINT uUsage // RGB or palette index
);


Parameters
....

cScanLines
Specifies the number of scan lines to retrieve.

....
Wie du hier siehst macht Windows also gar nicht so viel mehr als auch nur ein paar ScanLines in einen Puffer zu kopieren. Windows speichert dabei aber eine Bitmap in den zwei unterschiedlichen Teilen ab (die Bits und die BitmapInfo Struktur). Delphi's Kapselung fast nur diese beiden Teile zusammen. Zudem sind Delphi Bitmaps Devicedependend.
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:
finalize(bits);
setLength(bits, 0);
wieder frei geben.

Gruß Der Unwissende
  Mit Zitat antworten Zitat
Antwort Antwort
Seite 2 von 2     12   


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 23:01 Uhr.
Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz