我还没有找到一个功能FMX.Platform获得的截图(反正无处...)。
随着VCL,有很多答案(计算器,谷歌,...)。
但如何获得Windows和Mac OS X的图像(位图或其他)的屏幕截图?
问候,
W.
更新: 从Tipiweb链接给出了OS X的一个很好的解决方案
关于Windows的一部分:我有编码,但我不喜欢使用VCL,和流来实现它...任何更好的建议,意见?
谢谢。
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, 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捕获- > T流
API的Windows捕获- > Vcl.Graphics.TBitmap - > T流。
在那之后,我打开我的Windows或Mac T流在FMX.Types.TBitmap(自流负载)
窗口单位代码:
unit tools_WIN;
interface
{$IFDEF MSWINDOWS}
uses Classes {$IFDEF MSWINDOWS} , Windows {$ENDIF}, System.SysUtils, FMX.Types, 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,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,Screen.Width,Screen.Height,Dc,0,0,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,
FMX.Types,
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);
如果您有其他的想法,请跟我:-)
由于Tipiweb的代码(他的回答),一个GitHub的项目已在此基础上开始; 与一些改进(能力获取屏幕截图仅在一定的窗口,或采取一个完整的屏幕截图)。
该单元被命名为xscreenshot.pas(适用于所有平台的单一单元)
GitHub的项目页面:
- https://github.com/z505/screenshot-delphi
在本单位提供的实用程序:
// take screenshot of full screen
procedure TakeScreenshot(...)
// take screenshot only of a specific window
procedure TakeWindowShot(...)
在Mac OS收尾需要采取特定的窗口截图一些工作。
再次,感谢Tipiweb他的回答得到该项目的启动。
您可以使用一个很好的解决方案,从这个网站做的Mac OSX屏幕截图。
不要与Windows API这样相同的工作:
procedure ScreenShot(x, y, Width, Height: integer; bm: TBitMap);
var
dc: HDC; lpPal : PLOGPALETTE;
begin
{test width and height}
if ((Width = 0) OR (Height = 0)) then exit;
bm.Width := Width;
bm.Height := 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,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,x,y,SRCCOPY);
//release the screen dc
ReleaseDc(0, dc);
end;
在此之后,包括您不同的单位:
uses
{$IFDEF MSWINDOWS}
mytools_win,
{$ENDIF MSWINDOWS}
{$IFDEF MACOS}
mytools_mac,
{$ENDIF MACOS}