blind

suckless command-line video editing utility
git clone git://git.suckless.org/blind
Log | Files | Refs | README | LICENSE

commit ccd26e2affb0fb4a10b7261a85cb85b2525e5d9e
parent 698481451a63e0bd81aeb1ad3bf794ce7aaadef2
Author: Mattias Andrée <maandree@kth.se>
Date:   Sun, 23 Jul 2017 20:48:18 +0200

Fix some errors, add manual for blind-colour-matrix and add blind-primary-key

Signed-off-by: Mattias Andrée <maandree@kth.se>

Diffstat:
.gitignore | 1+
Makefile | 1+
README | 3+++
TODO | 10+++++++++-
blind-primary-key | 114+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
man/blind-chroma-key.1 | 3++-
man/blind-colour-matrix.1 | 76++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
man/blind-dual-key.1 | 3++-
man/blind-primary-key.1 | 84+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
man/blind.7 | 3+++
src/blind-affine-colour.c | 13+++++++++++--
src/blind-colour-matrix.c | 72+++++++++++++++++++++++++++++++++++++++---------------------------------
src/blind-from-named.c | 4+---
src/util.c | 6++++--
14 files changed, 350 insertions(+), 43 deletions(-)

diff --git a/.gitignore b/.gitignore @@ -13,3 +13,4 @@ !/blind-rotate-90 !/blind-rotate-180 !/blind-rotate-270 +!/blind-primary-key diff --git a/Makefile b/Makefile @@ -106,6 +106,7 @@ BIN =\ # blind-temporal-mean SCRIPTS =\ + blind-primary-key\ blind-rotate-90\ blind-rotate-180\ blind-rotate-270 diff --git a/README b/README @@ -174,6 +174,9 @@ UTILITIES blind-premultiply(1) Premultiply the alpha channel of a video + blind-primary-key(1) + Replace a primary with transparency + blind-quaternion-product(1) Calculate the quaternion product of colours in a video diff --git a/TODO b/TODO @@ -1,6 +1,14 @@ +This command should not noticeably change the image: + + RGB="$(./blind-colour-srgb -ld1 1 0 0) $(./blind-colour-srgb -ld1 0 1 0) $(./blind-colour-srgb -ld1 0 0 1)" + ./blind-from-image < in.png | ./blind-affine-colour -al <(./blind-colour-matrix $RGB) | \ + ./blind-affine-colour -al <(./blind-colour-matrix $RGB | ./blind-invert-matrix -ae) | \ + ./blind-to-image | convert - out.png + + + 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-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-find-frame a graphical tool for locating frames, should highlight key frames, and diff --git a/blind-primary-key b/blind-primary-key @@ -0,0 +1,114 @@ +#!/bin/bash + +set -e + +if printf '%s\n' "$0" | grep / >/dev/null 2>/dev/null; then + export PATH="$(printf '%s\n' "$0" | tr '/\n' '\n/' | sed \$d | tr '/\n' '\n/'):${PATH}" +fi + +pid=$$ +o='0 0 0 0' +E='1 1 1 1' + +x=x; y=y; z=z +ciexyy=0 +zflag= +grey=0 + +usage () { + xyy="-z x1 y1 x2 y2 x3 y3 [white-x white-y]" + xyz="X1 Y1 Z1 X2 Y2 Z2 X3 Y3 Z3 [white-X white-Y white-Z]" + printf 'usage: %s [-1 | -2 | -3] [-g] [%s | %s]\n' "$0" "$xyy" "$xyz" >&2 + exit 1 +} + +while ! test $# = 0; do + if test "$1" = --; then + shift 1 + break + elif test "${1::1}" = -; then + arg="${1:1}" + shift 1 + while test -n "${arg::1}"; do + flag="${arg::1}" + arg="${arg:1}" + if test "$flag" = 1; then + x=x; y=y; z=z + elif test "$flag" = 2; then + x=y; y=z; z=x + elif test "$flag" = 3; then + x=z; y=x; z=y + elif test "$flag" = g; then + grey=1 + elif test "$flag" = z; then + ciexyy=1 + else + usage + fi + done + else + break + fi +done + +a=$(( ( 3 - $ciexyy ) * 3 )) +b=$(( ( 3 - $ciexyy ) * 4 )) +if test $# != 0 && test $# != $a && test $# != $b; then + usage +elif test $ciexyy = 1 && test $# = 0; then + usage +fi + +read frames width height pixfmt < <(blind-read-head) + +if test $# = 0; then + convert () { cat; } + unconvert () { cat; } +else + if test $ciexyy = 1; then + zflag=-z + fi + convert () { + blind-affine-colour -al \ + <(blind-colour-matrix -F "$pixfmt" $zflag -- "$@" | \ + blind-tee \ + >(blind-invert-matrix -ae | \blind-to-named -a blind-${pid}-invmat) | \ + blind-repeat inf -) + } + unconvert () { + blind-affine-colour -al \ + <(blind-from-named -a blind-${pid}-invmat blind-repeat inf -) + } +fi + +if test $grey = 0; then + finalise () { unconvert; } +else + finalise () { + unconvert | blind-set-saturation <(blind-single-colour -f inf -w $width -h $height 0) + } +fi + +(blind-write-head $frames $width $height "$pixfmt" ; cat) | \ + convert "$@" | \ + blind-split-chans -c \ + >(blind-to-named -a blind-${pid}-x) \ + >(blind-to-named -a blind-${pid}-y) \ + >(blind-to-named -a blind-${pid}-z) \ + - | \ + blind-arithm mul \ + <(blind-single-colour -f inf -w $width -h $height 0 0 0 1 | \ + blind-arithm sub \ + <(blind-from-named -a blind-${pid}-$x \ + blind-affine-colour -l \ + <(printf '%s %s %s %s\n' \ + 1 4 4 xyza \ + $o $o $o $o \ + $o $o $o $o \ + $o $o $o $o \ + $E $E $E $o | \ + blind-from-text | \ + blind-repeat inf -))) | \ + blind-from-named -f 8 -a blind-${pid}-$y blind-arithm add /dev/fd/8 | \ + blind-from-named -f 9 -a blind-${pid}-$z blind-arithm add /dev/fd/9 | \ + finalise diff --git a/man/blind-chroma-key.1 b/man/blind-chroma-key.1 @@ -33,7 +33,8 @@ colour, twos alpha values are inverted. .BR blind-from-text (1), .BR blind-colour-ciexyz (1), .BR blind-colour-srgb (1), -.BR blind-dual-key (1) +.BR blind-dual-key (1), +.BR blind-primary-key (1) .SH AUTHORS Mattias Andrée .RI < maandree@kth.se > diff --git a/man/blind-colour-matrix.1 b/man/blind-colour-matrix.1 @@ -0,0 +1,76 @@ +.TH BLIND-COLOUR-MATRIX 1 blind +.SH NAME +blind-colour-matrix - Create colour space conversion matrix +.SH SYNOPSIS +.B blind-colour-matrix +[-F +.IR pixel-format ] +(-z +.I x1 +.I y1 +.I x2 +.I y2 +.I x3 +.I y3 +.RI [ white-x +.IR white-y ] +| +.I X1 +.I Y1 +.I Z1 +.I X2 +.I Y2 +.I Z2 +.I X3 +.I Y3 +.I Z3 +.RI [ white-X +.I white-Y +.IR white-Z ]) +.SH DESCRIPTION +.B blind-colour-matrix +creates a colour conversion matrix, that is +printed as blind video to stdout, for conversion +from the colour space used by blind to a colour +space with the primaries whose CIE XYZ values are +.RI ( X1 +.I Y1 +.IR Z1 ), +.RI ( X2 +.I Y2 +.IR Z2 ), +and +.RI ( X3 +.I Y3 +.IR Z3 ) +and whose white point is the colour whose +CIE XYZ values are +.RI ( white-X +.I white-Y +.IR white-Z ). +If the white point is not specified, +CIE Standard Illuminant D65 is used. +.SH OPTIONS +.TP +.BR -F " "\fIpixel-format\fP +Select pixel format, see +.BR blind-convert (1) +for more information. +.TP +.B -z +Parse arguments as CIE XYY instead of CIE XYZ. +.SH NOTES +.B blind-colour-matrix +may be changed in the future to use some other colour model, +therefore, it is recommended to also use +.BR blind-colour-ciexyz (1) +if you are specifying the colour in CIE XYZ. +.SH SEE ALSO +.BR blind (7), +.BR blind-colour-ciexyz (1), +.BR blind-colour-srgb (1), +.BR blind-invert-matrix (1), +.BR blind-affine-colour (1) +.SH AUTHORS +Mattias Andrée +.RI < maandree@kth.se > diff --git a/man/blind-dual-key.1 b/man/blind-dual-key.1 @@ -50,7 +50,8 @@ example black and white or green and magenta. .BR blind (7), .BR blind-colour-ciexyz (1), .BR blind-colour-srgb (1), -.BR blind-chroma-key (1) +.BR blind-chroma-key (1), +.BR blind-primary-key (1) .SH AUTHORS Mattias Andrée .RI < maandree@kth.se > diff --git a/man/blind-primary-key.1 b/man/blind-primary-key.1 @@ -0,0 +1,84 @@ +.TH BLIND-PRIMARY-KEY 1 blind +.SH NAME +blind-primary-key - Replace a primary with transparency +.SH SYNOPSIS +.B blind-primary-key +[-1 | -2 | -3] [-g] (-z +.I x1 +.I y1 +.I x2 +.I y2 +.I x3 +.I y3 +.RI [ white-x +.IR white-y ] +| +.I X1 +.I Y1 +.I Z1 +.I X2 +.I Y2 +.I Z2 +.I X3 +.I Y3 +.I Z3 +.RI [ white-X +.I white-Y +.IR white-Z ]) +.SH DESCRIPTION +.B blind-primary-key +reads a video from stdin and replaces a primary +with transparency and prints the resulting video +to stdout. +.B blind-primary-key +internally converts colour space to the one +with the primaries whose CIE XYZ values are +.RI ( X1 +.I Y1 +.IR Z1 ), +.RI ( X2 +.I Y2 +.IR Z2 ), +and +.RI ( X3 +.I Y3 +.IR Z3 ) +and whose white point is the colour whose +CIE XYZ values are +.RI ( white-X +.I white-Y +.IR white-Z ), +and replaces the first primary with transparency. +If the white point is not specified, +CIE Standard Illuminant D65 is used. +.P +If the colour space is specified, no conversion +is done internally. +.SH OPTIONS +.TP +.B -1 +Replace the the first primary with transparency. (Default.) +.TP +.B -2 +Replace the the second primary, instead +of the first primary, with transparency. +.TP +.B -3 +Replace the the third primary, instead +of the first primary, with transparency. +.TP +.B -g +The video is, with the exception of the keyed primary, +greyscale and the output video shall remain greyscale. +.TP +.B -z +Parse arguments as CIE XYY instead of CIE XYZ. +.SH SEE ALSO +.BR blind (7), +.BR blind-colour-ciexyz (1), +.BR blind-colour-srgb (1), +.BR blind-invert-matrix (1), +.BR blind-affine-colour (1) +.SH AUTHORS +Mattias Andrée +.RI < maandree@kth.se > diff --git a/man/blind.7 b/man/blind.7 @@ -192,6 +192,9 @@ Calculate the norm of colours in a video .BR blind-premultiply (1) Premultiply the alpha channel of a video .TP +.BR blind-primary-key (1) +Replace a primary with transparency +.TP .BR blind-quaternion-product (1) Calculate the quaternion product of colours in a video .TP diff --git a/src/blind-affine-colour.c b/src/blind-affine-colour.c @@ -88,14 +88,23 @@ PROCESS(struct stream *colour, struct stream *matrix) if (!x) { if (!y && !eread_segment(matrix, mbuf, dim * matrix->row_size)) break; - if (!per_pixel) + if (!per_pixel) { + if (!y) { + mat = (TYPE *)mbuf; + 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]; + } 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]; + 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++) { diff --git a/src/blind-colour-matrix.c b/src/blind-colour-matrix.c @@ -1,7 +1,33 @@ /* See LICENSE file for copyright and license details. */ #include "common.h" -USAGE("[-F pixel-format] (-z x1 y1 x2 y2 x3 y3 white-x white-y | X1 Y1 Z1 X2 Y2 Z2 X3 Y3 Z3 [white-X white-Y white-Z])") +USAGE("[-F pixel-format] (-z x1 y1 x2 y2 x3 y3 [white-x white-y] | X1 Y1 Z1 X2 Y2 Z2 X3 Y3 Z3 [white-X white-Y white-Z])") + +static void +invert(double M[3][6]) +{ + size_t r1, r2, i; + double t; + for (r1 = 0; r1 < 3; r1++) { + if (!M[r1][r1]) { + for (r2 = r1 + 1; r2 < 3 && !M[r2][r1]; r2++); + if (r2 >= 3) + eprintf("the colour space's rank is less than 3\n"); + for (i = 0; i < 6; i++) + t = M[r1][i], M[r1][i] = M[r2][i], M[r2][i] = t; + } + t = 1. / M[r1][r1]; + for (i = 0; i < 6; i++) + M[r1][i] *= t; + for (r2 = r1 + 1; r2 < 3; r2++) + for (i = 0, t = M[r2][r1]; i < 6; i++) + M[r2][i] -= M[r1][i] * t; + } + for (r1 = 3; --r1;) + for (r2 = r1; r2--;) + for (i = 0, t = M[r2][r1]; i < 6; i++) + M[r2][i] -= M[r1][i] * t; +} int main(int argc, char *argv[]) @@ -12,7 +38,7 @@ main(int argc, char *argv[]) double x[4], y[4], z[4], M[3][6], t; double Mlf[9 * 4]; float Mf[9 * 4]; - size_t i, j, r1, r2; + size_t i, j; ARGBEGIN { case 'F': @@ -59,15 +85,6 @@ main(int argc, char *argv[]) x[3] = argc > 9 ? etolf_arg("white-X", argv[9]) : D65_XYZ_X; y[3] = argc > 9 ? etolf_arg("white-Y", argv[10]) : 1; z[3] = argc > 9 ? etolf_arg("white-Z", argv[11]) : D65_XYZ_Z; - for (i = 0; i < 4; i++) { - if (y[i] && y[i] != 1.) { - x[i] /= y[i]; - z[i] /= y[i]; - y[i] = 1.; - } else if (!y[i]) { - x[i] = y[i] = z[i] = 0.; - } - } } for (i = 0; i < 3; i++) { @@ -78,25 +95,7 @@ main(int argc, char *argv[]) M[i][3 + i] = 1.; } - for (r1 = 0; r1 < 3; r1++) { - if (!M[r1][r1]) { - for (r2 = r1 + 1; r2 < 3 && !M[r2][r1]; r2++); - if (r2 >= 3) - eprintf("the colour space's rank is less than 3\n"); - for (i = 0; i < 6; i++) - t = M[r1][i], M[r1][i] = M[r2][i], M[r2][i] = t; - } - t = 1. / M[r1][r1]; - for (i = 0; i < 6; i++) - M[r1][i] *= t; - for (r2 = r1; r2--;) - for (i = 0, t = M[r2][r1]; i < 6; i++) - M[r2][i] -= M[r1][i] * t; - } - for (r1 = 3; r1--;) - for (r2 = r1; r2--;) - for (i = 0, t = M[r2][r1]; i < 6; i++) - M[r2][i] -= M[r1][i] * t; + invert(M); for (i = 0; i < 3; i++) { t = M[i][3] * x[3] + M[i][4] * y[3] + M[i][5] * z[3]; @@ -105,15 +104,22 @@ main(int argc, char *argv[]) M[2][i] = t * z[i]; } + for (i = 0; i < 3; i++) { + M[i][3] = M[i][4] = M[i][5] = 0.; + M[i][3 + i] = 1.; + } + + invert(M); + eset_pixel_format(&stream, pixfmt); fprint_stream_head(stdout, &stream); efflush(stdout, "<stdout>"); for (i = 0; i < 3; i++) { for (j = 0; j < 3; j++) { - Mlf[i * 12 + j * 4 + 0] = M[i][j]; - Mlf[i * 12 + j * 4 + 1] = M[i][j]; - Mlf[i * 12 + j * 4 + 2] = M[i][j]; + Mlf[i * 12 + j * 4 + 0] = M[i][3 + j]; + Mlf[i * 12 + j * 4 + 1] = M[i][3 + j]; + Mlf[i * 12 + j * 4 + 2] = M[i][3 + j]; Mlf[i * 12 + j * 4 + 3] = 1.; } } diff --git a/src/blind-from-named.c b/src/blind-from-named.c @@ -107,9 +107,7 @@ retry: eprintf("execvp %s:", argv[0]); } - while ((n = read(fd, buf, sizeof(buf))) > 0) + while ((n = eread(fd, buf, sizeof(buf), "<received file>"))) ewriteall(STDOUT_FILENO, buf, (size_t)n, "<stdout>"); - if (n < 0) - eprintf("read <received file>:"); return 0; } diff --git a/src/util.c b/src/util.c @@ -158,16 +158,18 @@ getfile(int fd, void *buffer, size_t *restrict ptr, size_t *restrict size) { char *restrict *restrict buf = buffer; void *new; + size_t new_size; ssize_t r; for (;;) { if (*ptr == *size) { - if (!(new = realloc(*buf, *size << 1))) { + new_size = *size ? *size << 1 : BUFSIZ; + if (!(new = realloc(*buf, new_size))) { errno = ENOMEM; return -1; } *buf = new; - *size <<= 1; + *size = new_size; } r = read(fd, *buf + *ptr, *size - *ptr); if (r <= 0) {