mirror of
https://github.com/hyprwm/hyprpicker.git
synced 2024-12-22 14:19:48 +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)))
|
||||
LDLIBS += $(foreach p,$(PKGS),$(shell pkg-config --libs $(p)))
|
||||
|
||||
default: all
|
||||
|
||||
wlr-layer-shell-unstable-v1-protocol.h:
|
||||
$(WAYLAND_SCANNER) client-header \
|
||||
protocols/wlr-layer-shell-unstable-v1.xml $@
|
||||
|
@ -58,3 +60,8 @@ all:
|
|||
make clear
|
||||
make protocols
|
||||
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
|
||||
|
||||
`--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))
|
||||
|
||||
|
|
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) {
|
||||
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
|
||||
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),
|
||||
|
@ -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);
|
||||
|
||||
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:
|
||||
{
|
||||
auto toHex = [](int i) -> std::string {
|
||||
|
@ -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);
|
||||
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();
|
||||
|
|
|
@ -5,8 +5,11 @@
|
|||
#include "helpers/PoolBuffer.hpp"
|
||||
|
||||
enum eOutputMode {
|
||||
OUTPUT_HEX = 0,
|
||||
OUTPUT_RGB
|
||||
OUTPUT_CMYK = 0,
|
||||
OUTPUT_HEX,
|
||||
OUTPUT_RGB,
|
||||
OUTPUT_HSL,
|
||||
OUTPUT_HSV
|
||||
};
|
||||
|
||||
class CHyprpicker {
|
||||
|
|
|
@ -33,6 +33,7 @@ extern "C" {
|
|||
#include <cairo.h>
|
||||
#include <cairo/cairo.h>
|
||||
#include <fcntl.h>
|
||||
#include <getopt.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
|
70
src/main.cpp
70
src/main.cpp
|
@ -1,42 +1,56 @@
|
|||
#include <strings.h>
|
||||
#include <iostream>
|
||||
#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) {
|
||||
g_pHyprpicker = std::make_unique<CHyprpicker>();
|
||||
|
||||
// parse args
|
||||
// 1 - format
|
||||
int currentlyParsing = 0;
|
||||
for (int i = 1; i < argc; i++) {
|
||||
std::string arg = argv[i];
|
||||
while (true) {
|
||||
int option_index = 0;
|
||||
static struct option long_options[] = {
|
||||
{"format", required_argument, NULL, 'f'},
|
||||
{"help", no_argument, NULL, 'h'},
|
||||
{"no-fancy", no_argument, NULL, 'n'},
|
||||
{NULL, 0, NULL, 0 }
|
||||
};
|
||||
|
||||
if (currentlyParsing == 0) {
|
||||
if (arg == "--format") {
|
||||
currentlyParsing = 1;
|
||||
continue;
|
||||
} else if (arg == "--no-fancy") {
|
||||
g_pHyprpicker->m_bFancyOutput = false;
|
||||
} else if (arg == "--autocopy") {
|
||||
g_pHyprpicker->m_bAutoCopy = true;
|
||||
} else {
|
||||
std::cout << "Hyprpicker usage: hyprpicker [arg [...]].\n\nArguments:\n" <<
|
||||
" --format [fmt] | Specifies the output format (hex, rgb)\n" <<
|
||||
" --no-fancy | Disables the \"fancy\" (aka. colored) outputting\n" <<
|
||||
" --autocopy | Automatically copies the output to the clipboard (requires wl-clipboard)\n" <<
|
||||
" --help | Show this help message\n";
|
||||
exit(1);
|
||||
}
|
||||
} else if (currentlyParsing == 1) {
|
||||
if (arg == "hex") g_pHyprpicker->m_bSelectedOutputMode = OUTPUT_HEX;
|
||||
else if (arg == "rgb") g_pHyprpicker->m_bSelectedOutputMode = OUTPUT_RGB;
|
||||
int c = getopt_long(argc, argv, ":f:hn", long_options, &option_index);
|
||||
if (c == -1)
|
||||
break;
|
||||
|
||||
switch (c) {
|
||||
case 'f':
|
||||
if (strcasecmp(optarg, "cmyk") == 0)
|
||||
g_pHyprpicker->m_bSelectedOutputMode = OUTPUT_CMYK;
|
||||
else if (strcasecmp(optarg, "hex") == 0)
|
||||
g_pHyprpicker->m_bSelectedOutputMode = OUTPUT_HEX;
|
||||
else if (strcasecmp(optarg, "rgb") == 0)
|
||||
g_pHyprpicker->m_bSelectedOutputMode = OUTPUT_RGB;
|
||||
else if (strcasecmp(optarg, "hsl") == 0)
|
||||
g_pHyprpicker->m_bSelectedOutputMode = OUTPUT_HSL;
|
||||
else if (strcasecmp(optarg, "hsv") == 0)
|
||||
g_pHyprpicker->m_bSelectedOutputMode = OUTPUT_HSV;
|
||||
else {
|
||||
Debug::log(NONE, "Unrecognized format %s", arg.c_str());
|
||||
Debug::log(NONE, "Unrecognized format %s", optarg);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
currentlyParsing = 0;
|
||||
continue;
|
||||
break;
|
||||
case 'h':
|
||||
help();
|
||||
exit(0);
|
||||
case 'n':
|
||||
g_pHyprpicker->m_bFancyOutput = false;
|
||||
break;
|
||||
default:
|
||||
help();
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue