| blind-apply-kernel.c - blind - suckless command-line video editing utility | |
| git clone git://git.suckless.org/blind | |
| Log | |
| Files | |
| Refs | |
| README | |
| LICENSE | |
| --- | |
| blind-apply-kernel.c (3898B) | |
| --- | |
| 1 /* See LICENSE file for copyright and license details. */ | |
| 2 #ifndef TYPE | |
| 3 #include "common.h" | |
| 4 | |
| 5 USAGE("[-apPxy] kernel-stream") | |
| 6 | |
| 7 static int no_alpha = 0; | |
| 8 static int dont_premultiply = 0; | |
| 9 static int per_pixel = 0; | |
| 10 static int wrap_x = 0; | |
| 11 static int wrap_y = 0; | |
| 12 static size_t kern_w; | |
| 13 static size_t kern_h; | |
| 14 | |
| 15 #define FILE "blind-apply-kernel.c" | |
| 16 #include "define-functions.h" | |
| 17 | |
| 18 int | |
| 19 main(int argc, char *argv[]) | |
| 20 { | |
| 21 struct stream colour, kernel; | |
| 22 void (*process)(struct stream *colour, struct stream *kernel); | |
| 23 size_t tmp; | |
| 24 | |
| 25 ARGBEGIN { | |
| 26 case 'a': | |
| 27 no_alpha = 1; | |
| 28 break; | |
| 29 case 'p': | |
| 30 per_pixel = 1; | |
| 31 break; | |
| 32 case 'P': | |
| 33 dont_premultiply = 1; | |
| 34 break; | |
| 35 case 'x': | |
| 36 wrap_x = 1; | |
| 37 break; | |
| 38 case 'y': | |
| 39 wrap_y = 1; | |
| 40 break; | |
| 41 default: | |
| 42 usage(); | |
| 43 } ARGEND; | |
| 44 | |
| 45 if (argc != 1) | |
| 46 usage(); | |
| 47 | |
| 48 eopen_stream(&colour, NULL); | |
| 49 eopen_stream(&kernel, argv[0]); | |
| 50 | |
| 51 SELECT_PROCESS_FUNCTION(&colour); | |
| 52 CHECK_ALPHA_CHAN(&colour); | |
| 53 CHECK_N_CHAN(&colour, 4, 4); | |
| 54 if (colour.encoding != kernel.encoding || colour.n_chan != kerne… | |
| 55 eprintf("videos use incompatible pixel formats"); | |
| 56 if (per_pixel && !(kernel.width % colour.width || kernel.height … | |
| 57 eprintf("-p is specified but the dimensions of kernel-st… | |
| 58 "are not multiples of the dimensions of stdin."); | |
| 59 | |
| 60 kern_w = per_pixel ? kernel.width / colour.width : kernel.widt… | |
| 61 kern_h = per_pixel ? kernel.height / colour.height : kernel.heig… | |
| 62 | |
| 63 tmp = kernel.height, kernel.height = kern_h; | |
| 64 echeck_dimensions(&colour, WIDTH | HEIGHT, NULL); | |
| 65 echeck_dimensions(&kernel, WIDTH | HEIGHT, NULL); | |
| 66 kernel.height = tmp; | |
| 67 | |
| 68 fprint_stream_head(stdout, &colour); | |
| 69 efflush(stdout, "<stdout>"); | |
| 70 process(&colour, &kernel); | |
| 71 return 0; | |
| 72 } | |
| 73 | |
| 74 #else | |
| 75 | |
| 76 static void | |
| 77 PROCESS(struct stream *colour, struct stream *kernel) | |
| 78 { | |
| 79 TYPE *out, *clr, *krn, *kern, *pix; | |
| 80 size_t i, x, y, n, x2, y2; | |
| 81 ssize_t cx, cy, xoff, yoff; | |
| 82 | |
| 83 out = emalloc(colour->frame_size); | |
| 84 clr = emalloc(colour->frame_size); | |
| 85 krn = emalloc2(kern_h, kernel->row_size); | |
| 86 | |
| 87 xoff = (ssize_t)(kern_w / 2); | |
| 88 yoff = (ssize_t)(kern_h / 2); | |
| 89 | |
| 90 n = colour->width * colour->height * colour->n_chan; | |
| 91 while (eread_frame(colour, clr)) { | |
| 92 /* premultiply */ | |
| 93 if (!no_alpha && !dont_premultiply) { | |
| 94 for (i = 0; i < n; i += 4) { | |
| 95 clr[i + 0] *= clr[i + 3]; | |
| 96 clr[i + 1] *= clr[i + 3]; | |
| 97 clr[i + 2] *= clr[i + 3]; | |
| 98 } | |
| 99 } | |
| 100 | |
| 101 /* apply kernel */ | |
| 102 memset(out, 0, colour->frame_size); | |
| 103 pix = out; | |
| 104 for (y = 0; y < colour->height; y++) { | |
| 105 if ((!y || per_pixel) && !eread_segment(kernel, … | |
| 106 goto done; | |
| 107 for (x = 0; x < colour->width; x++, pix += colou… | |
| 108 kern = per_pixel ? (krn + x * kern_w * k… | |
| 109 for (y2 = 0; y2 < kern_h; y2++, kern += … | |
| 110 cy = (ssize_t)(y + y2) - yoff; | |
| 111 if (cy < 0 || (size_t)cy >= colo… | |
| 112 if (!wrap_y) | |
| 113 continue; | |
| 114 cy %= (ssize_t)(colour->… | |
| 115 if (cy < 0) | |
| 116 cy += (ssize_t)(… | |
| 117 } | |
| 118 for (x2 = 0; x2 < kern_w; x2++) { | |
| 119 cx = (ssize_t)(x + x2) -… | |
| 120 if (cx < 0 || (size_t)cx… | |
| 121 if (!wrap_x) | |
| 122 continue; | |
| 123 cx %= (ssize_t)(… | |
| 124 if (cx < 0) | |
| 125 cx += (s… | |
| 126 } | |
| 127 for (i = 0; i < colour->… | |
| 128 pix[i] += kern[x… | |
| 129 clr[((… | |
| 130 } | |
| 131 } | |
| 132 } | |
| 133 } | |
| 134 | |
| 135 /* unpremultiply */ | |
| 136 if (!dont_premultiply) { | |
| 137 for (i = 0; i < n; i += 4) { | |
| 138 if (out[i + 3]) { | |
| 139 out[i + 0] /= out[i + 3]; | |
| 140 out[i + 1] /= out[i + 3]; | |
| 141 out[i + 2] /= out[i + 3]; | |
| 142 } | |
| 143 } | |
| 144 } | |
| 145 | |
| 146 /* ensure video is opaque if -a was used */ | |
| 147 if (no_alpha) | |
| 148 for (i = 0; i < n; i += 4) | |
| 149 out[i + 3] = 1; | |
| 150 | |
| 151 /* output video */ | |
| 152 ewriteall(STDOUT_FILENO, out, colour->frame_size, "<stdo… | |
| 153 } | |
| 154 done: | |
| 155 | |
| 156 free(out); | |
| 157 free(clr); | |
| 158 free(krn); | |
| 159 } | |
| 160 | |
| 161 #endif |