Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Programmieren allgemein (https://www.delphipraxis.net/40-programmieren-allgemein/)
-   -   Screenshot und Skalierung (https://www.delphipraxis.net/216205-screenshot-und-skalierung.html)

tofse01 20. Nov 2024 08:42

Screenshot und Skalierung
 
Hallo zusammen

ich habe hier eine Delphi XE Installation unter Win 10 und seit einigen Jahren nicht mehr wirklich damit gearbeitet.

Habe nun die Aufgabe bekommen, ein Programm zu schreiben, das einen Screenshot von einem andere Programm erzeugt und dazu Infos aus einer DB lädt, und beides zusammen an eine Schnittstelle schickt.
Habe ich in der Vergangenheit in anderen Konstellationen schon gemacht und dachte mir, wird kein Problem sein.

Im Prinzip habe ich auch schon alles, musste aber feststellen, dass gerade die Aktion mit dem Screenshot für mich ein größeres Problem darstellt.
Ich erstelle den SCreenhot, bekomme die Koordinaten von dem anderen Programm, nur leider passen die nicht zusammen. Speichere ich also an Hand der Koordination den Bildausschnitt vom Screenshot ab, stimmt das nicht überein, soll heißen, die Rändern sind verschoben und ich bekomme einen komplett anderen Bereich bzw. auch nur einen Teilausschnitt

Zuerst wusste ich nicht, woran das hängt, bis ich auf die Skalierung gekommen bin. Bei uns in der Firma ist diese auf 125% eingestellt. Ändere ich es mir auf 100%, passt es soweit.

Nur ich muss halt mit 125% klar kommen. Ich habe das Netz durchforstet und bin aber nicht klar gekommen. Problem ist halt auch, dass ich ca. 7-8 Jahre nichts mit Delphi zu tun hatte. Habe Infos gefunden, dass man in der IDE was einstellen kann in Bezug auf High DPI, aber das gibt es bei XE wohl nicht. Auch habe ich zu Manifest Dateien was gefunden, aber keine wirklich verständliche Vorgehensweise

Ich dachte, das mit dem Screenshot wäre simpel, ist es aber hier nicht
Hat jemand einen Tipp für mich?

Habe schon versucht, die Screenshot Koordinaten umzurechnen, aber das klappt nicht, kommt immer was anderes raus, bzw. die 25% Unterschied zeigen sich nicht in der Realität.
Habe z.B. mit Greenshot die "echten" Koordinaten ermittelt und mit den verglichen, die ich im Programm erhalte. Da besteht für mich kein Zusammenhang mit 100% zu 125%

Hilfe :-)

Danke
Christof

dummzeuch 20. Nov 2024 08:48

AW: Screenshot und Skalierung
 
Wie erstellst Du denn den Screenshot?

Nach dem, was Du schreibst, ist das ja der komplette Bildschirm (also was man mit Ctrl+Druck bekommt), Dann muss man natürlich den entsprechenden Ausschnitt bestimmen, wo dann die Skalierung Probleme bereitet.

Wenn ich mich recht erinnere, gibt es auch die Möglichkeit, nur einen Screenshot von einem bestimmten Fenster zu erzeugen (= Alt+Druck). Dann bräuchte man den Ausschnitt nicht mehr selbst ermitteln.

tofse01 20. Nov 2024 08:52

AW: Screenshot und Skalierung
 
Hallo,

ich verstehe nicht, was du meinst.
Ich habe das Handle von dem Programm, das ich als Screenshot benötige


Habe diese Code, mit GetWindowRect bekomme ich die Koordinaten, aber die passen nicht
Delphi-Quellcode:
procedure ScreenShot(hWindow: HWND; bm: TBitmap; te:TEdit);
var
  Left, Top, Width, Height: Word;
  R: TRect;
  dc: HDC;
  lpPal: PLOGPALETTE;
begin
  {Check if valid window handle}
  if not IsWindow(hWindow) then Exit;
  {Retrieves the rectangular coordinates of the specified window}
  GetWindowRect(hWindow, R);

  te.Text:='L: '+inttostr(R.Left)+' T: '+inttostr(R.Top)+' B: '+inttostr(R.Bottom)+' R:'+inttostr(R.Right)+' ';

  //R.Right:=round(R.Right*1.25);

  Left := R.Left;
  Top := R.Top;
  Width := R.Right - R.Left;
  Height := R.Bottom - R.Top;
  bm.Width := Width;
  bm.Height := Height;
  {get the screen dc}
  dc := GetDc(0);
  if (dc = 0) then
  begin
    Exit;
  end;
  {do we have a palette device?}
  if (GetDeviceCaps(dc, RASTERCAPS) and
    RC_PALETTE = RC_PALETTE) then
  begin
    {allocate memory for a logical palette}
    GetMem(lpPal,
      SizeOf(TLOGPALETTE) +
    (255 * SizeOf(TPALETTEENTRY)));
    {zero it out to be neat}
    FillChar(lpPal^,
      SizeOf(TLOGPALETTE) +
    (255 * SizeOf(TPALETTEENTRY)),
      #0);
    {fill in the palette version}
    lpPal^.palVersion := $300;
    {grab the system palette entries}
    lpPal^.palNumEntries :=
      GetSystemPaletteEntries(dc,
      0,
      256,
      lpPal^.palPalEntry);
    if (lpPal^.PalNumEntries <> 0) then
    begin
      {create the palette}
      bm.Palette := CreatePalette(lpPal^);
    end;
    FreeMem(lpPal, SizeOf(TLOGPALETTE) +
    (255 * SizeOf(TPALETTEENTRY)));
  end;
  {copy from the screen to the bitmap}
  BitBlt(bm.Canvas.Handle,
    0,
    0,
    Width,
    Height,
    Dc,
    Left,
    Top,
    SRCCOPY);
  {release the screen dc}
  ReleaseDc(0, dc);
end;

tofse01 20. Nov 2024 08:58

AW: Screenshot und Skalierung
 
Liste der Anhänge anzeigen (Anzahl: 1)
Ich demonstriere mal das Problem mit dem "Windows Rechner" als Beispielprogramm.

Die "echten" linken, oberen Koordinaten sind 252 x 193

Mein Programm bekommt mit dem obigen Code aber das hier raus, siehe Bild, alles ist versetzt und abgeschnitten

supermulti81 20. Nov 2024 09:23

AW: Screenshot und Skalierung
 
Moin,
probiere bzw. ersetze mal:
GetWindowRect(hWindow, R);

durch

GetClientRect(hWindow, R);
Width := R.Width;
Height := R.Height;

tofse01 20. Nov 2024 09:25

AW: Screenshot und Skalierung
 
Danke, ich brauche aber die Koordinaten von dem Programm, und die von dir genannte GetClientRect hat keine Parameter

himitsu 20. Nov 2024 09:34

AW: Screenshot und Skalierung
 
Doch, hat sie, wenn du die Richtige benutzt.
* Self.GetClientRect von der Form, bzw. TCustomForm
* Windows.GetClientRect aus der Windows.pas, bzw. Winapi.Windows.pas

Die machen aber natürlich beide genau das Gleiche.
Delphi-Quellcode:
R := DelphiKomponente.GetClientRect;
oder
Delphi-Quellcode:
GetClientRect(HandleDerKomponente, R);



Dein Programm ist skaliert, also bekommt es auch die Koordinaten skaliert, aus seiner eigenen verbogenen Sichtweise.
Wäre dein Programm für HighDPI ausgelegt, also es dem Windoes sagt "ich kann das", dann wird es nicht skalliert und bekommt auch alle Canvas und Koordinaten in unverfäschter Form.

Genauso wird dein Programm in aktuellen Windowsen virtualisiert, also wenn dein Programm fragt, welche Windowsversions das ist, bekommt es meistens XP oder Vista gesagt, weil sich dein Programm nicht als kompatibel mit der dem Windows geoutet hat.
https://www.delphipraxis.net/216149-...skmanager.html

tofse01 20. Nov 2024 09:43

AW: Screenshot und Skalierung
 
Verstehe ich leider nicht
Ich will die Koordinaten von einem externen Programm, das rein gar nichts mit dem Delphi Programm zu tun hat. Als Beispiel verwende ich den "Windows Rechner", hierzu suche ich mir den Handler raus

Verwende ich

Delphi-Quellcode:
GetWindowRect(Prog, t);
Bekomme ich als Ergebnis 351 x 284 (links oben) raus

Verwende ich das hier

Delphi-Quellcode:
Windows.GetClientRect(Prog,t);
Bekomme ich als Ergebnis 0 x 0 raus

"Prog" ist hier der Handler von dem "Win Rechner"

tofse01 20. Nov 2024 09:54

AW: Screenshot und Skalierung
 
Liste der Anhänge anzeigen (Anzahl: 2)
Es liegt definitiv an den Win Einstellungen, verwende ich hier 100% (Was ich aber im Produktiveinsatz nicht machen kann) dann bekomme ich das gewünschte Ergebnis, siehe Anhang

supermulti81 20. Nov 2024 09:58

AW: Screenshot und Skalierung
 
Oben links brauchst du doch gar nicht.

du holst doch das Bild über das Handle und das startet bei x=0 und y=0.
und GetClientRect(hWindow, R);
gibt dir ein Rect zurück. Da verwendest du Width und Height.

Width := R.Width;
Height := R.Height;

und bitte noch setzen:
Left := 0;
Top := 0;

dann klappt auch dein BitBlt.

BitBlt(bm.Canvas.Handle,
0,
0,
Width,
Height,
Dc,
Left,
Top,
SRCCOPY);

DeddyH 20. Nov 2024 09:59

AW: Screenshot und Skalierung
 
Hier ist es noch einmal erklärt: https://stackoverflow.com/questions/...xternal-window

tofse01 25. Nov 2024 08:37

AW: Screenshot und Skalierung
 
Liste der Anhänge anzeigen (Anzahl: 1)
Hallo
ich komme erst jetzt wieder dazu, mich damit zu beschäftigen, deshalb erst heute meine Rückmeldung
Ich stehe total auf dem Schlauch, auch in Bezug auf diese Antwort. Wieso startet das bei 0,0 ?

Ich habe nochmal ein Bild angehängt worum es mir geht.
Es gibt eine beliebige Anwendung, Position der Anwendung ist variabel. Ich benötige einen Screenshot dieser Anwendung. Handle der Anwendung hab ich.

Ich erstelle also einen Screenshot vom kompletten Desktop, wie im Anhang zu sehen. Über das Handle bekomme ich die Koordinaten des Fenster der anderen Anwendung, hier im Beispiel 45 x 160. Das ist ja nicht 0 x 0
Die anderen Koordinaten habe ich ja auch. Ich muss also aus dem kompletten Screenshot den rot markierten Bereich rauskopieren. Wenn ich die Skalierung auf 100% hab, funktioniert es, wenn die Skalierung windowsseitig bei 125% ist, ist alles verschoben und die Maße passen nicht



Zitat:

Zitat von supermulti81 (Beitrag 1543306)
Oben links brauchst du doch gar nicht.

du holst doch das Bild über das Handle und das startet bei x=0 und y=0.
und GetClientRect(hWindow, R);
gibt dir ein Rect zurück. Da verwendest du Width und Height.

Width := R.Width;
Height := R.Height;

und bitte noch setzen:
Left := 0;
Top := 0;

dann klappt auch dein BitBlt.

BitBlt(bm.Canvas.Handle,
0,
0,
Width,
Height,
Dc,
Left,
Top,
SRCCOPY);


tofse01 25. Nov 2024 10:30

AW: Screenshot und Skalierung
 
Was ich erst jetzt verstanden hab, ich kann auch einen SCreenshot vom aktiven Fenster machen und muss gar nicht "rauskopieren"
Habe diese Funktion nun im Einsatz

Das Problem mit der Skalierung bleibt aber, habe dann bei dem rot markierten Code das ganze noch so berücksichtigt. Damit scheint es nun zu funktionieren

iWidth := round((Rec.Right - Rec.Left)*1.25);
iHeight := round((Rec.Bottom - Rec.Top)*1.25);


Delphi-Quellcode:
function FormularSaveScreenShot(FileName: String; h : hWnd): Boolean;
var
  Rec: TRect;
  iWidth, iHeight: Integer;
begin
  with TBitmap.Create do try
    GetWindowRect(h, Rec);

    iWidth := round((Rec.Right - Rec.Left)*1.25);
    iHeight := round((Rec.Bottom - Rec.Top)*1.25);

    Width := iWidth;
    Height := iHeight;

    BitBlt(Canvas.Handle, 0, 0, iWidth, iHeight, GetWindowDC(h), 0, 0, SRCCOPY);

    Result := True;

    try SaveToFile(Filename) except Result := False end;
  finally
    ReleaseDC(h, GetWindowDC(h));
    Free;
  end;
end;

Kas Ob. 25. Nov 2024 11:12

AW: Screenshot und Skalierung
 
@tofse01 , do yourself a favor and drop using this half baked approach by copying DC, because this will always have problems unless it get way more complicated, a complexity which very needed here to do it right.

See, you are creating a DC then copying from the target application DC, did you queried the target DC scaling ? no you did not, to be done right this way you should align the DC in parameters (dimensions, color, device capability and of course scaling ), here comes the OS forced values and the target application if it is following the OS request or is doing it by its own custom drawing, example AlphaSkins does the scaling on its own (only if configured to do that or just leave it the OS).

Anyway, drop that approach and ask the target application to to the drawing for you ! this is simpler and will work exactly as intended no matter what OS is doing.

Please take a look at the answer here https://stackoverflow.com/questions/...ap-object-in-c

And use PrintWindow, or even the better approach with SendMessage of WM_PRINTCLIENT or WM_PRINT ..
https://learn.microsoft.com/en-us/wi...wm-printclient

Kas Ob. 25. Nov 2024 11:14

AW: Screenshot und Skalierung
 
One more thing, with these Print function/messages the target will be drawn even if it is behind other windows, so you are not screenshot the desktop (as your code now), no, you are drawing the application as it would be if it is focused and on top.


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