Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix screen capture for Mac. #242

Merged
merged 14 commits into from
Oct 16, 2016
7 changes: 4 additions & 3 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,12 @@ function bitmap(width, height, byteWidth, bitsPerPixel, bytesPerPixel, image)
this.bitsPerPixel = bitsPerPixel;
this.bytesPerPixel = bytesPerPixel;
this.image = image;

this.colorAt = function(x, y)
{
return robotjs.getColor(this, x, y);
};

}

module.exports.screen.capture = function(x, y, width, height)
Expand All @@ -30,6 +31,6 @@ module.exports.screen.capture = function(x, y, width, height)
{
b = robotjs.captureScreen();
}

return new bitmap(b.width, b.height, b.byteWidth, b.bitsPerPixel, b.bytesPerPixel, b.image);
};
};
9 changes: 9 additions & 0 deletions src/bmp_io.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,11 @@
#include "MMBitmap.h"
#include "io.h"

#ifdef __cplusplus
extern "C"
{
#endif

enum _BMPReadError {
kBMPGenericError = 0,
kBMPAccessError,
Expand Down Expand Up @@ -51,4 +56,8 @@ int saveMMBitmapAsBMP(MMBitmapRef bitmap, const char *path);
*/
void flipBitmapData(void *data, size_t width, size_t height, size_t bytewidth);

#ifdef __cplusplus
}
#endif

#endif /* BMP_IO_H */
9 changes: 9 additions & 0 deletions src/io.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@
#include <stddef.h>
#include <stdint.h>

#ifdef __cplusplus
extern "C"
{
#endif

enum _MMImageType {
kInvalidImageType = 0,
Expand Down Expand Up @@ -43,4 +47,9 @@ int saveMMBitmapToFile(MMBitmapRef bitmap, const char *path, MMImageType type);
* Returned string is constant and hence should not be freed. */
const char *MMIOErrorString(MMImageType type, MMIOError error);

#ifdef __cplusplus
}
#endif


#endif /* IO_H */
86 changes: 43 additions & 43 deletions src/robotjs.cc
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@ int mouseDelay = 10;
int keyboardDelay = 10;

/*
__ __
| \/ | ___ _ _ ___ ___
__ __
| \/ | ___ _ _ ___ ___
| |\/| |/ _ \| | | / __|/ _ \
| | | | (_) | |_| \__ \ __/
|_| |_|\___/ \__,_|___/\___|
Expand Down Expand Up @@ -241,21 +241,21 @@ NAN_METHOD(setMouseDelay)
info.GetReturnValue().Set(Nan::New(1));
}

NAN_METHOD(scrollMouse)
NAN_METHOD(scrollMouse)
{
Nan::HandleScope scope;

//Get the values of magnitude and direction from the arguments list.
if(info.Length() == 2)
if(info.Length() == 2)
{
int scrollMagnitude = info[0]->Int32Value();
char *s;

Nan::Utf8String sstr(info[1]);
s = *sstr;

MMMouseWheelDirection scrollDirection;

if (strcmp(s, "up") == 0)
{
scrollDirection = DIRECTION_UP;
Expand All @@ -268,26 +268,26 @@ NAN_METHOD(scrollMouse)
{
return Nan::ThrowError("Invalid scroll direction specified.");
}

scrollMouse(scrollMagnitude, scrollDirection);
microsleep(mouseDelay);

info.GetReturnValue().Set(Nan::New(1));
}
else
}
else
{
return Nan::ThrowError("Invalid number of arguments.");
}
}
/*
_ __ _ _
_ __ _ _
| |/ /___ _ _| |__ ___ __ _ _ __ __| |
| ' // _ \ | | | '_ \ / _ \ / _` | '__/ _` |
| . \ __/ |_| | |_) | (_) | (_| | | | (_| |
|_|\_\___|\__, |_.__/ \___/ \__,_|_| \__,_|
|___/
|___/
*/
struct KeyNames
struct KeyNames
{
const char* name;
MMKeyCode key;
Expand Down Expand Up @@ -340,7 +340,7 @@ static KeyNames key_names[] =
{ "space", K_SPACE },
{ "printscreen", K_PRINTSCREEN },
{ "insert", K_INSERT },

{ "audio_mute", K_AUDIO_VOLUME_MUTE },
{ "audio_vol_down", K_AUDIO_VOLUME_DOWN },
{ "audio_vol_up", K_AUDIO_VOLUME_UP },
Expand All @@ -364,7 +364,7 @@ static KeyNames key_names[] =
{ "numpad_7", K_NUMPAD_7 },
{ "numpad_8", K_NUMPAD_8 },
{ "numpad_9", K_NUMPAD_9 },

{ "lights_mon_up", K_LIGHTS_MON_UP },
{ "lights_mon_down", K_LIGHTS_MON_DOWN },
{ "lights_kbd_toggle",K_LIGHTS_KBD_TOGGLE },
Expand All @@ -387,7 +387,7 @@ int CheckKeyCodes(char* k, MMKeyCode *key)
*key = K_NOT_A_KEY;

KeyNames* kn = key_names;
while (kn->name)
while (kn->name)
{
if (strcmp(k, kn->name) == 0)
{
Expand All @@ -397,7 +397,7 @@ int CheckKeyCodes(char* k, MMKeyCode *key)
kn++;
}

if (*key == K_NOT_A_KEY)
if (*key == K_NOT_A_KEY)
{
return -2;
}
Expand Down Expand Up @@ -605,9 +605,9 @@ NAN_METHOD(typeStringDelayed)
{
char *str;
Nan::Utf8String string(info[0]);

str = *string;

size_t cpm = info[1]->Int32Value();

typeStringDelayed(str, cpm);
Expand All @@ -628,12 +628,12 @@ NAN_METHOD(setKeyboardDelay)
}

/*
____
/ ___| ___ _ __ ___ ___ _ __
\___ \ / __| '__/ _ \/ _ \ '_ \
____
/ ___| ___ _ __ ___ ___ _ __
\___ \ / __| '__/ _ \/ _ \ '_ \
___) | (__| | | __/ __/ | | |
|____/ \___|_| \___|\___|_| |_|

*/

/**
Expand All @@ -654,7 +654,7 @@ NAN_METHOD(getPixelColor)
{
return Nan::ThrowError("Invalid number of arguments.");
}

MMBitmapRef bitmap;
MMRGBHex color;

Expand All @@ -669,9 +669,9 @@ NAN_METHOD(getPixelColor)
bitmap = copyMMBitmapFromDisplayInRect(MMRectMake(x, y, 1, 1));

color = MMRGBHexAtPoint(bitmap, 0, 0);

char hex[7];

padHex(color, hex);

destroyMMBitmap(bitmap);
Expand Down Expand Up @@ -714,18 +714,18 @@ NAN_METHOD(setXDisplayName)
#endif
}

NAN_METHOD(captureScreen)
NAN_METHOD(captureScreen)
{
size_t x;
size_t y;
size_t w;
size_t h;
//If user has provided screen coords, use them!

//If user has provided screen coords, use them!
if (info.Length() == 4)
{
//TODO: Make sure requested coords are within the screen bounds, or we get a seg fault.
// An error message is much nicer!
// An error message is much nicer!

x = info[0]->Int32Value();
y = info[1]->Int32Value();
Expand All @@ -737,15 +737,15 @@ NAN_METHOD(captureScreen)
//We're getting the full screen.
x = 0;
y = 0;

//Get screen size.
MMSize displaySize = getMainDisplaySize();
w = displaySize.width;
h = displaySize.height;
}

MMBitmapRef bitmap = copyMMBitmapFromDisplayInRect(MMRectMake(x, y, w, h));

uint32_t bufferSize = bitmap->bytewidth * bitmap->height;
Local<Object> buffer = Nan::NewBuffer((char*)bitmap->imageBuffer, bufferSize, destroyMMBitmapBuffer, NULL).ToLocalChecked();

Expand All @@ -756,17 +756,17 @@ NAN_METHOD(captureScreen)
Nan::Set(obj, Nan::New("bitsPerPixel").ToLocalChecked(), Nan::New<Number>(bitmap->bitsPerPixel));
Nan::Set(obj, Nan::New("bytesPerPixel").ToLocalChecked(), Nan::New<Number>(bitmap->bytesPerPixel));
Nan::Set(obj, Nan::New("image").ToLocalChecked(), buffer);

info.GetReturnValue().Set(obj);
}

/*
____ _ _
| __ )(_) |_ _ __ ___ __ _ _ __
| _ \| | __| '_ ` _ \ / _` | '_ \
____ _ _
| __ )(_) |_ _ __ ___ __ _ _ __
| _ \| | __| '_ ` _ \ / _` | '_ \
| |_) | | |_| | | | | | (_| | |_) |
|____/|_|\__|_| |_| |_|\__,_| .__/
|_|
|____/|_|\__|_| |_| |_|\__,_| .__/
|_|
*/

class BMP
Expand All @@ -781,7 +781,7 @@ class BMP
};

//Convert object from Javascript to a C++ class (BMP).
BMP buildBMP(Local<Object> info)
BMP buildBMP(Local<Object> info)
{
Local<Object> obj = Nan::To<v8::Object>(info).ToLocalChecked();

Expand Down Expand Up @@ -853,7 +853,7 @@ NAN_MODULE_INIT(InitAll)

Nan::Set(target, Nan::New("mouseToggle").ToLocalChecked(),
Nan::GetFunction(Nan::New<FunctionTemplate>(mouseToggle)).ToLocalChecked());

Nan::Set(target, Nan::New("scrollMouse").ToLocalChecked(),
Nan::GetFunction(Nan::New<FunctionTemplate>(scrollMouse)).ToLocalChecked());

Expand All @@ -880,10 +880,10 @@ NAN_MODULE_INIT(InitAll)

Nan::Set(target, Nan::New("getScreenSize").ToLocalChecked(),
Nan::GetFunction(Nan::New<FunctionTemplate>(getScreenSize)).ToLocalChecked());

Nan::Set(target, Nan::New("captureScreen").ToLocalChecked(),
Nan::GetFunction(Nan::New<FunctionTemplate>(captureScreen)).ToLocalChecked());

Nan::Set(target, Nan::New("getColor").ToLocalChecked(),
Nan::GetFunction(Nan::New<FunctionTemplate>(getColor)).ToLocalChecked());

Expand Down
60 changes: 24 additions & 36 deletions src/screengrab.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,54 +19,42 @@ MMBitmapRef copyMMBitmapFromDisplayInRect(MMRect rect)
{
#if defined(IS_MACOSX)

size_t bytewidth;
uint8_t bitsPerPixel, bytesPerPixel;
//uint8_t *buffer;
MMBitmapRef bitmap = NULL;
uint8_t *buffer = NULL;
size_t bufferSize = 0;

CGDirectDisplayID displayID = CGMainDisplayID();

//Replacement for CGDisplayBitsPerPixel.
CGDisplayModeRef mode = CGDisplayCopyDisplayMode(displayID);
size_t depth = 0;
CGImageRef image = CGDisplayCreateImageForRect(displayID,
CGRectMake(rect.origin.x,
rect.origin.y,
rect.size.width,
rect.size.height));

CFStringRef pixEnc = CGDisplayModeCopyPixelEncoding(mode);
if(CFStringCompare(pixEnc, CFSTR(IO32BitDirectPixels), kCFCompareCaseInsensitive) == kCFCompareEqualTo)
depth = 32;
else if(CFStringCompare(pixEnc, CFSTR(IO16BitDirectPixels), kCFCompareCaseInsensitive) == kCFCompareEqualTo)
depth = 16;
else if(CFStringCompare(pixEnc, CFSTR(IO8BitIndexedPixels), kCFCompareCaseInsensitive) == kCFCompareEqualTo)
depth = 8;
if (!image) { return NULL; }

CGDisplayModeRelease(mode);
CFRelease(pixEnc);
CFDataRef imageData = CGDataProviderCopyData(CGImageGetDataProvider(image));

bitsPerPixel = (uint8_t) depth;
bytesPerPixel = bitsPerPixel / 8;
/* Align width to padding. */
//bytewidth = ADD_PADDING(rect.size.width * bytesPerPixel);
bytewidth = rect.size.width * bytesPerPixel;
if (!imageData) { return NULL; }

/* Convert Quartz point to postscript point. */
//rect.origin.y = CGDisplayPixelsHigh(displayID) - rect.origin.y - rect.size.height;
bufferSize = CFDataGetLength(imageData);
buffer = malloc(bufferSize);

CGImageRef image = CGDisplayCreateImageForRect(displayID, CGRectMake(rect.origin.x, rect.origin.y, rect.size.width, rect.size.height));
CFDataGetBytes(imageData, CFRangeMake(0,bufferSize), buffer);

// Request access to the raw pixel data via the image's DataProvider.
CGDataProviderRef provider = CGImageGetDataProvider(image);
CFDataRef data = CGDataProviderCopyData(provider);
bitmap = createMMBitmap(buffer,
CGImageGetWidth(image),
CGImageGetHeight(image),
CGImageGetBytesPerRow(image),
CGImageGetBitsPerPixel(image),
CGImageGetBitsPerPixel(image) / 8);

size_t width, height;
width = CGImageGetWidth(image);
height = CGImageGetHeight(image);
size_t bpp = CGImageGetBitsPerPixel(image) / 8;
CFRelease(imageData);

uint8 *pixels = malloc(width * height * bpp);
memcpy(pixels, CFDataGetBytePtr(data), width * height * bpp);
CFRelease(data);
CGImageRelease(image);
CGImageRelease(image);

return bitmap;

return createMMBitmap(pixels, rect.size.width, rect.size.height, bytewidth,
bitsPerPixel, bytesPerPixel);
#elif defined(USE_X11)
MMBitmapRef bitmap;

Expand Down
Loading