aboutsummaryrefslogtreecommitdiffstats
path: root/src/blind-make-kernel.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/blind-make-kernel.c156
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;
+}