0 /* See LICENSE file for copyright and license details. */
1 #if defined(TERMINAL_IMG_VIEWER) && defined(__has_include) && \
2 !(__has_include(<stb_image.h>))
3 #warning Unable to build built-in image viewer, stb_image header not found
4 #endif
5 #include "img.h"
6
7 #ifdef TERMINAL_IMG_VIEWER
8 #include <termbox.h>
9 #include "gemini.h"
10 #define STB_IMAGE_IMPLEMENTATION
11 #include <stb_image.h>
12
13 int color_abs(int c, int x, int i) {
14 return abs(c -= i > 215?i * 10 - 2152:x * 40 + !!x * 55);
15 }
16
17 int color(uint8_t r, uint8_t g, uint8_t b) {
18 int m = 0, t = 0;
19 int i = 240, l = 240;
20 while (i--) {
21 t = color_abs(r, i/36, i) +
22 color_abs(g, i/6%6, i) +
23 color_abs(b, i%6, i);
24 if (t < l) {
25 l = t;
26 m = i;
27 }
28 }
29 i=m+16;
30 return i;
31 }
32
33 int color8(int r, int g, int b) {
34 if (r < 20 && g < 20 && b < 20)
35 return TB_BLACK;
36 if (r > 150 && g > 150 && b > 150 && r + g + b > 490)
37 return TB_WHITE;
38 if (r > (b + 10) * 2 && g > (b + 10) * 2 && g - r <= 10 * (g > r?1:-1))
39 return TB_YELLOW;
40 if (b > (r + 10) && g > (r + 10) && b > 80 && g > 80)
41 return TB_CYAN;
42 if (g > (r + b + 50)/2)
43 return TB_GREEN;
44 if (r > g + 30 && b > g + 30) // purple
45 return TB_MAGENTA;
46 if (b > (r + g + 50)/2)
47 return TB_BLUE;
48 if (r > g + 30 && g > b + 30 && b > 30 && g < b * 2) // brown
49 return TB_WHITE;
50 if (r > (g + b + 50)/2)
51 return TB_RED;
52 if (r > 120 && g > 60 && b > 130 && g < r && g < b)
53 return TB_MAGENTA;
54 if (r + g + b > 380)
55 return TB_WHITE;
56 return TB_BLACK;
57 }
58
59 int average_pixel(uint8_t* data, int x, int y, int w, int h,
60 float ratio, int c8) {
61 int pixels = 0;
62 int r = 0, g = 0, b = 0;
63 float precision = 2;
64 for (int i = x - ratio/precision; i < x + ratio/precision; i++) {
65 if (i >= w || i < 0) continue;
66 for (int j = y - ratio/precision;
67 j < y + ratio/precision; j++) {
68 if (j >= h || j < 0) continue;
69 r += data[(i + j * w) * 3];
70 g += data[(i + j * w) * 3 + 1];
71 b += data[(i + j * w) * 3 + 2];
72 pixels++;
73 }
74 }
75 if (pixels == 0) return 0;
76 return c8?color8(r/pixels, g/pixels, b/pixels):
77 color(r/pixels, g/pixels, b/pixels);
78 }
79
80 int img_display(uint8_t* data, int w, int h, int offsety) {
81 int c8 = !client.c256;
82
83 double w_ratio = (double)w/(tb_width());
84 double h_ratio = (double)h/((tb_height() - offsety - 2) * 2);
85 if (w_ratio < h_ratio)
86 w_ratio = h_ratio;
87 else
88 h_ratio = w_ratio;
89 int _x = 0;
90 int _y = 0;
91 for (double x = 0; x < (double)w; x += w_ratio) {
92 for (double y = 0; y < (double)h; y += h_ratio) {
93 int fg = average_pixel(data, x, y + 1, w, h,
94 h_ratio, c8);
95 int bg = average_pixel(data, x, y, w, h,
96 h_ratio, c8);
97 tb_print(_x, _y+offsety,
98 fg,
99 bg,
100 "▄");
101 y += h_ratio;
102 _y++;
103 }
104 _y = 0;
105 _x++;
106 }
107 return 0;
108 }
109
110 #else
111 typedef int remove_iso_warning;
112 #endif
113