mirror of
https://github.com/hyprwm/hyprpicker.git
synced 2024-11-17 00:25:57 +01:00
Support HSL, HSV, CMYK, short options, minor I/O fix, and add a manual page (#12)
* use getopt_long(3) and support short options Now instead of `--format`, `--no-fancy`, and `--help` you can also use `-f`, `-n`, and `-h`. Additionally instead of just being able to do `--format <fmt>` you can now do the standard `--format=<fmt>`. * remove initial space when m_bFancyOutput is true * add the HSL format * add the HSV format * add a manual page * silence compiler warning * make all the default target, and add install rule * add the CMYK format * add new formats to the README
This commit is contained in:
parent
a82b20e979
commit
7d2db8b232
7 changed files with 225 additions and 35 deletions
7
Makefile
7
Makefile
|
@ -10,6 +10,8 @@ PKGS = wlroots wayland-server
|
||||||
CFLAGS += $(foreach p,$(PKGS),$(shell pkg-config --cflags $(p)))
|
CFLAGS += $(foreach p,$(PKGS),$(shell pkg-config --cflags $(p)))
|
||||||
LDLIBS += $(foreach p,$(PKGS),$(shell pkg-config --libs $(p)))
|
LDLIBS += $(foreach p,$(PKGS),$(shell pkg-config --libs $(p)))
|
||||||
|
|
||||||
|
default: all
|
||||||
|
|
||||||
wlr-layer-shell-unstable-v1-protocol.h:
|
wlr-layer-shell-unstable-v1-protocol.h:
|
||||||
$(WAYLAND_SCANNER) client-header \
|
$(WAYLAND_SCANNER) client-header \
|
||||||
protocols/wlr-layer-shell-unstable-v1.xml $@
|
protocols/wlr-layer-shell-unstable-v1.xml $@
|
||||||
|
@ -58,3 +60,8 @@ all:
|
||||||
make clear
|
make clear
|
||||||
make protocols
|
make protocols
|
||||||
make release
|
make release
|
||||||
|
|
||||||
|
install:
|
||||||
|
mkdir -p ${DESTDIR}${PREFIX}/bin ${DESTDIR}${PREFIX}/share/man/man1
|
||||||
|
cp doc/hyprpicker.1 ${DESTDIR}${PREFIX}/share/man/man1
|
||||||
|
cp build/hyprpicker ${DESTDIR}${PREFIX}/bin
|
||||||
|
|
|
@ -10,9 +10,11 @@ Launch it. Click. That's it.
|
||||||
|
|
||||||
## Options
|
## Options
|
||||||
|
|
||||||
`--format [fmt]` to specify the output format (`hex`, `rgb`)
|
`-f | --format=[fmt]` specifies the output format (`cmyk`, `hex`, `rgb`, `hsl`, `hsv`)
|
||||||
|
|
||||||
`--no-fancy` disables the "fancy" (aka. colored) outputting
|
`-n | --no-fancy` disables the "fancy" (aka. colored) outputting
|
||||||
|
|
||||||
|
`-h | --help` prints a help message
|
||||||
|
|
||||||
`--autocopy` automatically copies the output to the clipboard (requires [wl-clipboard](https://github.com/bugaevc/wl-clipboard))
|
`--autocopy` automatically copies the output to the clipboard (requires [wl-clipboard](https://github.com/bugaevc/wl-clipboard))
|
||||||
|
|
||||||
|
|
85
doc/hyprpicker.1
Normal file
85
doc/hyprpicker.1
Normal file
|
@ -0,0 +1,85 @@
|
||||||
|
.Dd $Mdocdate: November 14 2022 $
|
||||||
|
.Dt HYPRPICKER 1
|
||||||
|
.Os Linux
|
||||||
|
.Sh NAME
|
||||||
|
.Nm hyprpicker
|
||||||
|
.Nd wlroots-compatible wayland color picker
|
||||||
|
.Sh SYNOPSIS
|
||||||
|
.Nm
|
||||||
|
.Op Fl nh
|
||||||
|
.Op Fl f Ar fmt
|
||||||
|
.Sh DESCRIPTION
|
||||||
|
The
|
||||||
|
.Nm
|
||||||
|
utility is a color-picker with support for various output formats.
|
||||||
|
When
|
||||||
|
.Nm
|
||||||
|
is invoked the cursor is transformed into a magnifying lens, and clicking on any
|
||||||
|
pixel of the screen will print out that pixels color to the standard output.
|
||||||
|
The default output format is hexadecimal, but that can be configured with the
|
||||||
|
.Fl f
|
||||||
|
option.
|
||||||
|
.Pp
|
||||||
|
The options are as follows:
|
||||||
|
.Bl -tag -width Ds
|
||||||
|
.It Fl f Ns , Fl \-format Ns = Ns Ar fmt
|
||||||
|
Select the format to output the selected pixels color in.
|
||||||
|
The argument
|
||||||
|
.Ar fmt
|
||||||
|
is case-insensitive.
|
||||||
|
The available options are:
|
||||||
|
.Pp
|
||||||
|
.Bl -hang -compact
|
||||||
|
.It Ar cmyk
|
||||||
|
.Pq Dq C% M% Y% K%
|
||||||
|
.It Ar hex
|
||||||
|
.Pq Dq #RRGGBB
|
||||||
|
.It Ar rgb
|
||||||
|
.Pq Dq R G B
|
||||||
|
.It Ar hsl
|
||||||
|
.Pq Dq H S% L%
|
||||||
|
.It Ar hsv
|
||||||
|
.Pq Dq H S% V%
|
||||||
|
.El
|
||||||
|
.Pp
|
||||||
|
The default format is
|
||||||
|
.Ar hex .
|
||||||
|
.It Fl n Ns , Fl \-no\-fancy
|
||||||
|
Disable colored output.
|
||||||
|
Default behavior is to color the output in the same color as the selected pixel.
|
||||||
|
.It Fl h Ns , Fl \-help
|
||||||
|
Display a help message and exit successfully from the program.
|
||||||
|
.El
|
||||||
|
.Sh ENVIRONMENT
|
||||||
|
.Bl -tag -width NO_COLOR
|
||||||
|
.It Ev NO_COLOR
|
||||||
|
If set, disables colored output.
|
||||||
|
.El
|
||||||
|
.Sh EXIT STATUS
|
||||||
|
.Ex -std
|
||||||
|
.Sh EXAMPLES
|
||||||
|
Get a pixels color:
|
||||||
|
.Pp
|
||||||
|
.Dl $ hyprpicker
|
||||||
|
.Pp
|
||||||
|
Get a pixels color in HSL, wrapped in a CSS
|
||||||
|
.Fn hsl
|
||||||
|
function:
|
||||||
|
.Pp
|
||||||
|
.Dl $ hyprpicker -f hsl | sed 's/^/rgb(/; s/$/)/; y/ /,/'
|
||||||
|
.Sh SEE ALSO
|
||||||
|
.Xr hyprctl 1 ,
|
||||||
|
.Xr hyprland 1 ,
|
||||||
|
.Xr sed 1
|
||||||
|
.Pp
|
||||||
|
.Lk https://github.com/hyprwm/hyprpicker "The Hyprpicker Sources"
|
||||||
|
.Sh AUTHORS
|
||||||
|
.An -nosplit
|
||||||
|
The
|
||||||
|
.Nm
|
||||||
|
utility was originally written by
|
||||||
|
.An Vaxerski Aq Lk https://github.com/vaxerski
|
||||||
|
and the manual page by
|
||||||
|
.An Thomas Voss Aq Mt mail@thomasvoss.com .
|
||||||
|
.Sh BUGS
|
||||||
|
.Lk https://github.com/hyprwm/hyprpicker/issues "The Hyprpicker Bug Tracker"
|
|
@ -118,6 +118,13 @@ void Events::handlePointerMotion(void *data, struct wl_pointer *wl_pointer, uint
|
||||||
}
|
}
|
||||||
|
|
||||||
void Events::handlePointerButton(void *data, struct wl_pointer *wl_pointer, uint32_t serial, uint32_t time, uint32_t button, uint32_t button_state) {
|
void Events::handlePointerButton(void *data, struct wl_pointer *wl_pointer, uint32_t serial, uint32_t time, uint32_t button, uint32_t button_state) {
|
||||||
|
auto fmax3 = [](float a, float b, float c) -> float {
|
||||||
|
return (a > b && a > c) ? a : (b > c) ? b : c;
|
||||||
|
};
|
||||||
|
auto fmin3 = [](float a, float b, float c) -> float {
|
||||||
|
return (a < b && a < c) ? a : (b < c) ? b : c;
|
||||||
|
};
|
||||||
|
|
||||||
// get the px and print it
|
// get the px and print it
|
||||||
const auto SCALE = Vector2D{
|
const auto SCALE = Vector2D{
|
||||||
g_pHyprpicker->m_pLastSurface->screenBuffer.pixelSize.x / (g_pHyprpicker->m_pLastSurface->buffers[0].pixelSize.x / g_pHyprpicker->m_pLastSurface->m_pMonitor->scale),
|
g_pHyprpicker->m_pLastSurface->screenBuffer.pixelSize.x / (g_pHyprpicker->m_pLastSurface->buffers[0].pixelSize.x / g_pHyprpicker->m_pLastSurface->m_pMonitor->scale),
|
||||||
|
@ -129,6 +136,30 @@ void Events::handlePointerButton(void *data, struct wl_pointer *wl_pointer, uint
|
||||||
const auto COL = g_pHyprpicker->getColorFromPixel(g_pHyprpicker->m_pLastSurface, CLICKPOS);
|
const auto COL = g_pHyprpicker->getColorFromPixel(g_pHyprpicker->m_pLastSurface, CLICKPOS);
|
||||||
|
|
||||||
switch (g_pHyprpicker->m_bSelectedOutputMode) {
|
switch (g_pHyprpicker->m_bSelectedOutputMode) {
|
||||||
|
case OUTPUT_CMYK:
|
||||||
|
{
|
||||||
|
// http://www.codeproject.com/KB/applications/xcmyk.aspx
|
||||||
|
|
||||||
|
float r = 1 - COL.r / 255.0f,
|
||||||
|
g = 1 - COL.g / 255.0f,
|
||||||
|
b = 1 - COL.b / 255.0f;
|
||||||
|
float k = fmin3(r, g, b),
|
||||||
|
K = 1 - k;
|
||||||
|
float c = (r - k) / K,
|
||||||
|
m = (g - k) / K,
|
||||||
|
y = (b - k) / K;
|
||||||
|
|
||||||
|
c = std::round(c * 100);
|
||||||
|
m = std::round(m * 100);
|
||||||
|
y = std::round(y * 100);
|
||||||
|
k = std::round(k * 100);
|
||||||
|
|
||||||
|
if (g_pHyprpicker->m_bFancyOutput)
|
||||||
|
Debug::log(NONE, "\033[38;2;%i;%i;%im%g%% %g%% %g%% %g%%\033[0m", COL.r, COL.g, COL.b, c, m, y, k);
|
||||||
|
else
|
||||||
|
Debug::log(NONE, "%g%% %g%% %g%% %g%%", c, m, y, k);
|
||||||
|
break;
|
||||||
|
}
|
||||||
case OUTPUT_HEX:
|
case OUTPUT_HEX:
|
||||||
{
|
{
|
||||||
auto toHex = [](int i) -> std::string {
|
auto toHex = [](int i) -> std::string {
|
||||||
|
@ -143,7 +174,7 @@ void Events::handlePointerButton(void *data, struct wl_pointer *wl_pointer, uint
|
||||||
};
|
};
|
||||||
|
|
||||||
if (g_pHyprpicker->m_bFancyOutput)
|
if (g_pHyprpicker->m_bFancyOutput)
|
||||||
Debug::log(NONE, "\033[38;2;%i;%i;%im #%s%s%s\033[0m", COL.r, COL.g, COL.b, toHex(COL.r).c_str(), toHex(COL.g).c_str(), toHex(COL.b).c_str());
|
Debug::log(NONE, "\033[38;2;%i;%i;%im#%s%s%s\033[0m", COL.r, COL.g, COL.b, toHex(COL.r).c_str(), toHex(COL.g).c_str(), toHex(COL.b).c_str());
|
||||||
else
|
else
|
||||||
Debug::log(NONE, "#%s%s%s", toHex(COL.r).c_str(), toHex(COL.g).c_str(), toHex(COL.b).c_str());
|
Debug::log(NONE, "#%s%s%s", toHex(COL.r).c_str(), toHex(COL.g).c_str(), toHex(COL.b).c_str());
|
||||||
|
|
||||||
|
@ -154,7 +185,7 @@ void Events::handlePointerButton(void *data, struct wl_pointer *wl_pointer, uint
|
||||||
case OUTPUT_RGB:
|
case OUTPUT_RGB:
|
||||||
{
|
{
|
||||||
if (g_pHyprpicker->m_bFancyOutput)
|
if (g_pHyprpicker->m_bFancyOutput)
|
||||||
Debug::log(NONE, "\033[38;2;%i;%i;%im %i %i %i\033[0m", COL.r, COL.g, COL.b, COL.r, COL.g, COL.b);
|
Debug::log(NONE, "\033[38;2;%i;%i;%im%i %i %i\033[0m", COL.r, COL.g, COL.b, COL.r, COL.g, COL.b);
|
||||||
else
|
else
|
||||||
Debug::log(NONE, "%i %i %i", COL.r, COL.g, COL.b);
|
Debug::log(NONE, "%i %i %i", COL.r, COL.g, COL.b);
|
||||||
|
|
||||||
|
@ -162,6 +193,53 @@ void Events::handlePointerButton(void *data, struct wl_pointer *wl_pointer, uint
|
||||||
Clipboard::copy("%i %i %i", COL.r, COL.g, COL.b);
|
Clipboard::copy("%i %i %i", COL.r, COL.g, COL.b);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case OUTPUT_HSL:
|
||||||
|
case OUTPUT_HSV:
|
||||||
|
{
|
||||||
|
// https://en.wikipedia.org/wiki/HSL_and_HSV#From_RGB
|
||||||
|
|
||||||
|
auto floatEq = [](float a, float b) -> bool {
|
||||||
|
return std::nextafter(a, std::numeric_limits<double>::lowest()) <= b && std::nextafter(a, std::numeric_limits<double>::max()) >= b;
|
||||||
|
};
|
||||||
|
|
||||||
|
float h, s, l, v;
|
||||||
|
float r = COL.r / 255.0f,
|
||||||
|
g = COL.g / 255.0f,
|
||||||
|
b = COL.b / 255.0f;
|
||||||
|
float max = fmax3(r, g, b),
|
||||||
|
min = fmin3(r, g, b);
|
||||||
|
float c = max - min;
|
||||||
|
|
||||||
|
v = max;
|
||||||
|
if (c == 0)
|
||||||
|
h = 0;
|
||||||
|
else if (v == r)
|
||||||
|
h = 60 * (0 + (g - b) / c);
|
||||||
|
else if (v == g)
|
||||||
|
h = 60 * (2 + (b - r) / c);
|
||||||
|
else /* v == b */
|
||||||
|
h = 60 * (4 + (r - g) / c);
|
||||||
|
|
||||||
|
float l_or_v;
|
||||||
|
if (g_pHyprpicker->m_bSelectedOutputMode == OUTPUT_HSL) {
|
||||||
|
l = (max + min) / 2;
|
||||||
|
s = (floatEq(l, 0.0f) || floatEq(l, 1.0f)) ? 0 : (v - l) / std::min(l, 1 - l);
|
||||||
|
l_or_v = std::round(l * 100);
|
||||||
|
} else {
|
||||||
|
v = max;
|
||||||
|
s = floatEq(v, 0.0f) ? 0 : c / v;
|
||||||
|
l_or_v = std::round(v * 100);
|
||||||
|
}
|
||||||
|
|
||||||
|
h = std::round(h);
|
||||||
|
s = std::round(s * 100);
|
||||||
|
|
||||||
|
if (g_pHyprpicker->m_bFancyOutput)
|
||||||
|
Debug::log(NONE, "\033[38;2;%i;%i;%im%g %g%% %g%%\033[0m", COL.r, COL.g, COL.b, h, s, l_or_v);
|
||||||
|
else
|
||||||
|
Debug::log(NONE, "%g %g%% %g%%", h, s, l_or_v);
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
g_pHyprpicker->finish();
|
g_pHyprpicker->finish();
|
||||||
|
|
|
@ -5,8 +5,11 @@
|
||||||
#include "helpers/PoolBuffer.hpp"
|
#include "helpers/PoolBuffer.hpp"
|
||||||
|
|
||||||
enum eOutputMode {
|
enum eOutputMode {
|
||||||
OUTPUT_HEX = 0,
|
OUTPUT_CMYK = 0,
|
||||||
OUTPUT_RGB
|
OUTPUT_HEX,
|
||||||
|
OUTPUT_RGB,
|
||||||
|
OUTPUT_HSL,
|
||||||
|
OUTPUT_HSV
|
||||||
};
|
};
|
||||||
|
|
||||||
class CHyprpicker {
|
class CHyprpicker {
|
||||||
|
|
|
@ -33,6 +33,7 @@ extern "C" {
|
||||||
#include <cairo.h>
|
#include <cairo.h>
|
||||||
#include <cairo/cairo.h>
|
#include <cairo/cairo.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
|
#include <getopt.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
70
src/main.cpp
70
src/main.cpp
|
@ -1,42 +1,56 @@
|
||||||
|
#include <strings.h>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include "hyprpicker.hpp"
|
#include "hyprpicker.hpp"
|
||||||
|
|
||||||
|
static void help(void) {
|
||||||
|
std::cout << "Hyprpicker usage: hyprpicker [arg [...]].\n\nArguments:\n" <<
|
||||||
|
" -f | --format=fmt | Specifies the output format (cmyk, hex, rgb, hsl, hsv)\n" <<
|
||||||
|
" -n | --no-fancy | Disables the \"fancy\" (aka. colored) outputting\n" <<
|
||||||
|
" -h | --help | Show this help message\n";
|
||||||
|
}
|
||||||
|
|
||||||
int main(int argc, char** argv, char** envp) {
|
int main(int argc, char** argv, char** envp) {
|
||||||
g_pHyprpicker = std::make_unique<CHyprpicker>();
|
g_pHyprpicker = std::make_unique<CHyprpicker>();
|
||||||
|
|
||||||
// parse args
|
while (true) {
|
||||||
// 1 - format
|
int option_index = 0;
|
||||||
int currentlyParsing = 0;
|
static struct option long_options[] = {
|
||||||
for (int i = 1; i < argc; i++) {
|
{"format", required_argument, NULL, 'f'},
|
||||||
std::string arg = argv[i];
|
{"help", no_argument, NULL, 'h'},
|
||||||
|
{"no-fancy", no_argument, NULL, 'n'},
|
||||||
|
{NULL, 0, NULL, 0 }
|
||||||
|
};
|
||||||
|
|
||||||
if (currentlyParsing == 0) {
|
int c = getopt_long(argc, argv, ":f:hn", long_options, &option_index);
|
||||||
if (arg == "--format") {
|
if (c == -1)
|
||||||
currentlyParsing = 1;
|
break;
|
||||||
continue;
|
|
||||||
} else if (arg == "--no-fancy") {
|
switch (c) {
|
||||||
g_pHyprpicker->m_bFancyOutput = false;
|
case 'f':
|
||||||
} else if (arg == "--autocopy") {
|
if (strcasecmp(optarg, "cmyk") == 0)
|
||||||
g_pHyprpicker->m_bAutoCopy = true;
|
g_pHyprpicker->m_bSelectedOutputMode = OUTPUT_CMYK;
|
||||||
} else {
|
else if (strcasecmp(optarg, "hex") == 0)
|
||||||
std::cout << "Hyprpicker usage: hyprpicker [arg [...]].\n\nArguments:\n" <<
|
g_pHyprpicker->m_bSelectedOutputMode = OUTPUT_HEX;
|
||||||
" --format [fmt] | Specifies the output format (hex, rgb)\n" <<
|
else if (strcasecmp(optarg, "rgb") == 0)
|
||||||
" --no-fancy | Disables the \"fancy\" (aka. colored) outputting\n" <<
|
g_pHyprpicker->m_bSelectedOutputMode = OUTPUT_RGB;
|
||||||
" --autocopy | Automatically copies the output to the clipboard (requires wl-clipboard)\n" <<
|
else if (strcasecmp(optarg, "hsl") == 0)
|
||||||
" --help | Show this help message\n";
|
g_pHyprpicker->m_bSelectedOutputMode = OUTPUT_HSL;
|
||||||
exit(1);
|
else if (strcasecmp(optarg, "hsv") == 0)
|
||||||
}
|
g_pHyprpicker->m_bSelectedOutputMode = OUTPUT_HSV;
|
||||||
} else if (currentlyParsing == 1) {
|
|
||||||
if (arg == "hex") g_pHyprpicker->m_bSelectedOutputMode = OUTPUT_HEX;
|
|
||||||
else if (arg == "rgb") g_pHyprpicker->m_bSelectedOutputMode = OUTPUT_RGB;
|
|
||||||
else {
|
else {
|
||||||
Debug::log(NONE, "Unrecognized format %s", arg.c_str());
|
Debug::log(NONE, "Unrecognized format %s", optarg);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
currentlyParsing = 0;
|
case 'h':
|
||||||
continue;
|
help();
|
||||||
|
exit(0);
|
||||||
|
case 'n':
|
||||||
|
g_pHyprpicker->m_bFancyOutput = false;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
help();
|
||||||
|
exit(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue