1 /* tiv - terminal image viewer - MIT 2013-2019 - pancake */
2
3 #include <r_cons.h>
4
5 #define XY(b,x,y) ( b+((y)*(w*3))+(x*3) )
6 #define ABS(x) (((x)<0)?-(x):(x))
7 #define POND(x,y) (ABS((x)) * (y))
8
9 void (*renderer)(PrintfCallback cb_printf, const ut8*, const ut8 *);
10
reduce8(int r,int g,int b)11 static int reduce8 (int r, int g, int b) {
12 int colors_len = 8;
13 int select = 0;
14 int odistance = -1;
15 int i, k = 1;
16 int colors[][3] = {
17 { 0x00,0x00,0x00 }, // black
18 { 0xd0,0x10,0x10 }, // red
19 { 0x10,0xe0,0x10 }, // green
20 { 0xf7,0xf5,0x3a }, // yellow
21 { 0x10,0x10,0xf0 }, // blue // XXX
22 { 0xfb,0x3d,0xf8 }, // pink
23 { 0x10,0xf0,0xf0 }, // turqoise
24 { 0xf0,0xf0,0xf0 }, // white
25 };
26
27 r /= k; r *= k;
28 g /= k; g *= k;
29 b /= k; b *= k;
30 // B&W
31 if (r<30 && g<30 && b<30) return 0;
32 if (r>200&& g>200&& b>200) return 7;
33 odistance = -1;
34 for (i = 0; i<colors_len; i++) {
35 int distance =
36 POND (colors[i][0]-r, r)
37 + POND (colors[i][1]-g, g)
38 + POND (colors[i][2]-b, b);
39 if (odistance == -1 || distance < odistance) {
40 odistance = distance;
41 select = i;
42 }
43 }
44 return select;
45 }
46
render_ansi(PrintfCallback cb_printf,const ut8 * c,const ut8 * d)47 static void render_ansi(PrintfCallback cb_printf, const ut8 *c, const ut8 *d) {
48 int fg = 0;
49 int color = reduce8 (c[0], c[1], c[2]);
50 if (color == -1)return;
51 //if (c[0]<30 && c[1]<30 && c[2]<30) fg = 1;
52 cb_printf ("\x1b[%dm", color+(fg?30:40));
53 }
54
rgb(int r,int g,int b)55 static int rgb(int r, int g, int b) {
56 r = R_DIM (r, 0, 255);
57 g = R_DIM (g, 0, 255);
58 b = R_DIM (b, 0, 255);
59 r = (int)(r/50.6);
60 g = (int)(g/50.6);
61 b = (int)(b/50.6);
62 return 16 + (r*36) + (g*6) + b;
63 }
64
render_256(PrintfCallback cb_printf,const ut8 * c,const ut8 * d)65 static void render_256(PrintfCallback cb_printf, const ut8 *c, const ut8 *d) {
66 cb_printf ("\x1b[%d;5;%dm", 38, rgb (c[0], c[1], c[2]));
67 cb_printf ("\x1b[%d;5;%dm", 48, rgb (d[0], d[1], d[2]));
68 }
69
render_rgb(PrintfCallback cb_printf,const ut8 * c,const ut8 * d)70 static void render_rgb(PrintfCallback cb_printf, const ut8 *c, const ut8 *d) {
71 cb_printf ("\x1b[38;2;%d;%d;%dm", c[0], c[1], c[2]);
72 cb_printf ("\x1b[48;2;%d;%d;%dm", d[0], d[1], d[2]);
73 }
74
render_greyscale(PrintfCallback cb_printf,const ut8 * c,const ut8 * d)75 static void render_greyscale(PrintfCallback cb_printf, const ut8 *c, const ut8 *d) {
76 int color1, color2, k;
77 color1 = (c[0]+c[1]+c[2]) / 3;
78 color2 = (d[0]+d[1]+d[2]) / 3;
79 k = 231 + ((int)((float)color1/10.3));
80 if (k<232) k = 232;
81 cb_printf ("\x1b[%d;5;%dm", 48, k); // bg
82 k = 231 + ((int)((float)color2/10.3));
83 if (k<232) k = 232;
84 cb_printf ("\x1b[%d;5;%dm", 38, k); // fg
85 }
86
render_ascii(PrintfCallback cb_printf,const ut8 * c,const ut8 * d)87 static void render_ascii(PrintfCallback cb_printf, const ut8 *c, const ut8 *d) {
88 const char *pal = " `.,-:+*%$#";
89 int idx, pal_len = strlen (pal);
90 float p = (c[0]+c[1]+c[2])/3;
91 float q = (d[0]+d[1]+d[2])/3;
92 idx = ((p+q)/2) / (255/pal_len);
93 if (idx >= pal_len) idx = pal_len-1;
94 cb_printf ("%c", pal[idx]);
95 }
96
dorender(PrintfCallback cb_printf,const ut8 * buf,int len,int w,int h)97 static void dorender (PrintfCallback cb_printf, const ut8 *buf, int len, int w, int h) {
98 const ut8 *c, *d;
99 int x, y;
100 for (y=0; y<h; y+=2) {
101 for (x=0; x<w; x++) {
102 c = XY (buf, x, y);
103 d = XY (buf, x, y+1);
104 if (d> (buf+len)) break;
105 renderer (cb_printf, c, d);
106 if (renderer != render_ascii) {
107 render_ascii (cb_printf, c, d);
108 }
109 }
110 cb_printf ((renderer==render_ascii)?"\n":"\x1b[0m\n");
111 }
112 }
113
selectrenderer(int mode)114 static void selectrenderer(int mode) {
115 switch (mode) {
116 case 'a':
117 renderer = render_ascii;
118 break;
119 case 'A':
120 renderer = render_ansi;
121 break;
122 case 'g': renderer = render_greyscale; break;
123 case '2': renderer = render_256; break;
124 default:
125 renderer = render_rgb;
126 break;
127 }
128 }
129
r_cons_image(const ut8 * buf,int bufsz,int width,int mode)130 R_API void r_cons_image(const ut8 *buf, int bufsz, int width, int mode) {
131 int height = (bufsz / width) / 3;
132 selectrenderer (mode);
133 dorender (r_cons_printf, buf, bufsz, width, height);
134 }
135
136 #if 0
137 int
138 main(int argc, const char **argv) {
139 ut8 *buf, *c, *d;
140 int n, x, y, w, h, imgsz, readsz;
141 if (argc<3) {
142 printf ("stiv . suckless terminal image viewer\n");
143 printf ("Usage: stiv [width] [height] [ascii|ansi|grey|256|rgb] < rgb24\n");
144 return 1;
145 }
146 w = atoi (argv[1]);
147 h = atoi (argv[2]);
148 if (argc>3) {
149 selectrenderer (argv[3]);
150 } else renderer = render_rgb;
151 if (w<1 || h<1) {
152 printf ("Invalid arguments\n");
153 return 1;
154 }
155 imgsz = w * h * 3;
156 buf = malloc (imgsz);
157 readsz = 0;
158 do {
159 n = read(0, buf+readsz, imgsz);
160 if (n<1) break;
161 readsz += n;
162 } while (readsz < imgsz);
163
164 dorender (buf, readsz, w, h);
165
166 free (buf);
167 return 0;
168 }
169 #endif
170