blind-find-rectangle.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-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.pixel_size, colour, stream.pixel_size))
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_height)
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", stream.pixfmt);
131 }
132
133 fshut(stdout, "<stdout>");
134 free(stack);
135 free(cache);
136 free(buf);
137 return 0;
138 }