0.014 release
[imager-screenshot.git] / scdarwin2.c
CommitLineData
759271f8
TC
1/* Darwin support via Quartz Display Services */
2#include "imext.h"
3#include "imss.h"
4#include <ApplicationServices/ApplicationServices.h>
5
6/* Largely based on:
7
8http://stackoverflow.com/questions/448125/how-to-get-pixel-data-from-a-uiimage-cocoa-touch-or-cgimage-core-graphics
9
10*/
11
12i_img *
13imss_darwin(i_img_dim left, i_img_dim top, i_img_dim right, i_img_dim bottom) {
14 i_clear_error();
15 CGDirectDisplayID disp = CGMainDisplayID();
16 if (!disp) {
17 i_push_error(0, "No main display");
18 return NULL;
19 }
20
21 /* for now, only interested in the first display */
22 CGRect rect = CGDisplayBounds(disp);
23 i_img_dim screen_width = rect.size.width;
24 i_img_dim screen_height = rect.size.height;
25
26 /* adjust negative/zero values to window size */
27 if (left < 0)
28 left += screen_width;
29 if (top < 0)
30 top += screen_height;
31 if (right <= 0)
32 right += screen_width;
33 if (bottom <= 0)
34 bottom += screen_height;
35
36 /* clamp */
37 if (left < 0)
38 left = 0;
39 if (right > screen_width)
40 right = screen_width;
41 if (top < 0)
42 top = 0;
43 if (bottom > screen_height)
44 bottom = screen_height;
45
46 /* validate */
47 if (right <= left || bottom <= top) {
48 i_push_error(0, "image would be empty");
49 return NULL;
50 }
51
52 i_img_dim width = right - left;
53 i_img_dim height = bottom - top;
54
55 CGRect cap_rect;
56 cap_rect.origin.x = left;
57 cap_rect.origin.y = top; /* flipped relative to I::S API */
58 cap_rect.size.width = width;
59 cap_rect.size.height = height;
60
61 CGImageRef image = CGDisplayCreateImageForRect(disp, cap_rect);
62 if (!image) {
63 i_push_error(0, "CGDisplayCreateImageForRect failed");
64 return NULL;
65 }
66
67 int channels = CGImageGetAlphaInfo(image) == kCGImageAlphaNone ? 3 : 4;
68 i_img *result = i_img_8_new(width, height, channels);
69 if (!result) {
70 CGImageRelease(image);
71 return NULL;
72 }
73
74 /* bytes per row - round up to the closest 16 byte boundary */
75 size_t bytes_per_row = channels * width;
76 bytes_per_row = (bytes_per_row + 15) & ~15U;
77
78 unsigned char *data = mymalloc(bytes_per_row * height);
79 CGColorSpaceRef color_space = CGColorSpaceCreateDeviceRGB();
80
81 CGContextRef context = CGBitmapContextCreate
82 (data, width, height, 8, bytes_per_row, color_space,
83 kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big);
84 CGColorSpaceRelease(color_space);
85
86 CGContextDrawImage(context, CGRectMake(0, 0, width, height), image);
87 CGContextRelease(context);
88
89 CGImageRelease(image);
90
91 const unsigned char *p = data;
92 i_img_dim y;
93 for (y = 0; y < height; ++y) {
94 i_psamp(result, 0, width, y, p, NULL, channels);
95
96 p += bytes_per_row;
97 }
98
99 i_tags_setn(&result->tags, "ss_window_width", width);
100 i_tags_setn(&result->tags, "ss_window_height", height);
101 i_tags_set(&result->tags, "ss_type", "Darwin", 6);
102 i_tags_set(&result->tags, "ss_variant", "11+", 3);
103 i_tags_setn(&result->tags, "ss_left", left);
104 i_tags_setn(&result->tags, "ss_top", top);
105
106 return result;
107}