Last active
October 6, 2022 05:43
-
-
Save IAmJSD/202a8924b2b06832380cbf2b9e1b09da to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <nan.h> | |
#include <node.h> | |
#include <X11/Xlib.h> | |
#include <X11/extensions/Xrandr.h> | |
using namespace v8; | |
void GetScreenshot(const Nan::FunctionCallbackInfo<Value>& args) { | |
// Get both expected arguments as integers. | |
Isolate* isolate = args.GetIsolate(); | |
if (args.Length() != 2) { | |
isolate->ThrowException(Exception::Error(String::NewFromUtf8(isolate, "Wrong number of arguments").ToLocalChecked())); | |
return; | |
} | |
Local<Value> firstArg = args[0]; | |
if (!firstArg->IsNumber()) { | |
isolate->ThrowException(Exception::Error(String::NewFromUtf8(isolate, "Argument is not a number").ToLocalChecked())); | |
return; | |
} | |
int boundsX = firstArg.As<Number>()->Value(); | |
Local<Value> secondArg = args[1]; | |
if (!firstArg->IsNumber()) { | |
isolate->ThrowException(Exception::Error(String::NewFromUtf8(isolate, "Argument is not a number").ToLocalChecked())); | |
return; | |
} | |
int boundsY = secondArg.As<Number>()->Value(); | |
// Get the display and its default screen. Note screens are not monitors! | |
Display* display = XOpenDisplay(NULL); | |
Screen* screen = DefaultScreenOfDisplay(display); | |
if (!screen) { | |
isolate->ThrowException(Exception::Error(String::NewFromUtf8(isolate, "Could not get default screen").ToLocalChecked())); | |
return; | |
} | |
// Get the screens root window. This will be what we want to capture. | |
Window win = XRootWindowOfScreen(screen); | |
// Find a monitor that matches the top-left corner we were given. | |
bool found = false; | |
int monitorCount; | |
XRRMonitorInfo monitor; | |
XRRMonitorInfo* monitors = XRRGetMonitors(display, win, true, &monitorCount); | |
for (int i = 0; i < monitorCount; i++) { | |
// Get the monitor. | |
monitor = monitors[i]; | |
// Handle checking the top left. | |
if (monitor.x == boundsX && monitor.y == boundsY) { | |
printf("matched monitor at x: %d, y: %d\n", monitor.x, monitor.y); | |
found = true; | |
} else { | |
printf("scanned monitor at x: %d, y: %d - no match!\n", monitor.x, monitor.y); | |
} | |
// At the end of everything, break. | |
if (found) { | |
break; | |
} | |
} | |
XFree(monitors); | |
// If said monitor was not found, throw an error. | |
if (!found) { | |
isolate->ThrowException(Exception::Error(String::NewFromUtf8(isolate, "Could not find monitor").ToLocalChecked())); | |
return; | |
} | |
// Get the image from the window. | |
XImage* image = XGetImage(display, win, monitor.x, monitor.y, monitor.width, monitor.height, AllPlanes, ZPixmap); | |
XCloseDisplay(display); | |
if (image == NULL) { | |
isolate->ThrowException(Exception::Error(String::NewFromUtf8(isolate, "Could not get image").ToLocalChecked())); | |
return; | |
} | |
// Create a new allocation and turn it into RGBA. | |
size_t size = image->width * image->height * 4; | |
uint8_t* bytes = new uint8_t[size]; | |
for (int blockStart = 0; blockStart < size; blockStart += 4) { | |
bytes[blockStart] = image->data[blockStart + 2]; | |
bytes[blockStart + 1] = image->data[blockStart + 1]; | |
bytes[blockStart + 2] = image->data[blockStart]; | |
bytes[blockStart + 3] = image->data[blockStart + 3]; | |
} | |
// Create an array buffer from this new allocation and free the old image. | |
Nan::MaybeLocal<Object> buf = Nan::NewBuffer((char*)bytes, size); | |
XFree(image); | |
// Set the buffer as the return value. | |
args.GetReturnValue().Set(buf.ToLocalChecked()); | |
} | |
void Initialize(Local<Object> exports) { | |
Local<Context> context = exports->CreationContext(); | |
exports->Set(context, | |
Nan::New("getScreenshotForBounds").ToLocalChecked(), | |
Nan::New<FunctionTemplate>(GetScreenshot) | |
->GetFunction(context) | |
.ToLocalChecked()); | |
} | |
NODE_MODULE(NODE_GYP_MODULE_NAME, Initialize) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment