我需要捕捉没有背景图片(壁纸)的屏幕截图。我可以尝试禁用壁纸,拍摄屏幕然后再启用它,但是:
有谁知道解决方案或想法在哪里搜索解决方案? 也许有可能暂时禁用壁纸?
更新:屏幕截图是注册错误程序的一部分,所以我需要所有可能有用的信息(可见表单,任务栏,...),非常希望保持屏幕拍摄无损格式(更可读,更快的压缩) 。其中一个选项是捕获将它们存储为AVI的镜头,因此处理时间也很重要。背景使图像更大,这是我试图删除它的唯一原因。我可以使用一些算法来减少使用的颜色,它大大提高了压缩率,但这是一个耗时的过程。所以最重要的是删除背景图片。
更新2:为了从镜头序列生成AVI,我使用了FrançoisPIETTE的单位(基于this article):
Avi := TAviFromBitmaps.CreateAviFile(
nil,
AviFilename,
MKFOURCC('S', 'C', 'L', 'S'), // msu-sc-codec
2, 1); // 2 frames per second
// called by timer
procedure TfrmSnapshot.RecordFrame;
begin
TakeSnapshot; // get snap shot to BMP:TBitmap
Avi.AppendNewFrame(Bmp.Handle);
end;
因此,如果我能够从快照中删除背景,AVI压缩也会得到改善。
我使用的最终代码部分:
TAppRects = class
protected
FMonitor: TMonitor;
FRects: TList<TRect>;
function GetRegion(AArea: TRect): HRGN;
public
constructor Create(AMonitor: TMonitor);
destructor Destroy; override;
// fill all Area which is not covered by Rects (application forms)
procedure FillBackground(ABmp: TBitmap; AArea: TRect);
property Rects: TList<TRect> read FRects;
property Monitor: TMonitor read FMonitor;
end;
// Check for WS_EX_APPWINDOW will hide start button menu/popup menus outside of
// the forms etc, but it makes final AVI much smaller (and usually it is anough
// to have main forms recorded).
function EnumWindowsProc(hwnd: HWND; lParam: LPARAM): BOOL; stdcall;
var
r: TRect;
begin
Result := True;
if IsWindowVisible(hwnd) and
(GetWindow(hwnd, GW_OWNER)=0) and // is not owned by another window
(GetWindowLongPtr(hwnd, GWL_STYLE) and WS_EX_APPWINDOW<>0) and // is app
GetWindowRect(hwnd, r) and
(r.Width>0) and (r.Height>0)
then
with TAppRects(lParam) do
if (FMonitor=nil) or
(FMonitor.Handle=0) or
(FMonitor.Handle=MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST))
then
FRects.Add(r);
end;
{ TAppRects }
constructor TAppRects.Create(AMonitor: TMonitor);
begin
FMonitor := AMonitor;
FRects := TList<TRect>.Create;
EnumWindows(@EnumWindowsProc, NativeInt(self));
end;
destructor TAppRects.Destroy;
begin
FreeAndNil(FRects);
end;
function TAppRects.GetRegion(AArea: TRect): HRGN;
var
c: array of integer;
p: array of TPoint;
i: Integer;
begin
setlength(c, FRects.Count);
setlength(p, FRects.Count*4);
for i := 0 to FRects.Count-1 do
begin
c[i] := 4;
with FRects[i] do
begin
p[i*4 ] := Point(Left,Top);
p[i*4+1] := Point(Right,Top);
p[i*4+2] := Point(Right,Bottom);
p[i*4+3] := Point(Left,Bottom);
end;
end;
result := CreatePolyPolygonRgn(p[0], c[0], length(c), WINDING);
end;
procedure TAppRects.FillBackground(ABmp: TBitmap; AArea: TRect);
var
h1,h2,h3: HRGN;
begin
h1 := 0;
h2 := 0;
h3 := 0;
try
h1 := GetRegion(AArea);
if h1=0 then
exit;
h2 := CreateRectRgn(AArea.Left,AArea.Top,AArea.Right,AArea.Bottom);
h3 := CreateRectRgn(AArea.Left,AArea.Top,AArea.Right,AArea.Bottom);
if (h2<>0) and (h3<>0) and
not (CombineRgn(h3, h2,h1, RGN_DIFF) in [NULLREGION,RGN_ERROR])
then
FillRgn(ABmp.Canvas.Handle, h3, ABmp.Canvas.Brush.Handle);
finally
if h1<>0 then DeleteObject(h1);
if h2<>0 then DeleteObject(h2);
if h3<>0 then DeleteObject(h3);
end;
end;
procedure RemoveBackground(ASnapshot: TBitmap; AMonitor: TMonitor);
var
e: TAppRects;
c: TColor;
begin
e := nil;
try
e := TAppRects.Create(AMonitor);
c := ASnapshot.Canvas.Brush.Color;
ASnapshot.Canvas.Brush.Color := $FEA249; // kind of blue (~default for win8)
e.FillBackground(ASnapshot, e.Monitor.WorkareaRect);
ASnapshot.Canvas.Brush.Color := c;
finally
e.free;
end;
end;
答案 0 :(得分:4)
禁用壁纸会导致烦人的闪烁/重绘。无论如何,我期待。 枚举桌面上可见的所有窗口,找到它们的尺寸/位置,然后确定所有这些矩形之外的区域将更加清晰。使该区域不可见。即白色,打印时节省纸张,或其他颜色以满足您的目的。这个答案只是为了描述一般方法,但我认为这是要走的路,除非出现一些神奇的“银弹”。
答案 1 :(得分:0)
有一种简单的方法可以做到这一点:
*)或操纵位图就好像它们是数组一样。 确保两个位图的颜色深度相同。
所有相同的像素将显示为黑色。
现在把你操控的结果放到面具里;屏蔽截图,用PNG压缩并发送。
当我离开iPad时会产生代码。