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:
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);