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 }