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 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 }