URI: 
       Add blind-{,un}premultiply, blind-{dot,cross,quaternion}-product, and blind-vector-projection - blind - suckless command-line video editing utility
  HTML git clone git://git.suckless.org/blind
   DIR Log
   DIR Files
   DIR Refs
   DIR README
   DIR LICENSE
       ---
   DIR commit 4dfdb29707bf7af8df1fae28907d5e492338e8b8
   DIR parent f9adfc4c7c21dc0526c0d13285e41f4292176378
  HTML Author: Mattias Andrée <maandree@kth.se>
       Date:   Sun,  2 Jul 2017 16:59:44 +0200
       
       Add blind-{,un}premultiply, blind-{dot,cross,quaternion}-product, and blind-vector-projection
       
       Signed-off-by: Mattias Andrée <maandree@kth.se>
       
       Diffstat:
         M Makefile                            |       6 ++++++
         M README                              |      18 ++++++++++++++++++
         M TODO                                |       7 +++++++
         M man/blind-arithm.1                  |       4 ++++
         A man/blind-cross-product.1           |      32 +++++++++++++++++++++++++++++++
         A man/blind-dot-product.1             |      31 +++++++++++++++++++++++++++++++
         A man/blind-premultiply.1             |      27 +++++++++++++++++++++++++++
         A man/blind-quaternion-product.1      |      36 +++++++++++++++++++++++++++++++
         A man/blind-unpremultiply.1           |      29 +++++++++++++++++++++++++++++
         A man/blind-vector-projection.1       |      41 +++++++++++++++++++++++++++++++
         M man/blind.7                         |      18 ++++++++++++++++++
         A src/blind-cross-product.c           |      62 +++++++++++++++++++++++++++++++
         A src/blind-dot-product.c             |      55 +++++++++++++++++++++++++++++++
         A src/blind-premultiply.c             |      76 +++++++++++++++++++++++++++++++
         A src/blind-quaternion-product.c      |      62 +++++++++++++++++++++++++++++++
         A src/blind-unpremultiply.c           |      78 +++++++++++++++++++++++++++++++
         A src/blind-vector-projection.c       |      91 +++++++++++++++++++++++++++++++
       
       17 files changed, 673 insertions(+), 0 deletions(-)
       ---
   DIR diff --git a/Makefile b/Makefile
       @@ -11,10 +11,12 @@ BIN =\
                blind-concat\
                blind-convert\
                blind-crop\
       +        blind-cross-product\
                blind-cut\
                blind-decompress\
                blind-disperse\
                blind-dissolve\
       +        blind-dot-product\
                blind-extend\
                blind-find-rectangle\
                blind-flip\
       @@ -29,6 +31,8 @@ BIN =\
                blind-invert-luma\
                blind-make-kernel\
                blind-next-frame\
       +        blind-quaternion-product\
       +        blind-premultiply\
                blind-read-head\
                blind-repeat\
                blind-reverse\
       @@ -51,6 +55,8 @@ BIN =\
                blind-to-video\
                blind-translate\
                blind-transpose\
       +        blind-unpremultiply\
       +        blind-vector-projection\
                blind-write-head\
                blind-kernel\
                blind-temporal-mean
   DIR diff --git a/README b/README
       @@ -33,12 +33,18 @@ UTILITIES
               blind-convert(1)
                      Change pixel format of a video
        
       +       blind-cross-product(1)
       +              Calculate the cross product of colours in a video
       +
               blind-crop(1)
                      Extract subframes for all frames
        
               blind-cut(1)
                      Retain consecutive frames
        
       +       blind-dot-product(1)
       +              Calculate the dot product of colours in a video
       +
               blind-dissolve(1)
                      Fade a video by chaning it's alpha channel
        
       @@ -87,6 +93,12 @@ UTILITIES
               blind-next-frame(1)
                      Extracts the next frame from a video
        
       +       blind-premultiply(1)
       +              Premultiply the alpha channel of a video
       +
       +       blind-quaternion-product(1)
       +              Calculate the quaternion product of colours in a video
       +
               blind-read-head(1)
                      Reads the head from a video
        
       @@ -162,6 +174,12 @@ UTILITIES
               blind-transpose(1)
                      Transpose a video
        
       +       blind-unpremultiply(1)
       +              Unpremultiply the alpha channel of a video
       +
       +       blind-vector-projection(1)
       +              Calculate the projection or rejection of colours in a video
       +
               blind-write-head(1)
                      Writes the head of a video
        
   DIR diff --git a/TODO b/TODO
       @@ -64,6 +64,13 @@ long double (xyza q) could be added as another format.
        unsigned char (xyza 8) could be added as another format, it's probably good for previewing
        
        
       +UNTESTED:
       +        blind-dot-product
       +        blind-cross-product
       +        blind-quaternion-product
       +        blind-vector-projection
       +
       +
        HELP REQUIRED:
                blind-z-map                create a Z-map video from two or more videos
                blind-track                track the movement of a point
   DIR diff --git a/man/blind-arithm.1 b/man/blind-arithm.1
       @@ -77,6 +77,10 @@ Do not modify the Y channel (the second channel).
        Do not modify the Z channel (the third channel).
        .SH SEE ALSO
        .BR blind (7),
       +.BR blind-dot-product (1),
       +.BR blind-cross-product (1),
       +.BR blind-quaternion-product (1),
       +.BR blind-vector-projection (1),
        .BR blind-single-colour (1),
        .BR blind-set-alpha (1),
        .BR blind-set-luma (1),
   DIR diff --git a/man/blind-cross-product.1 b/man/blind-cross-product.1
       @@ -0,0 +1,32 @@
       +.TH BLIND-CROSS-PRODUCT 1 blind
       +.SH NAME
       +blind-cross-product - Calculate the cross product of colours in a video
       +.SH SYNOPSIS
       +.B blind-cross-product
       +.I right-hand-stream
       +.SH DESCRIPTION
       +.B blind-cross-product
       +reads left-hand operands from stdin, and right-hand
       +operands from
       +.IR right-hand-stream ,
       +and calculates the cross product of the colours.
       +The values of the alpha channels multiple with each
       +others with regular scalar-scalar multiplication.
       +.P
       +If stdin is longer than
       +.IR right-hand-stream ,
       +the remainder of stdin is printed without any changes.
       +If stdin is shorter than
       +.IR right-hand-stream ,
       +the remainder of
       +.I right-hand-stream
       +is ignored but may be partially read.
       +.SH SEE ALSO
       +.BR blind (7),
       +.BR blind-arithm (1),
       +.BR blind-dot-product (1),
       +.BR blind-quaternion-product (1),
       +.BR blind-vector-projection (1)
       +.SH AUTHORS
       +Mattias Andrée
       +.RI < maandree@kth.se >
   DIR diff --git a/man/blind-dot-product.1 b/man/blind-dot-product.1
       @@ -0,0 +1,31 @@
       +.TH BLIND-DOT-PRODUCT 1 blind
       +.SH NAME
       +blind-dot-product - Calculate the dot product of colours in a video
       +.SH SYNOPSIS
       +.B blind-dot-product
       +.I right-hand-stream
       +.SH DESCRIPTION
       +.B blind-dot-product
       +reads left-hand operands from stdin, and right-hand
       +operands from
       +.IR right-hand-stream ,
       +and calculates the dot product of the colours. The
       +product is store in all four channels.
       +.P
       +If stdin is longer than
       +.IR right-hand-stream ,
       +the remainder of stdin is printed without any changes.
       +If stdin is shorter than
       +.IR right-hand-stream ,
       +the remainder of
       +.I right-hand-stream
       +is ignored but may be partially read.
       +.SH SEE ALSO
       +.BR blind (7),
       +.BR blind-arithm (1),
       +.BR blind-cross-product (1),
       +.BR blind-quaternion-product (1),
       +.BR blind-vector-projection (1)
       +.SH AUTHORS
       +Mattias Andrée
       +.RI < maandree@kth.se >
   DIR diff --git a/man/blind-premultiply.1 b/man/blind-premultiply.1
       @@ -0,0 +1,27 @@
       +.TH BLIND-PREMULTIPLY 1 blind
       +.SH NAME
       +blind-premultiply - Premultiply the alpha channel of a video
       +.SH SYNOPSIS
       +.B blind-premultiply
       +[-xyz]
       +.SH DESCRIPTION
       +.B blind-premultiply
       +reads a video from stdin and multiplies the
       +colour values with the alpha value for each pixel,
       +and prints the resulting video to stdout.
       +.SH OPTIONS
       +.TP
       +.B -x
       +Do not modify the X channel (the first channel).
       +.TP
       +.B -y
       +Do not modify the Y channel (the second channel).
       +.TP
       +.B -z
       +Do not modify the Z channel (the third channel).
       +.SH SEE ALSO
       +.BR blind (7),
       +.BR blind-unpremultiply (1)
       +.SH AUTHORS
       +Mattias Andrée
       +.RI < maandree@kth.se >
   DIR diff --git a/man/blind-quaternion-product.1 b/man/blind-quaternion-product.1
       @@ -0,0 +1,36 @@
       +.TH BLIND-QUATERNION-PRODUCT 1 blind
       +.SH NAME
       +blind-quaternion-product - Calculate the quaternion product of colours in a video
       +.SH SYNOPSIS
       +.B blind-quaternion-product
       +.I right-hand-stream
       +.SH DESCRIPTION
       +.B blind-quaternion-product
       +reads left-hand operands from stdin, and right-hand
       +operands from
       +.IR right-hand-stream ,
       +and calculates the quaternion product of the colours.
       +The values in the the first channel (the X channel) are
       +treated as real, the values in the the second channel
       +(the Y channel) are treated as i-imaginary, the values
       +in the the third channel (the Z channel) are treated
       +as j-imaginary, and the values in the the fourth channel
       +(the alpha channel) are treated as k-imaginary.
       +.P
       +If stdin is longer than
       +.IR right-hand-stream ,
       +the remainder of stdin is printed without any changes.
       +If stdin is shorter than
       +.IR right-hand-stream ,
       +the remainder of
       +.I right-hand-stream
       +is ignored but may be partially read.
       +.SH SEE ALSO
       +.BR blind (7),
       +.BR blind-arithm (1),
       +.BR blind-cross-product (1),
       +.BR blind-quaternion-product (1),
       +.BR blind-vector-projection (1)
       +.SH AUTHORS
       +Mattias Andrée
       +.RI < maandree@kth.se >
   DIR diff --git a/man/blind-unpremultiply.1 b/man/blind-unpremultiply.1
       @@ -0,0 +1,29 @@
       +.TH BLIND-UNPREMULTIPLY 1 blind
       +.SH NAME
       +blind-unpremultiply - Unpremultiply the alpha channel of a video
       +.SH SYNOPSIS
       +.B blind-unpremultiply
       +[-xyz]
       +.SH DESCRIPTION
       +.B blind-unpremultiply
       +reads a video from stdin and divides the colour
       +with the alpha value for each pixel, and prints
       +the resulting video to stdout, effectively
       +undoing affects of
       +.BR blind-unpremultiply (1).
       +.SH OPTIONS
       +.TP
       +.B -x
       +Do not modify the X channel (the first channel).
       +.TP
       +.B -y
       +Do not modify the Y channel (the second channel).
       +.TP
       +.B -z
       +Do not modify the Z channel (the third channel).
       +.SH SEE ALSO
       +.BR blind (7),
       +.BR blind-premultiply (1)
       +.SH AUTHORS
       +Mattias Andrée
       +.RI < maandree@kth.se >
   DIR diff --git a/man/blind-vector-projection.1 b/man/blind-vector-projection.1
       @@ -0,0 +1,41 @@
       +.TH BLIND-VECTOR-PROJECTION 1 blind
       +.SH NAME
       +blind-vector-projection - Calculate the projection or rejection of colours in a video
       +.SH SYNOPSIS
       +.B blind-vector-projection
       +[-r | -s]
       +.I plane-stream
       +.SH DESCRIPTION
       +.B blind-vector-projection
       +reads a video from stdin and a video from
       +.IR plane-stream ,
       +and calculates the projection of the colours from
       +stdin onto the colours from
       +.I plane-stream
       +and prints the resulting video to stdout.
       +.P
       +If stdin is longer than
       +.IR plane-stream ,
       +the remainder of stdin is printed without any changes.
       +If stdin is shorter than
       +.IR plane-stream ,
       +the remainder of
       +.I plane-stream
       +is ignored but may be partially read.
       +.SH OPTIONS
       +.TP
       +.B -r
       +Calculate the vector rejection instead of the vector projection.
       +.TP
       +.B -s
       +Calculate the scalar projection instead of the vector projection.
       +The scalar projection is stored in all four channels.
       +.SH SEE ALSO
       +.BR blind (7),
       +.BR blind-arithm (1),
       +.BR blind-dot-product (1),
       +.BR blind-cross-product (1),
       +.BR blind-quaternion-product (1)
       +.SH AUTHORS
       +Mattias Andrée
       +.RI < maandree@kth.se >
   DIR diff --git a/man/blind.7 b/man/blind.7
       @@ -43,6 +43,9 @@ Concatenate videos
        .BR blind-convert (1)
        Change pixel format of a video
        .TP
       +.BR blind-cross-product (1)
       +Calculate the cross product of colours in a video
       +.TP
        .BR blind-crop (1)
        Extract subframes for all frames
        .TP
       @@ -58,6 +61,9 @@ Fade a video by chaning it's alpha channel
        .BR blind-disperse (1)
        Framewise split a video into multiple videos
        .TP
       +.BR blind-dot-product (1)
       +Calculate the dot product of colours in a video
       +.TP
        .BR blind-extend (1)
        Add margins to a video
        .TP
       @@ -100,6 +106,12 @@ Create a custom convolution matrix
        .BR blind-next-frame (1)
        Extracts the next frame from a video
        .TP
       +.BR blind-premultiply (1)
       +Premultiply the alpha channel of a video
       +.TP
       +.BR blind-quaternion-product (1)
       +Calculate the quaternion product of colours in a video
       +.TP
        .BR blind-read-head (1)
        Reads the head from a video
        .TP
       @@ -177,6 +189,12 @@ Perform framewise translation of a video
        .BR blind-transpose (1)
        Transpose a video
        .TP
       +.BR blind-unpremultiply (1)
       +Unpremultiply the alpha channel of a video
       +.TP
       +.BR blind-vector-projection (1)
       +Calculate the projection or rejection of colours in a video
       +.TP
        .BR blind-write-head (1)
        Writes the head of a video
        .SH SEE ALSO
   DIR diff --git a/src/blind-cross-product.c b/src/blind-cross-product.c
       @@ -0,0 +1,62 @@
       +/* See LICENSE file for copyright and license details. */
       +#include "common.h"
       +
       +USAGE("right-hand-stream")
       +
       +#if defined(__GNUC__) && !defined(__clang__)
       +# pragma GCC diagnostic push
       +# pragma GCC diagnostic ignored "-Wunsafe-loop-optimizations"
       +#endif
       +
       +#define PROCESS(TYPE, SUFFIX)\
       +        static void\
       +        process_##SUFFIX(struct stream *left, struct stream *right, size_t n)\
       +        {\
       +                size_t i;\
       +                TYPE *lx, *ly, *lz, *la, *rx, *ry, *rz, *ra, x, y, z, a;\
       +                for (i = 0; i < n; i += 4 * sizeof(TYPE)) {\
       +                        lx = ((TYPE *)(left->buf + i)) + 0, rx = ((TYPE *)(right->buf + i)) + 0;\
       +                        ly = ((TYPE *)(left->buf + i)) + 1, ry = ((TYPE *)(right->buf + i)) + 1;\
       +                        lz = ((TYPE *)(left->buf + i)) + 2, rz = ((TYPE *)(right->buf + i)) + 2;\
       +                        la = ((TYPE *)(left->buf + i)) + 3, ra = ((TYPE *)(right->buf + i)) + 3;\
       +                        x = *ly * *rz - *lz * *ry;\
       +                        y = *lz * *rx - *lx * *rz;\
       +                        z = *lx * *ry - *ly * *rx;\
       +                        a = *la * *ra;\
       +                        *lx = x;\
       +                        *ly = y;\
       +                        *lz = z;\
       +                        *la = a;\
       +                }\
       +        }
       +
       +PROCESS(double, lf)
       +PROCESS(float, f)
       +
       +#if defined(__GNUC__) && !defined(__clang__)
       +# pragma GCC diagnostic pop
       +#endif
       +
       +int
       +main(int argc, char *argv[])
       +{
       +        struct stream left, right;
       +        void (*process)(struct stream *left, struct stream *right, size_t n);
       +
       +        UNOFLAGS(argc != 2);
       +
       +        eopen_stream(&left, NULL);
       +        eopen_stream(&right, argv[1]);
       +
       +        if (!strcmp(left.pixfmt, "xyza"))
       +                process = process_lf;
       +        else if (!strcmp(left.pixfmt, "xyza f"))
       +                process = process_f;
       +        else
       +                eprintf("pixel format %s is not supported, try xyza\n", left.pixfmt);
       +
       +        fprint_stream_head(stdout, &left);
       +        efflush(stdout, "<stdout>");
       +        process_two_streams(&left, &right, STDOUT_FILENO, "<stdout>", process);
       +        return 0;
       +}
   DIR diff --git a/src/blind-dot-product.c b/src/blind-dot-product.c
       @@ -0,0 +1,55 @@
       +/* See LICENSE file for copyright and license details. */
       +#include "common.h"
       +
       +USAGE("right-hand-stream")
       +
       +#if defined(__GNUC__) && !defined(__clang__)
       +# pragma GCC diagnostic push
       +# pragma GCC diagnostic ignored "-Wunsafe-loop-optimizations"
       +#endif
       +
       +#define PROCESS(TYPE, SUFFIX)\
       +        static void\
       +        process_##SUFFIX(struct stream *left, struct stream *right, size_t n)\
       +        {\
       +                size_t i;\
       +                TYPE *lx, *ly, *lz, *la, *rx, *ry, *rz, *ra;\
       +                for (i = 0; i < n; i += 4 * sizeof(TYPE)) {\
       +                        lx = ((TYPE *)(left->buf + i)) + 0, rx = ((TYPE *)(right->buf + i)) + 0;\
       +                        ly = ((TYPE *)(left->buf + i)) + 1, ry = ((TYPE *)(right->buf + i)) + 1;\
       +                        lz = ((TYPE *)(left->buf + i)) + 2, rz = ((TYPE *)(right->buf + i)) + 2;\
       +                        la = ((TYPE *)(left->buf + i)) + 3, ra = ((TYPE *)(right->buf + i)) + 3;\
       +                        *lx = *ly = *lz = *la = *lx * *rx + *ly * *ry + *lz * *rz + *la * *ra;\
       +                }\
       +        }
       +
       +PROCESS(double, lf)
       +PROCESS(float, f)
       +
       +#if defined(__GNUC__) && !defined(__clang__)
       +# pragma GCC diagnostic pop
       +#endif
       +
       +int
       +main(int argc, char *argv[])
       +{
       +        struct stream left, right;
       +        void (*process)(struct stream *left, struct stream *right, size_t n);
       +
       +        UNOFLAGS(argc != 2);
       +
       +        eopen_stream(&left, NULL);
       +        eopen_stream(&right, argv[1]);
       +
       +        if (!strcmp(left.pixfmt, "xyza"))
       +                process = process_lf;
       +        else if (!strcmp(left.pixfmt, "xyza f"))
       +                process = process_f;
       +        else
       +                eprintf("pixel format %s is not supported, try xyza\n", left.pixfmt);
       +
       +        fprint_stream_head(stdout, &left);
       +        efflush(stdout, "<stdout>");
       +        process_two_streams(&left, &right, STDOUT_FILENO, "<stdout>", process);
       +        return 0;
       +}
   DIR diff --git a/src/blind-premultiply.c b/src/blind-premultiply.c
       @@ -0,0 +1,76 @@
       +/* See LICENSE file for copyright and license details. */
       +#include "common.h"
       +
       +USAGE("[-xyz]")
       +
       +static int skip_x = 0;
       +static int skip_y = 0;
       +static int skip_z = 0;
       +
       +
       +#define PROCESS(TYPE, SUFFIX)\
       +        static void\
       +        process_##SUFFIX(struct stream *stream)\
       +        {\
       +                size_t i, n;\
       +                TYPE a;\
       +                do {\
       +                        n = stream->ptr / stream->pixel_size;\
       +                        for (i = 0; i < n; i++) {\
       +                                a = ((TYPE *)(stream->buf))[4 * i + 3];\
       +                                if (!skip_x)\
       +                                        ((TYPE *)(stream->buf))[4 * i + 0] *= a;\
       +                                if (!skip_y)\
       +                                        ((TYPE *)(stream->buf))[4 * i + 1] *= a;\
       +                                if (!skip_z)\
       +                                        ((TYPE *)(stream->buf))[4 * i + 2] *= a;\
       +                        }\
       +                        n *= stream->pixel_size;\
       +                        ewriteall(STDOUT_FILENO, stream->buf, n, "<stdout>");\
       +                        memmove(stream->buf, stream->buf + n, stream->ptr -= n);\
       +                } while (eread_stream(stream, SIZE_MAX));\
       +                if (stream->ptr)\
       +                        eprintf("%s: incomplete frame\n", stream->file);\
       +        }
       +
       +PROCESS(double, lf)
       +PROCESS(float, f)
       +
       +
       +int
       +main(int argc, char *argv[])
       +{
       +        struct stream stream;
       +        void (*process)(struct stream *stream);
       +
       +        ARGBEGIN {
       +        case 'x':
       +                skip_x = 1;
       +                break;
       +        case 'y':
       +                skip_y = 1;
       +                break;
       +        case 'z':
       +                skip_z = 1;
       +                break;
       +        default:
       +                usage();
       +        } ARGEND;
       +
       +        if (argc)
       +                usage();
       +
       +        eopen_stream(&stream, NULL);
       +
       +        if (!strcmp(stream.pixfmt, "xyza"))
       +                process = process_lf;
       +        else if (!strcmp(stream.pixfmt, "xyza f"))
       +                process = process_f;
       +        else
       +                eprintf("pixel format %s is not supported, try xyza\n", stream.pixfmt);
       +
       +        fprint_stream_head(stdout, &stream);
       +        efflush(stdout, "<stdout>");
       +        process(&stream);
       +        return 0;
       +}
   DIR diff --git a/src/blind-quaternion-product.c b/src/blind-quaternion-product.c
       @@ -0,0 +1,62 @@
       +/* See LICENSE file for copyright and license details. */
       +#include "common.h"
       +
       +USAGE("right-hand-stream")
       +
       +#if defined(__GNUC__) && !defined(__clang__)
       +# pragma GCC diagnostic push
       +# pragma GCC diagnostic ignored "-Wunsafe-loop-optimizations"
       +#endif
       +
       +#define PROCESS(TYPE, SUFFIX)\
       +        static void\
       +        process_##SUFFIX(struct stream *left, struct stream *right, size_t n)\
       +        {\
       +                size_t i;\
       +                TYPE *lx, *ly, *lz, *la, *rx, *ry, *rz, *ra, x, y, z, a;\
       +                for (i = 0; i < n; i += 4 * sizeof(TYPE)) {\
       +                        lx = ((TYPE *)(left->buf + i)) + 0, rx = ((TYPE *)(right->buf + i)) + 0;\
       +                        ly = ((TYPE *)(left->buf + i)) + 1, ry = ((TYPE *)(right->buf + i)) + 1;\
       +                        lz = ((TYPE *)(left->buf + i)) + 2, rz = ((TYPE *)(right->buf + i)) + 2;\
       +                        la = ((TYPE *)(left->buf + i)) + 3, ra = ((TYPE *)(right->buf + i)) + 3;\
       +                        x = *lx * *rx - *ly * *ry - *lz * *rz - *la * *ra;\
       +                        y = *lz * *ra - *la * *rz + *lx * *ry + *ly * *rx;\
       +                        z = *la * *ry - *ly * *rz + *lx * *rz + *lz * *rx;\
       +                        a = *ly * *rz - *lz * *rz + *lx * *ra + *la * *rx;\
       +                        *lx = x;\
       +                        *ly = y;\
       +                        *lz = z;\
       +                        *la = a;\
       +                }\
       +        }
       +
       +PROCESS(double, lf)
       +PROCESS(float, f)
       +
       +#if defined(__GNUC__) && !defined(__clang__)
       +# pragma GCC diagnostic pop
       +#endif
       +
       +int
       +main(int argc, char *argv[])
       +{
       +        struct stream left, right;
       +        void (*process)(struct stream *left, struct stream *right, size_t n);
       +
       +        UNOFLAGS(argc != 2);
       +
       +        eopen_stream(&left, NULL);
       +        eopen_stream(&right, argv[1]);
       +
       +        if (!strcmp(left.pixfmt, "xyza"))
       +                process = process_lf;
       +        else if (!strcmp(left.pixfmt, "xyza f"))
       +                process = process_f;
       +        else
       +                eprintf("pixel format %s is not supported, try xyza\n", left.pixfmt);
       +
       +        fprint_stream_head(stdout, &left);
       +        efflush(stdout, "<stdout>");
       +        process_two_streams(&left, &right, STDOUT_FILENO, "<stdout>", process);
       +        return 0;
       +}
   DIR diff --git a/src/blind-unpremultiply.c b/src/blind-unpremultiply.c
       @@ -0,0 +1,78 @@
       +/* See LICENSE file for copyright and license details. */
       +#include "common.h"
       +
       +USAGE("[-xyz]")
       +
       +static int skip_x = 0;
       +static int skip_y = 0;
       +static int skip_z = 0;
       +
       +
       +#define PROCESS(TYPE, SUFFIX)\
       +        static void\
       +        process_##SUFFIX(struct stream *stream)\
       +        {\
       +                size_t i, n;\
       +                TYPE a;\
       +                do {\
       +                        n = stream->ptr / stream->pixel_size;\
       +                        for (i = 0; i < n; i++) {\
       +                                a = ((TYPE *)(stream->buf))[4 * i + 3];\
       +                                if (!a)\
       +                                        continue;\
       +                                if (!skip_x)\
       +                                        ((TYPE *)(stream->buf))[4 * i + 0] /= a;\
       +                                if (!skip_y)\
       +                                        ((TYPE *)(stream->buf))[4 * i + 1] /= a;\
       +                                if (!skip_z)\
       +                                        ((TYPE *)(stream->buf))[4 * i + 2] /= a;\
       +                        }\
       +                        n *= stream->pixel_size;\
       +                        ewriteall(STDOUT_FILENO, stream->buf, n, "<stdout>");\
       +                        memmove(stream->buf, stream->buf + n, stream->ptr -= n);\
       +                } while (eread_stream(stream, SIZE_MAX));\
       +                if (stream->ptr)\
       +                        eprintf("%s: incomplete frame\n", stream->file);\
       +        }
       +
       +PROCESS(double, lf)
       +PROCESS(float, f)
       +
       +
       +int
       +main(int argc, char *argv[])
       +{
       +        struct stream stream;
       +        void (*process)(struct stream *stream);
       +
       +        ARGBEGIN {
       +        case 'x':
       +                skip_x = 1;
       +                break;
       +        case 'y':
       +                skip_y = 1;
       +                break;
       +        case 'z':
       +                skip_z = 1;
       +                break;
       +        default:
       +                usage();
       +        } ARGEND;
       +
       +        if (argc)
       +                usage();
       +
       +        eopen_stream(&stream, NULL);
       +
       +        if (!strcmp(stream.pixfmt, "xyza"))
       +                process = process_lf;
       +        else if (!strcmp(stream.pixfmt, "xyza f"))
       +                process = process_f;
       +        else
       +                eprintf("pixel format %s is not supported, try xyza\n", stream.pixfmt);
       +
       +        fprint_stream_head(stdout, &stream);
       +        efflush(stdout, "<stdout>");
       +        process(&stream);
       +        return 0;
       +}
   DIR diff --git a/src/blind-vector-projection.c b/src/blind-vector-projection.c
       @@ -0,0 +1,91 @@
       +/* See LICENSE file for copyright and license details. */
       +#include "common.h"
       +
       +USAGE("[-r | -s] plane-stream")
       +
       +static int level = 1;
       +
       +#if defined(__GNUC__) && !defined(__clang__)
       +# pragma GCC diagnostic push
       +# pragma GCC diagnostic ignored "-Wunsafe-loop-optimizations"
       +#endif
       +
       +#define PROCESS(TYPE, SUFFIX)\
       +        static void\
       +        process_##SUFFIX(struct stream *left, struct stream *right, size_t n)\
       +        {\
       +                size_t i;\
       +                TYPE *lx, *ly, *lz, *la, rx, ry, rz, ra, x, y, z, a, norm;\
       +                for (i = 0; i < n; i += 4 * sizeof(TYPE)) {\
       +                        lx = ((TYPE *)(left->buf + i)) + 0, rx = ((TYPE *)(right->buf + i))[0];\
       +                        ly = ((TYPE *)(left->buf + i)) + 1, ry = ((TYPE *)(right->buf + i))[1];\
       +                        lz = ((TYPE *)(left->buf + i)) + 2, rz = ((TYPE *)(right->buf + i))[2];\
       +                        la = ((TYPE *)(left->buf + i)) + 3, ra = ((TYPE *)(right->buf + i))[3];\
       +                        norm = rx * rx + ry * ry + rz * rz + ra * ra;\
       +                        norm = sqrt(norm);\
       +                        x = y = z = a = *lx * rx + *ly * ry + *lz * rz + *la * ra;\
       +                        if (level) {\
       +                                x *= rx;\
       +                                y *= ry;\
       +                                z *= rz;\
       +                                a *= rz;\
       +                                if (level > 1) {\
       +                                        x = *lx - x;\
       +                                        y = *ly - y;\
       +                                        z = *lz - z;\
       +                                        a = *la - a;\
       +                                }\
       +                        }\
       +                        *lx = x;\
       +                        *ly = y;\
       +                        *lz = z;\
       +                        *la = a;\
       +                }\
       +        }
       +
       +PROCESS(double, lf)
       +PROCESS(float, f)
       +
       +#if defined(__GNUC__) && !defined(__clang__)
       +# pragma GCC diagnostic pop
       +#endif
       +
       +int
       +main(int argc, char *argv[])
       +{
       +        struct stream left, right;
       +        void (*process)(struct stream *left, struct stream *right, size_t n);
       +
       +        ARGBEGIN {
       +        case 'r':
       +                if (level == 0)
       +                        usage();
       +                level = 2;
       +                break;
       +        case 's':
       +                if (level == 2)
       +                        usage();
       +                level = 0;
       +                break;
       +        default:
       +                usage();
       +        } ARGEND;
       +
       +        if (argc != 2)
       +                usage();
       +
       +        eopen_stream(&left, NULL);
       +        eopen_stream(&right, argv[1]);
       +
       +        if (!strcmp(left.pixfmt, "xyza"))
       +                process = process_lf;
       +        else if (!strcmp(left.pixfmt, "xyza f"))
       +                process = process_f;
       +        else
       +                eprintf("pixel format %s is not supported, try xyza\n", left.pixfmt);
       +
       +        fprint_stream_head(stdout, &left);
       +        efflush(stdout, "<stdout>");
       +        process_two_streams(&left, &right, STDOUT_FILENO, "<stdout>", process);
       +        return 0;
       +}