blind-mosaic.c - blind - suckless command-line video editing utility
(HTM) git clone git://git.suckless.org/blind
(DIR) Log
(DIR) Files
(DIR) Refs
(DIR) README
(DIR) LICENSE
---
blind-mosaic.c (4819B)
---
1 /* See LICENSE file for copyright and license details. */
2 #include "common.h"
3
4 USAGE("[-xy] mosaic-stream")
5
6 static int tiled_x = 0;
7 static int tiled_y = 0;
8
9 #define TEST(X, Y)\
10 (!*(size_t *)(img + (Y) * mosaic->width + (X)) &&\
11 mos[(Y) * mosaic->width + (X)][0] == ch1 &&\
12 mos[(Y) * mosaic->width + (X)][1] == ch2 &&\
13 mos[(Y) * mosaic->width + (X)][2] == ch3 &&\
14 mos[(Y) * mosaic->width + (X)][3] == ch4)
15
16 #define SEARCH(TYPE, SEARCH_FUNCTION)\
17 do {\
18 typedef TYPE pixel_t[4];\
19 \
20 pixel_t *restrict mos = (pixel_t *)mbuf;\
21 pixel_t *restrict img = (pixel_t *)output;\
22 size_t n, s, e, w;\
23 \
24 *(size_t *)(img + y * mosaic->width + x) = index;\
25 \
26 n = y ? y - 1 : tiled_y ? mosaic->height - 1 : y;\
27 s = y <= mosaic->height ? y + 1 : tiled_y ? 0 : y;\
28 w = x ? x - 1 : tiled_x ? mosaic->width - 1 : x;\
29 e = x <= mosaic->width ? x + 1 : tiled_x ? 0 : x;\
30 \
31 if (TEST(x, n)) SEARCH_FUNCTION(output, mbuf, mosaic, x, n, index, ch1, ch2, ch3, ch4);\
32 if (TEST(x, s)) SEARCH_FUNCTION(output, mbuf, mosaic, x, s, index, ch1, ch2, ch3, ch4);\
33 if (TEST(e, y)) SEARCH_FUNCTION(output, mbuf, mosaic, e, y, index, ch1, ch2, ch3, ch4);\
34 if (TEST(w, y)) SEARCH_FUNCTION(output, mbuf, mosaic, w, y, index, ch1, ch2, ch3, ch4);\
35 } while (0)\
36
37 #define PROCESS(TYPE, SEARCH_FUNCTION)\
38 do {\
39 typedef TYPE pixel_t[4];\
40 \
41 static pixel_t *avg = NULL;\
42 static TYPE *cnt = NULL;\
43 static size_t size = 0;\
44 \
45 pixel_t *restrict clr = (pixel_t *)cbuf;\
46 pixel_t *restrict mos = (pixel_t *)mbuf;\
47 pixel_t *img = (pixel_t *)output;\
48 size_t index = 0;\
49 size_t x, y, i;\
50 \
51 memset(img, 0, mosaic->frame_size);\
52 \
53 for (y = 0; y < mosaic->height; y++)\
54 for (x = 0; x < mosaic->width; x++)\
55 if (!*(size_t *)(img + y * mosaic->width + x))\
56 SEARCH_FUNCTION(img, mos, mosaic, x, y, ++index,\
57 mos[y * mosaic->width + x][0],\
58 mos[y * mosaic->width + x][1],\
59 mos[y * mosaic->width + x][2],\
60 mos[y * mosaic->width + x][3]);\
61 \
62 if (index > size) {\
63 size = index;\
64 avg = erealloc2(avg, size, sizeof(*avg));\
65 cnt = erealloc2(cnt, size, sizeof(*cnt));\
66 }\
67 memset(avg, 0, index * sizeof(*avg));\
68 memset(cnt, 0, index * sizeof(*cnt));\
69 \
70 for (y = 0; y < mosaic->height; y++) {\
71 for (x = 0; x < mosaic->width; x++) {\
72 i = y * mosaic->width + x;\
73 index = *(size_t *)(img + i) - 1;\
74 cnt[index] += (TYPE)1;\
75 avg[index][0] *= (cnt[index] - (TYPE)1) / cnt[index];\
76 avg[index][1] *= (cnt[index] - (TYPE)1) / cnt[index];\
77 avg[index][2] *= (cnt[index] - (TYPE)1) / cnt[index];\
78 avg[index][3] *= (cnt[index] - (TYPE)1) / cnt[index];\
79 avg[index][3] += clr[i][3] /= cnt[index];\
80 avg[index][0] += clr[i][0] *= clr[i][3];\
81 avg[index][1] += clr[i][1] *= clr[i][3];\
82 avg[index][2] += clr[i][2] *= clr[i][3];\
83 }\
84 }\
85 \
86 for (i = 0; i < index; i++) {\
87 if (avg[i][3]) {\
88 avg[i][0] /= avg[i][3];\
89 avg[i][1] /= avg[i][3];\
90 avg[i][2] /= avg[i][3];\
91 }\
92 }\
93 \
94 for (y = 0; y < mosaic->height; y++) {\
95 for (x = 0; x < mosaic->width; x++) {\
96 i = y * mosaic->width + x;\
97 index = *(size_t *)(img + i) - 1;\
98 img[i][0] = avg[index][0];\
99 img[i][1] = avg[index][1];\
100 img[i][2] = avg[index][2];\
101 img[i][3] = avg[index][3];\
102 }\
103 }\
104 \
105 (void) colour;\
106 } while (0)
107
108 static void
109 search_lf(void *restrict output, void *restrict mbuf, struct stream *mosaic,
110 size_t x, size_t y, size_t index, double ch1, double ch2, double ch3, double ch4)
111 {
112 SEARCH(double, search_lf);
113 }
114
115 static void
116 search_f(void *restrict output, void *restrict mbuf, struct stream *mosaic,
117 size_t x, size_t y, size_t index, float ch1, float ch2, float ch3, float ch4)
118 {
119 SEARCH(float, search_f);
120 }
121
122 static void
123 process_lf(char *restrict output, char *restrict cbuf, char *restrict mbuf,
124 struct stream *colour, struct stream *mosaic)
125 {
126 PROCESS(double, search_lf);
127 }
128
129 static void
130 process_f(char *restrict output, char *restrict cbuf, char *restrict mbuf,
131 struct stream *colour, struct stream *mosaic)
132 {
133 PROCESS(float, search_f);
134 }
135
136 int
137 main(int argc, char *argv[])
138 {
139 struct stream colour, mosaic;
140 void (*process)(char *restrict output, char *restrict cbuf, char *restrict mbuf,
141 struct stream *colour, struct stream *mosaic);
142
143 ARGBEGIN {
144 case 'x':
145 tiled_x = 1;
146 break;
147 case 'y':
148 tiled_y = 1;
149 break;
150 default:
151 usage();
152 } ARGEND;
153
154 if (argc != 1)
155 usage();
156
157 eopen_stream(&colour, NULL);
158 eopen_stream(&mosaic, argv[0]);
159
160 SELECT_PROCESS_FUNCTION(&colour);
161 CHECK_ALPHA(&colour);
162 CHECK_N_CHAN(&colour, 4, 4);
163
164 echeck_compat(&colour, &mosaic);
165 fprint_stream_head(stdout, &colour);
166 efflush(stdout, "<stdout>");
167 process_each_frame_two_streams(&colour, &mosaic, STDOUT_FILENO, "<stdout>", process);
168 return 0;
169 }