aboutsummaryrefslogtreecommitdiffstats
path: root/src/blind-from-image.c
diff options
context:
space:
mode:
authorMattias Andrée <maandree@kth.se>2017-01-13 09:05:08 +0100
committerMattias Andrée <maandree@kth.se>2017-01-13 09:05:08 +0100
commit4674ec0e4b833ab0d0365225ba99228df14abe87 (patch)
tree1b89fe1559fc9a2422e20048700e694a72d17751 /src/blind-from-image.c
parentvu-from-video: fix Y'UV encoding + add vu-to-video (diff)
downloadblind-4674ec0e4b833ab0d0365225ba99228df14abe87.tar.gz
blind-4674ec0e4b833ab0d0365225ba99228df14abe87.tar.bz2
blind-4674ec0e4b833ab0d0365225ba99228df14abe87.tar.xz
Rename to blind
Signed-off-by: Mattias Andrée <maandree@kth.se>
Diffstat (limited to 'src/blind-from-image.c')
-rw-r--r--src/blind-from-image.c273
1 files changed, 273 insertions, 0 deletions
diff --git a/src/blind-from-image.c b/src/blind-from-image.c
new file mode 100644
index 0000000..9c2d047
--- /dev/null
+++ b/src/blind-from-image.c
@@ -0,0 +1,273 @@
+/* See LICENSE file for copyright and license details. */
+#include "util.h"
+
+#include <arpa/inet.h>
+#include <sys/wait.h>
+#include <inttypes.h>
+#include <string.h>
+#include <unistd.h>
+
+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_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)
+{
+ 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 status, pipe_rw[2], i, old_fd, forked = 0;
+ int headless = 0, farbfeld = 0, pam = 0;
+ pid_t pid = 0;
+ size_t off, n;
+ ssize_t r;
+ const char *file = "<subprocess>";
+ const char *conv_fail_msg = "convertion failed, if converting a farbfeld file, try -f";
+
+ ARGBEGIN {
+ case 'f':
+ farbfeld = 1;
+ break;
+ case 'h':
+ headless = 1;
+ break;
+ case 'p':
+ pam = 1;
+ break;
+ default:
+ usage();
+ } ARGEND;
+
+ if (argc || (farbfeld && pam))
+ usage();
+
+ 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;
+ }
+
+ 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)
+ eprintf("no stdout open\n");
+ for (i = 0; i < 2; i++) {
+ if (pipe_rw[i] == STDERR_FILENO) {
+ pipe_rw[i] = dup(old_fd = pipe_rw[i]);
+ if (pipe_rw[i] < 0)
+ eprintf("dup:");
+ close(old_fd);
+ }
+ }
+
+ pid = fork();
+ if (pid < 0)
+ eprintf("fork:");
+
+ if (!pid) {
+ close(pipe_rw[0]);
+ if (dup2(pipe_rw[1], STDOUT_FILENO) == -1)
+ eprintf("dup2:");
+ close(pipe_rw[1]);
+ /* XXX Is there a way to convert directly to raw XYZ? (Would avoid gamut truncation) */
+ execlp("convert", "convert", "-", "-depth", "32", "-alpha", "activate", "pam:-", NULL);
+ eprintf("exec convert:");
+ }
+
+ close(pipe_rw[1]);
+after_fork:
+
+ 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);
+
+ if (!headless) {
+ printf("1 %s %s xyza\n%cuivf", width, height, 0);
+ efflush(stdout, "<stdout>");
+ }
+
+ for (;;) {
+ 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;
+ }
+
+ if (!forked)
+ return 0;
+ close(pipe_rw[0]);
+ while (waitpid(pid, &status, 0) != pid);
+ return !!status;
+}