delphi - 如何在 Windows 中拍摄没有背景/壁纸图片的整个桌面的屏幕截图

标签 delphi screen-capture desktop-wallpaper

我需要捕获没有背景图片(壁纸)的屏幕截图。我可以尝试禁用壁纸,拍摄屏幕截图,然后重新启用它,但是:

  1. 目前我不知道如何禁用/恢复壁纸(在简单的情况下,它是分配为桌面的图片文件,带有一些平铺选项,但在现代版本的 Windows 中可以有不同的东西吗?)。
  2. 如果用户在我切换回壁纸之前杀死应用程序,那么壁纸将保持禁用状态,这不好。

有谁知道解决方案或想法在哪里寻找解决方案? 也许可以暂时禁用壁纸?

更新:屏幕截图是注册错误程序的一部分,因此我需要所有潜在有用的信息(可见表单、任务栏等),并且非常希望将屏幕截图保持为无损格式(更具可读性,更快的压缩) 。其中一种选择是捕获镜头并将其存储为 AVI,因此处理时间也很重要。背景使图像变得更大,这是我尝试删除它的唯一原因。我可以使用一些算法来减少使用的颜色,它可以大大提高压缩比,但这是一个耗时的过程。所以最好的是完全删除背景图片。

更新 2:为了从镜头序列生成 AVI,我使用 François PIETTE 的单元(基于 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;

最佳答案

禁用壁纸会导致恼人的闪烁/重画。无论如何,我期待着。 枚举桌面上所有可见的窗口,找到它们的尺寸/位置,然后确定所有这些矩形之外的区域会更清晰。使该区域不可见。即白色,以在打印时节省纸张,或其他颜色以满足您的目的。这个答案只是描述一般方法,但我认为这是可行的方法,除非出现一些神奇的“银弹”。

关于delphi - 如何在 Windows 中拍摄没有背景/壁纸图片的整个桌面的屏幕截图,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19097770/

相关文章:

delphi - 有没有一种低开销的方法来使用Delphi Hook 鼠标双击?

delphi - 如何使用 TDBChart VCL Teechart 组件使用单个数据集制作堆积条形图?

php - COM 对象方法未定义

delphi - 如何将 list <requestedPrivileges>信息添加到delphi项目中

c++ - 如何保存24位BMP

c++ - 独立于桌面环境或窗口管理器以编程方式更改 Linux 中的墙纸

c++ - 使用 C++ 和 Windows API 以编程方式更改墙纸

java - 将 GLSurfaceView 的屏幕捕获到位图

linux - Linux 上的屏幕截图

windows - 如何使用批量更改壁纸