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 }