diff --git a/xpick.c b/xpick.c index c6fc5eb..248f530 100644 --- a/xpick.c +++ b/xpick.c @@ -1,10 +1,57 @@ -#include +/* Copyright (c) 2020 Stefan Hagen + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ + +#include #include #include #include +#include +#include +// original implementation in tmux colour.c +static int rgb_to_x256(uint8_t r, uint8_t g, uint8_t b) +{ + // Calculate the nearest 0-based color index at 16 .. 231 + #define v2ci(v) (v < 48 ? 0 : v < 115 ? 1 : (v - 35) / 40) + int ir = v2ci(r), ig = v2ci(g), ib = v2ci(b); // 0..5 each + #define color_index() (36 * ir + 6 * ig + ib) /* 0..215, lazy evaluation */ -int main() { + // Calculate the nearest 0-based gray index at 232 .. 255 + int average = (r + g + b) / 3; + int gray_index = average > 238 ? 23 : (average - 3) / 10; // 0..23 + + // Calculate the represented colors back from the index + static const int i2cv[6] = {0, 0x5f, 0x87, 0xaf, 0xd7, 0xff}; + int cr = i2cv[ir], cg = i2cv[ig], cb = i2cv[ib]; // r/g/b, 0..255 each + int gv = 8 + 10 * gray_index; // same value for r/g/b, 0..255 + + // Return the one which is nearer to the original input rgb value + #define dist_square(A,B,C, a,b,c) ((A-a)*(A-a) + (B-b)*(B-b) + (C-c)*(C-c)) + int color_err = dist_square(cr, cg, cb, r, g, b); + int gray_err = dist_square(gv, gv, gv, r, g, b); + return color_err <= gray_err ? 16 + color_index() : 232 + gray_index; +} + +int main(int argc, char *argv[]) { + + if(argc <= 1) { + printf("Usage: xpick [-rhx]\n"); + printf(" -r RGB notation RR/GG/BB\n"); + printf(" -h HEX notation #RRGGBB\n"); + printf(" -x XTerm nearest terminal color\n"); + return 2; + } Display *dpy = XOpenDisplay(NULL); Window root = RootWindow(dpy, DefaultScreen(dpy)); @@ -15,7 +62,7 @@ int main() { bgc.red = -1; bgc.green = -1; bgc.blue = -1; XRecolorCursor(dpy, cursor, &fgc, &bgc); - XGrabPointer(dpy, root, 0, ButtonReleaseMask, GrabModeAsync, GrabModeAsync, + XGrabPointer(dpy, root, 0, ButtonReleaseMask, GrabModeAsync, GrabModeAsync, None, cursor, CurrentTime); XEvent event; @@ -26,10 +73,28 @@ int main() { unsigned long p = XGetPixel(ximage, 0, 0); XDestroyImage(ximage); - XColor result; result.pixel = p; XQueryColor(dpy, DefaultColormap(dpy, DefaultScreen(dpy)), &result); - printf("#%02x%02x%02x\n", - result.red/256, result.green/256, result.blue/256); + + int opt; + while((opt = getopt(argc, argv, ":hrx")) != -1){ + switch(opt){ + case 'h': + printf("#%02x%02x%02x\n", + result.red/256, result.green/256, result.blue/256); + break; + case 'r': + printf("%03d/%03d/%03d\n", + result.red/256, result.green/256, result.blue/256); + break; + case 'x': + printf("%d\n", rgb_to_x256(result.red/256, result.green/256, + result.blue/256)); + break; + case '?': //used for some unknown opts + printf("Unknown option: %c\n", optopt); + break; + } + } return 0; }