Search code examples
javascriptnode.jscolorsjimprobotjs

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


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


Solution

  • 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.