ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/util/rcrop.c
Revision: 1.10
Committed: Wed Mar 16 15:50:24 2022 UTC (2 years, 1 month ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 1.9: +46 -38 lines
Log Message:
refactor(rcrop): Minor code rearrangements and improvements

File Contents

# Content
1 #ifndef lint
2 static const char RCSid[] = "$Id: rcrop.c,v 1.9 2022/03/16 01:51:16 greg Exp $";
3 #endif
4 /*
5 * rcrop.c - crop a Radiance picture or matrix data
6 */
7
8 #include <ctype.h>
9 #include "rtio.h"
10 #include "platform.h"
11 #include "color.h"
12 #include "fvect.h"
13 #include "view.h"
14
15 #define MAXWORD 64 /* maximum word (number) length */
16
17 char *progname; /* global argv[0] */
18
19 VIEW vw = STDVIEW;
20 int gotvw = 0;
21 char fmt[MAXFMTLEN] = "ascii"; /* assumed when unspecified */
22 int ncomp = 0;
23 RESOLU res;
24 int rmin, cmin, nrows, ncols;
25
26 /* Process header line, copying to stdout when appropriate */
27 static int
28 headline(char *s, void *p)
29 {
30 if (formatval(fmt, s))
31 return(0);
32 if (!strncmp(s, "NCOMP=", 6)) {
33 ncomp = atoi(s+6);
34 return(-(ncomp <= 0));
35 }
36 if (!strncmp(s, "NROWS=", 6)) {
37 res.rt = PIXSTANDARD;
38 res.yr = atoi(s+6);
39 return(-(res.yr <= 0));
40 }
41 if (!strncmp(s, "NCOLS=", 6)) {
42 res.rt = PIXSTANDARD;
43 res.xr = atoi(s+6);
44 return(-(res.xr <= 0));
45 }
46 if (isview(s)) {
47 gotvw += sscanview(&vw, s);
48 return(0);
49 }
50 fputs(s, stdout); /* copy other header info. */
51 return(0);
52 }
53
54 /* Copy routine for COLR data */
55 static int
56 colr_copyf(FILE *fp)
57 {
58 const int width = scanlen(&res);
59 COLR *scan = (COLR *)malloc(sizeof(COLR)*width);
60 int y;
61
62 if (!scan) {
63 fputs(progname, stderr);
64 fputs(": out of memory!\n", stderr);
65 return(0);
66 }
67 for (y = 0; y < rmin; y++) /* initial skip */
68 if (freadcolrs(scan, width, fp) < 0)
69 goto readerr;
70 /* scanlines to copy */
71 for (y = 0; y < nrows; y++) {
72 if (freadcolrs(scan, width, fp) < 0)
73 goto readerr;
74 if (fwritecolrs(scan+cmin, ncols, stdout) < 0)
75 goto writerr;
76 }
77 free(scan);
78 if (fflush(stdout) == 0)
79 return(1);
80 writerr:
81 fputs(progname, stderr);
82 fputs(": error writing picture\n", stderr);
83 return(0);
84 readerr:
85 fputs(progname, stderr);
86 fputs(": error reading picture\n", stderr);
87 return(0);
88 }
89
90 /* Copy routine for binary data (asize = sizeof(type)) */
91 static int
92 binary_copyf(FILE *fp, int asize)
93 {
94 const int skip_thresh = 8192;
95 const size_t elsiz = asize*ncomp;
96 const int width = scanlen(&res);
97 const long skip_len = (width-ncols)*elsiz;
98 char *buf;
99 int y;
100 /* check if fseek() useful */
101 if (skip_len > skip_thresh &&
102 fseek(fp, (rmin*width + cmin)*elsiz, SEEK_CUR) == 0) {
103 buf = (char *)malloc(ncols*elsiz);
104 if (!buf)
105 goto memerr;
106 for (y = nrows; y-- > 0; ) {
107 if (getbinary(buf, elsiz, ncols, fp) != ncols)
108 goto readerr;
109 if (putbinary(buf, elsiz, ncols, stdout) != ncols)
110 goto writerr;
111 if (y && fseek(fp, skip_len, SEEK_CUR) < 0) {
112 fputs(progname, stderr);
113 fputs(": unexpected seek error on input\n", stderr);
114 return(0);
115 }
116 }
117 free(buf); /* success! */
118 return(1);
119 } /* else need to read it all... */
120 buf = (char *)malloc(width*elsiz);
121 if (!buf)
122 goto memerr;
123 /* skip rows as requested */
124 if (skip_len > skip_thresh ||
125 (rmin && fseek(fp, rmin*width*elsiz, SEEK_CUR) < 0))
126 for (y = 0; y < rmin; y++)
127 if (getbinary(buf, elsiz, width, fp) != width)
128 goto readerr;
129 for (y = 0; y < nrows; y++) { /* copy portion */
130 if (getbinary(buf, elsiz, width, fp) != width)
131 goto readerr;
132 if (putbinary(buf+cmin*elsiz, elsiz, ncols, stdout) != ncols)
133 goto writerr;
134 }
135 free(buf); /* we're done */
136 if (fflush(stdout) == 0)
137 return(1);
138 writerr:
139 fputs(progname, stderr);
140 fputs(": error writing binary data\n", stderr);
141 return(0);
142 readerr:
143 fputs(progname, stderr);
144 fputs(": error reading binary data\n", stderr);
145 return(0);
146 memerr:
147 fputs(progname, stderr);
148 fputs(": out of memory!\n", stderr);
149 return(0);
150 }
151
152 /* Read (and copy) specified number of white-space-separated words */
153 static int
154 readwords(FILE *finp, int nwords, FILE *fout)
155 {
156 while (nwords-- > 0) {
157 int c;
158 do {
159 c = getc(finp);
160 } while (isspace(c));
161 if (c == EOF)
162 return(-1);
163 if (fout && fputc(' ', fout) == EOF)
164 return(-1);
165 do {
166 if (fout)
167 putc(c, fout);
168 } while ((c = getc(finp)) != EOF && !isspace(c));
169 }
170 return(0);
171 }
172
173 /* Copy routine for ascii data */
174 static int
175 ascii_copyf(FILE *fp)
176 {
177 const int width = scanlen(&res);
178 int x, y;
179
180 SET_FILE_TEXT(fp); /* started as binary */
181 SET_FILE_TEXT(stdout);
182 /* skip rows as requested */
183 if (readwords(fp, rmin*width*ncomp, NULL) < 0)
184 goto io_err;
185 for (y = 0; y < nrows; y++) { /* copy part */
186 if (readwords(fp, cmin*ncomp, NULL) < 0)
187 goto io_err;
188 if (readwords(fp, ncols*ncomp, stdout) < 0)
189 goto io_err;
190 fputc('\n', stdout); /* newline per row */
191 if (readwords(fp, (width-ncols-cmin)*ncomp, NULL) < 0)
192 goto io_err;
193 }
194 if (fflush(stdout) == 0)
195 return(1);
196 io_err:
197 fputs(progname, stderr);
198 fputs(": error copying ascii data\n", stderr);
199 return(0);
200 }
201
202 /* Adjust (crop) our view */
203 static int
204 adjust_view(void)
205 {
206 double p0[2], p1[2];
207 const char *err;
208
209 if (res.rt & YMAJOR) {
210 p0[0] = cmin/(double)res.xr;
211 p0[1] = rmin/(double)res.yr;
212 p1[0] = (cmin+ncols)/(double)res.xr;
213 p1[1] = (rmin+nrows)/(double)res.yr;
214 } else {
215 p0[0] = rmin/(double)res.xr;
216 p0[1] = cmin/(double)res.yr;
217 p1[0] = (rmin+nrows)/(double)res.xr;
218 p1[1] = (cmin+ncols)/(double)res.yr;
219 }
220 if (res.rt & XDECR) {
221 p0[0] = 1. - p0[0];
222 p1[0] = 1. - p1[0];
223 }
224 if (res.rt & YDECR) {
225 p0[1] = 1. - p0[1];
226 p1[1] = 1. - p1[1];
227 }
228 err = cropview(&vw, p0[0], p0[1], p1[0], p1[1]);
229 if (err) {
230 fputs(progname, stderr);
231 fputs(": view error - ", stderr);
232 fputs(err, stderr);
233 fputc('\n', stderr);
234 return(0);
235 }
236 return(1);
237 }
238
239
240 /* Main routine -- load header and call processor */
241 int
242 main(int argc, char *argv[])
243 {
244 FILE *fp = stdin;
245 int asiz = 0;
246 int gotdims;
247
248 progname = argv[0];
249 /* get input and output */
250 if ((argc < 5) | (argc > 7))
251 goto usage;
252 if (!isint(argv[1]) | !isint(argv[2]) |
253 !isint(argv[3]) | !isint(argv[4]))
254 goto usage;
255 rmin = atoi(argv[1]);
256 cmin = atoi(argv[2]);
257 nrows = atoi(argv[3]);
258 ncols = atoi(argv[4]);
259 if ((rmin < 0) | (cmin < 0) | (nrows < 0) | (ncols < 0))
260 goto usage;
261 if (argc <= 5)
262 SET_FILE_BINARY(fp);
263 else if (!(fp = fopen(argv[5], "rb"))) {
264 fputs(argv[5], stderr);
265 fputs(": cannot open for reading\n", stderr);
266 return(1);
267 }
268 if (argc <= 6)
269 SET_FILE_BINARY(stdout);
270 else if (!freopen(argv[6], "wb", stdout)) {
271 fputs(argv[6], stderr);
272 fputs(": cannot open for writing\n", stderr);
273 return(1);
274 }
275 #ifdef getc_unlocked /* avoid stupid semaphores */
276 flockfile(fp);
277 flockfile(stdout);
278 #endif
279 /* process information header */
280 if (getheader(fp, headline, NULL) < 0) {
281 fputs(progname, stderr);
282 fputs(": bad input header\n", stderr);
283 return(1);
284 }
285 gotdims = (res.rt == PIXSTANDARD) & (res.xr > 0) & (res.yr > 0);
286 if (!gotdims && !fgetsresolu(&res, fp)) {
287 fputs(progname, stderr);
288 fputs(": missing input dimensions\n", stderr);
289 return(1);
290 }
291 if (!nrows)
292 nrows = numscans(&res) - rmin;
293 if (!ncols)
294 ncols = scanlen(&res) - cmin;
295 if ((nrows <= 0) | (ncols <= 0) |
296 (rmin+nrows > numscans(&res)) |
297 (cmin+ncols > scanlen(&res))) {
298 fputs(progname, stderr);
299 fputs(": illegal crop\n", stderr);
300 return(1);
301 }
302 printargs(5, argv, stdout); /* add to header */
303 if (gotvw && adjust_view()) {
304 fputs(VIEWSTR, stdout); /* write adjusted view */
305 fprintview(&vw, stdout);
306 fputc('\n', stdout);
307 }
308 if (gotdims) /* dimensions + format */
309 printf("NROWS=%d\nNCOLS=%d\n", nrows, ncols);
310 if (ncomp)
311 printf("NCOMP=%d\n", ncomp);
312 fputformat(fmt, stdout); /* will align bytes if it can */
313 fputc('\n', stdout); /* end of new header */
314 if (!gotdims) { /* add resolution string? */
315 RESOLU newres;
316 if (res.rt & YMAJOR) {
317 newres.xr = ncols;
318 newres.yr = nrows;
319 } else {
320 newres.xr = nrows;
321 newres.yr = ncols;
322 }
323 newres.rt = res.rt;
324 fputsresolu(&newres, stdout);
325 }
326 /* call appropriate processor */
327 if (!strcmp(fmt, "float")) {
328 asiz = sizeof(float);
329 } else if (!strcmp(fmt, "double")) {
330 asiz = sizeof(double);
331 } else if (!strcmp(fmt, "32-bit_encoded_normal")) {
332 asiz = 4;
333 ncomp = 1;
334 } else if (!strcmp(fmt, "16-bit_encoded_depth")) {
335 asiz = 2;
336 ncomp = 1;
337 } else if (globmatch(PICFMT, fmt)) {
338 asiz = -1;
339 if (!ncomp) ncomp = 3;
340 else ncomp *= (ncomp == 3);
341 } else if (strcasecmp(fmt, "ascii")) {
342 fputs(progname, stderr);
343 fputs(": unsupported format - ", stderr);
344 fputs(fmt, stderr);
345 fputc('\n', stderr);
346 return(1);
347 }
348 if (ncomp <= 0) {
349 fputs(progname, stderr);
350 fputs(": illegal number of components\n", stderr);
351 return(1);
352 }
353 if (!(asiz < 0 ? colr_copyf(fp) :
354 asiz ? binary_copyf(fp, asiz) : ascii_copyf(fp)))
355 return(1);
356 /* need to consume the rest? */
357 if (fp == stdin && rmin+nrows < numscans(&res) &&
358 fseek(fp, 0L, SEEK_END) < 0)
359 while (getc(fp) != EOF)
360 ;
361 return(0);
362 usage:
363 fputs("Usage: ", stderr);
364 fputs(progname, stderr);
365 fputs(" row0 col0 nrows ncols [input [output]]\n", stderr);
366 return(1);
367 }