【问题标题】:Take desktop screenshot with Electron使用 Electron 截取桌面截图
【发布时间】:2021-01-16 14:29:46
【问题描述】:

我正在使用 Electron 创建一个创建全屏透明覆盖窗口的 Windows 应用程序。此叠加层的目的是:

  1. 截取整个屏幕的屏幕截图(不是透明的覆盖层本身,而是屏幕“下方”),
  2. 通过将图像作为字节流发送到我的 python 服务器来处理此图像,并且
  3. 在叠加层上画一些东西

我卡在第一步,即截图捕获过程。

我尝试了选项1,也就是使用capturePage():

this.electronService.remote.getCurrentWindow().webContents.capturePage()
    .then((img: Electron.NativeImage) => { ... }

但这仅捕获我的覆盖窗口(而不是桌面屏幕)。这将是一个空白图像,对我来说毫无用处。

选项2是使用desktopCapturer

this.electronService.remote.desktopCapturer.getSources({types: ['screen']}).then(sources => {
    for (const source of sources) {
        if (source.name === 'Screen 1') {
            try {
                const mediaDevices = navigator.mediaDevices as any;
                mediaDevices.getUserMedia({
                    audio: false,
                    video: { // this specification is only available for Chrome -> Electron runs on Chromium browser
                        mandatory: {
                            chromeMediaSource: 'desktop',
                            chromeMediaSourceId: source.id,
                            minWidth: 1280,
                            maxWidth: 1280,
                            minHeight: 720,
                            maxHeight: 720
                        }
                    }
                }).then((stream: MediaStream) => { // stream.getVideoTracks()[0] contains the video track I need
                    this.handleStream(stream);
                });
            } catch (e) {
            }
        }
    }
});

下一步对我来说变得模糊。我如何处理获得的MediaStream 以从屏幕截图中获取字节流?我看到很多如何在网页上显示此流的示例,但我希望将其发送到我的后端。 This StackOverflow post 提到了如何做到这一点,但我没有让它正常工作。这就是我实现handleStream()的方式:

import * as MediaStreamRecorder from 'msr';

private handleStream(stream: MediaStream): void {
    recorder.stop()
    const recorder = new MediaStreamRecorder(stream);
    recorder.ondataavailable = (blob: Blob) => { // I immediately get a blob, while the linked SO page got an event and had to get a blob through event.data
        this.http.post<Result>('http://localhost:5050', blob);
    };

    // make data available event fire every one second
    recorder.start(1000);
}

blob 未被 Python 服务器接受。检查Blob的内容后,我怀疑这是一个视频。我用以下代码验证了这一点:

let url = URL.createObjectURL(blob);
window.open(url, '_blank')

在新窗口中打开 blob。它显示可能半秒的视频,但我想要一个静态图像。那么如何从中获取特定的快照呢?我也不确定是否只需在 POST 正文中发送 Javascript blob 格式就可以让 Python 正确解释它。在 Java 中,它只需发送图像的 byte[] 即可工作,因此我验证了 Python 服务器实现按预期工作。

除了使用desktopCapturer 之外的任何建议也可以。这个实现也捕获了我的鼠标,我宁愿没有。我必须承认,我没想到这个功能会这么难实现。

【问题讨论】:

    标签: javascript angular electron


    【解决方案1】:

    以下是截取桌面屏幕截图的方法:

    const { desktopCapturer } = require('electron')
    
    document.getElementById('screenshot-button').addEventListener('click', () => { // The button which takes the screenshot
        desktopCapturer.getSources({ types: ['screen'] })
            .then( sources => {
                document.getElementById('screenshot-image').src = sources[0].thumbnail.toDataURL() // The image to display the screenshot
            })
    })
    

    使用“屏幕”将截取整个桌面的屏幕截图。 使用“windows”将只截取应用程序的屏幕截图。

    另请参阅以下文档:https://www.electronjs.org/docs/api/desktop-capturer

    【讨论】:

    • 我不知道有thumbnail 选项。这个解决方案更干净、更短,所以我实际上更喜欢这个。需要注意的是,缩略图大小默认为 150x150,因此应设置为所需的尺寸。我将我的解决方案添加到未来访问者的单独答案中。
    • 缩略图大小是desktopCapturer.getSources() 的一个选项。请注意,如果不使用缩略图,则应将大小设置为 0 以提高性能。 (毕竟我没有添加单独的答案。我在写它时意识到它对已经发布的答案几乎没有附加价值。)
    • 在 2022 年传递给 ipcRenderer 后如何工作? main.js 里有什么,preload 里有什么?
    【解决方案2】:

    desktopCapturer 只拍摄视频。因此,您需要从中获取单个帧。您可以为此使用 html5 canvas。这是一个例子: https://ourcodeworld.com/articles/read/280/creating-screenshots-of-your-app-or-the-screen-in-electron-framework

    或者,使用 npm 上提供的一些第三方截图库。 one I found 需要在 linux 上安装 ImageMagick,但可能还有更多,或者您不需要支持 linux。您需要在主电子流程中执行此操作,您可以在其中执行您可以在节点中执行的任何操作。

    【讨论】:

    • 我看到了那个博客,但我误解了它。我以为它是嵌入到 html 中,但它正在创建一个不可见的 div 来临时从中获取快照...感谢您的澄清。
    • 请注意,如果您从视频捕获中获得一些帧,您会遇到这个stackoverflow.com/questions/65270137/…
    猜你喜欢
    • 1970-01-01
    • 2019-02-12
    • 2021-06-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-09-23
    相关资源
    最近更新 更多