截图与视频

截图与视频

截图

最简单的截图就是直接使用 getSources,但是 desktopCapturer.getSources 会导致整个程序挂起,挂起时间与屏幕分辨率、屏幕数量和电脑性能有关。

desktopCapturer.getSources(
  {
    types: ["screen"],
    thumbnailSize: {
      width: width * scaleFactor,
      height: height * scaleFactor
    }
  },
  (error, sources) => {
    console.timeEnd("capture");
    let imgSrc = sources[0].thumbnail.toDataURL();
    let capture = new CaptureRenderer($canvas, $bg, imgSrc, scaleFactor);
  }
);

替代的方法是可以使用 getUserMedia:

const handleStream = stream => {
  document.body.style.cursor = oldCursor;
  document.body.style.opacity = "1";
  // Create hidden video tag
  let video = document.createElement("video");
  video.style.cssText = "position:absolute;top:-10000px;left:-10000px;";
  // Event connected to stream

  let loaded = false;
  video.onloadedmetadata = () => {
    if (loaded) {
      return;
    }
    loaded = true;
    // Set video ORIGINAL height (screenshot)
    video.style.height = video.videoHeight + "px"; // videoHeight
    video.style.width = video.videoWidth + "px"; // videoWidth

    // Create canvas
    let canvas = document.createElement("canvas");
    canvas.width = video.videoWidth;
    canvas.height = video.videoHeight;
    let ctx = canvas.getContext("2d");
    // Draw video on canvas
    ctx.drawImage(video, 0, 0, canvas.width, canvas.height);

    if (this.callback) {
      // Save screenshot to png - base64
      this.callback(canvas.toDataURL("image/png"));
    } else {
      // console.log('Need callback!')
    }

    // Remove hidden video tag
    video.remove();
    try {
      stream.getTracks()[0].stop();
    } catch (e) {
      // nothing
    }
  };
  video.srcObject = stream;
  document.body.appendChild(video);
};

// mac 和 windows 获取 chromeMediaSourceId 的方式不同
if (require("os").platform() === "win32") {
  require("electron").desktopCapturer.getSources(
    {
      types: ["screen"],
      thumbnailSize: { width: 1, height: 1 }
    },
    (e, sources) => {
      let selectSource = sources.filter(
        source => source.display_id + "" === curScreen.id + ""
      )[0];
      navigator.getUserMedia(
        {
          audio: false,
          video: {
            mandatory: {
              chromeMediaSource: "desktop",
              chromeMediaSourceId: selectSource.id + "",
              minWidth: 1280,
              minHeight: 720,
              maxWidth: 8000,
              maxHeight: 8000
            }
          }
        },
        handleStream,
        handleError
      );
    }
  );
} else {
  navigator.getUserMedia(
    {
      audio: false,
      video: {
        mandatory: {
          chromeMediaSource: "desktop",
          chromeMediaSourceId: `screen:${curScreen.id}`,
          minWidth: 1280,
          minHeight: 720,
          maxWidth: 8000,
          maxHeight: 8000
        }
      }
    },
    handleStream,
    handleError
  );
}

多屏幕支持

由于全屏情况,窗口只能占据一个屏幕,所以多屏截图只能用多个截屏窗口来处理了。

const captureScreen = (e, args) => {
  if (captureWins.length) {
    return;
  }
  const { screen } = require("electron");

  let displays = screen.getAllDisplays();

  // 循环创建截屏窗口
  captureWins = displays.map(display => {
    let captureWin = new BrowserWindow({
      // window 使用 fullscreen,  mac 设置为 undefined, 不可为 false
      fullscreen: os.platform() === "win32" || undefined,
      width: display.bounds.width,
      height: display.bounds.height,
      x: display.bounds.x,
      y: display.bounds.y,
      transparent: true,
      frame: false,
      movable: false,
      resizable: false,
      enableLargerThanScreen: true,
      hasShadow: false
    });
    captureWin.setAlwaysOnTop(true, "screen-saver");
    captureWin.setFullScreenable(false);

    captureWin.loadFile(path.join(__dirname, "capture.html"));

    // 调试用
    // captureWin.openDevTools()

    // 一个窗口关闭则关闭所有窗口
    captureWin.on("closed", () => {
      let index = captureWins.indexOf(captureWin);
      if (index !== -1) {
        captureWins.splice(index, 1);
      }
      captureWins.forEach(win => win.close());
    });
    return captureWin;
  });
};

然后每个窗口截取当前屏幕的画面进行操作,获取当前屏幕可以下面的方法:

// 因为窗口是全屏的, 所以可以直接用 x, y 来对比
const getCurrentScreen = () => {
  let { x, y } = currentWindow.getBounds();
  return screen
    .getAllDisplays()
    .filter(d => d.bounds.x === x && d.bounds.y === y)[0];
};

MAC 下截取全屏窗口

let captureWin = new BrowserWindow({
  // window 使用 fullscreen,  mac 设置为 undefined, 不可为 false
  fullscreen: os.platform() === "win32" || undefined,
  width: display.bounds.width,
  height: display.bounds.height,
  x: display.bounds.x,
  y: display.bounds.y,
  transparent: true,
  frame: false,
  movable: false,
  resizable: false,
  enableLargerThanScreen: true,
  hasShadow: false,
  show: false
});

// 黑魔法...
app.dock.hide();
captureWin.setAlwaysOnTop(true, "screen-saver");
captureWin.setVisibleOnAllWorkspaces(true);
captureWin.setFullScreenable(false);
captureWin.show();
app.dock.show();
captureWin.setVisibleOnAllWorkspaces(false);
上一页