blind-from-image.c - blind - suckless command-line video editing utility
(HTM) git clone git://git.suckless.org/blind
(DIR) Log
(DIR) Files
(DIR) Refs
(DIR) README
(DIR) LICENSE
---
blind-from-image.c (6714B)
---
1 /* See LICENSE file for copyright and license details. */
2 #include "common.h"
3
4 USAGE("[-h] [-f | -p]")
5
6 static char buf[BUFSIZ];
7 static char width[INTSTRLEN(size_t) + 1] = {0};
8 static char height[INTSTRLEN(size_t) + 1] = {0};
9 static const char *conv_fail_msg = "convertion failed, if converting a farbfeld file, try -f";
10 static size_t pixel_size;
11 static double value_max;
12 static double (*get_value)(char **bufp);
13 static void (*convert)(size_t n);
14 static int with_alpha = 1;
15 static int with_colour = 1;
16
17 static double
18 get_value_u8(char** bufp)
19 {
20 uint8_t value = *(uint8_t *)(*bufp);
21 *bufp += 1;
22 return (double)value / (double)value_max;
23 }
24
25 static double
26 get_value_u16(char** bufp)
27 {
28 uint16_t value = ntohs(*(uint16_t *)(*bufp));
29 *bufp += 2;
30 return (double)value / (double)value_max;
31 }
32
33 static double
34 get_value_u32(char** bufp)
35 {
36 uint32_t value = ntohl(*(uint32_t *)(*bufp));
37 *bufp += 4;
38 return (double)value / (double)value_max;
39 }
40
41 static double
42 get_value_u64(char** bufp)
43 {
44 uint64_t value;
45 value = (uint64_t)(buf[0]) << 56;
46 value |= (uint64_t)(buf[1]) << 48;
47 value |= (uint64_t)(buf[2]) << 40;
48 value |= (uint64_t)(buf[3]) << 32;
49 value |= (uint64_t)(buf[4]) << 24;
50 value |= (uint64_t)(buf[5]) << 16;
51 value |= (uint64_t)(buf[6]) << 8;
52 value |= (uint64_t)(buf[7]);
53 *bufp += 8;
54 return (double)value / (double)value_max;
55 }
56
57 static void
58 from_srgb(size_t n)
59 {
60 double red, green, blue, pixel[4];
61 size_t ptr;
62 char *p;
63 for (ptr = 0; ptr + pixel_size <= n; ptr += pixel_size) {
64 p = buf + ptr;
65 red = srgb_decode(get_value(&p));
66 green = with_colour ? srgb_decode(get_value(&p)) : red;
67 blue = with_colour ? srgb_decode(get_value(&p)) : red;
68 pixel[3] = with_alpha ? get_value(&p) : 1;
69 srgb_to_ciexyz(red, green, blue, pixel + 0, pixel + 1, pixel + 2);
70 ewriteall(STDOUT_FILENO, pixel, sizeof(pixel), "<stdout>");
71 }
72 }
73
74 static size_t
75 farbfeld_head(int fd, const char *fname)
76 {
77 if (ereadall(fd, buf, 16, fname) != 16)
78 eprintf("%s\n", conv_fail_msg);
79 if (memcmp(buf, "farbfeld", 8))
80 eprintf("%s\n", conv_fail_msg);
81 sprintf(width, "%"PRIu32, ntohl(*(uint32_t *)(buf + 8)));
82 sprintf(height, "%"PRIu32, ntohl(*(uint32_t *)(buf + 12)));
83 pixel_size = 4 * sizeof(uint16_t);
84 value_max = UINT16_MAX;
85 get_value = get_value_u16;
86 convert = from_srgb;
87 return 0;
88 }
89
90 static size_t
91 pam_head(int fd, const char *fname)
92 {
93 size_t ptr;
94 size_t r;
95 char *p;
96 unsigned long long int maxval = UINT8_MAX;
97 for (ptr = 0;;) {
98 if (!(r = eread(fd, buf + ptr, sizeof(buf) - 1, fname)))
99 eprintf("%s\n", conv_fail_msg);
100 ptr += r;
101 for (;;) {
102 p = memchr(buf, '\n', ptr);
103 if (!p) {
104 if (ptr == sizeof(buf))
105 eprintf("%s\n", conv_fail_msg);
106 break;
107 }
108 *p++ = '\0';
109 if (strstr(buf, "WIDTH ") == buf) {
110 if (*width || !buf[6] || strlen(buf + 6) >= sizeof(width))
111 eprintf("%s\n", conv_fail_msg);
112 strcpy(width, buf + 6);
113 } else if (strstr(buf, "HEIGHT ") == buf) {
114 if (*height || !buf[7] || strlen(buf + 7) >= sizeof(height))
115 eprintf("%s\n", conv_fail_msg);
116 strcpy(height, buf + 7);
117 } else if (strstr(buf, "MAXVAL ") == buf) {
118 if (tollu(buf + 7, 0, UINT64_MAX, &maxval)) {
119 if (errno != ERANGE)
120 eprintf("%s\n", conv_fail_msg);
121 eprintf("image uses greater colour resolution than supported\n");
122 } else if (!maxval) {
123 eprintf("%s\n", conv_fail_msg);
124 }
125 } else if (strstr(buf, "TUPLTYPE ") == buf) {
126 if (!strcmp(buf, "TUPLTYPE BLACKANDWHITE"))
127 maxval = 1, with_colour = 0, with_alpha = 0;
128 else if (!strcmp(buf, "TUPLTYPE BLACKANDWHITE_ALPHA"))
129 maxval = 1, with_colour = 0, with_alpha = 1;
130 else if (!strcmp(buf, "TUPLTYPE GRAYSCALE"))
131 with_colour = 0, with_alpha = 0;
132 else if (!strcmp(buf, "TUPLTYPE GRAYSCALE_ALPHA"))
133 with_colour = 0, with_alpha = 1;
134 else if (!strcmp(buf, "TUPLTYPE RGB"))
135 with_colour = 1, with_alpha = 0;
136 else if (!strcmp(buf, "TUPLTYPE RGB_ALPHA"))
137 with_colour = 1, with_alpha = 1;
138 else
139 eprintf("image uses an unsupported tuple type: %s\n", buf + STRLEN("TUPLTYPE "));
140 } else if (!strcmp(buf, "ENDHDR")) {
141 memmove(buf, p, ptr -= (size_t)(p - buf));
142 goto header_done;
143 }
144 memmove(buf, p, ptr -= (size_t)(p - buf));
145 }
146 }
147 header_done:
148 if (maxval <= (size_t)UINT8_MAX) {
149 pixel_size = sizeof(uint8_t);
150 get_value = get_value_u8;
151 } else if (maxval <= (size_t)UINT16_MAX) {
152 pixel_size = sizeof(uint16_t);
153 get_value = get_value_u16;
154 } else if (maxval <= (size_t)UINT32_MAX) {
155 pixel_size = sizeof(uint32_t);
156 get_value = get_value_u32;
157 } else {
158 pixel_size = sizeof(uint64_t);
159 get_value = get_value_u64;
160 }
161 value_max = (double)maxval;
162 pixel_size *= (size_t)((with_colour ? 3 : 1) + with_alpha);
163 convert = from_srgb;
164 return ptr;
165 }
166
167 int
168 main(int argc, char *argv[])
169 {
170 int status, pipe_rw[2], i, old_fd, forked = 0;
171 int headless = 0, farbfeld = 0, pam = 0;
172 pid_t pid = 0;
173 size_t off, n;
174 ssize_t r;
175 const char *file = "<subprocess>";
176
177 ARGBEGIN {
178 case 'f':
179 farbfeld = 1;
180 break;
181 case 'h':
182 headless = 1;
183 break;
184 case 'p':
185 pam = 1;
186 break;
187 default:
188 usage();
189 } ARGEND;
190
191 if (argc || (farbfeld && pam))
192 usage();
193
194 if (farbfeld)
195 conv_fail_msg = "not a valid farbfeld file, try without -f";
196 else if (pam)
197 conv_fail_msg = "not a valid RGBA portable arbitrary map file, try without -p";
198 else
199 forked = 1;
200
201 if (!forked) {
202 file = "<stdin>";
203 pipe_rw[0] = STDIN_FILENO;
204 goto after_fork;
205 }
206
207 epipe(pipe_rw);
208 if (pipe_rw[0] == STDIN_FILENO || pipe_rw[1] == STDIN_FILENO)
209 eprintf("no stdin open\n");
210 if (pipe_rw[0] == STDOUT_FILENO || pipe_rw[1] == STDOUT_FILENO)
211 eprintf("no stdout open\n");
212 for (i = 0; i < 2; i++) {
213 if (pipe_rw[i] == STDERR_FILENO) {
214 pipe_rw[i] = edup(old_fd = pipe_rw[i]);
215 close(old_fd);
216 }
217 }
218
219 pid = efork();
220 if (!pid) {
221 close(pipe_rw[0]);
222 edup2(pipe_rw[1], STDOUT_FILENO);
223 close(pipe_rw[1]);
224 /* XXX Is there a way to convert directly to raw XYZ? (Would avoid gamut truncation) */
225 eexeclp("convert", "convert", "-", "-depth", "32", "-alpha", "activate", "pam:-", NULL);
226 }
227
228 close(pipe_rw[1]);
229 after_fork:
230
231 if (farbfeld)
232 n = farbfeld_head(pipe_rw[0], file);
233 else
234 n = pam_head(pipe_rw[0], file);
235
236 if (!*width || !*height)
237 eprintf("%s\n", conv_fail_msg);
238
239 if (!headless) {
240 FPRINTF_HEAD_FMT(stdout, "%i", 1, "%s", width, "%s", height, "xyza");
241 efflush(stdout, "<stdout>");
242 }
243
244 for (;;) {
245 convert(n);
246 off = n - (n % pixel_size);
247 memmove(buf, buf + off, n -= off);
248 r = read(pipe_rw[0], buf + n, sizeof(buf) - n);
249 if (r < 0)
250 eprintf("read %s:", file);
251 if (r == 0)
252 break;
253 n += (size_t)r;
254 }
255
256 if (!forked)
257 return 0;
258 close(pipe_rw[0]);
259 while (waitpid(pid, &status, 0) != pid);
260 return !!status;
261 }