blind-from-image.c - blind - suckless command-line video editing utility | |
git clone git://git.suckless.org/blind | |
Log | |
Files | |
Refs | |
README | |
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 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)) : re… | |
67 blue = with_colour ? srgb_decode(get_value(&p)) : re… | |
68 pixel[3] = with_alpha ? get_value(&p) : 1; | |
69 srgb_to_ciexyz(red, green, blue, pixel + 0, pixel + 1, p… | |
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)… | |
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… | |
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, &maxva… | |
119 if (errno != ERANGE) | |
120 eprintf("%s\n", conv_fai… | |
121 eprintf("image uses greater colo… | |
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, wit… | |
128 else if (!strcmp(buf, "TUPLTYPE BLACKAND… | |
129 maxval = 1, with_colour = 0, wit… | |
130 else if (!strcmp(buf, "TUPLTYPE GRAYSCAL… | |
131 with_colour = 0, with_alpha = 0; | |
132 else if (!strcmp(buf, "TUPLTYPE GRAYSCAL… | |
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_ALPH… | |
137 with_colour = 1, with_alpha = 1; | |
138 else | |
139 eprintf("image uses an unsupport… | |
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 … | |
196 else if (pam) | |
197 conv_fail_msg = "not a valid RGBA portable arbitrary map… | |
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? (W… | |
225 eexeclp("convert", "convert", "-", "-depth", "32", "-alp… | |
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", hei… | |
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 } |