Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Win32/Win64 API (native code) (https://www.delphipraxis.net/17-win32-win64-api-native-code/)
-   -   Delphi nonVCL - Bitmap in Bitmap kopieren (https://www.delphipraxis.net/53913-nonvcl-bitmap-bitmap-kopieren.html)

turboPASCAL 25. Sep 2005 11:00


nonVCL - Bitmap in Bitmap kopieren
 
Hi,

wie kann man ein Bitmap in ein anderes kopieren ? Diese Procedure zeichnet nur darüber:

Delphi-Quellcode:
procedure SetBitmap(hWnd: HWND);
begin
  h_DC := GetDC(GetDlgItem(hwnd, IDC_IMG1));

  hBitmapDC := CreateCompatibleDC(h_DC);
  hOldBitmap := SelectObject(hBitmapDC, Bitmap);

  BitBlt(h_DC, 0, 0, 32, 32, hBitmapDC, 0, 0, SRCCOPY);
                                           
  SelectObject(hBitmapDC, hOldBitmap);
  DeleteDC(hBitmapDC);
  ReleaseDC(hwnd, h_DC);
end;
Ich möchte in einem Dialog enth. Bitmap mein eigenes einsetzen.

VCL:
Delphi-Quellcode:
ImageX.Picture.Assign(MyBitmap);

Olli 25. Sep 2005 12:24

Re: nonVCL - Bitmap in Bitmap kopieren
 
Ich weiß zwar nicht genau was du willst, aber entweder mußt du wohl ein anderes Flag in BitBlt() einsetzen als SRCCOPY - damit kannst du zwei Bitmaps "mischen".

Zitat:

Zitat von turboPASCAL
VCL:
Delphi-Quellcode:
ImageX.Picture.Assign(MyBitmap);

Das gibt es so ohne VCL nicht. Im Grunde macht diese Zuweisung intern nur, daß das alte Handle (und assoziierter Speicher) freigegeben wird und ein neues Handle zugewiesen wird. Es sorgt also im Gegensatz zu einer fälschlichen Direktzuweisung ala "Bitmap1 := Bitmap2" dafür, daß keine Speicherlecks auftreten.

Flocke 25. Sep 2005 13:07

Re: nonVCL - Bitmap in Bitmap kopieren
 
Wenn's ein STATIC-Element ist dann suchst du vielleicht nach der Meldung MSDN-Library durchsuchenSTM_SETIMAGE.

turboPASCAL 25. Sep 2005 15:58

Re: nonVCL - Bitmap in Bitmap kopieren
 
Zitat:

Zitat von Olli
...entweder mußt du wohl ein anderes Flag in BitBlt() einsetzen als SRCCOPY - damit kannst du zwei Bitmaps "mischen".

"Mischen" will ich die Bitmaps nicht. :wink:

Zitat:

Zitat von Olli
Zitat:

Zitat von turboPASCAL
Delphi-Quellcode:
ImageX.Picture.Assign(MyBitmap);

Das gibt es so ohne VCL nicht.

Ja, ne ist klar. Das sollte ein Beispiel zum Verstäntnis sein, was ich machen möchte. :wink:

Zitat:

Zitat von Olli
Im Grunde macht diese Zuweisung intern nur, daß das alte Handle (und assoziierter Speicher) freigegeben wird und ein neues Handle zugewiesen wird. Es sorgt also im Gegensatz zu einer fälschlichen Direktzuweisung ala "Bitmap1 := Bitmap2" dafür, daß keine Speicherlecks auftreten.

Ja und das möchte ich ohne VCL machen.

Zitat:

Zitat von Flocke
Wenn's ein STATIC-Element ist dann suchst du vielleicht nach der Meldung MSDN-Library durchsuchenSTM_SETIMAGE.

Das habe ich gesucht.


Doch nun stecke ich wieder fest.
Also ich möchte ein vorhandenes Image (Bitmap) auf einem Dialog durch ein selbst erstelltes (aus einer Bitmap-Resource) ersetzen.

Delphi-Quellcode:
// var ResBitmap: HBITMAP ist global def.
// ResBitmap := LoadBitmap(hInstance, MAKEINTRESOURCE(1));

procedure SetBitmap(hWnd: HWND);
var
  myBitmapDC: HDC;
  ResBitmapDC: HDC;
  myBitmap: HBITMAP;
  hOldBitmap: HBITMAP;
begin
  // DC von DlgItem (Image) holen
  myBitmapDC := GetDC(GetDlgItem(hwnd, IDC_IMG1));
  // DC für ResBitmap erstellen
  ResBitmapDC := CreateCompatibleDC(myBitmapDC);

  // Mem-Bitmap erzeugen
  myBitmap  := CreateCompatibleBitmap(myBitmapDC, 32, 32);

  // dem Mem-Bitmap einen DC zuweisen
  SelectObject(myBitmapDC, myBitmap);

  // dem ResBitmap einen DC zuweisen
  hOldBitmap := SelectObject(ResBitmapDC, ResBitmap);

  // Bild von ResBitmap zu Mem-Bitmap kopieren
  BitBlt(myBitmapDC, 0, 0, 32, 32, ResBitmapDC, 0, 0, SRCCOPY);

  // dem DlgItem-Image das neue (Mem)Bitmap senden
  SendDlgItemMessage(hwnd, IDC_IMG1, STM_SETIMAGE, IMAGE_BITMAP, myBitmap);

  SelectObject(ResBitmapDC, hOldBitmap);
  DeleteDC(ResBitmapDC);
  ReleaseDC(GetDlgItem(hwnd, IDC_IMG1), myBitmapDC);
end;
So funktioniert das nicht. Irgendwie habe ich den Durchblick verloren... :gruebel:

Olli 25. Sep 2005 16:18

Re: nonVCL - Bitmap in Bitmap kopieren
 
Laß den Rest weg und weise einfach ResBitmap über SendDlgItemMessage(hwnd, IDC_IMG1, STM_SETIMAGE, IMAGE_BITMAP, ResBitmap); zu. Dazu vorher mit ResBitmap := LoadBitmap(hInstance, MAKEINTRESOURCE(1)); laden.

turboPASCAL 25. Sep 2005 16:28

Re: nonVCL - Bitmap in Bitmap kopieren
 
Das geht nicht, äh.. schon aber ich will nur einen Ausschnitt aus dem ResBitmap auf/in das "DlgItem-Image" machen. :wink:

Delphi-Quellcode:
BitBlt(myBitmapDC, 0, 0, 32, 32, ResBitmapDC, count * 32 - 32,
    Animation[AnimType].Offset * 32, SRCCOPY);
Sonst wäre es ja zu einfach. :zwinker:

Olli 25. Sep 2005 16:41

Re: nonVCL - Bitmap in Bitmap kopieren
 
Aha, na das kann man ja nicht wissen :zwinker:

In diesem Falle holst du dir den DC des (Client-)Fensters, erstellst einen kompatiblen (Mem-)DC. Dann selektierst du deine Ressourcen-Bitmap in den Mem-DC. Danach blittest du von dem Mem-DC auf den des Fensters mit den entsprechenden von dir vorgesehenen Offsets. An deiner Stelle würde ich die Ressourcen-Bitmap aber immer geladen lassen!!!

Flocke 25. Sep 2005 16:46

Re: nonVCL - Bitmap in Bitmap kopieren
 
Zitat:

Zitat von Olli
Aha, na das kann man ja nicht wissen :zwinker:

In diesem Falle holst du dir den DC des (Client-)Fensters, erstellst einen kompatiblen (Mem-)DC. Dann selektierst du deine Ressourcen-Bitmap in den Mem-DC. Danach blittest du von dem Mem-DC auf den des Fensters mit den entsprechenden von dir vorgesehenen Offsets. An deiner Stelle würde ich die Ressourcen-Bitmap aber immer geladen lassen!!!

Müsste er das dann nicht bei jedem WM_PAINT machen? :gruebel:

Ansonsten: mit STM_GETIMAGE die Bitmap des fremden Fensters holen, modifizieren (wie von Olli beschrieben), und mit STM_SETIMAGE wieder setzen.

Olli 25. Sep 2005 17:49

Re: nonVCL - Bitmap in Bitmap kopieren
 
Zitat:

Zitat von Flocke
Müsste er das dann nicht bei jedem WM_PAINT machen? :gruebel:

Ich denke schon.

turboPASCAL 25. Sep 2005 19:48

Re: nonVCL - Bitmap in Bitmap kopieren
 
Ich auch. :wink:

Auf die Gefahr hin, dass ihr mich auf den Hof fegen schickt, hänge ich den Sourcecode mal an, in der Hoffnung, das ihr mal ein (oder auch zwei) Auge(n) drauf werft.

Ich komme einfach nicht weiter. Es geht um die Procedure SetBitmap(hWnd: HWND);.

[Edit=turboPASCAL] Anhang entfernt, kommt aber wo anders wieder. :tongue: [/Edit]

Flocke 25. Sep 2005 20:26

Re: nonVCL - Bitmap in Bitmap kopieren
 
Ich schreib's jetzt mal aus dem Kopf, habe hier schon alles beendet (da fehlen noch etliche try-finally-Blöcke)...

Delphi-Quellcode:
// Bitmap holen, DC erzeugen und hineinselektieren
// myDC malt jetzt in die Bitmap
myBitmap := SendMessage(GetDlgItem(hwnd, IDC_IMG1), STM_GETIMAGE, IMAGE_BITMAP, 0);
myDC := CreateCompatibleDC(0);
oldBitmap := SelectObject(myDC, myBitmap);

// Zweiten DC erzeugen und Ausgangsbitmap hineinselektieren
// myDC2 malt jetzt mit der Ressourcenbitmap
myDC2 := CreateCompatibleDC(0);
oldBitmap2 := SelectObject(myDC2, ResBitmap);

// Zeichnen
BitBlt(myDC, 0, 0, 32, 32, myDC2, count * 32 - 32, Animation[AnimType].Offset * 32, SRCCOPY);

// Zweiten DC freigeben
SelectObject(myDC2, oldBitmap2);
DeleteDC(myDC2);

// Ersten DC freigeben
SelectObject(myDC, oldBitmap);
DeleteDC(myDC);

// Bitmap wieder in das Element setzen, ggf. nicht nötig!
SendMessage(GetDlgItem(hwnd, IDC_IMG1), STM_SETIMAGE, IMAGE_BITMAP, myBitmap);

// Neu zeichnen
InvalidateRect(GetDlgItem(hwnd, IDC_IMG1), nil, TRUE);
und das nur ein mal (für jeden Animationsschritt) und nicht bei jedem WM_PAINT.

Olli 25. Sep 2005 20:32

Re: nonVCL - Bitmap in Bitmap kopieren
 
Zitat:

Zitat von Flocke
Ich schreib's jetzt mal aus dem Kopf, habe hier schon alles beendet (da fehlen noch etliche try-finally-Blöcke)...

Nicht vergessen die alten Bitmaps freizugeben. Aber so in etwa könnte es gehen. Ich schaue gerade selber über den Source.

Olli 25. Sep 2005 21:50

Re: nonVCL - Bitmap in Bitmap kopieren
 
Liste der Anhänge anzeigen (Anzahl: 1)
BITTE NEU HERUNTERLADEN!!!


So, hier meine Variante. Ich habe mal schamlos Flocke's Code weiterverwertet.
Habe ihn noch schnell auf Thread umgestellt (hatte zuvor mit Timer getestet).

In Sachen Thread hat sich ein wenig geändert und außerdem werden alle (Einzel-)Bitmaps der Animationen nun im Speicher gehalten. Man könnte das so optimieren, daß nur jeweils eine "Zeile" im Speicher bliebe. Die Arrays beginnen nun sinnvollerweise bei 0 und die Animationen werden bis auf die Bitmaps schon vorher initialisiert (keine Zuweisung mehr).

Hinweis: Die Transparenz habe ich komplett entfernt, da bei mir die Funktion nicht deklariert war und es so schneller ging. Da es nun funktioniert, sollte das das geringste Problem sein ;)

Zum Erstellen der Einzelbitmaps ...
Delphi-Quellcode:
function PrepareAnimations(var Anim: TAnimation): Boolean;
var
  i: TAniType;
  j: Integer;
  MemDC, MemDC2: HDC;
  oldBitmap,
    oldBitmap2,
    ResBitmap: HBITMAP;
begin
  Result := True;
  // Bitmap der Animationen laden
  ResBitmap := LoadBitmap(hInstance, MAKEINTRESOURCE(10));
  // DCs erzeugen
  MemDC := CreateCompatibleDC(0);
  MemDC2 := CreateCompatibleDC(0);
  for i := aniCat to aniGreenBounce do
    for j := 0 to Anim[i].MaxImages - 1 do
    begin
      Anim[i].Bitmaps[j] := CreateCompatibleBitmap(MemDC, BMPWIDTH, BMPHEIGHT);

      // Korrekte Bitmaps selektieren
      oldBitmap := SelectObject(MemDC, Anim[i].Bitmaps[j]);
      oldBitmap2 := SelectObject(MemDC2, ResBitmap);

      // Zeichnen auf MemDC von dem korrekten Offset in MemDC2 aus
      BitBlt(MemDC, 0, 0, BMPWIDTH, BMPHEIGHT, MemDC2, j * BMPWIDTH, Anim[i].Offset * BMPHEIGHT, SRCCOPY);

      // DC "freigeben" indem die alte Bitmap zurückselektiert wird
      SelectObject(MemDC2, oldBitmap2);
      // Alte Bitmap zurückselektieren und somit die Änderung in Anim[i].Bitmaps[j] schreiben
      SelectObject(MemDC, oldBitmap);
    end;

  // DCs freigeben
  DeleteDC(MemDC2);
  DeleteDC(MemDC);

  // Resourcenbitmap freigeben
  DeleteObject(ResBitmap);
end;

function UnprepareAnimations(var Anim: TAnimation): Boolean;
var
  i: TAniType;
  j: Integer;
begin
  Result := True;
  for i := aniCat to aniGreenBounce do
    for j := 0 to Anim[i].MaxImages - 1 do
      if (Anim[i].Bitmaps[j] <> 0) then
      begin
        // Bitmap freigeben
        DeleteObject(Anim[i].Bitmaps[j]);
        Anim[i].Bitmaps[j] := 0;
      end;
end;
Um "weiterzuschalten":
Delphi-Quellcode:
function SetNextAnimationStep(var Anim: TAnimation; hwnd: HWND; anitype: TAniType): Boolean;
begin
  Result := True;
  // Eins hochsetzen
  inc(Anim[anitype].Current);
  // Zurücksetzen bei Overflow
  if (Anim[anitype].Current >= Anim[anitype].MaxImages) then
    Anim[anitype].Current := 0;
  // Neuen Animationsschritt setzen
  SendMessage(hwnd, STM_SETIMAGE, IMAGE_BITMAP, Anim[anitype].Bitmaps[Anim[anitype].Current]);
end;

function MyTimerThreadFunc(Parameter: Pointer): Integer;
var
  parms: PThreadParamBlock;
begin
  parms := Parameter;
  if (Assigned(parms) and Assigned(parms^.Anim) and IsWindow(parms^.TargetWnd)) then
    while (not parms^.ExitThread) do
    begin
      SetNextAnimationStep(parms^.Anim^, parms^.TargetWnd, parms^.AnimType);
      Sleep(parms^.Anim^[parms^.AnimType].Times[0]);
    end;
  Result := 0; // Set up a 0 return value
  EndThread(0); // End the thread
end;
PS: Sorry, aber ich mußte einen Sourceformatter verwenden. Irgendwie kam ich mit weiten Teilen deiner Formatierung überhaupt nicht klar.

BITTE NEU HERUNTERLADEN!!! Verwendung: einfach die Datei durch die alte im obigen Archiv von Matti ersetzen.

turboPASCAL 26. Sep 2005 10:38

Re: nonVCL - Bitmap in Bitmap kopieren
 
:shock:


Zitat:

Zitat von Olli
BITTE NEU HERUNTERLADEN!!!

Habe ich gemacht. :wink:

Zitat:

Zitat von Olli
So, hier meine Variante. Ich habe mal schamlos Flocke's Code weiterverwertet.
Habe ihn noch schnell auf Thread umgestellt (hatte zuvor mit Timer getestet).

Ich auch, hat mir aber nicht so gefallen andauernt den Timer zu ändern. :wink:

Zitat:

Zitat von Olli
In Sachen Thread hat sich ein wenig geändert und außerdem werden alle (Einzel-)Bitmaps der Animationen nun im Speicher gehalten.

Nunja, was hat dir denn daran nicht gefallen das Bitmap im ganzen im Speicher zu halten dass du es aufteilen musstest ? :wink:

Zitat:

Zitat von Olli
Man könnte das so optimieren, daß nur jeweils eine "Zeile" im Speicher bliebe.

Jupp, wollte ich auch erst, habe es dann aber wieder verworfen. :wink:

Zitat:

Zitat von Olli
Die Arrays beginnen nun sinnvollerweise bei 0 ...

...jaja, das wollte ich auch noch machen... :wink:

Zitat:

Zitat von Olli
Hinweis: Die Transparenz habe ich komplett entfernt, da bei mir die Funktion nicht deklariert war und es so schneller ging.

Nanu, warum nicht ?

Delphi-Quellcode:
// def. in Windows.pas
function SetLayeredWindowAttributes(Wnd: hwnd; crKey: ColorRef; Alpha: Byte; dwFlags: DWORD): Boolean; stdcall; external 'user32.dll';
Zitat:

Zitat von Olli
Da es nun funktioniert, sollte das das geringste Problem sein ;)

Nunja, :wink: da das Bitmap mit
Delphi-Quellcode:
CreateCompatibleBitmap(MemDC, BMPWIDTH, BMPHEIGHT);
erstellt wird ist der Hintergrund schwarz, also müsste ich diese Sache durch
Delphi-Quellcode:
HBITMAP CreateBitmap(

    int nWidth,   // bitmap width, in pixels
    int nHeight,   // bitmap height, in pixels
    UINT cPlanes,   // number of color planes used by device
    UINT cBitsPerPel,   // number of bits required to identify a color
    CONST VOID *lpvBits    // pointer to array containing color data
   );
ersetzen. Wobei ich nicht so recht wei mit pointer to array containing color data etwas anzufangen.


Zitat:

Zitat von Olli
PS: Sorry, aber ich mußte einen Sourceformatter verwenden. Irgendwie kam ich mit weiten Teilen deiner Formatierung überhaupt nicht klar.

:wink: heheh... ich bin ja auch noch nicht fertig gewesen mit dem schreiben. Dass sollte dann ja auch mal besser aussehen. :mrgreen:

Vielen Dank an euch beide!

:hi:

Olli 26. Sep 2005 10:42

Re: nonVCL - Bitmap in Bitmap kopieren
 
Reicht es dir erstmal so, oder gibt es noch andere Probleme?

MSDN-Library durchsuchenTransparentBlt könntest du auch einfach benutzen, statt deine Idee von oben. Sollte auf allen Systemen vorhanden sein, auf denen es auch Layered Windows gibt ;)

turboPASCAL 26. Sep 2005 10:44

Re: nonVCL - Bitmap in Bitmap kopieren
 
Hm, eigentlich wollte ich so 'ne kleine Spielerei mit ein und Ausblenden einbauen.... desswegen.

Olli 26. Sep 2005 10:46

Re: nonVCL - Bitmap in Bitmap kopieren
 
Zitat:

Zitat von turboPASCAL
Hm, eigentlich wollte ich so 'ne kleine Spielerei mit ein und Ausblenden einbauen.... desswegen.

Sei mal nicht so wortkarg. Erklär mal genauer was dir noch fehlt, bzw. wo du nicht weiterkommst.
Ich geh jetzt erstmal mittagessen, hast also Zeit was Ausführliches zu schreiben :zwinker:

turboPASCAL 26. Sep 2005 10:51

Re: nonVCL - Bitmap in Bitmap kopieren
 
Zitat:

Zitat von Olli
Sei mal nicht so wortkarg. Erklär mal genauer was dir noch fehlt, bzw. wo du nicht weiterkommst.

Ähm...

Zitat:

Ich geh jetzt erstmal mittagessen
Ich auch...

Zitat:

, hast also Zeit was Ausführliches zu schreiben :zwinker:
Nö. :wink:

turboPASCAL 26. Sep 2005 12:51

Re: nonVCL - Bitmap in Bitmap kopieren
 
So, habe fertig.

Was ich machen wollte ist eine Alternative zu dem Programm Bounce for Sakura v1.0 von MaBuSE und das als Non VCL Version, weil SirThornberry fragte,
Zitat:

Zitat von SirThornberry
ist das ganze bereits nonvcl? (bischen groß die exe) Wenn das ganze noch weniger ressourcen benötigen würde wäre es supi.

und das wollte ich halt umsetzen. Das hast du aber sicherlich schon bemerkt.

Na ja, halt nicht so eins zu eins sondern mit einem kleinem Nutzen. Ich dachte mir wenn ich schon so eine nette kleine Animation unten rechts auf dem Desktop habe kann die auch ein bissel was Sinnvolles machen.
Das Programm wird einen kleinen Reminder enthalten, wie du sicherlich schon bemerkt hast.

Mit der Transparenz hatte ich mir das so vorgestellt, dass sich die Animation bei dem Programmstart ein- und beim Programm Ende ausblendet. Ob ich das noch während dem Wechsel zwischen den Animationen machen will ist noch nicht sicher.

Deswegen benötige ich das Layered Window. ( und die ganze Sache mit dem Bitmaps )

Ich hoffe mal dass ich deine Anfrage auf Ausführlichkeit meiner Antworten hiermit zu deiner Befriedigung beantworten konnte. :stupid:

PS.: Ich will halt auch mal (wieder) ein bisschen in der non VCL Sparte ein "Refresh" durchführen. Das ist schon lange, lange her und erinnert mich irgend wie doch stark an Turbo Pascal für Windows Version 1... .


// Nachtrag: @Flocke

Zitat:

Zitat von Flocke
Ich schreib's jetzt mal aus dem Kopf, habe hier schon alles beendet (da fehlen noch etliche try-finally-Blöcke)...

Wenn man so etwas aus dem Kopf macht, wozu braucht man dann noch einen PC ? :stupid:
Ich habe den Code gestern 1:1 übernommen und es has ohne Probleme Funktioniert. :thumb:

Olli 26. Sep 2005 13:38

Re: nonVCL - Bitmap in Bitmap kopieren
 
Ich schaue es mir heute am Abend oder im Laufe des morgigen Tages mal an. Jetzt am Nachmittag komme ich nicht mehr dazu.

Zitat:

Zitat von turboPASCAL
Wenn man so etwas aus dem Kopf macht, wozu braucht man dann noch einen PC ? :stupid:

... zum Kompilieren :mrgreen:

Olli 28. Sep 2005 10:23

Re: nonVCL - Bitmap in Bitmap kopieren
 
Wird wohl noch eine Weile dauern, bis ich es mir noch genauer anschauen kann. Ich behalte das Projekt solange auf der Platte. Könntest du mich mal spätestens am Wochenende an das Thema erinnern (per PN)?!

turboPASCAL 28. Sep 2005 11:17

Re: nonVCL - Bitmap in Bitmap kopieren
 
Naja, so wichtig ist das auch nicht :wink: , ich mache ja eh erst mal eine kleine Schaffenspause für das Projekt (bis zum WE :wink: ).


Alle Zeitangaben in WEZ +1. Es ist jetzt 12:37 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