加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 大数据 > 正文

delphi – 如何使用FireMonkey(多平台)截取屏幕截图

发布时间:2020-12-15 09:33:35 所属栏目:大数据 来源:网络整理
导读:我没有找到在FMX.Platform中获取屏幕截图的功能(无论如何,其他地方……). 有了VCL,有很多答案(stackoverflow,google,…). 但是如何在Windows和Mac OS X的图像(位图或其他)中获取屏幕截图? 问候, W. 更新: link from Tipiweb为OS X提供了一个很好的解决方案
我没有找到在FMX.Platform中获取屏幕截图的功能(无论如何,其他地方……).

有了VCL,有很多答案(stackoverflow,google,…).

但是如何在Windows和Mac OS X的图像(位图或其他)中获取屏幕截图?

问候,

W.

更新:
link from Tipiweb为OS X提供了一个很好的解决方案.

关于Windows部分:我编写了这个,但我不喜欢使用VCL和Stream来实现它…
有什么更好的建议,评论?

谢谢.

W.

uses ...,FMX.Types,Winapi.Windows,Vcl.Graphics;

...

function DesktopLeft: Integer;
begin
  Result := GetSystemMetrics(SM_XVIRTUALSCREEN);
end;

function DesktopWidth: Integer;
begin
  Result := GetSystemMetrics(SM_CXVIRTUALSCREEN);
end;

function DesktopTop: Integer;
begin
  Result := GetSystemMetrics(SM_YVIRTUALSCREEN);
end;

function DesktopHeight: Integer;
begin
  Result := GetSystemMetrics(SM_CYVIRTUALSCREEN);
end;


procedure GetScreenShot(var dest: FMX.Types.TBitmap);
var
  cVCL  : Vcl.Graphics.TCanvas;
  bmpVCL: Vcl.Graphics.TBitmap;
  msBmp : TMemoryStream;
begin
  bmpVCL      := Vcl.Graphics.TBitmap.Create;
  cVCL        := Vcl.Graphics.TCanvas.Create;
  cVCL.Handle := GetWindowDC(GetDesktopWindow);
  try
    bmpVCL.Width := DesktopWidth;
    bmpVCL.Height := DesktopHeight;
    bmpVCL.Canvas.CopyRect(Rect(0,DesktopWidth,DesktopHeight),cVCL,Rect(DesktopLeft,DesktopTop,DesktopLeft + DesktopWidth,DesktopTop + DesktopHeight)
                          );
  finally
    ReleaseDC(0,cVCL.Handle);
    cVCL.Free;
  end;

  msBmp := TMemoryStream.Create;
  try
    bmpVCL.SaveToStream(msBmp);
    msBmp.Position := 0;
    dest.LoadFromStream(msBmp);
  finally
    msBmp.Free;
  end;

解决方法

我构建了一个小应用程序来截取屏幕截图(Windows / Mac),它可以工作:-)!

对于Windows和Mac兼容性,我使用流.

API Mac Capture –> TStream

API Windows Capture –> Vcl.Graphics.TBitmap –> TStream.

之后,我将我的Windows或Mac TStream加载到FMX.Types.TBitmap中(从流中加载)

Windows单位代码:

unit tools_WIN;

interface
{$IFDEF MSWINDOWS}
uses Classes {$IFDEF MSWINDOWS},Windows {$ENDIF},System.SysUtils,VCL.Forms,VCL.Graphics;


  procedure TakeScreenshot(Dest: FMX.Types.TBitmap);
{$ENDIF MSWINDOWS}

implementation

{$IFDEF MSWINDOWS}


procedure WriteWindowsToStream(AStream: TStream);
var
  dc: HDC; lpPal : PLOGPALETTE;
  bm: TBitMap;
begin
{test width and height}
  bm := TBitmap.Create;

  bm.Width := Screen.Width;
  bm.Height := Screen.Height;

  //get the screen dc
  dc := GetDc(0);
  if (dc = 0) then exit;
 //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,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,Screen.Width,Screen.Height,Dc,SRCCOPY);

  bm.SaveToStream(AStream);

  FreeAndNil(bm);
  //release the screen dc
  ReleaseDc(0,dc);
end;


procedure TakeScreenshot(Dest: FMX.Types.TBitmap);
var
  Stream: TMemoryStream;
begin
  try
    Stream := TMemoryStream.Create;
    WriteWindowsToStream(Stream);
    Stream.Position := 0;
    Dest.LoadFromStream(Stream);
  finally
    Stream.Free;
  end;
end;

{$ENDIF MSWINDOWS}
end.

Mac单位代码:

unit tools_OSX;


interface
{$IFDEF MACOS}
uses

  Macapi.CoreFoundation,Macapi.CocoaTypes,Macapi.CoreGraphics,Macapi.ImageIO,system.Classes,system.SysUtils;

  procedure TakeScreenshot(Dest: TBitmap);
{$ENDIF MACOS}

implementation
{$IFDEF MACOS}

{$IF NOT DECLARED(CGRectInfinite)}
const
  CGRectInfinite: CGRect = (origin: (x: -8.98847e+30; y: -8.98847e+307);
    size: (width: 1.79769e+308; height: 1.79769e+308));
{$IFEND}


function PutBytesCallback(Stream: TStream; NewBytes: Pointer;
  Count: LongInt): LongInt; cdecl;
begin
  Result := Stream.Write(NewBytes^,Count);
end;

procedure ReleaseConsumerCallback(Dummy: Pointer); cdecl;
begin
end;

procedure WriteCGImageToStream(const AImage: CGImageRef; AStream: TStream;
  const AType: string = 'public.png'; AOptions: CFDictionaryRef = nil);
var
  Callbacks: CGDataConsumerCallbacks;
  Consumer: CGDataConsumerRef;
  ImageDest: CGImageDestinationRef;
  TypeCF: CFStringRef;
begin
  Callbacks.putBytes := @PutBytesCallback;
  Callbacks.releaseConsumer := ReleaseConsumerCallback;
  ImageDest := nil;
  TypeCF := nil;
  Consumer := CGDataConsumerCreate(AStream,@Callbacks);
  if Consumer = nil then RaiseLastOSError;
  try
    TypeCF := CFStringCreateWithCharactersNoCopy(nil,PChar(AType),Length(AType),kCFAllocatorNull); //wrap the Delphi string in a CFString shell
    ImageDest := CGImageDestinationCreateWithDataConsumer(Consumer,TypeCF,1,AOptions);
    if ImageDest = nil then RaiseLastOSError;
    CGImageDestinationAddImage(ImageDest,AImage,nil);
    if CGImageDestinationFinalize(ImageDest) = 0 then RaiseLastOSError;
  finally
    if ImageDest <> nil then CFRelease(ImageDest);
    if TypeCF <> nil then CFRelease(TypeCF);
    CGDataConsumerRelease(Consumer);
  end;
end;

procedure TakeScreenshot(Dest: TBitmap);
var
  Screenshot: CGImageRef;
  Stream: TMemoryStream;
begin
  Stream := nil;
  ScreenShot := CGWindowListCreateImage(CGRectInfinite,kCGWindowListOptionOnScreenOnly,kCGNullWindowID,kCGWindowImageDefault);
  if ScreenShot = nil then RaiseLastOSError;
  try
    Stream := TMemoryStream.Create;
    WriteCGImageToStream(ScreenShot,Stream);
    Stream.Position := 0;
    Dest.LoadFromStream(Stream);
  finally
    CGImageRelease(ScreenShot);
    Stream.Free;
  end;
end;



 {$ENDIF MACOS}
end.

在您的mainForm单元中:

...
{$IFDEF MSWINDOWS}
  uses tools_WIN;
{$ELSE}
  uses tools_OSX;
{$ENDIF MSWINDOWS}

...
var
  imgDest: TImageControl;
...
TakeScreenshot(imgDest.Bitmap);

如果您有其他想法,请与我联系:-)

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读