blind-mosaic.c - blind - suckless command-line video editing utility | |
git clone git://git.suckless.org/blind | |
Log | |
Files | |
Refs | |
README | |
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,… | |
32 if (TEST(x, s)) SEARCH_FUNCTION(output, mbuf, mosaic, x,… | |
33 if (TEST(e, y)) SEARCH_FUNCTION(output, mbuf, mosaic, e,… | |
34 if (TEST(w, y)) SEARCH_FUNCTION(output, mbuf, mosaic, w,… | |
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… | |
56 SEARCH_FUNCTION(img, mos, mosaic… | |
57 mos[y * mosaic->… | |
58 mos[y * mosaic->… | |
59 mos[y * mosaic->… | |
60 mos[y * mosaic->… | |
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) … | |
76 avg[index][1] *= (cnt[index] - (TYPE)1) … | |
77 avg[index][2] *= (cnt[index] - (TYPE)1) … | |
78 avg[index][3] *= (cnt[index] - (TYPE)1) … | |
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 *mos… | |
110 size_t x, size_t y, size_t index, double ch1, double ch2, doub… | |
111 { | |
112 SEARCH(double, search_lf); | |
113 } | |
114 | |
115 static void | |
116 search_f(void *restrict output, void *restrict mbuf, struct stream *mosa… | |
117 size_t x, size_t y, size_t index, float ch1, float ch2, float c… | |
118 { | |
119 SEARCH(float, search_f); | |
120 } | |
121 | |
122 static void | |
123 process_lf(char *restrict output, char *restrict cbuf, char *restrict mb… | |
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 mbu… | |
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… | |
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, … | |
168 return 0; | |
169 } |