💾 Archived View for gemini.rmf-dev.com › repo › Vaati › Vgmi › files › 753ea1f1a8f9bfdd30f5d7cae57b1… captured on 2023-12-28 at 15:43:15. Gemini links have been rewritten to link to archived content
-=-=-=-=-=-=-
0 /*
1 * ISC License
2 * Copyright (c) 2023 RMF <rawmonk@firemail.cc>
3 */
4 #include <stdlib.h>
5 #include "image.h"
6 #ifdef ENABLE_IMAGE
7 #include <stdio.h>
8 #include <stdint.h>
9 #include <unistd.h>
10 #include <string.h>
11 #include <poll.h>
12 #include "sandbox.h"
13 #include "termbox.h"
14 #include "error.h"
15 #include "proc.h"
16 #include "macro.h"
17 #include "config.h"
18
19 int image_process = 0;
20
21 static int _write(int fd, char *data, int length) {
22 int i;
23 for (i = 0; i < length;) {
24 int bytes = write(fd, &data[i], length - i);
25 if (bytes < 1) return -1;
26 i += bytes;
27 }
28 return 0;
29 }
30
31 static int _read(int fd, void *ptr, int length) {
32 int i;
33 char *data = ptr;
34 struct pollfd pfd;
35 pfd.fd = fd;
36 pfd.events = POLLIN;
37 for (i = 0; i < length;) {
38 int bytes;
39 if (!poll(&pfd, 1, 3000)) return -1;
40 bytes = read(fd, &data[i], length);
41 if (bytes < 1) return -1;
42 i += bytes;
43 }
44 return 0;
45 }
46
47 static int __read(int fd, void *ptr, int length) {
48 int i;
49 char *data = ptr;
50 for (i = 0; i < length;) {
51 int bytes;
52 bytes = read(fd, &data[i], length);
53 if (bytes < 1) return -1;
54 i += bytes;
55 }
56 return 0;
57 }
58
59 static int empty_pipe(int fd) {
60 struct pollfd pfd;
61 pfd.fd = fd;
62 pfd.events = POLLIN;
63 while (poll(&pfd, 1, 0)) {
64 uint8_t byte;
65 if (read(fd, &byte, 1) != 1) return -1;
66 }
67 return 0;
68 }
69
70 void image_parser(int in, int out) {
71
72 char *data;
73 uint8_t byte;
74 #ifdef STATIC_ALLOC
75 size_t length;
76
77 data = malloc(config.imageParserScratchPad);
78 if (!data) return;
79 memset(data, 0, config.imageParserScratchPad);
80 image_memory_set(data, config.imageParserScratchPad);
81
82 length = config.imageParserScratchPad / 2;
83 data = malloc(length);
84 if (!data) return;
85 memset(data, 0, length);
86 #else
87 data = NULL;
88 #endif
89
90 sandbox_set_name("vgmi [image]");
91 sandbox_isolate();
92
93 byte = 0;
94 write(out, &byte, 1);
95
96 while (1) {
97
98 int x, y, size;
99 void *img;
100
101 img = NULL;
102 size = y = x = 0;
103
104 if (read(in, P(size)) != sizeof(size)) break;
105 #ifdef STATIC_ALLOC
106 if ((unsigned)size > length) goto fail;
107 #else
108 data = malloc(size);
109 if (!data) goto fail;
110 #endif
111 if (!size) goto fail;
112 write(out, P(size));
113 if (__read(in, data, size)) goto fail;
114 img = image_load(data, size, &x, &y);
115 if (!img) goto fail;
116 #ifndef STATIC_ALLOC
117 free(data);
118 #endif
119 write(out, P(x));
120 write(out, P(y));
121 if (_write(out, img, x * y * 3)) break;
122 #ifndef STATIC_ALLOC
123 free(img);
124 #endif
125 continue;
126 fail:
127 size = -1;
128 write(out, P(size));
129 free(data);
130 }
131 }
132
133 #define OK(X) if (X) return NULL
134 int image_fd_out = -1;
135 int image_fd_in = -1;
136 void *image_parse(void *data, int len, int *x, int *y) {
137 int _x, _y, size;
138 void *img;
139 if (image_fd_out == -1 || image_fd_in == -1) return NULL;
140 empty_pipe(image_fd_in);
141 write(image_fd_out, P(len));
142 OK(_read(image_fd_in, P(size)));
143 OK(size != len);
144 OK(_write(image_fd_out, data, len));
145 OK(_read(image_fd_in, P(_x)));
146 OK(_x == -1);
147 OK(_read(image_fd_in, P(_y)));
148 size = _x * _y * 3;
149 OK(size < 1 || size > config.imageParserScratchPad);
150 img = malloc(size);
151 if (!img || _read(image_fd_in, img, size)) {
152 free(img);
153 return NULL;
154 }
155 *x = _x;
156 *y = _y;
157 return img;
158 }
159
160 int image_init() {
161 int ret;
162 if (!config.enableImage) return 0;
163 ret = proc_fork("--image", &image_fd_in, &image_fd_out);
164 if (ret) return ret;
165 image_process = 1;
166 return 0;
167 }
168
169 static int color_abs(int c, int x, int i) {
170 return abs(c -= i > 215 ? i * 10 - 2152:x * 40 + !!x * 55);
171 }
172
173 static int color(uint8_t r, uint8_t g, uint8_t b) {
174 int m = 0, t = 0, i = 240, l = 240;
175 while (i--) {
176 t = color_abs(r, i / 36, i) + color_abs(g, i / 6 % 6, i) +
177 color_abs(b, i % 6, i);
178 if (t < l) {
179 l = t;
180 m = i;
181 }
182 }
183 i = m + 16;
184 return i;
185 }
186
187 int average_pixel(uint8_t* data, int x, int y, int w, int h, float ratio) {
188 int pixels = 0;
189 int r = 0, g = 0, b = 0, i, j;
190 float precision = 2;
191 float rp = ratio / precision;
192 for (i = x - rp; i < x + rp; i++) {
193 if (i >= w || i < 0) continue;
194 for (j = y - rp; j < y + rp; j++) {
195 if (j >= h || j < 0) continue;
196 r += data[(i + j * w) * 3];
197 g += data[(i + j * w) * 3 + 1];
198 b += data[(i + j * w) * 3 + 2];
199 pixels++;
200 }
201 }
202 if (pixels == 0) return TB_DEFAULT;
203 return color(r / pixels, g / pixels, b / pixels);
204 }
205
206 int image_display(unsigned char* data, int w, int h, int offsety) {
207 int _x = 0, _y = 0;
208 double x, y;
209 double w_ratio = (double)w/(tb_width());
210 double h_ratio = (double)h/((tb_height() - offsety - 2) * 2);
211
212 if (w_ratio < h_ratio)
213 w_ratio = h_ratio;
214 else
215 h_ratio = w_ratio;
216
217 for (x = 0; x < (double)w; x += w_ratio) {
218 for (y = 0; y < (double)h; y += h_ratio) {
219 int fg = average_pixel(data, x, y + 1, w, h, h_ratio);
220 int bg = average_pixel(data, x, y, w, h, h_ratio);
221 tb_set_cell(_x, _y + offsety, 0x2584, fg, bg);
222 y += h_ratio;
223 _y++;
224 }
225 _y = 0;
226 _x++;
227 }
228 return 0;
229 }
230 #else
231 typedef int hide_warning;
232 #endif
233