blind

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

commit 698481451a63e0bd81aeb1ad3bf794ce7aaadef2
parent ebe2e88b44f46e59bdefef1eb585078d5fa6d4d4
Author: Mattias Andrée <maandree@kth.se>
Date:   Sun, 23 Jul 2017 12:00:07 +0200

Add blind-colour-matrix, and blind-invert-matrix: fix -e and add -axyz

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

Diffstat:
MMakefile | 1+
MREADME | 5++++-
MTODO | 1-
Mman/blind-colour-ciexyz.1 | 1+
Mman/blind-colour-srgb.1 | 3++-
Mman/blind-invert-matrix.1 | 14+++++++++++++-
Mman/blind.7 | 5+++++
Asrc/blind-colour-matrix.c | 130+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/blind-invert-matrix.c | 38++++++++++++++++++++++++++++++--------
9 files changed, 186 insertions(+), 12 deletions(-)

diff --git a/Makefile b/Makefile @@ -11,6 +11,7 @@ BIN =\ blind-cat-rows\ blind-chroma-key\ blind-colour-ciexyz\ + blind-colour-matrix\ blind-colour-srgb\ blind-compress\ blind-concat\ diff --git a/README b/README @@ -36,8 +36,11 @@ UTILITIES blind-colour-ciexyz(1) Convert CIE XYZ for use with blind-single-colour(1) + blind-colour-matrix(1) + Create colour space conversion matrix + blind-colour-srgb(1) - Convert sRGB for use with blind-single-colour(1) + Convert sRGB for use with blind-single-colour(1) and colour-colour-matrix(1) blind-concat(1) Concatenate videos diff --git a/TODO b/TODO @@ -1,7 +1,6 @@ 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-find-frame a graphical tool for locating frames, should highlight key frames, and diff --git a/man/blind-colour-ciexyz.1 b/man/blind-colour-ciexyz.1 @@ -24,6 +24,7 @@ with a luminosity of .SH SEE ALSO .BR blind (7), .BR blind-single-colour (1), +.BR blind-colour-matrix (1), .BR blind-colour-srgb (1) .SH AUTHORS Mattias Andrée diff --git a/man/blind-colour-srgb.1 b/man/blind-colour-srgb.1 @@ -1,6 +1,6 @@ .TH BLIND-COLOUR-SRGB 1 blind .SH NAME -blind-colour-srgb - Convert sRGB for use with blind-single-colour(1) +blind-colour-srgb - Convert sRGB for use with blind-single-colour(1) and blind-colour-matrix(1) .SH SYNOPSIS .B blind-colour-srgb [-d @@ -49,6 +49,7 @@ the sRGB transfer function. .SH SEE ALSO .BR blind (7), .BR blind-single-colour (1), +.BR blind-colour-matrix (1), .BR blind-colour-ciexyz (1) .SH AUTHORS Mattias Andrée diff --git a/man/blind-invert-matrix.1 b/man/blind-invert-matrix.1 @@ -3,7 +3,7 @@ blind-invert-matrix - Invert matrix-vidoes .SH SYNOPSIS .B blind-invert-matrix -[-e] +[-aexyz] .SH DESCRIPTION .B blind-invert-matrix reads a video representing a matrix from @@ -18,9 +18,21 @@ eliminated to the identity matrix and the resuling augment is printed. .SH OPTIONS .TP +.B -a +Ignore the alpha channel. +.TP .B -e Apply optimisation that assumes all channels are identical. +.TP +.B -x +Ignore the first channel (the X channel). +.TP +.B -y +Ignore the second channel (the Y channel). +.TP +.B -z +Ignore the third channel (the Z channel). .SH SEE ALSO .BR blind (7), .BR blind-multiply-matrices (1), diff --git a/man/blind.7 b/man/blind.7 @@ -44,9 +44,14 @@ Replace a colour range with transparency Convert CIE XYZ for use with .BR blind-single-colour (1) .TP +.BR blind-colour-matrix(1) +Create colour space conversion matrix +.TP .BR blind-colour-srgb (1) Convert sRGB for use with .BR blind-single-colour (1) +and +.BR colour-colour-matrix (1) .TP .BR blind-compress (1) Compress a video for network transmission diff --git a/src/blind-colour-matrix.c b/src/blind-colour-matrix.c @@ -0,0 +1,130 @@ +/* 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])") + +int +main(int argc, char *argv[]) +{ + static struct stream stream = { .width = 3, .height = 3, .frames = 1 }; + const char *pixfmt = "xyza"; + int ciexyy = 0; + 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; + + ARGBEGIN { + case 'F': + pixfmt = UARGF(); + break; + case 'z': + ciexyy = 1; + break; + default: + usage(); + } ARGEND; + + if (argc != (3 - ciexyy) * 3 && argc != (3 - ciexyy) * 4) + usage(); + + if (ciexyy) { + x[0] = etolf_arg("x1", argv[0]); + y[0] = etolf_arg("y1", argv[1]); + x[1] = etolf_arg("x2", argv[2]); + y[1] = etolf_arg("y2", argv[3]); + x[2] = etolf_arg("x3", argv[4]); + y[2] = etolf_arg("y3", argv[5]); + x[3] = argc > 6 ? etolf_arg("white-x", argv[6]) : D65_XYY_X; + y[3] = argc > 6 ? etolf_arg("white-y", argv[7]) : D65_XYY_Y; + for (i = 0; i < 4; i++) { + if (y[i]) { + z[i] = (1. - x[i] - y[i]) / y[i]; + x[i] /= y[i]; + y[i] = 1.; + } else { + x[i] = y[i] = z[i] = 1.; + } + } + } else { + x[0] = etolf_arg("X1", argv[0]); + y[0] = etolf_arg("Y1", argv[1]); + z[0] = etolf_arg("Z1", argv[2]); + x[1] = etolf_arg("X2", argv[3]); + y[1] = etolf_arg("Y2", argv[4]); + z[1] = etolf_arg("Z2", argv[5]); + x[2] = etolf_arg("X3", argv[6]); + y[2] = etolf_arg("Y3", argv[7]); + z[2] = etolf_arg("Z3", argv[8]); + 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++) { + M[0][i] = x[i]; + M[1][i] = y[i]; + M[2][i] = z[i]; + M[i][3] = M[i][4] = M[i][5] = 0.; + 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; + + for (i = 0; i < 3; i++) { + t = M[i][3] * x[3] + M[i][4] * y[3] + M[i][5] * z[3]; + M[0][i] = t * x[i]; + M[1][i] = t * y[i]; + M[2][i] = t * z[i]; + } + + 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 + 3] = 1.; + } + } + + if (stream.encoding == DOUBLE) { + ewriteall(STDOUT_FILENO, Mlf, sizeof(Mlf), "<stdout>"); + } else { + for (i = 0; i < ELEMENTSOF(Mlf); i++) + Mf[i] = (float)Mlf[i]; + ewriteall(STDOUT_FILENO, Mf, sizeof(Mf), "<stdout>"); + } + + return 0; +} diff --git a/src/blind-invert-matrix.c b/src/blind-invert-matrix.c @@ -2,9 +2,11 @@ #ifndef TYPE #include "common.h" -USAGE("") +USAGE("[-aexyz]") static int equal = 0; +static int skip_ch[] = {0, 0, 0, 0}; +static size_t first_included = 0; #define FILE "blind-invert-matrix.c" #include "define-functions.h" @@ -14,13 +16,25 @@ main(int argc, char *argv[]) { struct stream stream; size_t width, x, y, i, row_size; - char *buf, *one, *p; + char *buf, *one, *p, *q; void (*process)(struct stream *stream, void *buf); ARGBEGIN { + case 'a': + skip_ch[3] = 1; + break; case 'e': equal = 1; break; + case 'x': + skip_ch[0] = 1; + break; + case 'y': + skip_ch[1] = 1; + break; + case 'z': + skip_ch[2] = 1; + break; default: usage(); } ARGEND; @@ -28,6 +42,11 @@ main(int argc, char *argv[]) if (argc) usage(); + while (first_included < ELEMENTSOF(skip_ch) && skip_ch[first_included]) + first_included++; + if (first_included == ELEMENTSOF(skip_ch)) + equal = 0; + eopen_stream(&stream, NULL); echeck_dimensions(&stream, WIDTH | HEIGHT, NULL); width = stream.width; @@ -66,17 +85,20 @@ main(int argc, char *argv[]) } } if (equal) { - process(&stream, buf); + process(&stream, buf + first_included * stream.chan_size); for (y = 0; y < stream.height; y++) { for (x = 0; x < stream.width; x++) { - p = buf + y * row_size + x * stream.pixel_size; - for (i = 1; i < stream.n_chan; i++) - memcpy(p + i * stream.chan_size, p, stream.chan_size); + p = buf + y * row_size + x * stream.pixel_size + stream.col_size; + q = p + first_included * stream.chan_size; + for (i = 0; i < stream.n_chan; i++, p += stream.chan_size) + if (i != first_included && !skip_ch[i]) + memcpy(p, q, stream.chan_size); } } } else { for (i = 0; i < stream.n_chan; i++) - process(&stream, buf + i * stream.chan_size); + if (!skip_ch[i]) + process(&stream, buf + i * stream.chan_size); } for (y = 0; y < stream.height; y++) ewriteall(STDOUT_FILENO, buf + y * row_size + stream.col_size, row_size - stream.col_size, "<stdout>"); @@ -107,7 +129,7 @@ PROCESS(struct stream *stream, void *buf) for (r1 = 0; r1 < rn; r1++) { p1 = matrix + r1 * cn; - if (!p1[r1][0]) { + if (!p1[r1][0]) { for (r2 = r1 + 1; r2 < rn; r2++) { p2 = matrix + r2 * cn; if (p2[r1][0])