TeilScreenshot erstellen, so schnell wie möglich ..

Für alles, was in den übrigen Lazarusthemen keinen Platz, aber mit Lazarus zutun hat.
Antworten
Benutzeravatar
corpsman
Lazarusforum e. V.
Beiträge: 1629
Registriert: Sa 28. Feb 2009, 08:54
OS, Lazarus, FPC: Linux Mint Mate, Lazarus GIT Head, FPC 3.0
CPU-Target: 64Bit
Wohnort: Stuttgart
Kontaktdaten:

TeilScreenshot erstellen, so schnell wie möglich ..

Beitrag von corpsman »

Hallo Zusammen, ich benötige einen "Teilscreenshoot". Dazu habe ich mir aus diversen Code Schnipseln den unten stehenden Code gebastelt.

Dieser funktioniert auch Grundsätzlich, da das von mir aufgenommene Rechteck in der Regel aber recht klein und mein 4K Monitor doch recht groß ist, dauert der Umweg über den "kompletten" Screenshoot ewig (ca. 100ms).

Sieht da einer von Euch wie man das Beschleunigen könnte ?

Code: Alles auswählen

Function CaptureScreenRect(aTopLeft, aBottomRight: TPoint): TBitmap;
Var
  ScreenDC: HDC;
  tmp: TBitmap;
Begin
  tmp := TBitmap.Create;
{$IFDEF WINDOWS}
  tmp.Width := Screen.DesktopWidth;
  tmp.Height := Screen.DesktopHeight;
  tmp.Canvas.Brush.Color := clWhite;
  tmp.Canvas.FillRect(0, 0, tmp.Width, tmp.Height);
  ScreenDC := GetDC(GetDesktopWindow);
  BitBlt(tmp.Canvas.Handle, 0, 0, tmp.Width, tmp.Height, ScreenDC, Screen.DesktopLeft, Screen.DesktopTop, SRCCOPY);
  ReleaseDC(0, ScreenDC);
{$ENDIF}
{$IFDEF LINUX}
  tmp.Height := Screen.Height;
  tmp.Width := Screen.Width;
  ScreenDC := GetDC(0);
  tmp.LoadFromDevice(ScreenDC);
  ReleaseDC(0, ScreenDC);
{$ENDIF}
  result := TBitmap.Create;
  result.Width := abs(aTopLeft.X - aBottomRight.X + 1);
  result.Height := abs(aTopLeft.Y - aBottomRight.Y + 1);
  result.Canvas.Draw(-min(aTopLeft.X, aBottomRight.X), -min(aTopLeft.Y, aBottomRight.Y), tmp);
  tmp.free;
End; 
By the way, wenn das nur unter Linux schnell geht würde mir das Reichen ;), der Windowsteil ist quasi eine Altlast..
--
Just try it

MmVisual
Beiträge: 1581
Registriert: Fr 10. Okt 2008, 23:54
OS, Lazarus, FPC: Winuxarm (L 4 FPC 3.2.2)
CPU-Target: 32/64Bit

Re: TeilScreenshot erstellen, so schnell wie möglich ..

Beitrag von MmVisual »

Vor einigen Jahren hatte ich mal das Problem dass mein Programm auf einem RaspberryPi ca. 20 Sekunden braucht um zu starten.
Also musste ein Splas-Screen her ...
Doch dieser brauchte auch 8 Sekunden bis der dargestellt wurde.

Schlussendlich half nur dass man das Kopieren der Grafik manuell selbst in der FOR Schleife machte und man auch nur das eine Pixelformat unterstützt, das dauert dann weniger als 10ms auf dem RaspberryPi.

Von daher am besten selber kopieren, in einer möglichst schlanken Routine ohne den ganzen Format-IF-Optionen-Overhead dabei.
EleLa - Elektronik Lagerverwaltung - www.elela.de

Benutzeravatar
corpsman
Lazarusforum e. V.
Beiträge: 1629
Registriert: Sa 28. Feb 2009, 08:54
OS, Lazarus, FPC: Linux Mint Mate, Lazarus GIT Head, FPC 3.0
CPU-Target: 64Bit
Wohnort: Stuttgart
Kontaktdaten:

Re: TeilScreenshot erstellen, so schnell wie möglich ..

Beitrag von corpsman »

Lol, ok ich weis was du meinst, hab nu mal eine Art "enroling" gemacht, zumindest unter Linux ist das Faktor 4 bis 20 schneller (jittert zwischen 5 und 20 ms), ..

Code: Alles auswählen

Uses math, IntfGraphics, fpImage, GraphType;
(*
Erzeugt einen Teil Screenshot und gibt diesen zurück
*)

Function CaptureScreenRect(aTopLeft, aBottomRight: TPoint): TBitmap;
{$IFDEF WINDOWS}
Var
  ScreenDC: HDC;
  tmp: TBitmap;
Begin
  tmp := TBitmap.Create;
  tmp.Width := Screen.DesktopWidth;
  tmp.Height := Screen.DesktopHeight;
  tmp.Canvas.Brush.Color := clWhite;
  tmp.Canvas.FillRect(0, 0, tmp.Width, tmp.Height);
  ScreenDC := GetDC(GetDesktopWindow);
  BitBlt(tmp.Canvas.Handle, 0, 0, tmp.Width, tmp.Height, ScreenDC, Screen.DesktopLeft, Screen.DesktopTop, SRCCOPY);
  ReleaseDC(0, ScreenDC);
  result := TBitmap.Create;
  result.Width := abs(aTopLeft.X - aBottomRight.X + 1);
  result.Height := abs(aTopLeft.Y - aBottomRight.Y + 1);
  result.Canvas.Draw(-min(aTopLeft.X, aBottomRight.X), -min(aTopLeft.Y, aBottomRight.Y), tmp);
  tmp.free;
End;
{$ENDIF}
{$IFDEF LINUX}
Var
  ScreenDC: HDC;
  IntfImg: TLazIntfImage;
  R: TRect;
  RawImage: TRawImage;
Begin
  result := TBitmap.Create;
  ScreenDC := GetDC(0);
  IntfImg := TLazIntfImage.Create(0, 0, []);
  R.TopLeft := aTopLeft;
  R.BottomRight := aBottomRight;
  If Not RawImage_FromDevice(RawImage, ScreenDC, R) Then
    Raise FPImageException.Create('Failed to get raw image from device');
  IntfImg.SetRawImage(RawImage);
  result.LoadFromIntfImage(IntfImg);
  IntfImg.free;
  ReleaseDC(0, ScreenDC);
End;
{$ENDIF}  
--
Just try it

Benutzeravatar
theo
Beiträge: 10921
Registriert: Mo 11. Sep 2006, 19:01

Re: TeilScreenshot erstellen, so schnell wie möglich ..

Beitrag von theo »

Schon mal mit BGRABitmap probiert?

Soll wohl so funktionieren:

Code: Alles auswählen

uses  BGRABitmap;
...
 
procedure TForm1.BCButton1Click(Sender: TObject);
var MyCapture : TBgraBitmap;
var MyArea : TRect;
begin
  MyArea := Bounds(400,400,200,200);
  MyCapture := TBgraBitmap.Create();
  MyCapture.TakeScreenShot(MyArea);
  MyCapture.SaveToFile('F:\temp\MyCapture.png');
end;  
Ich weiss nicht ob das schneller ist, gehe aber davon aus, dass es optimiert ist.

Antworten