blind

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

commit bcac04b4316d64063e743e7a49195173a0c175a0
parent 4154609e5de76bc8858d3f86e0af09ba2700c488
Author: Mattias Andrée <maandree@kth.se>
Date:   Sun, 24 Sep 2017 01:26:08 +0200

Add -% to blind-to-text, blind-colour-srgb, and blind-colour-ciexyz

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

Diffstat:
TODO | 2--
man/blind-colour-ciexyz.1 | 38++++++++++++++++++++++++++++++++++++++
man/blind-colour-srgb.1 | 31+++++++++++++++++++++++++++++++
man/blind-to-text.1 | 39+++++++++++++++++++++++++++++++++++++++
src/blind-colour-ciexyz.c | 20+++++++++++++++++---
src/blind-colour-srgb.c | 10++++++++--
src/blind-to-text.c | 27++++++++++++++++++---------
src/define-functions.h | 14--------------
src/stream.c | 154+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
src/stream.h | 2++
src/util.c | 6+++++-
11 files changed, 312 insertions(+), 31 deletions(-)

diff --git a/TODO b/TODO @@ -35,8 +35,6 @@ blind-preview a graphical tool for previewing the output of a pipeline should have sliders to tune environment variables --- tool from creating blockwise transitions -blind-to-text, blind-from-text: support %a, %e, %g, and custom precision - Add [-j jobs] to blind-from-video, blind-to-video, blind-convert, and blind-apply-kernel. long double is slightly faster than long. diff --git a/man/blind-colour-ciexyz.1 b/man/blind-colour-ciexyz.1 @@ -3,6 +3,8 @@ blind-colour-ciexyz - Convert CIE XYZ for use with blind-single-colour(1) .SH SYNOPSIS .B blind-colour-ciexyz +[-% +.IR format ] .RI ( X .I Y .I Z @@ -21,6 +23,42 @@ that colour model. If only is specified, the colour will be CIE Standard Illuminant D65-grey with a luminosity of .IR Y . +.SH OPTIONS +.TP +.BR -% \ \fIformat\fP +Selects in what format parameters are printed. +.I format +may include the prefix +.B + +that specified that non-negative values should be prefixed with a +.BR + . +After any prefix, there may be a positive number specifying +the percision of the output, optionally followed by either of +the letters +.BR a , +.BR e , +.BR f , +other +.B g +(other their synonymous uppercases), +at most once, with the same semantics as in +.BR printf (3). +.B f +is used if this letter is omitted. + +If ommited, +.B 25f +is used unless all three of +.IR X , +.IR Y , +and +.I Z +is specified, in which case the parameters are +printed as-is. This default is selected for ease +of interoperability with other software, however, +.B a +is recommeded to improve performance and remove +truncation error. .SH SEE ALSO .BR blind (7), .BR blind-single-colour (1), diff --git a/man/blind-colour-srgb.1 b/man/blind-colour-srgb.1 @@ -3,6 +3,8 @@ blind-colour-srgb - Convert sRGB for use with blind-single-colour(1) and blind-colour-matrix(1) .SH SYNOPSIS .B blind-colour-srgb +[-% +.IR format ] [-d .IR depth ] [-l] @@ -38,6 +40,35 @@ unsigned integer with bits. .SH OPTIONS .TP +.BR -% \ \fIformat\fP +Selects in what format parameters are printed. +.I format +may include the prefix +.B + +that specified that non-negative values should be prefixed with a +.BR + . +After any prefix, there may be a positive number specifying +the percision of the output, optionally followed by either of +the letters +.BR a , +.BR e , +.BR f , +other +.B g +(other their synonymous uppercases), +at most once, with the same semantics as in +.BR printf (3). +.B f +is used if this letter is omitted. + +If ommited, +.B 25f +is used. This default is selected for ease of +interoperability with other software, however, +.B a +is recommeded to improve performance and remove +truncation error. +.TP .BR -d " "\fIdepth\fP If all three parameters are .RI 2^ depth -1, diff --git a/man/blind-to-text.1 b/man/blind-to-text.1 @@ -3,6 +3,8 @@ blind-to-text - Convert a video to text .SH SYNOPSIS .B blind-to-text +[-% +.IR format ] .SH DESCRIPTION .B blind-to-text reads a video from stdin and prints it @@ -36,6 +38,43 @@ line, after the head, where the second frame begins. The pixels are printed from left to right, from top to bottom, and from first frame to last frame. +.SH OPTIONS +.TP +.BR -% \ \fIformat\fP +Selects in what format parameters are printed. +.I format +may include the prefix +.B + +that specified that non-negative values should be prefixed with a +.BR + . +After any prefix, there may be a positive number specifying +the percision of the output, optionally followed by either of +the letters +.BR a , +.BR e , +.BR f , +other +.B g +(other their synonymous uppercases), +or if the input is integer typed, +.B d +or +.BR i , +at most once, with the same semantics as in +.BR printf (3). +.B f +is used if this letter is omitted. +The percision must be omitted the input is integer typed. + +If ommited, +.B 25f +or +.B i +is used. These defaults are selected for ease of +interoperability with other software, however, +.B a +is recommeded to improve performance and remove +truncation error. .SH SEE ALSO .BR blind (7), .BR blind-from-text (1), diff --git a/src/blind-colour-ciexyz.c b/src/blind-colour-ciexyz.c @@ -1,20 +1,34 @@ /* See LICENSE file for copyright and license details. */ #include "common.h" -USAGE("(X Y Z | Y)") +USAGE("[-% format] (X Y Z | Y)") int main(int argc, char *argv[]) { double X, Y, Z; + const char *fmt = NULL; - UNOFLAGS(0); + ARGBEGIN { + case '%': + fmt = UARGF(); + break; + default: + usage(); + } ARGEND; if (argc == 1) { + fmt = select_print_format("%! %! %!\n", DOUBLE, fmt); Y = etolf_arg("the Y value", argv[0]); X = Y * D65_XYZ_X; Z = Y * D65_XYZ_Z; - printf("%.50lf %.50lf %.50lf\n", X, Y, Z); + printf(fmt, X, Y, Z); + } else if (argc == 3 && fmt) { + fmt = select_print_format("%! %! %!\n", DOUBLE, fmt); + X = etolf_arg("the X value", argv[0]); + Y = etolf_arg("the Y value", argv[1]); + Z = etolf_arg("the Z value", argv[2]); + printf(fmt, X, Y, Z); } else if (argc == 3) { printf("%s %s %s\n", argv[0], argv[1], argv[2]); } else { diff --git a/src/blind-colour-srgb.c b/src/blind-colour-srgb.c @@ -1,7 +1,7 @@ /* See LICENSE file for copyright and license details. */ #include "common.h" -USAGE("[-d depth] [-l] red green blue") +USAGE("[-% format] [-d depth] [-l] red green blue") int main(int argc, char *argv[]) @@ -9,6 +9,7 @@ main(int argc, char *argv[]) unsigned long long int max; double red, green, blue, X, Y, Z; int depth = 8, linear = 0; + const char *fmt = NULL; ARGBEGIN { case 'd': @@ -17,6 +18,9 @@ main(int argc, char *argv[]) case 'l': linear = 1; break; + case '%': + fmt = UARGF(); + break; default: usage(); } ARGEND; @@ -24,6 +28,8 @@ main(int argc, char *argv[]) if (argc != 3) usage(); + fmt = select_print_format("%! %! %!\n", DOUBLE, fmt); + max = 1ULL << (depth - 1); max |= max - 1; red = etolf_arg("the red value", argv[0]) / (double)max; @@ -36,7 +42,7 @@ main(int argc, char *argv[]) } srgb_to_ciexyz(red, green, blue, &X, &Y, &Z); - printf("%.50lf %.50lf %.50lf\n", X, Y, Z); + printf(fmt, X, Y, Z); efshut(stdout, "<stdout>"); return 0; } diff --git a/src/blind-to-text.c b/src/blind-to-text.c @@ -3,7 +3,9 @@ #define INCLUDE_UINT16 #include "common.h" -USAGE("") +USAGE("[-% format]") + +const char *fmt = NULL; #define FILE "blind-to-text.c" #include "define-functions.h" @@ -14,10 +16,19 @@ main(int argc, char *argv[]) struct stream stream; void (*process)(struct stream *stream, size_t n); - UNOFLAGS(argc); + ARGBEGIN { + case '%': + fmt = UARGF(); + break; + default: + usage(); + } ARGEND; - eopen_stream(&stream, NULL); + if (argc) + usage(); + eopen_stream(&stream, NULL); + fmt = select_print_format("%! %! %! %!\n", stream.encoding, fmt); SELECT_PROCESS_FUNCTION(&stream); printf("%zu %zu %zu %s\n", stream.frames, stream.width, stream.height, stream.pixfmt); process_stream(&stream, process); @@ -32,12 +43,10 @@ PROCESS(struct stream *stream, size_t n) { size_t i; TYPE *p = (TYPE *)(stream->buf); - for (i = 0, n /= stream->chan_size; i < n; i++) -#ifdef INTEGER_TYPE - printf("%"PRINT_TYPE"%c", (PRINT_CAST)(p[i]), (i + 1) % stream->n_chan ? ' ' : '\n'); -#else - printf("%.25"PRINT_TYPE"%c", (PRINT_CAST)(p[i]), (i + 1) % stream->n_chan ? ' ' : '\n'); -#endif + for (i = 0, n /= stream->chan_size; i < n; i += 4) { + printf(fmt, (PRINT_CAST)(p[i + 0]), (PRINT_CAST)(p[i + 1]), + (PRINT_CAST)(p[i + 2]), (PRINT_CAST)(p[i + 3])); + } } #endif diff --git a/src/define-functions.h b/src/define-functions.h @@ -4,13 +4,11 @@ # define PROCESS process_lf # define TYPE double # define SCAN_TYPE "lf" -# define PRINT_TYPE "lf" # define PRINT_CAST double # include FILE # undef PROCESS # undef TYPE # undef SCAN_TYPE -# undef PRINT_TYPE # undef PRINT_CAST #endif @@ -18,13 +16,11 @@ # define PROCESS process_f # define TYPE float # define SCAN_TYPE "f" -# define PRINT_TYPE "lf" # define PRINT_CAST double # include FILE # undef PROCESS # undef TYPE # undef SCAN_TYPE -# undef PRINT_TYPE # undef PRINT_CAST #endif @@ -32,13 +28,11 @@ # define PROCESS process_llf # define TYPE long double # define SCAN_TYPE "Lf" -# define PRINT_TYPE "Lf" # define PRINT_CAST long double # include FILE # undef PROCESS # undef TYPE # undef SCAN_TYPE -# undef PRINT_TYPE # undef PRINT_CAST #endif @@ -46,14 +40,12 @@ # define PROCESS process_u8 # define TYPE uint8_t # define SCAN_TYPE SCNu8 -# define PRINT_TYPE "u" # define PRINT_CAST unsigned # define INTEGER_TYPE # include FILE # undef PROCESS # undef TYPE # undef SCAN_TYPE -# undef PRINT_TYPE # undef PRINT_CAST # undef INTEGER_TYPE #endif @@ -62,14 +54,12 @@ # define PROCESS process_u16 # define TYPE uint16_t # define SCAN_TYPE SCNu16 -# define PRINT_TYPE "u" # define PRINT_CAST unsigned # define INTEGER_TYPE # include FILE # undef PROCESS # undef TYPE # undef SCAN_TYPE -# undef PRINT_TYPE # undef PRINT_CAST # undef INTEGER_TYPE #endif @@ -78,14 +68,12 @@ # define PROCESS process_u32 # define TYPE uint32_t # define SCAN_TYPE SCNu32 -# define PRINT_TYPE PRIu32 # define PRINT_CAST uint32_t # define INTEGER_TYPE # include FILE # undef PROCESS # undef TYPE # undef SCAN_TYPE -# undef PRINT_TYPE # undef PRINT_CAST # undef INTEGER_TYPE #endif @@ -94,14 +82,12 @@ # define PROCESS process_u64 # define TYPE uint64_t # define SCAN_TYPE SCNu64 -# define PRINT_TYPE PRIu64 # define PRINT_CAST uint64_t # define INTEGER_TYPE # include FILE # undef PROCESS # undef TYPE # undef SCAN_TYPE -# undef PRINT_TYPE # undef PRINT_CAST # undef INTEGER_TYPE #endif diff --git a/src/stream.c b/src/stream.c @@ -369,6 +369,160 @@ get_pixel_format(const char *specified, const char *current) } +const char * +nselect_print_format(int status, const char *format, enum encoding encoding, const char *fmt) +{ + static char retbuf[512]; + int with_plus = 0, inttyped = -1; + const char *f = "", *orig = fmt; + char *proto = alloca((fmt ? strlen(fmt) : 0) + sizeof("%+#.50llx")), *p; + char *ret = retbuf; + size_t n, len; + + if (!orig) + goto check_done; + + for (; *fmt == '+'; fmt++) + with_plus = 1; + f = fmt + strspn(fmt, "0123456789"); + if (f[0] && f[1]) + enprintf(status, "invalid format: %s\n", orig); + + switch (*f) { + case '\0': + inttyped = -1; + break; + case 'd': case 'i': + inttyped = 1; + break; + case 'a': case 'A': + case 'e': case 'E': + case 'f': case 'F': + case 'g': case 'G': + inttyped = 0; + break; + default: + enprintf(status, "invalid format: %s\n", orig); + } + + switch (encoding) { + case FLOAT: + case DOUBLE: + case LONG_DOUBLE: + if (inttyped == 1) + enprintf(status, "invalid format `%s' is incompatible with the video format\n", orig); + inttyped = 0; + break; + case UINT8: + case UINT16: + case UINT32: + case UINT64: + if (*f != *fmt) + enprintf(status, "invalid format: %s\n", orig); + if (inttyped == 0) + enprintf(status, "invalid format `%s' is incompatible with the video format\n", orig); + inttyped = 1; + break; + default: + abort(); + } +check_done: + + p = proto; + *p++ = '%'; + if (with_plus) + *p++ = '+'; + + if (orig && *f != *fmt) { + *p++ = '.'; + p = stpncpy(p, fmt, (size_t)(f - fmt)); + } else if (orig && inttyped && *f != 'a' && *f != 'A') { + *p++ = '.'; + *p++ = '2'; + *p++ = '5'; + } + + inttyped = 1; + switch (encoding) { + case FLOAT: + inttyped = 0; + break; + case DOUBLE: + *p++ = 'l'; + inttyped = 0; + break; + case LONG_DOUBLE: + *p++ = 'L'; + inttyped = 0; + break; + case UINT8: + fmt = PRIi8; + break; + case UINT16: + fmt = PRIi16; + break; + case UINT32: + fmt = PRIi32; + break; + case UINT64: + fmt = PRIi64; + break; + default: + abort(); + } + + if (inttyped) + while (*fmt == 'l') + *p++ = *fmt++; + + switch (orig ? *f : '\0') { + case '\0': + *p++ = inttyped ? 'i' : 'f'; + break; + case 'd': case 'i': + *p++ = 'i'; + break; + case 'a': case 'A': + *p++ = 'a'; + break; + case 'e': case 'E': + *p++ = 'e'; + break; + case 'f': case 'F': + *p++ = 'f'; + break; + case 'g': case 'G': + *p++ = 'g'; + break; + } + + *p = '\0'; + + len = strlen(proto); + for (n = 1, f = format; *f; f++) { + if (f[0] == '%' && f[1] == '!') { + f++; + n += len; + } else { + n++; + } + } + + if (n > sizeof(retbuf)) + ret = enmalloc(status, n); + for (p = ret, f = format; *f; f++) { + if (f[0] == '%' && f[1] == '!') { + f++; + p = stpcpy(p, proto); + } else { + *p++ = *f; + } + } + + return ret; +} + + int enread_segment(int status, struct stream *stream, void *buf, size_t n) { diff --git a/src/stream.h b/src/stream.h @@ -43,6 +43,7 @@ #define echeck_dimensions(...) encheck_dimensions(1, __VA_ARGS__) #define echeck_dimensions_custom(...) encheck_dimensions_custom(1, __VA_ARGS__) #define echeck_compat(...) encheck_compat(1, __VA_ARGS__) +#define select_print_format(...) nselect_print_format(1, __VA_ARGS__) #define eread_segment(...) enread_segment(1, __VA_ARGS__) #define eread_frame(...) enread_frame(1, __VA_ARGS__) #define eread_row(...) enread_row(1, __VA_ARGS__) @@ -128,6 +129,7 @@ void eninf_check_fd(int status, int fd, const char *file); void encheck_dimensions(int status, const struct stream *stream, enum dimension dimensions, const char *prefix); void encheck_compat(int status, const struct stream *a, const struct stream *b); const char *get_pixel_format(const char *specified, const char *current); +const char *nselect_print_format(int status, const char *format, enum encoding encoding, const char *fmt); int enread_segment(int status, struct stream *stream, void *buf, size_t n); size_t ensend_frames(int status, struct stream *stream, int outfd, size_t frames, const char *outfname); size_t ensend_rows(int status, struct stream *stream, int outfd, size_t rows, const char *outfname); diff --git a/src/util.c b/src/util.c @@ -6,6 +6,7 @@ char *argv0; void weprintf(const char *fmt, ...) { + char end; va_list ap; va_start(ap, fmt); @@ -14,9 +15,12 @@ weprintf(const char *fmt, ...) vfprintf(stderr, fmt, ap); - if (fmt[0] && fmt[strlen(fmt)-1] == ':') { + end = *fmt ? strchr(fmt, '\0')[-1] : '\n'; + if (end == ':') { fputc(' ', stderr); perror(NULL); + } else if (end != '\n') { + fputc('\n', stderr); } va_end(ap);