How can I take a window screenshot in Node.js?

2020-06-16 03:20发布

问题:

I'm in a research to find a way to take a screenshot of a window using Node.js, and I'm trying to do this with node-ffi, but I don't know how... at a time I'm stuck here:

var ffi = require('ffi');

var user32 = new ffi.Library("user32", {
      FindWindowA: [ 'uint32' , [ 'string', 'string' ]]
    , PrintWindow: [ 'int32'  , [ 'int32', 'string', 'int32' ]]
});

var IMG;
var windowHandle = user32.FindWindowA(null, "Calculator");
var printWin = user32.PrintWindow(windowHandle, IMG, 0);

console.log(printWin);
console.log(IMG);

The result:

$ node get-print.js
1
undefined

EDITED

I found the following working code in C++

Bitmap bm = new Bitmap(1024, 768);
Graphics g = Graphics.FromImage(bm);
IntPtr hdc = g.GetHdc();
Form1.PrintWindow(this.Handle, hdc, 0);
g.ReleaseHdc(hdc);
g.Flush();
g.Dispose();
this.pictureBox1.Image = bm;

now I need to do this on NodeJs,

Anyone can help me?

回答1:

Although I don't have full code working, but in theory if you're able to do so in C++, then simply use node-gyp to compile the C++ file to a .node file, then include that in you're nodeJS file.

So some example pseudo-code, first of all make a binding.gyp file in a new directory, and put some code in it like this:

{
  "targets": [
    {
        "target_name": "addon",
        "sources": [ 
            "hi.cc"
        ]
    }
  ]
}

then in that same directory (for now) make another file called hi.cc, and put your C++ code in it, plus some more to make a node module out of it. So, based on the docs mentioned above, you could do something like this (untested):

/*don't know what includes you're using to git the Bitmap 
and  Graphics functions, but include them here */

 /*then to make a node module*/
#include <node.h>

using namespace v8;


void GetImage(const FunctionCallbackInfi<Value>& args) {
    Bitmap bm = new Bitmap(1024, 768);
    Graphics g = Graphics.FromImage(bm);
    IntPtr hdc = g.GetHdc();
    Form1.PrintWindow(this.Handle, hdc, 0);
    g.ReleaseHdc(hdc);
    g.Flush();
    /*
    this is the key part, although I'm not
    100% sure it will work since I don't 
    know exactly what type Graphics returns, 
    but basically just convert it somehow into 
    base64, or a plain old void* value
    (as in this following example), then make a new
    Local variable of it and set the return type
    (or make a function callback). So first get the 
    Graphics variable into a void* of the data, then 
    convert it to an ArrayBuffer to use in NodeJS, based on this
    answer. Anyway:
    */
    Local<
        ArrayBuffer
    > 
    v = 
    ArrayBuffer::New(i, /*some void* value*/ temp, 5000/*or some length*/);
    a.GetReturnValue().Set(v);
}


void Initialize(Local<Object> exports) {
  NODE_SET_METHOD(exports, "hello", GetImage);
}

NODE_MODULE(NODE_GYP_MODULE_NAME, Initialize)

Then make sure you actually have node-gyp and the proper build tools installed (see docs above, but its pretty much npm i -g node-gyp), then go to build -> Release -> addon.node and copy it to your main nodeJS directory, then make a new nodeJS file or include the following in an existing one:

let addon = require("./addon"),
    pictureData = Buffer.from(addon.hello()/* if you choose to return a base64 string instead, then insert: ,"base64"*/);


回答2:

You could use a NPM package called "desktop-screenshot". It's very simple to use.

Example on NPM:

var screenshot = require('desktop-screenshot');

screenshot("screenshot.png", function(error, complete) {
    if(error)
        console.log("Screenshot failed", error);
    else
        console.log("Screenshot succeeded");
});

https://www.npmjs.com/package/desktop-screenshot