commit 9fa7221a87817fe41a12a9cbdaa4bac6ee67b07d
parent 1870c353eb4697290cf7f49861e5d1b8699e3cd3
Author: Mattias Andrée <maandree@kth.se>
Date: Sun, 8 Jan 2017 08:00:53 +0100
Add vu-stack
Signed-off-by: Mattias Andrée <maandree@kth.se>
Diffstat:
| M | src/util.h | | | 25 | +++++++++++++++++++++++++ |
| A | src/vu-stack.c | | | 171 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
2 files changed, 196 insertions(+), 0 deletions(-)
diff --git a/src/util.h b/src/util.h
@@ -1,5 +1,6 @@
/* See LICENSE file for copyright and license details. */
+#include <math.h>
#include <stdio.h>
#define ELEMENTSOF(ARRAY) (sizeof(ARRAY) / sizeof(*(ARRAY)))
@@ -33,3 +34,27 @@ DEF_STR_TO_INT(toi, int, tolli, long long int)
int fshut(FILE *fp, const char *fname);
void enfshut(int status, FILE *fp, const char *fname);
void efshut(FILE *fp, const char *fname);
+
+static inline double
+srgb_encode(double t)
+{
+ double sign = 1;
+ if (t < 0) {
+ t = -t;
+ sign = -1;
+ }
+ t = t <= 0.0031306684425217108 ? 12.92 * t : 1.055 * pow(t, 1 / 2.4) - 0.055;
+ return t * sign;
+}
+
+static inline double
+srgb_decode(double t)
+{
+ double sign = 1;
+ if (t < 0) {
+ t = -t;
+ sign = -1;
+ }
+ t = t <= 0.0031306684425217108 * 12.92 ? t / 12.92 : pow((t + 0.055) / 1.055, 2.4);
+ return t * sign;
+}
diff --git a/src/vu-stack.c b/src/vu-stack.c
@@ -0,0 +1,171 @@
+/* See LICENSE file for copyright and license details. */
+#include "arg.h"
+#include "util.h"
+
+#include <fcntl.h>
+#include <inttypes.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+struct file
+{
+ int fd;
+ unsigned char buf[1024];
+ size_t ptr;
+ const char *file;
+};
+
+static unsigned int
+clip(unsigned int value)
+{
+ return value < 0 ? 0 : value > 255 ? 255 : value;
+}
+
+static void
+blend(struct file *files, size_t n_files, size_t n)
+{
+ double r1, g1, b1, a1;
+ double r2, g2, b2, a2;
+ size_t i, j;
+ for (i = 0; i < n; i += 4) {
+ r1 = srgb_decode(files->buf[i + 0] / 255.);
+ g1 = srgb_decode(files->buf[i + 1] / 255.);
+ b1 = srgb_decode(files->buf[i + 2] / 255.);
+ a1 = files->buf[i + 3] / 255.;
+ for (j = 1; j < n_files;) {
+ r2 = srgb_decode(files[j].buf[i + 0] / 255.);
+ g2 = srgb_decode(files[j].buf[i + 1] / 255.);
+ b2 = srgb_decode(files[j].buf[i + 2] / 255.);
+ a2 = files[j].buf[i + 3] / 255.;
+ a2 /= ++j;
+ r1 = r1 * a1 * (1 - a2) + r2 * a2;
+ g1 = g1 * a1 * (1 - a2) + g2 * a2;
+ b1 = b1 * a1 * (1 - a2) + b2 * a2;
+ a1 = a1 * (1 - a2) + a2;
+ }
+ r1 = srgb_encode(r1) * 255 + 0.5;
+ g1 = srgb_encode(g1) * 255 + 0.5;
+ b1 = srgb_encode(b1) * 255 + 0.5;
+ a1 = a1 * 255 * 0.5;
+ files->buf[i + 0] = clip((unsigned int)r1);
+ files->buf[i + 1] = clip((unsigned int)g1);
+ files->buf[i + 2] = clip((unsigned int)b1);
+ files->buf[i + 3] = clip((unsigned int)a1);
+ }
+}
+
+static void
+stack(struct file *files, size_t n_files, size_t n)
+{
+ double r1, g1, b1, a1;
+ double r2, g2, b2, a2;
+ size_t i, j;
+ for (i = 0; i < n; i += 4) {
+ r1 = srgb_decode(files->buf[i + 0] / 255.);
+ g1 = srgb_decode(files->buf[i + 1] / 255.);
+ b1 = srgb_decode(files->buf[i + 2] / 255.);
+ a1 = files->buf[i + 3] / 255.;
+ for (j = 1; j < n_files; j++) {
+ r2 = srgb_decode(files[j].buf[i + 0] / 255.);
+ g2 = srgb_decode(files[j].buf[i + 1] / 255.);
+ b2 = srgb_decode(files[j].buf[i + 2] / 255.);
+ a2 = files[j].buf[i + 3] / 255.;
+ r1 = r1 * a1 * (1 - a2) + r2 * a2;
+ g1 = g1 * a1 * (1 - a2) + g2 * a2;
+ b1 = b1 * a1 * (1 - a2) + b2 * a2;
+ a1 = a1 * (1 - a2) + a2;
+ }
+ r1 = srgb_encode(r1) * 255 + 0.5;
+ g1 = srgb_encode(g1) * 255 + 0.5;
+ b1 = srgb_encode(b1) * 255 + 0.5;
+ a1 = a1 * 255 * 0.5;
+ files->buf[i + 0] = clip((unsigned int)r1);
+ files->buf[i + 1] = clip((unsigned int)g1);
+ files->buf[i + 2] = clip((unsigned int)b1);
+ files->buf[i + 3] = clip((unsigned int)a1);
+ }
+}
+
+static void
+usage(void)
+{
+ eprintf("usage: %s [-b] bottom-image ... top-image\n", argv0);
+}
+
+int
+main(int argc, char *argv[])
+{
+ struct file *files;
+ size_t n_files;
+ int blend_flag = 0;
+ size_t i, j, n;
+ ssize_t r;
+ size_t closed;
+
+ ARGBEGIN {
+ case 'b':
+ blend_flag = 1;
+ break;
+ default:
+ usage();
+ } ARGEND;
+
+ if (argc < 2)
+ usage();
+
+ n_files = (size_t)argc;
+ files = calloc(n_files, sizeof(*files));
+ if (!files)
+ eprintf("calloc:");
+
+ for (i = 0; i < n_files; i++) {
+ files[i].fd = open(argv[i], O_RDONLY);
+ if (files[i].fd < 0)
+ eprintf("open %s:", argv[i]);
+ files[i].file = argv[i];
+ }
+
+ while (n_files) {
+ n = SIZE_MAX;
+ for (i = 0; i < n_files; i++) {
+ r = read(files[i].fd, files[i].buf + files[i].ptr, sizeof(files[i].buf) - files[i].ptr);
+ if (r < 0) {
+ eprintf("read %s:", files[i].file);
+ } else if (r == 0) {
+ close(files[i].fd);
+ files[i].fd = -1;
+ } else {
+ files[i].ptr += (size_t)r;
+ }
+ if (files[i].ptr && files[i].ptr < n)
+ n = files[i].ptr;
+ }
+ n -= n & 3;
+
+ (blend_flag ? blend : stack)(files, n_files, n);
+ for (j = 0; j < n;) {
+ r = write(STDOUT_FILENO, files->buf + j, n - j);
+ if (r < 0)
+ eprintf("write <stdout>:");
+ j += (size_t)r;
+ }
+
+ closed = SIZE_MAX;
+ for (i = 0; i < n_files; i++) {
+ memmove(files[i].buf, files[i].buf + n, files[i].ptr -= n);
+ if (files[i].ptr < 4 && files[i].fd < 0 && closed == SIZE_MAX)
+ closed = i;
+ }
+ if (closed != SIZE_MAX) {
+ for (i = (j = closed) + 1; i < n_files; i++)
+ if (files[i].ptr < 4 && files[i].fd < 0)
+ files[j++] = files[i];
+ n_files = j;
+ }
+ }
+
+ return 0;
+}