blind-find-rectangle.c - blind - suckless command-line video editing utility | |
git clone git://git.suckless.org/blind | |
Log | |
Files | |
Refs | |
README | |
LICENSE | |
--- | |
blind-find-rectangle.c (3127B) | |
--- | |
1 /* See LICENSE file for copyright and license details. */ | |
2 #include "common.h" | |
3 | |
4 USAGE("[-a min-area] [-h min-height] [-w min-width] X Y Z [alpha]") | |
5 | |
6 struct pair { | |
7 size_t x; | |
8 size_t w; | |
9 }; | |
10 | |
11 static struct stream stream; | |
12 static size_t min_width = 1; | |
13 static size_t min_height = 1; | |
14 static size_t min_area = 1; | |
15 static struct pair *stack = NULL; | |
16 static size_t *cache = NULL; | |
17 static char *buf = NULL; | |
18 | |
19 static void | |
20 process(const void *colour) | |
21 { | |
22 size_t y, x, x0, w, w0, h, top, area; | |
23 size_t best_area, x1, x2, y1, y2; | |
24 for (;;) { | |
25 top = x1 = x2 = y1 = y2 = best_area = 0; | |
26 memset(cache, 0, (stream.width + 1) * sizeof(*cache)); | |
27 for (y = 0; eread_row(&stream, buf); y++) { | |
28 w = 0; | |
29 for (x = 0; x <= stream.width; x++) { | |
30 if (x != stream.width) { | |
31 if (!memcmp(buf + x * stream.pix… | |
32 cache[x] += 1; | |
33 else | |
34 cache[x] = 0; | |
35 } | |
36 if (cache[x] > w) { | |
37 stack[top].x = x; | |
38 stack[top++].w = w; | |
39 w = cache[x]; | |
40 } else if (cache[x] < w) { | |
41 do { | |
42 x0 = stack[--top].x; | |
43 w0 = stack[top].w; | |
44 area = w * (x - x0); | |
45 if (area > best_area) { | |
46 best_area = area; | |
47 x1 = x0; | |
48 x2 = x - 1; | |
49 y1 = y - w + 1; | |
50 y2 = y; | |
51 } | |
52 w = w0; | |
53 } while (cache[x] < w); | |
54 if ((w = cache[x])) { | |
55 stack[top].x = x0; | |
56 stack[top++].w = w0; | |
57 } | |
58 } | |
59 } | |
60 fprintf(stderr, "%zu\n", y); | |
61 } | |
62 if (!y) | |
63 break; | |
64 w = x2 - x1 + 1; | |
65 h = y2 - y1 + 1; | |
66 if (best_area < min_area || w < min_width || h < min_hei… | |
67 printf("0 0 0 0\n"); | |
68 else | |
69 printf("%zu %zu %zu %zu\n", x1, y1, w, h); | |
70 } | |
71 } | |
72 | |
73 int | |
74 main(int argc, char *argv[]) | |
75 { | |
76 double colour_lf[4]; | |
77 float colour_f[4]; | |
78 double X, Y, Z, alpha = 1; | |
79 | |
80 ARGBEGIN { | |
81 case 'a': | |
82 min_area = etozu_flag('a', UARGF(), 1, SIZE_MAX); | |
83 break; | |
84 case 'h': | |
85 min_height = etozu_flag('h', UARGF(), 1, SIZE_MAX); | |
86 break; | |
87 case 'w': | |
88 min_width = etozu_flag('w', UARGF(), 1, SIZE_MAX); | |
89 break; | |
90 default: | |
91 usage(); | |
92 } ARGEND; | |
93 | |
94 if (argc != 3 && argc != 4) | |
95 usage(); | |
96 | |
97 X = etolf_arg("the X value", argv[0]); | |
98 Y = etolf_arg("the Y value", argv[1]); | |
99 Z = etolf_arg("the Z value", argv[2]); | |
100 if (argc > 3) | |
101 alpha = etolf_arg("the alpha value", argv[3]); | |
102 | |
103 eopen_stream(&stream, NULL); | |
104 echeck_dimensions(&stream, WIDTH, NULL); | |
105 if (stream.width == SIZE_MAX) | |
106 eprintf("video is too wide\n"); | |
107 if (stream.width > SIZE_MAX / stream.height) | |
108 eprintf("video is too large\n"); | |
109 | |
110 stack = emalloc2(stream.width + 1, sizeof(*stack)); | |
111 cache = emalloc2(stream.width + 1, sizeof(*cache)); | |
112 buf = emalloc(stream.row_size); | |
113 | |
114 if (argc > 3) | |
115 CHECK_ALPHA(&stream); | |
116 CHECK_N_CHAN(&stream, 1, 3 + !!stream.alpha); | |
117 if (stream.encoding == DOUBLE) { | |
118 colour_lf[0] = X; | |
119 colour_lf[1] = Y; | |
120 colour_lf[2] = Z; | |
121 colour_lf[3] = alpha; | |
122 process(colour_lf); | |
123 } else if (stream.encoding == FLOAT) { | |
124 colour_f[0] = (float)X; | |
125 colour_f[1] = (float)Y; | |
126 colour_f[2] = (float)Z; | |
127 colour_f[3] = (float)alpha; | |
128 process(colour_f); | |
129 } else { | |
130 eprintf("pixel format %s is not supported, try xyza\n", … | |
131 } | |
132 | |
133 fshut(stdout, "<stdout>"); | |
134 free(stack); | |
135 free(cache); | |
136 free(buf); | |
137 return 0; | |
138 } |