1+ /** Author: RedFantom
2+ * License: GNU GPLv3
3+ * Copyright (c) 2018-2019 RedFantom
4+ */
5+ #include <pthread.h>
6+ #include <stdbool.h>
7+ #include <stdlib.h>
8+ #include <X11/Xlib.h>
9+ #include <X11/X.h>
10+
11+
12+ typedef struct CaptureArgs {
13+ unsigned char * target_color ;
14+ pthread_mutex_t * target_lock ;
15+ pthread_mutex_t * exit_lock ;
16+ bool * exit_flag ;
17+ Display * display ;
18+ Window root ;
19+ XWindowAttributes gwa ;
20+ int divider ;
21+ int saturation_bias ;
22+ int upper_threshold ;
23+ int lower_threshold ;
24+ bool brightness_norm ;
25+ } CaptureArgs ;
26+
27+
28+ typedef struct Screenshot {
29+ unsigned char * data ;
30+ unsigned int w , h ;
31+ } Screenshot ;
32+
33+
34+ CaptureArgs * init_capture (int divider , int sat_bias , int lower , int upper ,
35+ bool brightness_norm ,
36+ unsigned char * target_color , pthread_mutex_t * target_lock ,
37+ bool * exit_flag , pthread_mutex_t * exit_lock ) {
38+ /** Initialize a CaptureArgs struct that can be passed as thread argument */
39+ CaptureArgs * args = (CaptureArgs * ) malloc (sizeof (CaptureArgs ));
40+
41+ args -> divider = divider ;
42+ args -> saturation_bias = sat_bias ;
43+ args -> lower_threshold = lower ;
44+ args -> upper_threshold = upper ;
45+ args -> brightness_norm = brightness_norm ;
46+ args -> target_color = target_color ;
47+ args -> target_lock = target_lock ;
48+ args -> exit_flag = exit_flag ;
49+ args -> exit_lock = exit_lock ;
50+
51+ args -> display = XOpenDisplay (NULL );
52+ args -> root = DefaultRootWindow (args -> display );
53+ if (XGetWindowAttributes (args -> display , args -> root , & (args -> gwa )) < 0 ) {
54+ XCloseDisplay (args -> display );
55+ free (args );
56+ return NULL ;
57+ }
58+
59+ return args ;
60+ }
61+
62+
63+ void capturer (struct CaptureArgs * args ) {
64+ /** Function designed to be run in a thread, captures screenshots
65+ *
66+ */
67+ while (true) {
68+ pthread_mutex_lock (args -> exit_lock );
69+ bool exit = * (args -> exit_flag );
70+ pthread_mutex_unlock (args -> exit_lock );
71+ if (exit )
72+ break ;
73+
74+ unsigned char target [3 ];
75+ Screenshot * screenshot ;
76+
77+ capture (& screenshot , args -> gwa , args -> display , args -> root );
78+ calc_dominant_color (screenshot -> data , screenshot -> w , screenshot -> h ,
79+ target , args -> divider , args -> saturation_bias ,
80+ args -> lower_threshold , args -> upper_threshold ,
81+ args -> brightness_norm );
82+
83+ free (screenshot -> data );
84+ free (screenshot );
85+
86+ pthread_mutex_lock (args -> target_lock );
87+ for (int i = 0 ; i < 3 ; i ++ )
88+ args -> target_color [i ] = target [i ];
89+ pthread_mutex_unlock (args -> target_lock );
90+ }
91+ }
92+
93+
94+ void capture (Screenshot * * screenshot , XWindowAttributes gwa ,
95+ Display * display , Window root ) {
96+ /** Capture screenshot and save it to Screenshot struct
97+ *
98+ * The data captured from X.org is in long int format (32-bit
99+ * integers), which have to be converted to three separate 8-bit
100+ * integers representing the pixels.
101+ */
102+ (* screenshot ) = (Screenshot * ) malloc (sizeof (Screenshot ));
103+ int width = gwa .width , height = gwa .height ;
104+
105+ (* screenshot )-> data = (unsigned char * ) malloc (
106+ width * height * 3 * sizeof (unsigned char ));
107+ XImage * img = XGetImage (
108+ display , root , 0 , 0 , width , height , AllPlanes , ZPixmap );
109+ unsigned long masks [3 ] = {
110+ img -> red_mask , img -> green_mask , img -> blue_mask };
111+
112+ for (int x = 0 ; x < width ; x ++ )
113+ for (int y = 0 ; y < height ; y ++ ) {
114+ unsigned long pix = XGetPixel (img , x , y );
115+ for (int i = 0 ; i < 3 ; i ++ )
116+ (* screenshot )-> data [(x + width * y ) * 3 + i ] =
117+ (unsigned char ) (pix >> (2 - i ) * 8 );
118+ }
119+
120+ XDestroyImage (img );
121+ }
122+
123+
124+ void calc_dominant_color (unsigned char * data , int w , int h ,
125+ unsigned char * target , int divider , int sat_bias ,
126+ int lower , int upper , bool brightness_norm ) {
127+ /** Calculate the dominant color in an array of pixels
128+ *
129+ *
130+ */
131+ unsigned char temp [3 ];
132+ unsigned long colors [3 ] = {0 };
133+ unsigned long n_pixels = 0 ;
134+
135+ int width = w / divider ;
136+
137+ /// Summing of pixels fitting criteria
138+ for (int x = 0 ; x < width ; x ++ ) {
139+ for (int y = 0 ; y < h ; y ++ ) {
140+ unsigned int sum = 0 ;
141+ unsigned char r , g , b ;
142+ int max_diff = 0 ;
143+ unsigned char * pixel = data [x + y * w ];
144+ for (int i = 0 ; i < 3 ; i ++ ) {
145+ int first = i , second = i + 1 < 3 ? i + 1 : 0 ;
146+ unsigned char diff = pixel [first ] - pixel [second ];
147+ max_diff = diff > max_diff ? diff : max_diff ;
148+ sum += pixel [i ];
149+ }
150+ if (sum < lower || sum > upper || max_diff < sat_bias )
151+ continue ;
152+ for (int i = 0 ; i < 3 ; i ++ )
153+ colors [i ] += pixel [i ];
154+ n_pixels += 1 ;
155+ }
156+ }
157+
158+ /// Averaging
159+ unsigned char color [3 ];
160+ unsigned char max = 0 ;
161+ for (int i = 0 ; i < 3 ; i ++ ) {
162+ if (n_pixels == 0 ) {
163+ target [i ] = 0xFF ; // Error condition
164+ continue ;
165+ }
166+ target [i ] = (unsigned char ) (colors [i ] / n_pixels );
167+ max = color [i ] > max ? color [i ] : max ;
168+ }
169+
170+ /// Normalization
171+ if (brightness_norm && max != 0xFF )
172+ for (int i = 0 ; i < 3 ; i ++ )
173+ target [i ] = (unsigned char ) ((double ) color [i ] * (255.0 / (double ) max ));
174+ }
0 commit comments