commit 38dfe2510b19c25901e9db08426319c21fabdf95
Author:     Mattias Andrée <[email protected]>
AuthorDate: Thu Jul 13 17:40:34 2017 +0200
Commit:     Mattias Andrée <[email protected]>
CommitDate: Thu Jul 13 17:43:17 2017 +0200

    Add blind-mosaic
    
    Signed-off-by: Mattias Andrée <[email protected]>

diff --git a/Makefile b/Makefile
index 4f2155a..91000b1 100644
--- a/Makefile
+++ b/Makefile
@@ -41,6 +41,7 @@ BIN =\
        blind-invert-luma\
        blind-linear-gradient\
        blind-make-kernel\
+       blind-mosaic\
        blind-next-frame\
        blind-norm\
        blind-quaternion-product\
diff --git a/README b/README
index 020fdb0..550212b 100644
--- a/README
+++ b/README
@@ -111,11 +111,14 @@ UTILITIES
        blind-invert-luma(1)
               Invert the luminosity of a video
 
+       blind-linear-gradient(1)
+              Generate a video with a linear gradient
+
        blind-make-kernel(1)
               Create a custom convolution matrix
 
-       blind-linear-gradient(1)
-              Generate a video with a linear gradient
+       blind-mosaic(1)
+              Redraw each frame in video as a mosaic
 
        blind-next-frame(1)
               Extracts the next frame from a video
diff --git a/man/blind-gauss-blur.1 b/man/blind-gauss-blur.1
index 99d0161..652a5e5 100644
--- a/man/blind-gauss-blur.1
+++ b/man/blind-gauss-blur.1
@@ -73,7 +73,7 @@ Use the Y value (multiplied by the alpha value) from
 .I sd-stream
 as the standard deviation all channels.
 .SH REQUIREMENTS
-.B blind-compress
+.B blind-gauss-blur
 requires enough free memory to load three full frames into
 memory. A frame requires 32 bytes per pixel it contains.
 .SH SEE ALSO
diff --git a/man/blind-hexagon-tessellation.1 b/man/blind-hexagon-tessellation.1
index 9d9bbbe..03cc9f7 100644
--- a/man/blind-hexagon-tessellation.1
+++ b/man/blind-hexagon-tessellation.1
@@ -28,7 +28,8 @@ for more information.
 .BR blind-triangle-tessellation (1),
 .BR blind-repeat-tessellation (1),
 .BR blind-get-colours (1),
-.BR blind-apply-palette (1)
+.BR blind-apply-palette (1),
+.BR blind-mosaic (1)
 .SH AUTHORS
 Mattias Andrée
 .RI < [email protected] >
diff --git a/man/blind-mosaic.1 b/man/blind-mosaic.1
new file mode 100644
index 0000000..4c68ad4
--- /dev/null
+++ b/man/blind-mosaic.1
@@ -0,0 +1,36 @@
+.TH BLIND-MOSAIC 1 blind
+.SH NAME
+blind-mosaic - Redraw each frame in video as a mosaic
+.SH SYNOPSIS
+.B blind-mosaic
+[-xy]
+.I mosaic-stream
+.SH DESCRIPTION
+.B blind-mosaic
+reads a video from stdin and a mosaic pattern video from
+.IR mosaic-stream .
+The video is printed to stdout, with each frame redraw in
+as a mosaic with the pattern found in the same frame in
+.IR mosaic-stream .
+.SH OPTIONS
+.TP
+.B -x
+When encountering the left or right edge of the video,
+wrap around to the opposite edge.
+.TP
+.B -y
+When encountering the upper or lower edge of the video,
+wrap around to the opposite edge.
+.SH REQUIREMENTS
+.B blind-mosaic
+requires enough free memory to load three full frames into
+memory. A frame requires 32 bytes per pixel it contains.
+.SH SEE ALSO
+.BR blind (7),
+.BR blind-hexagon-tessellation (1),
+.BR blind-rectangle-tessellation (1),
+.BR blind-triangle-tessellation (1),
+.BR blind-repeat-tessellation (1)
+.SH AUTHORS
+Mattias Andrée
+.RI < [email protected] >
diff --git a/man/blind-rectangle-tessellation.1 
b/man/blind-rectangle-tessellation.1
index 4bd4959..09a8d79 100644
--- a/man/blind-rectangle-tessellation.1
+++ b/man/blind-rectangle-tessellation.1
@@ -30,7 +30,8 @@ for more information.
 .BR blind-triangle-tessellation (1),
 .BR blind-repeat-tessellation (1),
 .BR blind-get-colours (1),
-.BR blind-apply-palette (1)
+.BR blind-apply-palette (1),
+.BR blind-mosaic (1)
 .SH AUTHORS
 Mattias Andrée
 .RI < [email protected] >
diff --git a/man/blind-repeat-tessellation.1 b/man/blind-repeat-tessellation.1
index ce027b1..f5ebe18 100644
--- a/man/blind-repeat-tessellation.1
+++ b/man/blind-repeat-tessellation.1
@@ -33,7 +33,8 @@ bytes per pixel it contains.
 .BR blind-apply-palette (1),
 .BR blind-hexagon-tessellation (1),
 .BR blind-rectangle-tessellation (1),
-.BR blind-triangle-tessellation (1)
+.BR blind-triangle-tessellation (1),
+.BR blind-mosaic (1)
 .SH AUTHORS
 Mattias Andrée
 .RI < [email protected] >
diff --git a/man/blind-triangle-tessellation.1 
b/man/blind-triangle-tessellation.1
index d8bbea6..e5148ff 100644
--- a/man/blind-triangle-tessellation.1
+++ b/man/blind-triangle-tessellation.1
@@ -33,7 +33,8 @@ for more information.
 .BR blind-triangle-tessellation (1),
 .BR blind-repeat-tessellation (1),
 .BR blind-get-colours (1),
-.BR blind-apply-palette (1)
+.BR blind-apply-palette (1),
+.BR blind-mosaic (1)
 .SH AUTHORS
 Mattias Andrée
 .RI < [email protected] >
diff --git a/man/blind.7 b/man/blind.7
index b45d00c..2623de9 100644
--- a/man/blind.7
+++ b/man/blind.7
@@ -133,6 +133,9 @@ Generate a video with a linear gradient
 .BR blind-make-kernel (1)
 Create a custom convolution matrix
 .TP
+.BR blind-mosaic (1)
+Redraw each frame in video as a mosaic
+.TP
 .BR blind-next-frame (1)
 Extracts the next frame from a video
 .TP
diff --git a/src/blind-mosaic.c b/src/blind-mosaic.c
new file mode 100644
index 0000000..226bcf5
--- /dev/null
+++ b/src/blind-mosaic.c
@@ -0,0 +1,174 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+
+USAGE("[-xy] mosaic-stream")
+
+static int tiled_x = 0;
+static int tiled_y = 0;
+
+#define TEST(X, Y)\
+       (!*(size_t *)(img + (Y) * mosaic->width + (X)) &&\
+        mos[(Y) * mosaic->width + (X)][0] == ch1 &&\
+        mos[(Y) * mosaic->width + (X)][1] == ch2 &&\
+        mos[(Y) * mosaic->width + (X)][2] == ch3 &&\
+        mos[(Y) * mosaic->width + (X)][3] == ch4)
+
+#define SEARCH(TYPE, SEARCH_FUNCTION)\
+       do {\
+               typedef TYPE pixel_t[4];\
+               \
+               pixel_t *restrict mos = (pixel_t *)mbuf;\
+               pixel_t *restrict img = (pixel_t *)output;\
+               size_t n, s, e, w;\
+               \
+               *(size_t *)(img + y * mosaic->width + x) = index;\
+               \
+               n = y ? y - 1 : tiled_y ? mosaic->height - 1 : y;\
+               s = y <= mosaic->height ? y + 1 : tiled_y ? 0 : y;\
+               w = x ? x - 1 : tiled_x ? mosaic->width - 1 : x;\
+               e = x <= mosaic->width ? x + 1 : tiled_x ? 0 : x;\
+               \
+               if (TEST(x, n)) SEARCH_FUNCTION(output, mbuf, mosaic, x, n, 
index, ch1, ch2, ch3, ch4);\
+               if (TEST(x, s)) SEARCH_FUNCTION(output, mbuf, mosaic, x, s, 
index, ch1, ch2, ch3, ch4);\
+               if (TEST(e, y)) SEARCH_FUNCTION(output, mbuf, mosaic, e, y, 
index, ch1, ch2, ch3, ch4);\
+               if (TEST(w, y)) SEARCH_FUNCTION(output, mbuf, mosaic, w, y, 
index, ch1, ch2, ch3, ch4);\
+       } while (0)\
+
+#define PROCESS(TYPE, SEARCH_FUNCTION)\
+       do {\
+               typedef TYPE pixel_t[4];\
+               \
+               static pixel_t *avg = NULL;\
+               static TYPE *cnt = NULL;\
+               static size_t size = 0;\
+               \
+               pixel_t *restrict clr = (pixel_t *)cbuf;\
+               pixel_t *restrict mos = (pixel_t *)mbuf;\
+               pixel_t *img = (pixel_t *)output;\
+               size_t index = 0;\
+               size_t x, y, i;\
+               \
+               memset(img, 0, mosaic->frame_size);\
+               \
+               for (y = 0; y < mosaic->height; y++)\
+                       for (x = 0; x < mosaic->width; x++)\
+                               if (!*(size_t *)(img + y * mosaic->width + x))\
+                                       SEARCH_FUNCTION(img, mos, mosaic, x, y, 
++index,\
+                                                       mos[y * mosaic->width + 
x][0],\
+                                                       mos[y * mosaic->width + 
x][1],\
+                                                       mos[y * mosaic->width + 
x][2],\
+                                                       mos[y * mosaic->width + 
x][3]);\
+               \
+               if (index > size) {\
+                       size = index;\
+                       avg = erealloc2(avg, size, sizeof(*avg));\
+                       cnt = erealloc2(cnt, size, sizeof(*cnt));\
+               }\
+               memset(avg, 0, index * sizeof(*avg));\
+               memset(cnt, 0, index * sizeof(*cnt));\
+               \
+               for (y = 0; y < mosaic->height; y++) {\
+                       for (x = 0; x < mosaic->width; x++) {\
+                               i = y * mosaic->width + x;\
+                               index = *(size_t *)(img + i) - 1;\
+                               cnt[index] += (TYPE)1;\
+                               avg[index][0] *= (cnt[index] - (TYPE)1) / 
cnt[index];\
+                               avg[index][1] *= (cnt[index] - (TYPE)1) / 
cnt[index];\
+                               avg[index][2] *= (cnt[index] - (TYPE)1) / 
cnt[index];\
+                               avg[index][3] *= (cnt[index] - (TYPE)1) / 
cnt[index];\
+                               avg[index][3] += clr[i][3] /= cnt[index];\
+                               avg[index][0] += clr[i][0] *= clr[i][3];\
+                               avg[index][1] += clr[i][1] *= clr[i][3];\
+                               avg[index][2] += clr[i][2] *= clr[i][3];\
+                       }\
+               }\
+               \
+               for (i = 0; i < index; i++) {\
+                       if (avg[i][3]) {\
+                               avg[i][0] /= avg[i][3];\
+                               avg[i][1] /= avg[i][3];\
+                               avg[i][2] /= avg[i][3];\
+                       }\
+               }\
+               \
+               for (y = 0; y < mosaic->height; y++) {\
+                       for (x = 0; x < mosaic->width; x++) {\
+                               i = y * mosaic->width + x;\
+                               index = *(size_t *)(img + i) - 1;\
+                               img[i][0] = avg[index][0];\
+                               img[i][1] = avg[index][1];\
+                               img[i][2] = avg[index][2];\
+                               img[i][3] = avg[index][3];\
+                       }\
+               }\
+               \
+               (void) colour;\
+       } while (0)
+
+static void
+search_lf(void *restrict output, void *restrict mbuf, struct stream *mosaic,
+         size_t x, size_t y, size_t index, double ch1, double ch2, double ch3, 
double ch4)
+{
+       SEARCH(double, search_lf);
+}
+
+static void
+search_f(void *restrict output, void *restrict mbuf, struct stream *mosaic,
+        size_t x, size_t y, size_t index, double ch1, double ch2, double ch3, 
double ch4)
+{
+       SEARCH(float, search_f);
+}
+
+static void
+process_lf(char *restrict output, char *restrict cbuf, char *restrict mbuf,
+          struct stream *colour, struct stream *mosaic)
+{
+       PROCESS(double, search_lf);
+}
+
+static void
+process_f(char *restrict output, char *restrict cbuf, char *restrict mbuf,
+         struct stream *colour, struct stream *mosaic)
+{
+       PROCESS(float, search_f);
+}
+
+int
+main(int argc, char *argv[])
+{
+       struct stream colour, mosaic;
+       void (*process)(char *restrict output, char *restrict cbuf, char 
*restrict mbuf,
+                       struct stream *colour, struct stream *mosaic);
+
+       ARGBEGIN {
+       case 'x':
+               tiled_x = 1;
+               break;
+       case 'y':
+               tiled_y = 1;
+               break;
+       default:
+               usage();
+       } ARGEND;
+
+       if (argc != 1)
+               usage();
+
+       eopen_stream(&colour, NULL);
+       eopen_stream(&mosaic, argv[0]);
+
+       if (!strcmp(colour.pixfmt, "xyza"))
+               process = process_lf;
+       else if (!strcmp(colour.pixfmt, "xyza f"))
+               process = process_f;
+       else
+               eprintf("pixel format %s is not supported, try xyza\n", 
colour.pixfmt);
+
+       echeck_compat(&colour, &mosaic);
+
+       fprint_stream_head(stdout, &colour);
+       efflush(stdout, "<stdout>");
+       process_each_frame_two_streams(&colour, &mosaic, STDOUT_FILENO, 
"<stdout>", process);
+
+       return 0;
+}

Reply via email to