4

It is posible to copy in real time the image of a element in BrowserWindow rendered at 60fps to other multiple BrowserWindows in Atom Electron?

3 visible browserWindow

Ciberman
  • 580
  • 7
  • 23
  • I don't know electron, but how are linked your different windows ? Are the others *BrowserWindow* accessible from the Master window ? (e.g is it the result of `window.open` ?) In this case, if you can access the canvas' context of the other pages, you can simply use `drawImage` : http://plnkr.co/edit/jDzbtPYrYItQ4peplOAN?p=preview – Kaiido Feb 14 '17 at 07:28
  • 1
    @Kaiido, no, in Electron it's not that easy. Each browserwindow is a separate process. – Ciberman Feb 14 '17 at 07:30
  • One other approach would be webRTC then (I don't know electron support for it). You can get your canvas stream directly from [`canvas.captureStream(fps)`](https://developer.mozilla.org/en-US/docs/Web/API/HTMLCanvasElement/captureStream), then just render the stream in an hidden video that you'll be able to draw on your different canvases. – Kaiido Feb 14 '17 at 07:39
  • Electron supports it. But I have never used it. You can pass the data in a raw format or do you need to compress it? (I am worried about the performance of the app) – Ciberman Feb 14 '17 at 07:42
  • 1
    It is encoded to a raw video format. You don't have to compress anything, the browser does handle it, at the end, it's just a video stream, not a canvas image anymore. – Kaiido Feb 14 '17 at 07:46
  • @ciberman did you get any further with this? I'm considering migrating from nwjs to electron with a very similar use case and this is the main obstacle. – AlexKempton Oct 24 '17 at 10:22

2 Answers2

3

Option 1: Use window.open()

As of May 2017, it is now possible to open a new window in Electron using window.open(), in a similar way to how nwjs does it. This means there is no need to worry about sending the image over different processes. See the electron documentation for more details. With a DOM reference to the canvas in the new window, you can easily copy the image from the old canvas every frame.

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

Option 2: Use WebRTC

You can do a stream from a canvas to a video element via WebRTC, locally between two windows. My solution is based on an answer to a related question as well as a useful WebRTC canvas example. Open the below two links and click connect.

The canvas to be streamed: https://jsfiddle.net/f5y48hcd/26/

var stream = canvas.captureStream();
    
...

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

The video element receiving the stream: https://jsfiddle.net/rfqhwo4z/10/

pc.ontrack = gotRemoteStream;

...

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

Please note that you'll need the canvas tab actively running for it to be animating on the video tab. I'm yet to test this in an electron build.

Glorfindel
  • 21,988
  • 13
  • 81
  • 109
AlexKempton
  • 1,648
  • 15
  • 28
  • Wow! I will try it this week with electron and tell you the results. Thanks! – Ciberman Oct 24 '17 at 19:03
  • I have tested it in electron and it works perfect! For those users interested, I have copied the provided jsfiddle code in two html files and spawned two windows from the main process (the `streamer.html` with `show:false` and the `receiver.html` with `show:true`) and it works perfect. Thanks! – Ciberman Oct 31 '17 at 07:20
  • Fantastic. I'd love to hear about what you're building, I don't know many people with with such a similar technical requirement to me! If you're interested, you can contact me via alex@funwithtriangles.net. – AlexKempton Oct 31 '17 at 11:16
  • @Ciberman it turns out there is a much easier way to do this now! See my edit above. – AlexKempton Nov 06 '17 at 13:13
  • Wooow. You are a genius. Thanks! I will try it out. – Ciberman Nov 06 '17 at 13:33
  • Update. (Yeah, half a year later). I have tried both methods. With the RTC method I obtain 30 fps. With the window.open() method I get >= 60 fps... So, I will use that. – Ciberman Jun 28 '18 at 09:09
0

How about creating a Unix socket and piping the bytes to that and reading it from your other process?:

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 Otherwise you could just open a socket on a port and communicate over that.

The main reason you don't want data going from the BrowserWindow back and forth to the main process is that your BrowserWindow handles stuff like window position and OS events so you don't want to slow it down by streaming your data through it.

PaulBGD
  • 2,018
  • 5
  • 22
  • 30
  • 1
    How do you get and set the bytes from a canvas? As far as I know, ctx.putImageData and ctx.getImageData are too slow to be executed at 60fps. – Ciberman Feb 14 '17 at 07:34
  • 1
    @Ciberman, these methods are slow, but you can do it @ 60fps on most modern machines (assuming your canvas is not 5000*5000px wide). Even if it is one of the slowest method in canvas2D API, it's still fast enough if you do it once per frame. – Kaiido Feb 14 '17 at 07:37
  • Yes. But my canvas is 1080p. And I have to copy to 3-4 external display (canvas). I am migrating my project from nwjs to Electron. In nwjs I can do this without problem. – Ciberman Feb 14 '17 at 07:39
  • 1
    Well 1920*1080 is quite small, I guess you've got more RAM than 4*15kb. If all you do on the other windows is render it, then GC will kick in-between the frames and you won't notice anything. – Kaiido Feb 14 '17 at 07:44