blind

suckless command-line video editing utility
git clone git://git.suckless.org/blind
Log | Files | Refs | README | LICENSE

commit bc7830ba80267a4a228ed1de62e0f65045b3d174
parent ab8f1c11c93e2d7fb56638006e13fb0646231b5a
Author: Mattias Andrée <maandree@kth.se>
Date:   Thu, 12 Jan 2017 11:27:40 +0100

Fix and improve vu-from-image

Signed-off-by: Mattias Andrée <maandree@kth.se>

Diffstat:
Msrc/util.c | 24++++++++++++++++++++----
Msrc/util/io.h | 12++++++++++++
Msrc/vu-from-image.c | 266++++++++++++++++++++++++++++++++++++++++++++++++++++---------------------------
3 files changed, 207 insertions(+), 95 deletions(-)

diff --git a/src/util.c b/src/util.c @@ -112,18 +112,34 @@ int writeall(int fd, void *buf, size_t n) { char *buffer = buf; - size_t ptr = 0; ssize_t r; - while (ptr < n) { + while (n) { r = write(fd, buffer, n); if (r < 0) return -1; - buffer += (size_t)ptr; - n -= (size_t)ptr; + buffer += (size_t)r; + n -= (size_t)r; } return 0; } +ssize_t +readall(int fd, void *buf, size_t n) +{ + char *buffer = buf; + size_t ptr = 0; + ssize_t r; + for (;;) { + r = read(fd, buffer + ptr, n - ptr); + if (r < 0) + return -1; + if (r == 0) + break; + r += (size_t)r; + } + return r; +} + static inline pid_t enfork(int status) diff --git a/src/util/io.h b/src/util/io.h @@ -1,6 +1,7 @@ /* See LICENSE file for copyright and license details. */ #define ewriteall(...) enwriteall(1, __VA_ARGS__) +#define ereadall(...) enreadall(1, __VA_ARGS__) int writeall(int fd, void *buf, size_t n); @@ -10,3 +11,14 @@ enwriteall(int status, int fd, void *buf, size_t n, const char *fname) if (writeall(fd, buf, n)) enprintf(status, "write %s:", fname); } + +ssize_t readall(int fd, void *buf, size_t n); + +static inline size_t +enreadall(int status, int fd, void *buf, size_t n, const char *fname) +{ + ssize_t r = readall(fd, buf, n); + if (r < 0) + enprintf(status, "read %s:", fname); + return (size_t)r; +} diff --git a/src/vu-from-image.c b/src/vu-from-image.c @@ -9,38 +9,172 @@ USAGE("[-h] [-f | -p]") +static char buf[BUFSIZ]; +static char width[3 * sizeof(size_t) + 1] = {0}; +static char height[3 * sizeof(size_t) + 1] = {0}; +static const char *conv_fail_msg = "convertion failed, if converting a farbfeld file, try -f"; +static size_t pixel_size; +static double value_max; +static double (*get_value)(char **bufp); +static void (*convert)(size_t n); +static int with_alpha = 1; +static int with_colour = 1; + +static double +get_value_u8(char** bufp) +{ + uint8_t value = *(uint8_t *)(*bufp); + *bufp += 1; + return value / value_max; +} + +static double +get_value_u16(char** bufp) +{ + uint16_t value = ntohs(*(uint16_t *)(*bufp)); + *bufp += 2; + return value / value_max; +} + +static double +get_value_u32(char** bufp) +{ + uint32_t value = ntohl(*(uint32_t *)(*bufp)); + *bufp += 4; + return value / value_max; +} + static double -get_value(void *buffer) +get_value_u64(char** bufp) +{ + uint64_t value; + value = (uint64_t)(buf[0]) << 56; + value |= (uint64_t)(buf[1]) << 48; + value |= (uint64_t)(buf[2]) << 40; + value |= (uint64_t)(buf[3]) << 32; + value |= (uint64_t)(buf[4]) << 24; + value |= (uint64_t)(buf[5]) << 16; + value |= (uint64_t)(buf[6]) << 8; + value |= (uint64_t)(buf[7]); + *bufp += 8; + return value / value_max; +} + +static void +from_srgb(size_t n) +{ + double red, green, blue, pixel[4]; + size_t ptr; + char *p; + for (ptr = 0; ptr + pixel_size <= n; ptr += pixel_size) { + p = buf + ptr; + red = srgb_decode(get_value(&p)); + green = with_colour ? srgb_decode(get_value(&p)) : red; + blue = with_colour ? srgb_decode(get_value(&p)) : red; + pixel[3] = with_alpha ? get_value(&p) : 1; + srgb_to_ciexyz(red, green, blue, pixel + 0, pixel + 1, pixel + 2); + ewriteall(STDOUT_FILENO, pixel, sizeof(pixel), "<stdout>"); + } +} + +static size_t +farbfeld_head(int fd, const char *fname) { - unsigned char *buf = buffer; - unsigned long int value; - double ret; - value = (unsigned long int)(buf[0]) << 12; - value += (unsigned long int)(buf[1]) << 8; - value += (unsigned long int)(buf[2]) << 4; - value += (unsigned long int)(buf[3]); - ret = value; - value = 1UL << 15; - value |= value - 1; - ret /= value; - return ret; + if (ereadall(fd, buf, 16, fname) != 16) + eprintf("%s\n", conv_fail_msg); + if (memcmp(buf, "farbfeld", 8)) + eprintf("%s\n", conv_fail_msg); + sprintf(width, "%"PRIu32, ntohl(*(uint32_t *)(buf + 8))); + sprintf(height, "%"PRIu32, ntohl(*(uint32_t *)(buf + 12))); + pixel_size = 4 * sizeof(uint16_t); + value_max = UINT16_MAX; + get_value = get_value_u16; + convert = from_srgb; + return 0; +} + +static size_t +pam_head(int fd, const char *fname) +{ + size_t ptr; + char *p; + unsigned long long int maxval = UINT8_MAX; + for (ptr = 0;;) { + ptr += ereadall(fd, buf + ptr, (size_t)buf - ptr, fname); + for (;;) { + p = memchr(buf, '\n', ptr); + if (!p) { + if (ptr == sizeof(buf)) + eprintf("%s\n", conv_fail_msg); + break; + } + *p++ = '\0'; + if (strstr(buf, "WIDTH ") == buf) { + if (*width || !buf[6] || strlen(buf + 6) >= sizeof(width)) + eprintf("%s\n", conv_fail_msg); + strcpy(width, buf + 6); + } else if (strstr(buf, "HEIGHT ") == buf) { + if (*height || !buf[7] || strlen(buf + 7) >= sizeof(height)) + eprintf("%s\n", conv_fail_msg); + strcpy(height, buf + 7); + } else if (strstr(buf, "MAXVAL ") == buf) { + if (tollu(buf + 7, 0, UINT64_MAX, &maxval)) { + if (errno != ERANGE) + eprintf("%s\n", conv_fail_msg); + eprintf("image uses greater colour resolution than supported\n"); + } else if (!maxval) { + eprintf("%s\n", conv_fail_msg); + } + } else if (strstr(buf, "TUPLTYPE ") == buf) { + if (!strcmp(buf, "TUPLTYPE BLACKANDWHITE")) + maxval = 1, with_colour = 0, with_alpha = 0; + else if (!strcmp(buf, "TUPLTYPE BLACKANDWHITE_ALPHA")) + maxval = 1, with_colour = 0, with_alpha = 1; + else if (!strcmp(buf, "TUPLTYPE GRAYSCALE")) + with_colour = 0, with_alpha = 0; + else if (!strcmp(buf, "TUPLTYPE GRAYSCALE_ALPHA")) + with_colour = 0, with_alpha = 1; + else if (!strcmp(buf, "TUPLTYPE RGB")) + with_colour = 1, with_alpha = 0; + else if (!strcmp(buf, "TUPLTYPE RGB_ALPHA")) + with_colour = 1, with_alpha = 1; + else + eprintf("image uses an unsupported tuple type: %s\n", buf + sizeof("TUPLTYPE")); + } else if (!strcmp(buf, "ENDHDR")) { + memmove(buf, p, ptr -= (size_t)(p - buf)); + goto header_done; + } + memmove(buf, p, ptr -= (size_t)(p - buf)); + } + } +header_done: + if (maxval < (size_t)UINT8_MAX) { + pixel_size = sizeof(uint8_t); + get_value = get_value_u8; + } else if (maxval < (size_t)UINT16_MAX) { + pixel_size = sizeof(uint16_t); + get_value = get_value_u16; + } else if (maxval < (size_t)UINT32_MAX) { + pixel_size = sizeof(uint32_t); + get_value = get_value_u32; + } else { + pixel_size = sizeof(uint64_t); + get_value = get_value_u64; + } + value_max = maxval; + pixel_size *= (with_colour ? 3 : 1) + with_alpha; + convert = from_srgb; + return ptr; } int main(int argc, char *argv[]) { - int pipe_rw[2]; - int i, old_fd; + int status, pipe_rw[2], i, old_fd, forked = 0; + int headless = 0, farbfeld = 0, pam = 0; pid_t pid = 0; - int status; - char buf[8096]; - size_t ptr, n; - char *p; + size_t off, n; ssize_t r; - double red, green, blue, pixel[4]; - char width[3 * sizeof(size_t) + 1] = {0}; - char height[3 * sizeof(size_t) + 1] = {0}; - int headless = 0, farbfeld = 0, pam = 0; const char *file = "<subprocess>"; const char *conv_fail_msg = "convertion failed, if converting a farbfeld file, try -f"; @@ -61,11 +195,14 @@ main(int argc, char *argv[]) if (argc || (farbfeld && pam)) usage(); - if (farbfeld || pam) { - if (farbfeld) - conv_fail_msg = "not a valid farbfeld file, try without -f"; - else - conv_fail_msg = "not a valid 16-bit RGBA portable arbitrary map file, try without -p"; + if (farbfeld) + conv_fail_msg = "not a valid farbfeld file, try without -f"; + else if (pam) + conv_fail_msg = "not a valid RGBA portable arbitrary map file, try without -p"; + else + forked = 1; + + if (forked) { file = "<stdin>"; pipe_rw[0] = STDIN_FILENO; goto after_fork; @@ -73,7 +210,6 @@ main(int argc, char *argv[]) if (pipe(pipe_rw)) eprintf("pipe:"); - if (pipe_rw[0] == STDIN_FILENO || pipe_rw[1] == STDIN_FILENO) eprintf("no stdin open\n"); if (pipe_rw[0] == STDOUT_FILENO || pipe_rw[1] == STDOUT_FILENO) @@ -104,56 +240,10 @@ main(int argc, char *argv[]) close(pipe_rw[1]); after_fork: - if (farbfeld) { - for (ptr = 0; ptr < 16; ptr++) { - r = read(pipe_rw[0], buf + ptr, sizeof(buf) - ptr); - if (r < 0) - eprintf("read %s:", file); - if (r == 0) - eprintf("%s\n", conv_fail_msg); - ptr += (size_t)r; - } - if (memcmp(buf, "farbfeld", 8)) - eprintf("%s\n", conv_fail_msg); - sprintf(width, "%"PRIu32, ntohl(*(uint32_t *)(buf + 8))); - sprintf(height, "%"PRIu32, ntohl(*(uint32_t *)(buf + 12))); - ptr = 0; - goto header_done; - } - - for (ptr = 0;;) { - r = read(pipe_rw[0], buf + ptr, sizeof(buf) - ptr); - if (r < 0) - eprintf("read %s:", file); - if (r == 0) - eprintf("%s\n", conv_fail_msg); - ptr += (size_t)r; - - for (;;) { - p = memchr(buf, '\n', ptr); - if (!p) { - if (ptr == sizeof(buf)) - eprintf("%s\n", conv_fail_msg); - break; - } - *p++ = '\0'; - if (strstr(buf, "WIDTH ") == buf) { - if (*width || !buf[6] || strlen(buf + 6) >= sizeof(width)) - eprintf("%s\n", conv_fail_msg); - strcpy(width, buf + 6); - } else if (strstr(buf, "HEIGHT ") == buf) { - if (*height || !buf[7] || strlen(buf + 7) >= sizeof(height)) - eprintf("%s\n", conv_fail_msg); - strcpy(height, buf + 7); - } else if (!strcmp(buf, "ENDHDR")) { - memmove(buf, p, ptr -= (size_t)(p - buf)); - goto header_done; - } - memmove(buf, p, ptr -= (size_t)(p - buf)); - } - } -header_done: - n = ptr; + if (farbfeld) + n = farbfeld_head(pipe_rw[0], file); + else + n = pam_head(pipe_rw[0], file); if (!*width || !*height) eprintf("%s\n", conv_fail_msg); @@ -164,24 +254,18 @@ header_done: } for (;;) { - for (ptr = 0; ptr + 15 < n; ptr += 16) { - red = srgb_decode(get_value(buf + ptr + 0)); - green = srgb_decode(get_value(buf + ptr + 4)); - blue = srgb_decode(get_value(buf + ptr + 8)); - pixel[3] = get_value(buf + ptr + 12); - - srgb_to_ciexyz(red, green, blue, pixel + 0, pixel + 1, pixel + 2); - ewriteall(STDOUT_FILENO, pixel, sizeof(pixel), "<stdout>"); - } - r = read(pipe_rw[0], buf, sizeof(buf)); + convert(n); + off = n - (n % pixel_size); + memmove(buf, buf + off, n -= off); + r = read(pipe_rw[0], buf + n, sizeof(buf) - n); if (r < 0) eprintf("read %s:", file); if (r == 0) break; - n = (size_t)r; + n += (size_t)r; } - if (farbfeld || pam) + if (!forked) return 0; close(pipe_rw[0]); while (waitpid(pid, &status, 0) != pid);