在 Atom Electron 中以 60fps 将 <canvas> 图像从 BrowserWindow 复制到另一个

Posted

技术标签:

【中文标题】在 Atom Electron 中以 60fps 将 <canvas> 图像从 BrowserWindow 复制到另一个【英文标题】:Copy <canvas> image from a BrowserWindow to another at 60fps in Atom Electron 【发布时间】:2017-02-14 05:30:50 【问题描述】:

是否可以将 BrowserWindow 中以 60fps 渲染的元素图像实时复制到 Atom Electron 中的其他多个 BrowserWindow?

【问题讨论】:

我不知道电子,但是你的不同窗口是如何链接的?其他 BrowserWindow 是否可以从主窗口访问? (例如它是window.open 的结果吗?)在这种情况下,如果您可以访问其他页面的画布上下文,您可以简单地使用drawImage:plnkr.co/edit/jDzbtPYrYItQ4peplOAN?p=preview @Kaiido,不,在 Electron 中这并不容易。每个浏览器窗口都是一个单独的进程。 那么另一种方法是 webRTC(我不知道电子支持它)。您可以直接从 canvas.captureStream(fps) 获取您的画布流,然后只需在隐藏视频中渲染流,您就可以在不同的画布上绘制。 Electron 支持它。但我从未使用过它。您可以以原始格式传递数据还是需要对其进行压缩? (我担心应用程序的性能) 它被编码为原始视频格式。您不必压缩任何东西,浏览器会处理它,最后,它只是一个视频流,不再是画布图像。 【参考方案1】:

选项 1:使用window.open()

截至 2017 年 5 月,现在可以使用 window.open() 在 Electron 中打开一个新窗口,其方式与 nwjs 的操作方式类似。这意味着无需担心通过不同的进程发送图像。有关详细信息,请参阅electron documentation。通过在新窗口中对画布的 DOM 引用,您可以轻松地在每一帧中从旧画布中复制图像。

newCanvas.drawImage(oldCanvas, 0, 0, width, height)

选项 2:使用 WebRTC

您可以在两个窗口之间本地通过 WebRTC 从画布流式传输到视频元素。我的解决方案基于对related question 以及有用的WebRTC canvas example 的回答。打开以下两个链接并点击连接。

要流式传输的画布: https://jsfiddle.net/f5y48hcd/26/

var stream = canvas.captureStream();

...

stream.getTracks().forEach(
    function(track) 
      pc.addTrack(
        track,
        stream
      );
    
);

接收流的视频元素: https://jsfiddle.net/rfqhwo4z/10/

pc.ontrack = gotRemoteStream;

...

function gotRemoteStream(e) 
  if (video.srcObject !== e.streams[0]) 
    video.srcObject = e.streams[0];
  

请注意,您需要画布选项卡主动运行,才能在视频选项卡上生成动画。我还没有在电子版本中对此进行测试。

【讨论】:

哇!这周我会用电子试试,然后告诉你结果。谢谢! ??? 我已经在电子中测试过它,它运行完美!对于那些感兴趣的用户,我已经将提供的 jsfiddle 代码复制到两个 html 文件中,并从主进程中生成了两个窗口(@98​​7654331@ 和 show:falsereceiver.htmlshow:true),它运行良好。谢谢! 太棒了。我很想听听您正在构建什么,我不知道有多少人和我有类似的技术要求!如果您有兴趣,可以通过 alex@funwithtriangles.net 与我联系。 @Ciberman 事实证明现在有一种更简单的方法可以做到这一点!请参阅上面的编辑。 哇。你是个天才。谢谢!我会试试看。【参考方案2】:

如何创建一个 Unix 套接字并将字节传送到该套接字并从您的其他进程中读取它?:

var net = require('net');

// This server listens on a Unix socket at /var/run/mysocket
var unixServer = net.createServer(function(client) 
    // Do something with the client connection
);
unixServer.listen('/var/run/mysocket');

https://nodejs.org/api/net.html 否则,您可以在端口上打开一个套接字并通过它进行通信。

您不希望数据从 BrowserWindow 来回传输到主进程的主要原因是您的 BrowserWindow 处理窗口位置和操作系统事件等内容,因此您不想通过流式传输数据来减慢速度它。

【讨论】:

如何从画布中获取和设置字节?据我所知,ctx.putImageData 和 ctx.getImageData 速度太慢,无法以 60fps 执行。 @Ciberman,这些方法很慢,但您可以在大多数现代机器上以 60fps 的速度进行操作(假设您的画布不是 5000*5000px 宽)。即使它是 canvas2D API 中最慢的方法之一,如果您每帧执行一次,它仍然足够快。 是的。但我的画布是 1080p。而且我必须复制到 3-4 个外部显示器(画布)。我正在将我的项目从 nwjs 迁移到 Electron。在 nwjs 中,我可以毫无问题地做到这一点。 嗯 1920*1080 很小,我猜你的 RAM 比 4*15kb 还多。如果你在其他窗口上所做的只是渲染它,那么 GC 将在帧之间启动,你不会注意到任何东西。

以上是关于在 Atom Electron 中以 60fps 将 <canvas> 图像从 BrowserWindow 复制到另一个的主要内容,如果未能解决你的问题,请参考以下文章

Atom Electron - 使用 javascript 关闭窗口

css dark.electron.atom.css

electron入门教程

在 Electron (Atom Shell) 应用程序中存储用户设置的位置?

如何为Electron / Atom Shell App设置应用程序图标

如何为 Electron / Atom Shell App 设置应用程序图标