URI: 
       Add blind-affine-colour and blind-split-chans - 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 fa20f84e2d12bf9998591ce4e464180586d957ff
   DIR parent 0a034f2bd5a44c3cc0c033eacc940bb3bf73662c
  HTML Author: Mattias Andrée <maandree@kth.se>
       Date:   Thu, 20 Jul 2017 20:03:52 +0200
       
       Add blind-affine-colour and blind-split-chans
       
       Signed-off-by: Mattias Andrée <maandree@kth.se>
       
       Diffstat:
         M Makefile                            |       2 ++
         M README                              |       6 ++++++
         M TODO                                |      25 ++++++++++++-------------
         A man/blind-affine-colour.1           |      71 +++++++++++++++++++++++++++++++
         M man/blind-arithm.1                  |       3 ++-
         M man/blind-invert-matrix.1           |       3 ++-
         M man/blind-multiply-matrices.1       |       3 ++-
         M man/blind-rewrite-head.1            |       3 ++-
         A man/blind-split-chans.1             |      47 +++++++++++++++++++++++++++++++
         M man/blind.7                         |       6 ++++++
         A src/blind-affine-colour.c           |     118 +++++++++++++++++++++++++++++++
         A src/blind-split-chans.c             |      65 +++++++++++++++++++++++++++++++
       
       12 files changed, 335 insertions(+), 17 deletions(-)
       ---
   DIR diff --git a/Makefile b/Makefile
       @@ -3,6 +3,7 @@ include $(CONFIGFILE)
        
        
        BIN =\
       +        blind-affine-colour\
                blind-apply-palette\
                blind-arithm\
                blind-cat-cols\
       @@ -76,6 +77,7 @@ BIN =\
                blind-spectrum\
                blind-spiral-gradient\
                blind-split\
       +        blind-split-chans\
                blind-split-cols\
                blind-split-rows\
                blind-square-gradient\
   DIR diff --git a/README b/README
       @@ -12,6 +12,9 @@ DESCRIPTION
               storing the video without first convert it with blind-to-video(1).
        
        UTILITIES
       +       blind-affine-colour(1)
       +              Apply an affine transformation to the colours in a video
       +
               blind-arithm(1)
                      Perform simple arithmetic on a video
        
       @@ -234,6 +237,9 @@ UTILITIES
               blind-split(1)
                      Split a video, by frame, into multiple videos
        
       +       blind-split-chans(1)
       +              Split colour channels into separate videos
       +
               blind-split-cols(1)
                      Split a video vertically into multiple videos
        
   DIR diff --git a/TODO b/TODO
       @@ -1,22 +1,17 @@
        Fix blind-from-named without command
        
       -blind-transform                affine transformation by matrix multiplication, -t for tiling, -s for
       -                                improve quality on downscaling (pixels' neighbours must not change).
       -blind-primary-key        replace a primary with transparency, -g for greyscaled images.
       -blind-primaries                given three selectable primaries split the video into three side-by-side which
       -                                only one primary active.
       -blind-apply-map                remap pixels (distortion) using the X and Y values, -t for tiling, -s for
       -                                improve quality on downscaling (pixels' neighbours must not change).
       +blind-transform                affine transformation by matrix multiplication, -[xy] for tiling, -s for
       +                                improve quality on downscaling (pixels' neighbours must not change)
       +blind-primary-key        replace a primary with transparency, -g for greyscaled images
       +blind-colour-matrix        create colour space conversion matrix
       +blind-apply-map                remap pixels (distortion) using the X and Y values, -[xy] for tiling, -s for
       +                                improve quality on downscaling (pixels' neighbours must not change)
        blind-apply-kernel        apply a convolution matrix.
        blind-find-frame        a graphical tool for locating frames, should highlight key frames, and
       -                                play audio. Should support both regular videos files and uivf.
       +                                play audio. Should support both regular videos files and uivf
                                        finding key frames: ffprobe -show_frames (lists all frames)
       -blind-affine-colour        apply an affine transformation to the colour of each pixel,
       -                                -a for ignoring the alpha channel,
       -                                -l for linear transformation,
       -                                -p for transforming each pixel with their own transformation.
        blind-invert-chroma        invert the chroma
       -blind-from-sent                convert a sent presentation to a one-frame-per-slide blind video.
       +blind-from-sent                convert a sent presentation to a one-frame-per-slide blind video
        
        blind-kirsch                https://en.wikipedia.org/wiki/Kirsch_operator
        blind-gaussian-noise        https://en.wikipedia.org/wiki/Gaussian_noise
       @@ -43,6 +38,10 @@ blind-mean                mean of multiple streams
                                https://en.wikipedia.org/wiki/Stolarsky_mean
        blind-temporal-arithm        blind-arithm but over all frames in a video instead of over all streams
        blind-apply-icc                apply ICC profile to video
       +blind-convex-gradient        create a gradient in the shape of a convex lens
       +blind-concave-gradient        create a gradient in the shape of a concave lens
       +                        (convexo-concave gradient is not necessary is blind-convex-gradient
       +                         or blind-concave-gradient can be combined with blind-arithm for this)
        
        blind-from-video: add options to:
                * just run ffmpeg just print the output
   DIR diff --git a/man/blind-affine-colour.1 b/man/blind-affine-colour.1
       @@ -0,0 +1,71 @@
       +.TH BLIND-AFFINE-COLOUR 1 blind
       +.SH NAME
       +blind-affine-colour - Apply an affine transformation to the colours in a video
       +.SH SYNOPSIS
       +.B blind-affine-colour
       +[-alp]
       +.I matrix-stream
       +.SH DESCRIPTION
       +.B blind-affine-colour
       +reads a video from stdin and a matrix video from
       +.I matrix-stream
       +and multiplies colours from stdin with matrices from
       +.I matrix-stream
       +and prints the resulting video to stdout.
       +.P
       +Each frame in
       +.I matrix-stream
       +is a matrix and shall have the width and height 5.
       +Each pixel in a frame is a cell in the matrix,
       +the pixels luma is multiples by its alpha value
       +to determine the value of the matrix cell.
       +.SH OPTIONS
       +.TP
       +.B -a
       +The width and height of the matrix shall be 4
       +instead of 5 (reduced by 1) and the alpha values
       +of the pixels shall not be modified.
       +.TP
       +.B -l
       +The width and height of the matrix shall be 4
       +instead of 5 (reduced by 1) making the transformation
       +linear instead of affine.
       +.TP
       +.B -p
       +Each frame in
       +.I matrix-stream
       +shall contain one matrix per pixel in a frame in
       +stdin. The video in
       +.I matrix-stream
       +shall be 5, 4, or 3, depending on whether
       +.B -a
       +and
       +.B -l
       +are specified, times are wide and tall as the
       +video in stdin.
       +.SH NOTES
       +If both
       +.B -a
       +and
       +.B -l
       +are specified, the matrices shall have the
       +width and height 3 instead of 5.
       +.SH REQUIREMENTS
       +.B blind-affine-colour
       +requires enough free memory to load 5, 4, or 3,
       +depending on whether
       +.B -a
       +and
       +.B -l
       +are specified, full rows from
       +.I matrix-stream
       +into memory. A frame requires 32 bytes per pixel
       +it contains.
       +.SH SEE ALSO
       +.BR blind (7),
       +.BR blind-arithm (1),
       +.BR blind-invert-matrix (1),
       +.BR blind-multiply-matrice (1)
       +.SH AUTHORS
       +Mattias Andrée
       +.RI < maandree@kth.se >
   DIR diff --git a/man/blind-arithm.1 b/man/blind-arithm.1
       @@ -90,7 +90,8 @@ Do not modify the Z channel (the third channel).
        .BR blind-set-alpha (1),
        .BR blind-set-luma (1),
        .BR blind-invert-luma (1),
       -.BR blind-set-saturation (1)
       +.BR blind-set-saturation (1),
       +.BR blind-affine-colour (1)
        .SH AUTHORS
        Mattias Andrée
        .RI < maandree@kth.se >
   DIR diff --git a/man/blind-invert-matrix.1 b/man/blind-invert-matrix.1
       @@ -29,7 +29,8 @@ are identical.
        .BR blind-flop (1),
        .BR blind-rotate-90 (1),
        .BR blind-rotate-180 (1),
       -.BR blind-rotate-270 (1)
       +.BR blind-rotate-270 (1),
       +.BR blind-rewrite-head (1)
        .SH AUTHORS
        Mattias Andrée
        .RI < maandree@kth.se >
   DIR diff --git a/man/blind-multiply-matrices.1 b/man/blind-multiply-matrices.1
       @@ -44,7 +44,8 @@ in reverse order.
        .BR blind-flop (1),
        .BR blind-rotate-90 (1),
        .BR blind-rotate-180 (1),
       -.BR blind-rotate-270 (1)
       +.BR blind-rotate-270 (1),
       +.BR blind-rewrite-head (1)
        .SH AUTHORS
        Mattias Andrée
        .RI < maandree@kth.se >
   DIR diff --git a/man/blind-rewrite-head.1 b/man/blind-rewrite-head.1
       @@ -72,7 +72,8 @@ two copies of on disc.
        .BR blind-from-video (1),
        .BR blind-split (1),
        .BR blind-read-head (1),
       -.BR blind-write-head (1)
       +.BR blind-write-head (1),
       +.BR blind-transpose (1)
        .SH AUTHORS
        Mattias Andrée
        .RI < maandree@kth.se >
   DIR diff --git a/man/blind-split-chans.1 b/man/blind-split-chans.1
       @@ -0,0 +1,47 @@
       +.TH BLIND-SPLIT-CHANS 1 blind
       +.SH NAME
       +blind-split-chans - Split colour channels into separate videos
       +.SH SYNOPSIS
       +.B blind-split-chans
       +.I X-file
       +.I Y-file
       +.I Z-file
       +.RI [ alpha-file ]
       +.SH DESCRIPTION
       +.B blind-split-chans
       +reads a video from stdin and prints
       +it to
       +.I X-file
       +with the values of the first channel
       +(the X channel) in written to all
       +channels, to
       +.I Y-file
       +with the values of the second channel
       +(the Y channel) in written to all
       +channels, to
       +.I Z-file
       +with the values of the third channel
       +(the Z channel) in written to all
       +channels, and to
       +.I alpha-file
       +with the values of the fourth channel
       +(the alpha channel) in written to all
       +channels.
       +.P
       +If
       +.I alpha-file
       +is omitted, values of the alpha channel
       +are instead written to the alpha channels
       +in
       +.IR X-file ,
       +.IR Y-file ,
       +and
       +.IR Z-file .
       +.SH SEE ALSO
       +.BR blind (7),
       +.BR blind-arithm (1),
       +.BR blind-cat-cols (1),
       +.BR blind-cat-rows (1)
       +.SH AUTHORS
       +Mattias Andrée
       +.RI < maandree@kth.se >
   DIR diff --git a/man/blind.7 b/man/blind.7
       @@ -19,6 +19,9 @@ first convert it with
        .BR blind-to-video (1).
        .SH UTILITIES
        .TP
       +.BR blind-affine-colour (1)
       +Apply an affine transformation to the colours in a video
       +.TP
        .BR blind-arithm (1)
        Perform simple arithmetic on a video
        .TP
       @@ -247,6 +250,9 @@ Generate a video with a spiral gradient
        .BR blind-split (1)
        Split a video, by frame, into multiple videos
        .TP
       +.BR blind-split-chans (1)
       +Split colour channels into separate videos
       +.TP
        .BR blind-split-cols (1)
        Split a video vertically into multiple videos
        .TP
   DIR diff --git a/src/blind-affine-colour.c b/src/blind-affine-colour.c
       @@ -0,0 +1,118 @@
       +/* See LICENSE file for copyright and license details. */
       +#ifndef TYPE
       +#include "common.h"
       +
       +USAGE("[-alp] matrix-stream")
       +
       +static int skip_alpha = 0;
       +static int linear = 0;
       +static int per_pixel = 0;
       +static size_t dim;
       +
       +#define FILE "blind-affine-colour.c"
       +#include "define-functions.h"
       +
       +int
       +main(int argc, char *argv[])
       +{
       +        struct stream colour, matrix;
       +        void (*process)(struct stream *colour, struct stream *matrix);
       +        size_t h;
       +
       +        ARGBEGIN {
       +        case 'a':
       +                skip_alpha = 1;
       +                break;
       +        case 'l':
       +                linear = 1;
       +                break;
       +        case 'p':
       +                per_pixel = 1;
       +                break;
       +        default:
       +                usage();
       +        } ARGEND;
       +
       +        if (argc != 1)
       +                usage();
       +
       +        eopen_stream(&colour, NULL);
       +        eopen_stream(&matrix, argv[0]);
       +
       +        SELECT_PROCESS_FUNCTION(&colour);
       +
       +        if (strcmp(colour.pixfmt, matrix.pixfmt))
       +                eprintf("videos use incompatible pixel formats\n");
       +
       +        dim = colour.n_chan - (size_t)skip_alpha + (size_t)!linear;
       +        h = matrix.height, matrix.height = dim;
       +        echeck_dimensions(&matrix, WIDTH | HEIGHT, "matrix");
       +        matrix.height = h;
       +
       +        if (per_pixel) {
       +                if (matrix.height != dim * colour.height || matrix.width != dim * colour.width)
       +                        eprintf("the matrice should have the size %zux%zu, but are %zux%zu",
       +                                dim * colour.height, dim * colour.width, matrix.height, matrix.width);
       +        } else {
       +                if (matrix.height != dim || matrix.width != dim)
       +                        eprintf("the matrice should have the size %zux%zu, but are %zux%zu",
       +                                dim, dim, matrix.height, matrix.width);
       +        }
       +
       +        fprint_stream_head(stdout, &colour);
       +        efflush(stdout, "<stdout>");
       +        process(&colour, &matrix);
       +        return 0;
       +}
       +
       +#else
       +
       +static void
       +PROCESS(struct stream *colour, struct stream *matrix)
       +{
       +        char *mbuf;
       +        TYPE *mat, *pixel, V[5], M[ELEMENTSOF(V)][ELEMENTSOF(V)];
       +        size_t ptr, i, j, w, x = 0, y = 0, cn;
       +
       +        mbuf = emalloc2(dim, matrix->row_size);
       +        mat = (TYPE *)mbuf;
       +        w = matrix->width * matrix->n_chan;
       +        cn = colour->n_chan - (size_t)skip_alpha;
       +
       +        memset(M, 0, sizeof(M));
       +        for (i = 0; i < ELEMENTSOF(V); i++)
       +                M[i][i] = V[i] = 1;
       +
       +        do {
       +                for (ptr = 0; ptr + colour->pixel_size <= colour->ptr; x = (x + 1) % colour->width, ptr += colour->pixel_size) {
       +                        if (!x) {
       +                                if (!y && !eread_segment(matrix, mbuf, dim * matrix->row_size))
       +                                        break;
       +                                if (!per_pixel)
       +                                        y = (y + 1) % colour->height;
       +                        }
       +                        if (per_pixel) {
       +                                mat = (TYPE *)(mbuf + x * dim * matrix->pixel_size);
       +                                for (i = 0; i < dim; i++, mat += w)
       +                                        for (j = 0; j < dim; j++)
       +                                                M[i][j] = mat[j * matrix->n_chan + 1] * mat[(j + 1) * matrix->n_chan - 1];
       +                        }
       +                        pixel = (TYPE *)(colour->buf + ptr);
       +                        for (i = 0; i < dim; i++) {
       +                                V[i] = 0;
       +                                for (j = 0; j < cn; j++)
       +                                        V[i] += M[i][j] * pixel[j];
       +                                for (; j < dim; j++)
       +                                        V[i] += M[i][j];
       +                        }
       +                        for (i = 0; i < cn; i++)
       +                                pixel[i] = V[i] / V[cn];
       +                }
       +                ewriteall(STDOUT_FILENO, colour->buf, ptr, "<stdout>");
       +                memmove(colour->buf, colour->buf + ptr, colour->ptr -= ptr);
       +        } while (eread_stream(colour, SIZE_MAX));
       +        if (colour->ptr)
       +                eprintf("%s: incomplete frame\n", colour->file);
       +}
       +
       +#endif
   DIR diff --git a/src/blind-split-chans.c b/src/blind-split-chans.c
       @@ -0,0 +1,65 @@
       +/* See LICENSE file for copyright and license details. */
       +#include "common.h"
       +
       +USAGE("X-file Y-file Z-file [alpha-file]")
       +
       +int
       +main(int argc, char *argv[])
       +{
       +        struct stream stream;
       +        char xbuf[BUFSIZ], ybuf[BUFSIZ], zbuf[BUFSIZ], abuf[BUFSIZ];
       +        int xfd, yfd, zfd, afd = -1;
       +        size_t i, n, ptr;
       +
       +        UNOFLAGS(argc != 3 && argc != 4);
       +
       +        eopen_stream(&stream, NULL);
       +
       +        xfd = eopen(argv[0], O_WRONLY | O_CREAT | O_TRUNC, 0666);
       +        yfd = eopen(argv[1], O_WRONLY | O_CREAT | O_TRUNC, 0666);
       +        zfd = eopen(argv[2], O_WRONLY | O_CREAT | O_TRUNC, 0666);
       +        if (argc == 4)
       +                afd = eopen(argv[3], O_WRONLY | O_CREAT | O_TRUNC, 0666);
       +
       +        if (DPRINTF_HEAD(xfd, stream.frames, stream.width, stream.height, stream.pixfmt) < 0)
       +                eprintf("dprintf %s:", argv[0]);
       +        if (DPRINTF_HEAD(yfd, stream.frames, stream.width, stream.height, stream.pixfmt) < 0)
       +                eprintf("dprintf %s:", argv[1]);
       +        if (DPRINTF_HEAD(zfd, stream.frames, stream.width, stream.height, stream.pixfmt) < 0)
       +                eprintf("dprintf %s:", argv[2]);
       +        if (afd >= 0 && DPRINTF_HEAD(afd, stream.frames, stream.width, stream.height, stream.pixfmt) < 0)
       +                eprintf("dprintf %s:", argv[3]);
       +
       +        n = (stream.n_chan - (afd < 0)) * stream.chan_size;
       +        do {
       +                for (ptr = 0; ptr + stream.pixel_size <= stream.ptr; ptr += stream.pixel_size) {
       +                        for (i = 0; i < n; i += stream.chan_size) {
       +                                memcpy(xbuf + ptr + i, stream.buf + ptr + 0 * stream.chan_size, stream.chan_size);
       +                                memcpy(ybuf + ptr + i, stream.buf + ptr + 1 * stream.chan_size, stream.chan_size);
       +                                memcpy(zbuf + ptr + i, stream.buf + ptr + 2 * stream.chan_size, stream.chan_size);
       +                                if (afd >= 0)
       +                                        memcpy(abuf + ptr + i, stream.buf + ptr + 3 * stream.chan_size, stream.chan_size);
       +                        }
       +                        if (afd < 0) {
       +                                memcpy(xbuf + ptr + n, stream.buf + ptr + 3 * stream.chan_size, stream.chan_size);
       +                                memcpy(ybuf + ptr + n, stream.buf + ptr + 3 * stream.chan_size, stream.chan_size);
       +                                memcpy(zbuf + ptr + n, stream.buf + ptr + 3 * stream.chan_size, stream.chan_size);
       +                        }
       +                }
       +                ewriteall(xfd, xbuf, ptr, argv[0]);
       +                ewriteall(yfd, ybuf, ptr, argv[1]);
       +                ewriteall(zfd, zbuf, ptr, argv[2]);
       +                if (afd >= 0)
       +                        ewriteall(afd, abuf, ptr, argv[3]);
       +                memmove(stream.buf, stream.buf + ptr, stream.ptr -= ptr);
       +        } while (eread_stream(&stream, SIZE_MAX));
       +        if (stream.ptr)
       +                eprintf("%s: incomplete frame\n", stream.file);
       +
       +        close(xfd);
       +        close(yfd);
       +        close(zfd);
       +        if (afd >= 0)
       +                close(afd);
       +        return 0;
       +}