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 }