Skip to content

Commit

Permalink
add --invert-colors option to image output
Browse files Browse the repository at this point in the history
  • Loading branch information
vergoh committed Sep 27, 2023
1 parent 6d283df commit adc7df0
Show file tree
Hide file tree
Showing 8 changed files with 109 additions and 10 deletions.
3 changes: 3 additions & 0 deletions CHANGES
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@
- New
- Show spinning animation at the beginning of -l / --live output line,
visibility configurable using LiveSpinner configuration option
- Add --invert-colors option to image output for facilitating for example
dark mode switching without needing to have multiple separate color
configurations


2.11 / 19-Aug-2023
Expand Down
14 changes: 13 additions & 1 deletion man/vnstati.1
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
.TH VNSTATI 1 "AUGUST 2023" "version 2.11" "User Manuals"
.TH VNSTATI 1 "SEPTEMBER 2023" "version 2.12" "User Manuals"
.SH NAME
vnstati \- image output support for vnStat

Expand Down Expand Up @@ -45,6 +45,8 @@ vnstati \- image output support for vnStat
.IR interface ]
.RB [ \-\-iface
.IR interface ]
.RB [ \-\-invert\-colors
.RI [ mode ]]
.RB [ \-\-large ]
.RB [ \-\-limit
.IR limit ]
Expand Down Expand Up @@ -251,6 +253,16 @@ option is optional and
can be used as parameter on the command line for selecting the used interface
even without the option being explicitly used.

.TP
.BI "--invert-colors " [mode]
Invert image colors. Results in black becoming white, dark colors becoming light,
light colors becoming dark and white becoming black. The optional
.I mode
parameter can be used to change the color inversion behaviour. Available modes:
0 = no color inversion, 1 = invert all colors except those used for rx and tx,
2 = invert all colors. When
.I mode
isn't specific, mode 1 will be used.

.TP
.B "-L, --large"
Expand Down
1 change: 1 addition & 0 deletions src/image.c
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ void initimagecontent(IMAGECONTENT *ic)
ic->font = gdFontGetSmall();
ic->lineheight = 12;
ic->large = 0;
ic->invert = 0;
ic->showheader = 1;
ic->showedge = 1;
ic->showlegend = 1;
Expand Down
2 changes: 1 addition & 1 deletion src/image.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ typedef struct {
interfaceinfo interface;
int cbackground, cedge, cheader, cheadertitle, cheaderdate, ctext, cline, clinel, cvnstat;
int crx, crxd, ctx, ctxd, cbgoffset, cbgoffsetmore, showheader, showedge, showlegend, altdate;
int lineheight, large;
int lineheight, large, invert;
char headertext[65], databegin[18], dataend[18];
time_t current;
} IMAGECONTENT;
Expand Down
49 changes: 42 additions & 7 deletions src/image_support.c
Original file line number Diff line number Diff line change
Expand Up @@ -7,75 +7,93 @@

void imageinit(IMAGECONTENT *ic, const int width, const int height)
{
int rgb[3];
int rgb[3], invert = 1;

ic->im = gdImageCreate(width, height);

if (ic->invert > 0) {
invert = -1;
}

/* text, edge and header colors */
hextorgb(cfg.ctext, rgb);
if (ic->invert > 0) { invertcolor(rgb); }
ic->ctext = gdImageColorAllocate(ic->im, rgb[0], rgb[1], rgb[2]);
colorinitcheck("ctext", ic->ctext, cfg.ctext, rgb);
hextorgb(cfg.cedge, rgb);
if (ic->invert > 0) { invertcolor(rgb); }
ic->cedge = gdImageColorAllocate(ic->im, rgb[0], rgb[1], rgb[2]);
colorinitcheck("cedge", ic->cedge, cfg.cedge, rgb);
hextorgb(cfg.cheader, rgb);
if (ic->invert > 0) { invertcolor(rgb); }
ic->cheader = gdImageColorAllocate(ic->im, rgb[0], rgb[1], rgb[2]);
colorinitcheck("cheader", ic->cheader, cfg.cheader, rgb);
hextorgb(cfg.cheadertitle, rgb);
if (ic->invert > 0) { invertcolor(rgb); }
ic->cheadertitle = gdImageColorAllocate(ic->im, rgb[0], rgb[1], rgb[2]);
colorinitcheck("cheadertitle", ic->cheadertitle, cfg.cheadertitle, rgb);
hextorgb(cfg.cheaderdate, rgb);
if (ic->invert > 0) { invertcolor(rgb); }
ic->cheaderdate = gdImageColorAllocate(ic->im, rgb[0], rgb[1], rgb[2]);
colorinitcheck("cheaderdate", ic->cheaderdate, cfg.cheaderdate, rgb);

/* lines */
hextorgb(cfg.cline, rgb);
if (ic->invert > 0) { invertcolor(rgb); }
ic->cline = gdImageColorAllocate(ic->im, rgb[0], rgb[1], rgb[2]);
colorinitcheck("cline", ic->cline, cfg.cline, rgb);
if (cfg.clinel[0] == '-') {
modcolor(rgb, 50, 1);
modcolor(rgb, 50 * invert, 1);
} else {
hextorgb(cfg.clinel, rgb);
if (ic->invert > 0) { invertcolor(rgb); }
}
ic->clinel = gdImageColorAllocate(ic->im, rgb[0], rgb[1], rgb[2]);
colorinitcheck("clinel", ic->clinel, cfg.clinel, rgb);

/* background */
hextorgb(cfg.cbg, rgb);
if (ic->invert > 0) { invertcolor(rgb); }
ic->cbackground = gdImageColorAllocate(ic->im, rgb[0], rgb[1], rgb[2]);
colorinitcheck("cbackground", ic->cbackground, cfg.cbg, rgb);
modcolor(rgb, -35, 0);
modcolor(rgb, -35 * invert, 0);
ic->cvnstat = gdImageColorAllocate(ic->im, rgb[0], rgb[1], rgb[2]);
colorinitcheck("cvnstat", ic->cvnstat, cfg.cbg, rgb);
hextorgb(cfg.cbg, rgb);
modcolor(rgb, -15, 0);
if (ic->invert > 0) { invertcolor(rgb); }
modcolor(rgb, -15 * invert, 0);
ic->cbgoffset = gdImageColorAllocate(ic->im, rgb[0], rgb[1], rgb[2]);
colorinitcheck("cbgoffset", ic->cbgoffset, cfg.cbg, rgb);
hextorgb(cfg.cbg, rgb);
modcolor(rgb, -40, 0);
if (ic->invert > 0) { invertcolor(rgb); }
modcolor(rgb, -40 * invert, 0);
ic->cbgoffsetmore = gdImageColorAllocate(ic->im, rgb[0], rgb[1], rgb[2]);
colorinitcheck("cbgoffsetmore", ic->cbgoffsetmore, cfg.cbg, rgb);

/* rx */
hextorgb(cfg.crx, rgb);
if (ic->invert > 1) { invertcolor(rgb); }
ic->crx = gdImageColorAllocate(ic->im, rgb[0], rgb[1], rgb[2]);
colorinitcheck("crx", ic->crx, cfg.crx, rgb);
if (cfg.crxd[0] == '-') {
modcolor(rgb, -50, 1);
modcolor(rgb, -50 * invert, 1);
} else {
hextorgb(cfg.crxd, rgb);
if (ic->invert > 1) { invertcolor(rgb); }
}
ic->crxd = gdImageColorAllocate(ic->im, rgb[0], rgb[1], rgb[2]);
colorinitcheck("crxd", ic->crxd, cfg.crxd, rgb);

/* tx */
hextorgb(cfg.ctx, rgb);
if (ic->invert > 1) { invertcolor(rgb); }
ic->ctx = gdImageColorAllocate(ic->im, rgb[0], rgb[1], rgb[2]);
colorinitcheck("ctx", ic->ctx, cfg.ctx, rgb);
if (cfg.ctxd[0] == '-') {
modcolor(rgb, -50, 1);
modcolor(rgb, -50 * invert, 1);
} else {
hextorgb(cfg.ctxd, rgb);
if (ic->invert > 1) { invertcolor(rgb); }
}
ic->ctxd = gdImageColorAllocate(ic->im, rgb[0], rgb[1], rgb[2]);
colorinitcheck("ctxd", ic->ctxd, cfg.ctxd, rgb);
Expand Down Expand Up @@ -429,6 +447,23 @@ void modcolor(int *rgb, const int offset, const int force)
}
}

void invertcolor(int *rgb)
{
int i;

if (debug) {
printf("invert: %d, %d, %d -> ", rgb[0], rgb[1], rgb[2]);
}

for (i = 0; i < 3; i++) {
rgb[i] = 255 - rgb[i];
}

if (debug) {
printf("%d, %d, %d\n", rgb[0], rgb[1], rgb[2]);
}
}

char *getimagevalue(const uint64_t b, const int len, const int rate)
{
static char buffer[64];
Expand Down
1 change: 1 addition & 0 deletions src/image_support.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ void drawarrowup(IMAGECONTENT *ic, const int x, const int y);
void drawarrowright(IMAGECONTENT *ic, const int x, const int y);
void hextorgb(const char *input, int *rgb);
void modcolor(int *rgb, const int offset, const int force);
void invertcolor(int *rgb);
char *getimagevalue(const uint64_t b, const int len, const int rate);
char *getimagescale(const uint64_t b, const int rate);
uint64_t getscale(const uint64_t input, const int rate);
Expand Down
23 changes: 22 additions & 1 deletion src/vnstati.c
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,8 @@ void showihelp(const IPARAMS *p)
#if HAVE_DECL_GD_NEAREST_NEIGHBOUR
printf(" --scale <percent> change image size by scaling it\n");
#endif
printf(" --transparent [enabled] toggle background transparency\n\n");
printf(" --transparent [enabled] toggle background transparency\n");
printf(" --invert-colors <mode> invert image colors (0-2)\n\n");

printf("See also \"man vnstati\".\n");
}
Expand Down Expand Up @@ -502,6 +503,26 @@ void parseargs(IPARAMS *p, IMAGECONTENT *ic, int argc, char **argv)
fprintf(stderr, "Error: Invalid or missing parameter for %s.\n", argv[currentarg]);
exit(EXIT_FAILURE);
}
} else if (strcmp(argv[currentarg], "--invert-colors") == 0) {
if (currentarg + 1 < argc && (strlen(argv[currentarg + 1]) == 1 || ishelprequest(argv[currentarg + 1]))) {
if (!isdigit(argv[currentarg + 1][0]) || atoi(argv[currentarg + 1]) > 2 || atoi(argv[currentarg + 1]) < 0) {
if (!ishelprequest(argv[currentarg + 1]))
fprintf(stderr, "Error: Invalid parameter \"%s\".\n", argv[currentarg + 1]);
printf(" Valid parameters for %s:\n", argv[currentarg]);
printf(" 0 - no color inversion\n");
printf(" 1 - invert all colors except rx and tx\n");
printf(" 2 - invert all colors\n");
exit(EXIT_FAILURE);
}
ic->invert = atoi(argv[currentarg + 1]);
if (debug)
printf("Invert colors changed: %d\n", ic->invert);
currentarg++;
} else {
ic->invert = !ic->invert;
if (debug)
printf("Invert colors changed: %d\n", ic->invert);
}
} else if ((strcmp(argv[currentarg], "-v") == 0) || (strcmp(argv[currentarg], "--version")) == 0) {
printf("vnStat image output %s by Teemu Toivola <tst at iki dot fi> (SQLite %s, LibGD %d.%d.%d)\n", getversion(), sqlite3_libversion(), GD_MAJOR_VERSION, GD_MINOR_VERSION, GD_RELEASE_VERSION);
exit(EXIT_SUCCESS);
Expand Down
26 changes: 26 additions & 0 deletions tests/image_tests.c
Original file line number Diff line number Diff line change
Expand Up @@ -871,6 +871,31 @@ START_TEST(modcolor_mods_colors)
}
END_TEST

START_TEST(invertcolor_inverts_colors)
{
int rgb[3];

debug = 1;
suppress_output();

rgb[0] = 0;
rgb[1] = 10;
rgb[2] = 255;
invertcolor(rgb);
ck_assert_int_eq(rgb[0], 255);
ck_assert_int_eq(rgb[1], 245);
ck_assert_int_eq(rgb[2], 0);

rgb[0] = 50;
rgb[1] = 150;
rgb[2] = 200;
invertcolor(rgb);
ck_assert_int_eq(rgb[0], 205);
ck_assert_int_eq(rgb[1], 105);
ck_assert_int_eq(rgb[2], 55);
}
END_TEST

void add_image_tests(Suite *s)
{
TCase *tc_image = tcase_create("Image");
Expand All @@ -897,5 +922,6 @@ void add_image_tests(Suite *s)
tcase_add_test(tc_image, element_output_check);
tcase_add_test(tc_image, hextorgb_can_convert);
tcase_add_test(tc_image, modcolor_mods_colors);
tcase_add_test(tc_image, invertcolor_inverts_colors);
suite_add_tcase(s, tc_image);
}

0 comments on commit adc7df0

Please sign in to comment.