1515 #include <string.h>
1616#endif
1717
18+ #if defined(IS_MACOSX )
19+ #elif defined(IS_WINDOWS )
20+ static void destroyMMBitmapWindowsDIB (char * bitmapBuffer , void * hint )
21+ {
22+ if (hint != NULL ) {
23+ DeleteObject ((HGDIOBJ )hint );
24+ }
25+ }
26+ #endif
27+
1828MMBitmapRef copyMMBitmapFromDisplayInRect (MMRect rect )
1929{
2030#if defined(IS_MACOSX )
2131
2232 MMBitmapRef bitmap = NULL ;
33+ CGContextRef context = NULL ;
34+ CGColorSpaceRef colorSpace = NULL ;
2335 uint8_t * buffer = NULL ;
24- size_t bufferSize = 0 ;
36+ const size_t width = rect .size .width ;
37+ const size_t height = rect .size .height ;
38+ const size_t bytesPerPixel = 4 ;
39+ const size_t bytesPerRow = width * bytesPerPixel ;
2540
2641 CGDirectDisplayID displayID = CGMainDisplayID ();
2742
@@ -33,23 +48,54 @@ MMBitmapRef copyMMBitmapFromDisplayInRect(MMRect rect)
3348
3449 if (!image ) { return NULL ; }
3550
36- CFDataRef imageData = CGDataProviderCopyData (CGImageGetDataProvider (image ));
51+ colorSpace = CGColorSpaceCreateWithName (kCGColorSpaceSRGB );
52+ if (colorSpace == NULL ) {
53+ CGImageRelease (image );
54+ return NULL ;
55+ }
3756
38- if (!imageData ) { return NULL ; }
57+ buffer = calloc (height , bytesPerRow );
58+ if (buffer == NULL ) {
59+ CGColorSpaceRelease (colorSpace );
60+ CGImageRelease (image );
61+ return NULL ;
62+ }
3963
40- bufferSize = CFDataGetLength (imageData );
41- buffer = malloc (bufferSize );
64+ context = CGBitmapContextCreate (buffer ,
65+ width ,
66+ height ,
67+ 8 ,
68+ bytesPerRow ,
69+ colorSpace ,
70+ kCGImageAlphaNoneSkipFirst |
71+ kCGBitmapByteOrder32Little );
72+ if (context == NULL ) {
73+ free (buffer );
74+ CGColorSpaceRelease (colorSpace );
75+ CGImageRelease (image );
76+ return NULL ;
77+ }
4278
43- CFDataGetBytes (imageData , CFRangeMake (0 ,bufferSize ), buffer );
79+ /* RobotJS bitmaps use a top-left origin. Flip the Quartz context so the
80+ * captured image keeps that coordinate system after color conversion. */
81+ CGContextTranslateCTM (context , 0 , height );
82+ CGContextScaleCTM (context , 1 , -1 );
83+ CGContextSetBlendMode (context , kCGBlendModeCopy );
84+ CGContextSetInterpolationQuality (context , kCGInterpolationNone );
85+ CGContextDrawImage (context , CGRectMake (0 , 0 , width , height ), image );
4486
4587 bitmap = createMMBitmap (buffer ,
46- CGImageGetWidth (image ),
47- CGImageGetHeight (image ),
48- CGImageGetBytesPerRow (image ),
49- CGImageGetBitsPerPixel (image ),
50- CGImageGetBitsPerPixel (image ) / 8 );
88+ width ,
89+ height ,
90+ bytesPerRow ,
91+ 32 ,
92+ 4 );
93+ if (bitmap == NULL ) {
94+ free (buffer );
95+ }
5196
52- CFRelease (imageData );
97+ CGContextRelease (context );
98+ CGColorSpaceRelease (colorSpace );
5399
54100 CGImageRelease (image );
55101
@@ -85,6 +131,7 @@ MMBitmapRef copyMMBitmapFromDisplayInRect(MMRect rect)
85131 void * data ;
86132 HDC screen = NULL , screenMem = NULL ;
87133 HBITMAP dib ;
134+ HGDIOBJ previousObject = NULL ;
88135 BITMAPINFO bi ;
89136
90137 /* Initialize bitmap info. */
@@ -105,10 +152,15 @@ MMBitmapRef copyMMBitmapFromDisplayInRect(MMRect rect)
105152
106153 /* Get screen data in display device context. */
107154 dib = CreateDIBSection (screen , & bi , DIB_RGB_COLORS , & data , NULL , 0 );
155+ if (dib == NULL || data == NULL ) {
156+ if (dib != NULL ) DeleteObject (dib );
157+ ReleaseDC (NULL , screen );
158+ return NULL ;
159+ }
108160
109161 /* Copy the data into a bitmap struct. */
110162 if ((screenMem = CreateCompatibleDC (screen )) == NULL ||
111- SelectObject (screenMem , dib ) == NULL ||
163+ ( previousObject = SelectObject (screenMem , dib ) ) == NULL ||
112164 !BitBlt (screenMem ,
113165 (int )0 ,
114166 (int )0 ,
@@ -127,21 +179,22 @@ MMBitmapRef copyMMBitmapFromDisplayInRect(MMRect rect)
127179 return NULL ;
128180 }
129181
130- bitmap = createMMBitmap (NULL ,
131- rect .size .width ,
132- rect .size .height ,
133- 4 * rect .size .width ,
134- (uint8_t )bi .bmiHeader .biBitCount ,
135- 4 );
136-
137- /* Copy the data to our pixel buffer. */
138- if (bitmap != NULL ) {
139- bitmap -> imageBuffer = malloc (bitmap -> bytewidth * bitmap -> height );
140- memcpy (bitmap -> imageBuffer , data , bitmap -> bytewidth * bitmap -> height );
182+ bitmap = createMMBitmapWithCleanup ((uint8_t * )data ,
183+ rect .size .width ,
184+ rect .size .height ,
185+ 4 * rect .size .width ,
186+ (uint8_t )bi .bmiHeader .biBitCount ,
187+ 4 ,
188+ destroyMMBitmapWindowsDIB ,
189+ dib );
190+ if (previousObject != NULL ) {
191+ SelectObject (screenMem , previousObject );
192+ }
193+ if (bitmap == NULL ) {
194+ DeleteObject (dib );
141195 }
142196
143197 ReleaseDC (NULL , screen );
144- DeleteObject (dib );
145198 DeleteDC (screenMem );
146199
147200 return bitmap ;
0 commit comments