t* A cli color picker URI git clone git://git.codevoid.de/xpick.git DIR Log DIR Files DIR Refs DIR README DIR LICENSE --- txpick.c (3942B) --- 1 /* Copyright (c) 2020 Stefan Hagen <sh+ports[at]codevoid[dot]de> 2 * 3 * Permission to use, copy, modify, and distribute this software for any 4 * purpose with or without fee is hereby granted, provided that the above 5 * copyright notice and this permission notice appear in all copies. 6 * 7 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 8 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 9 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 10 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 11 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 12 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 13 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ 14 15 #include <X11/Xlib.h> 16 #include <X11/Xutil.h> 17 #include <X11/cursorfont.h> 18 #include <stdio.h> 19 #include <string.h> 20 #include <unistd.h> 21 #include <stdint.h> 22 23 // original implementation in tmux colour.c 24 static int rgb_to_x256(uint8_t r, uint8_t g, uint8_t b) 25 { 26 // Calculate the nearest 0-based color index at 16 .. 231 27 #define v2ci(v) (v < 48 ? 0 : v < 115 ? 1 : (v - 35) / 40) 28 int ir = v2ci(r), ig = v2ci(g), ib = v2ci(b); // 0..5 each 29 #define color_index() (36 * ir + 6 * ig + ib) /* 0..215, lazy evaluation */ 30 31 // Calculate the nearest 0-based gray index at 232 .. 255 32 int average = (r + g + b) / 3; 33 int gray_index = average > 238 ? 23 : (average - 3) / 10; // 0..23 34 35 // Calculate the represented colors back from the index 36 static const int i2cv[6] = {0, 0x5f, 0x87, 0xaf, 0xd7, 0xff}; 37 int cr = i2cv[ir], cg = i2cv[ig], cb = i2cv[ib]; // r/g/b, 0..255 each 38 int gv = 8 + 10 * gray_index; // same value for r/g/b, 0..255 39 40 // Return the one which is nearer to the original input rgb value 41 #define dist_square(A,B,C, a,b,c) ((A-a)*(A-a) + (B-b)*(B-b) + (C-c)*(C-c)) 42 int color_err = dist_square(cr, cg, cb, r, g, b); 43 int gray_err = dist_square(gv, gv, gv, r, g, b); 44 return color_err <= gray_err ? 16 + color_index() : 232 + gray_index; 45 } 46 47 int main(int argc, char *argv[]) { 48 49 if(argc <= 1) { 50 printf("Usage: xpick [-rhx]\n"); 51 printf(" -r RGB notation RR/GG/BB\n"); 52 printf(" -h HEX notation #RRGGBB\n"); 53 printf(" -x XTerm nearest terminal color\n"); 54 return 2; 55 } 56 57 Display *dpy = XOpenDisplay(NULL); 58 Window root = RootWindow(dpy, DefaultScreen(dpy)); 59 60 Cursor cursor = XCreateFontCursor(dpy, XC_tcross); 61 XColor fgc, bgc; 62 fgc.red = -1; fgc.green = 0; fgc.blue = 0; 63 bgc.red = -1; bgc.green = -1; bgc.blue = -1; 64 65 XRecolorCursor(dpy, cursor, &fgc, &bgc); 66 XGrabPointer(dpy, root, 0, ButtonReleaseMask, GrabModeAsync, GrabModeAsync, 67 None, cursor, CurrentTime); 68 69 XEvent event; 70 XNextEvent(dpy, &event); 71 XUngrabPointer(dpy, CurrentTime); 72 XImage *ximage = XGetImage(dpy, root, event.xbutton.x_root, 73 event.xbutton.y_root, 1, 1, -1, ZPixmap); 74 75 unsigned long p = XGetPixel(ximage, 0, 0); 76 XDestroyImage(ximage); 77 XColor result; result.pixel = p; 78 XQueryColor(dpy, DefaultColormap(dpy, DefaultScreen(dpy)), &result); 79 80 int opt; 81 while((opt = getopt(argc, argv, ":hrx")) != -1){ 82 switch(opt){ 83 case 'h': 84 printf("#%02x%02x%02x\n", 85 result.red/256, result.green/256, result.blue/256); 86 break; 87 case 'r': 88 printf("%03d/%03d/%03d\n", 89 result.red/256, result.green/256, result.blue/256); 90 break; 91 case 'x': 92 printf("%d\n", rgb_to_x256(result.red/256, result.green/256, 93 result.blue/256)); 94 break; 95 case '?': //used for some unknown opts 96 printf("Unknown option: %c\n", optopt); 97 break; 98 } 99 } 100 return 0; 101 }