ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/util/rcrop.c
Revision: 1.17
Committed: Wed Jun 5 17:30:56 2024 UTC (9 months, 3 weeks ago) by greg
Content type: text/plain
Branch: MAIN
CVS Tags: HEAD
Changes since 1.16: +4 -2 lines
Log Message:
perf(rcrop): Took call to fileno() out of loop, where it was a performance hit due to idiotic semaphore

File Contents

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