diff options
Diffstat (limited to 'src/blind-make-kernel.c')
| -rw-r--r-- | src/blind-make-kernel.c | 156 |
1 files changed, 156 insertions, 0 deletions
diff --git a/src/blind-make-kernel.c b/src/blind-make-kernel.c new file mode 100644 index 0000000..67f8691 --- /dev/null +++ b/src/blind-make-kernel.c @@ -0,0 +1,156 @@ +/* See LICENSE file for copyright and license details. */ +#include "stream.h" +#include "util.h" + +#include <ctype.h> +#include <string.h> + +USAGE("[-d denominator] ... [-nxyza] [-- value ...] ...") + +static void +new_row(double **kernel, size_t *col, size_t *rows, size_t *cols) +{ + if (!*col) + return; + if (*rows && *col != *cols) + eprintf("the rows in the matrix do not have the same number of columns\n"); + *kernel = erealloc3(*kernel, 1 + ++*rows, *cols = *col, sizeof(**kernel)); + *col = 0; +} + +static void +new_col(char *arg, double **kernel, size_t *col, size_t *rows, size_t *cols) +{ + if (*rows && *col >= *cols) + eprintf("the rows in the matrix do not have the same number of columns\n"); + if (!*rows) + *kernel = erealloc2(*kernel, *col + 1, sizeof(**kernel)); + if (tolf(arg, &(*kernel)[*rows * *cols + (*col)++])) + eprintf("matrix cell values must be floating-point values\n"); +} + +static void +finalise(double **kernel, size_t col, size_t *rows, size_t *cols) +{ + if (col) + new_row(kernel, &col, rows, cols); + if (!*rows) + eprintf("the matrix cannot be null-sized\n"); +} + +static double * +read_matrix_cmdline(char *args[], size_t *rows, size_t *cols) +{ + size_t col = 0; + double *kernel = NULL; + *rows = *cols = 0; + for (; *args; args++) { + if (!strcmp(*args, "--")) + new_row(&kernel, &col, rows, cols); + else + new_col(*args, &kernel, &col, rows, cols); + } + finalise(&kernel, col, rows, cols); + return kernel; +} + +static double * +read_matrix_stdin(size_t *rows, size_t *cols) +{ + char *line = NULL, *p, *q; + size_t size = 0, col; + double *kernel = NULL; + ssize_t len; + *rows = *cols = 0; + while ((len = getline(&line, &size, stdin)) >= 0) { + col = 0; + for (p = line;; p = q) { + while (*p && isspace(*p)) p++; + if (!*(q = p)) + break; + while (*q && !isspace(*q)) q++; + *q++ = '\0'; + new_col(p, &kernel, &col, rows, cols); + } + new_row(&kernel, &col, rows, cols); + } + free(line); + if (ferror(stdout)) + eprintf("getline:"); + finalise(&kernel, col, rows, cols); + return kernel; +} + +int +main(int argc, char *argv[]) +{ + int normalise = 0; + double denominator = 1; + int null_x = 1, null_y = 1, null_z = 1, null_a = 1; + size_t rows, cols, y, x, n; + double *kernel, *kern, sum = 0, value; + double *buffer, *buf; + + ARGBEGIN { + case 'd': + denominator *= etolf_flag('d', UARGF()); + break; + case 'n': + normalise = 1; + break; + case 'x': + null_x = 0; + break; + case 'y': + null_y = 0; + break; + case 'z': + null_z = 0; + break; + case 'a': + null_a = 0; + break; + default: + usage(); + } ARGEND; + + if (null_x && null_y && null_z && null_a) + null_x = null_y = null_z = null_a = 0; + + if (argc) + kernel = read_matrix_cmdline(argv, &rows, &cols); + else + kernel = read_matrix_stdin(&rows, &cols); + + FPRINTF_HEAD(stdout, (size_t)1, cols, rows, "xyza"); + efflush(stdout, "<stdout>"); + + buffer = emalloc2(cols, 4 * sizeof(double)); + n = cols * 4 * sizeof(double); + + if (normalise) { + kern = kernel; + for (y = 0; y < rows; y++) + for (x = 0; x < cols; x++) + sum += *kern++; + denominator *= sum; + } + + kern = kernel; + for (y = 0; y < rows; y++) { + buf = buffer; + for (x = 0; x < cols; x++) { + value = *kern++ / denominator; + buf[0] = null_x ? 0.0 : value; + buf[1] = null_y ? 0.0 : value; + buf[2] = null_z ? 0.0 : value; + buf[3] = null_a ? 0.0 : value; + buf += 4; + } + ewriteall(STDOUT_FILENO, buffer, n, "<stdout>"); + } + + free(kernel); + free(buffer); + return 0; +} |
