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 }