0

I have a program that takes a robotjs screen capture and saves it to a file, like a 1 fps live stream.

const Jimp=require("jimp");
const robot=require("robotjs");
const fs=require("fs");
setInterval(function(){
    var img=robot.screen.capture();
    new Jimp({
        "data":img.image,
        "width":img.width,
        "height":img.height
    },function(err,image){
        if(err){
            fs.writeFile(__dirname+"/data/screen.png","",function(){});
        }else{
            image.write(__dirname+"/data/screen.png");
        }
    });
},1000);

At the current moment, every second it:

  1. Takes a screen capture
  2. Creates a Jimp instance from that
  3. Writes it to screen.png

I can't think of any obvious reason for why this would cause some colors to be inverted when I take a screen capture.

For example, when I look at the image after visiting Stack Overflow, the Stack Overflow icon looks blue instead of the usual orange, and after waiting a second (so that it can take a screenshot of me looking at the screenshot), in the screenshot in the screenshot, the colors are back to normal - the original orange SO logo. The screenshot in the screenshot in the screenshot is blue again, and so on. An important thing to note is that not all colors are inversed - the logo is, but the white background isn't.

I run this file (app.js) with node app.js. One thing I tried is to create a Jimp instance from the robotjs screenshot, and then create a Jimp instance from the Jimp instance, so that hopefully the colors would get reversed back, but it looks the same. I am guessing that the problem has something to do with the robotjs image data, but I can't be sure.

How would I get an unaltered screenshot and save it to a file?

Edit:

Here's an example:

Normal (not inverted) colors:

Normal (not inverted) colors

Inverted colors:

Inverted colors

Lakshya Raj
  • 1,669
  • 3
  • 10
  • 34
  • I don't know anything about robotjs or jimp, but you might look into how they write/expect their color channels. It might be the case that robotjs outputs an image in BGR and jimp expects RGB or vice-versa in which case you'd need to convert between the two. – Chris Aug 09 '21 at 21:21
  • @Chris: That's what I was thinking too - as you can see in the top right of the image, the magenta in the gradient remains the same - #ff00ff is the same in RGB and BGR. Blue #0000ff always becomes #ff0000 and vice versa. – Lakshya Raj Aug 09 '21 at 21:23

1 Answers1

2

The buffer from robotjs is in the format BGRA (Blue, Green, Red, Alpha/Opacity). Before, it took about 100 to 150 ms to take a screenshot and save, and now it takes 250 to 300 ms after converting to RGBA (which Jimp uses). It got 150 ms slower, but it works. Here is the full code:

const Jimp=require("jimp");
const robot=require("robotjs");
const fs=require("fs");
setInterval(function(){
    var img=robot.screen.capture();
    var data=[];
    var bitmap=img.image;
    var i=0,l=bitmap.length;
    for(i=0;i<l;i+=4){
        data.push(bitmap[i+2],bitmap[i+1],bitmap[i],bitmap[i+3]);
    }
    new Jimp({
        "data":new Uint8Array(data),
        "width":img.width,
        "height":img.height
    },function(err,image){
        if(err){
            fs.writeFile(__dirname+"/data/screen.png","",function(){});
        }else{
            image.write(__dirname+"/data/screen.png");
        }
    });
},1000);

Side note: this is optimized code. Before, I used a piece of code which made a copy of img.image into data and then used a forEach to loop over every element and make necessary changes on the way. That was very slow, at around 800 ms to execute. If you know of any faster way, please comment, or better, edit the answer.

Lakshya Raj
  • 1,669
  • 3
  • 10
  • 34