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 }