blind-translate.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-translate.c (4130B)
---
1 /* See LICENSE file for copyright and license details. */
2 #include "common.h"
3
4 USAGE("[-wp] translation-stream")
5
6 static int invtrans = 0;
7 static char zeroes[BUFSIZ];
8
9 static void*
10 next_pixel(struct stream *stream, size_t *ptr)
11 {
12 void *ret;
13 if (*ptr + stream->pixel_size >= stream->ptr) {
14 memmove(stream->buf, stream->buf + *ptr, stream->ptr -= *ptr);
15 *ptr = 0;
16 while (stream->ptr < stream->pixel_size)
17 if (!eread_stream(stream, SIZE_MAX))
18 return NULL;
19 }
20 ret = stream->buf + *ptr;
21 *ptr += stream->pixel_size;
22 return ret;
23 }
24
25 static int
26 process_frame(struct stream *stream, char *buf, size_t above, size_t below, size_t left, size_t right)
27 {
28 #define ZEROES(N) ewritezeroes(STDOUT_FILENO, zeroes, sizeof(zeroes), N, "<stdout>")
29
30 size_t i, w = stream->row_size - left - right;
31 int first = 1;
32
33 if (!eread_row(stream, buf))
34 return 0;
35
36 for (i = 0; i < above; i++)
37 ZEROES(stream->row_size);
38 for (i = 0; i < below; i++, first = 0)
39 if (!first && !eread_row(stream, buf))
40 goto eof;
41
42 for (i = above + below; i < stream->height; i++, first = 0) {
43 if (!first && !eread_row(stream, buf))
44 goto eof;
45 ZEROES((size_t)left);
46 ewriteall(STDOUT_FILENO, buf + right, w, "<stdout>");
47 ZEROES((size_t)right);
48 }
49
50 for (i = 0; i < below; i++)
51 ZEROES(stream->row_size);
52 for (i = 0; i < above; i++, first = 0)
53 if (!first && !eread_row(stream, buf))
54 goto eof;
55
56 return 1;
57 eof:
58 eprintf("%s: file is shorter than expected\n", stream->file);
59 }
60
61 static void
62 process(struct stream *stream, struct stream *trstream)
63 {
64 char *buf;
65 size_t p = 0;
66 double *trans, tmp;
67 ssize_t trx = 0, try = 0;
68 size_t above = 0, below = 0, left = 0, right = 0;
69
70 memset(zeroes, 0, sizeof(zeroes));
71
72 echeck_dimensions(stream, WIDTH, NULL);
73 buf = emalloc(stream->row_size);
74
75 do {
76 if ((trans = next_pixel(trstream, &p))) {
77 trx = (ssize_t)(tmp = round(invtrans ? -trans[0] : trans[0]));
78 try = (ssize_t)(tmp = round(invtrans ? -trans[1] : trans[1]));
79
80 above = try > 0 ? (size_t)try : 0;
81 below = try < 0 ? (size_t)-try : 0;
82 left = (trx > 0 ? (size_t)trx : 0) * stream->pixel_size;
83 right = (trx < 0 ? (size_t)-trx : 0) * stream->pixel_size;
84
85 above = MIN(above, stream->height);
86 below = MIN(below, stream->height);
87 left = MIN(left, stream->row_size);
88 right = MIN(right, stream->row_size);
89 }
90 } while (process_frame(stream, buf, above, below, left, right));
91
92 free(buf);
93 }
94
95 static void
96 process_wrap(struct stream *stream, struct stream *trstream)
97 {
98 char *buf, *row;
99 size_t p = 0;
100 double *trans, tmp;
101 ssize_t trx = 0, try = 0, py;
102 size_t off = 0, y;
103
104 echeck_dimensions(stream, WIDTH | HEIGHT, NULL);
105 buf = emalloc(stream->frame_size);
106
107 while (eread_frame(stream, buf)) {
108 if ((trans = next_pixel(trstream, &p))) {
109 trx = (ssize_t)(tmp = round(invtrans ? -trans[0] : trans[0]));
110 try = (ssize_t)(tmp = round(invtrans ? -trans[1] : trans[1]));
111 trx %= (ssize_t)stream->width;
112 if (trx < 0)
113 trx += (ssize_t)stream->width;
114 off = (stream->width - (size_t)trx) % stream->width;
115 off = off * stream->pixel_size;
116 }
117
118 for (y = 0; y < stream->height; y++) {
119 py = ((ssize_t)y - try) % (ssize_t)stream->height;
120 if (py < 0)
121 py += (ssize_t)stream->height;
122 row = buf + (size_t)py * stream->row_size;
123 ewriteall(STDOUT_FILENO, row + off, stream->row_size - off, "<stdout>");
124 ewriteall(STDOUT_FILENO, row, off, "<stdout>");
125 }
126 }
127
128 free(buf);
129 }
130
131 int
132 main(int argc, char *argv[])
133 {
134 struct stream stream;
135 struct stream trstream;
136 int wrap = 0;
137
138 ARGBEGIN {
139 case 'w':
140 wrap = 1;
141 break;
142 case 'p':
143 invtrans = 1;
144 break;
145 default:
146 usage();
147 } ARGEND;
148
149 if (argc != 1)
150 usage();
151
152 eopen_stream(&stream, NULL);
153 eopen_stream(&trstream, argv[0]);
154
155 if (trstream.width != 1 || trstream.height != 1)
156 eprintf("translation-stream does not have 1x1 geometry\n");
157
158 if (strcmp(trstream.pixfmt, "xyza"))
159 eprintf("pixel format of translation-stream %s "
160 "is not supported, try xyza\n", trstream.pixfmt);
161
162 fprint_stream_head(stdout, &stream);
163 efflush(stdout, "<stdout>");
164
165 (wrap ? process_wrap : process)(&stream, &trstream);
166 close(trstream.fd);
167 return 0;
168 }