/* Draw some ANSI text with a gradient from blue to orange through white. * * Truecolor escape sequences from ISO-8613-3 are supported in konsole * for a few years now, but in libvte (and thus gnome-terminal, * mate-terminal, xfce-terminal, etc.) only since 2014 and in xterm * only since version 282. Older terminals will probably interpret * these sequences as something different. * * Here’s a screenshot of the output in konsole: begin 644 gradient.png MB5!.1PT*&@H````-24A$4@```"4````."`8```"H]=7V```"$TE$051(QV-@ M8&#X/P@QB)`&8G:2-#(S,?\W4#$`8Q5I%30Y)J"X!!BK2`N1ZZ@[0&Q!DD8N M=J[_*^I6_#\R^A,8$T#&/5S'\=S3$ZBA+),$W0*SQ7T[P$4Y\5PE+ZR!%"N!"B'*`-! M:>?N,H;_B="0T02&W+<=$,<2Y2@06T)('QQ]()SI?^E_4>ACH)@!BN43+X?_;30S_L_RQYC["F(=3 MXC\_MRRXB*!&50(*,7EQ!F!.QEE.# #include #include void usage(const char *argv0) { fprintf(stderr, "Usage: %s message\n", argv0); fprintf(stderr, "Displays `message` in a color gradient, blue to white to orange.\n"); } int red(float f) { return (f > 0.5 ? 255 : (int)(0.5 + f * 2 * 255)); } int green(float f) { return (int)(0.5 + red(f) * 0.75); } int blue(float f) { return red(1 - f); } /* This is enough to cover the BMP so who cares */ uint8_t utf_8_len[] = { 1, 1, 1, 1, 1, 1, 1, 1, /* ...0111 */ 1, 1, 1, 1, /* 1000, 1001, 1010, 1011 */ 2, 2, 3, 4, /* 1100, 1101, 1110, 1111 */ }; typedef struct { char *p, *e; uint8_t bytes_left; /* in this character */ } u8iter; int u8iter_is_empty(u8iter *p) { return p->p == p->e; } void u8iter_embrace_nul_terminated(u8iter *p, char *s) { p->p = s; p->e = s + strlen(s); p->bytes_left = 0; } int u8iter_next_byte(u8iter *p, char *c) { if (!p->bytes_left) return 0; p->bytes_left--; *c = *p->p; p->p++; return 1; } void u8iter_next_codepoint(u8iter *p) { if (u8iter_is_empty(p)) return; while (p->bytes_left) { char c; u8iter_next_byte(p, &c); } if (!u8iter_is_empty(p)) { p->bytes_left = utf_8_len[(int)((uint8_t)*p->p >> 4)]; } } int utf_8_strlen(char *utf8z) { u8iter it; int n = 0; u8iter_embrace_nul_terminated(&it, utf8z); while (!u8iter_is_empty(&it)) { u8iter_next_codepoint(&it); n++; } return n; } #define CSI "\033[" #define RGB CSI "38;2;" void rgb(int r, int g, int b, char *dest) { /* This kind of use of sprintf is often insecure. Do not imitate. */ sprintf(dest, RGB "%d;%d;%dm", r, g, b); } int main(int argc, char **argv) { if (argc != 2) { usage(argv[0]); return 1; } int n = utf_8_strlen(argv[1]); u8iter it; u8iter_embrace_nul_terminated(&it, argv[1]); for (int i = 0; i != n; i++) { float f = (float)i/(n-1); char rgbbuf[32]; rgb(red(f), green(f), blue(f), rgbbuf); fputs(rgbbuf, stdout); u8iter_next_codepoint(&it); char c; while (u8iter_next_byte(&it, &c)) { putchar(c); } } fputs(CSI "0m\n", stdout); return 0; }