aboutsummaryrefslogtreecommitdiffstats
path: root/src/blind-to-image.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/blind-to-image.c')
-rw-r--r--src/blind-to-image.c150
1 files changed, 150 insertions, 0 deletions
diff --git a/src/blind-to-image.c b/src/blind-to-image.c
new file mode 100644
index 0000000..4b3d20c
--- /dev/null
+++ b/src/blind-to-image.c
@@ -0,0 +1,150 @@
+/* See LICENSE file for copyright and license details. */
+#include "stream.h"
+#include "util.h"
+
+#include <arpa/inet.h>
+#include <inttypes.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+USAGE("[-d depth | -f]")
+
+static int luma_warning_triggered = 0;
+static int gamut_warning_triggered = 0;
+static int alpha_warning_triggered = 0;
+
+static void
+write_pixel(double R, double G, double B, double A, int bytes, unsigned long long int max)
+{
+ unsigned long long int colours[4];
+ unsigned char buf[4 * 8];
+ int i, j, k, bm = bytes - 1;
+
+ if (R < 0 || G < 0 || B < 0 || R > 1 || G > 1 || B > 1) {
+ if (gamut_warning_triggered) {
+ gamut_warning_triggered = 1;
+ weprintf("warning: out-of-gamut colour detected\n");
+ }
+ ; /* TODO gamut */
+ R = R < 0 ? 0 : R > 1 ? 1 : R;
+ G = G < 0 ? 0 : G > 1 ? 1 : G;
+ B = B < 0 ? 0 : B > 1 ? 1 : B;
+ }
+
+ if (A < 0 || A > 1) {
+ if (alpha_warning_triggered) {
+ alpha_warning_triggered = 1;
+ weprintf("warning: alpha values truncated\n");
+ }
+ A = A < 0 ? 0 : 1;
+ }
+
+ colours[0] = srgb_encode(R) * max + 0.5;
+ colours[1] = srgb_encode(G) * max + 0.5;
+ colours[2] = srgb_encode(B) * max + 0.5;
+ colours[3] = A * max + 0.5;
+
+ for (i = k = 0; i < 4; i++) {
+ for (j = 0; j < bytes; j++, k++) {
+ buf[k + bm - j] = (unsigned char)(colours[j]);
+ colours[j] >>= 8;
+ }
+ }
+
+ ewriteall(STDOUT_FILENO, buf, (size_t)bytes * 4, "<stdout>");
+}
+
+static void
+process_xyza(struct stream *stream, size_t n, int bytes, unsigned long long int max)
+{
+ size_t i;
+ double X, Y, Z, A, R, G, B;
+ for (i = 0; i < n; i += stream->pixel_size) {
+ X = ((double *)(stream->buf + i))[0];
+ Y = ((double *)(stream->buf + i))[1];
+ Z = ((double *)(stream->buf + i))[2];
+ A = ((double *)(stream->buf + i))[3];
+
+ if (Y < 0 || Y > 1) {
+ if (luma_warning_triggered) {
+ luma_warning_triggered = 1;
+ weprintf("warning: %s colour detected\n",
+ Y < 0 ? "subblack" : "superwhite");
+ }
+ }
+
+ srgb_to_ciexyz(X, Y, Z, &R, &G, &B);
+ write_pixel(R, G, B, A, bytes, max);
+ }
+}
+
+int
+main(int argc, char *argv[])
+{
+ struct stream stream;
+ int depth = 16, bytes, farbfeld = 0;
+ unsigned long long int max;
+ size_t n;
+ void (*process)(struct stream *stream, size_t n, int bytes, unsigned long long int max);
+
+ ARGBEGIN {
+ case 'd':
+ depth = etoi_flag('d', EARG(), 1, 64);
+ break;
+ case 'f':
+ farbfeld = 1;
+ break;
+ default:
+ usage();
+ } ARGEND;
+
+ if (argc || (farbfeld && depth != 16))
+ usage();
+
+ stream.fd = STDIN_FILENO;
+ stream.file = "<stdin.h>";
+ einit_stream(&stream);
+
+ max = 1ULL << (depth - 1);
+ max |= max - 1;
+ for (bytes = 1; bytes * 8 < depth; bytes++);
+
+ if (!strcmp(stream.pixfmt, "xyza"))
+ process = process_xyza;
+ else
+ eprintf("pixel format %s is not supported, try xyza\n", stream.pixfmt);
+
+ if (farbfeld) {
+ uint32_t width = stream.width, height = stream.height;
+ if (stream.width > UINT32_MAX)
+ eprintf("%s: frame is too wide\n", stream.file);
+ if (stream.height > UINT32_MAX)
+ eprintf("%s: frame is too tall\n", stream.file);
+ printf("farbfeld");
+ memmove(stream.buf + 8, stream.buf, stream.ptr);
+ stream.ptr += 8;
+ width = htonl(width);
+ height = htonl(height);
+ memcpy(stream.buf + 0, &width, 4);
+ memcpy(stream.buf + 4, &height, 4);
+ } else {
+ printf("P7\n"
+ "WIDTH %zu\n"
+ "HEIGHT %zu\n"
+ "DEPTH 4\n" /* Depth actually means channels */
+ "MAXVAL %llu\n"
+ "TUPLTYPE RGB_ALPHA\n"
+ "ENDHDR\n", stream.width, stream.height, max);
+ }
+ efflush(stdout, "<stdout>");
+
+ do {
+ n = stream.ptr - (stream.ptr % stream.pixel_size);
+ process(&stream, n, bytes, max);
+ memmove(stream.buf, stream.buf + n, stream.ptr -= n);
+ } while (eread_stream(&stream, SIZE_MAX));
+
+ return 0;
+}