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 days, 5 hours 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

# User Rev Content
1 greg 1.1 #ifndef lint
2 greg 1.17 static const char RCSid[] = "$Id: rcrop.c,v 1.16 2024/05/17 20:50:57 greg Exp $";
3 greg 1.1 #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 greg 1.8 char fmt[MAXFMTLEN] = "ascii"; /* assumed when unspecified */
20 greg 1.1 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 greg 1.14 if (isncomp(s)) {
31     ncomp = ncompval(s);
32 greg 1.1 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 greg 1.4 fputs(": error writing picture\n", stderr);
81 greg 1.1 return(0);
82     readerr:
83     fputs(progname, stderr);
84 greg 1.4 fputs(": error reading picture\n", stderr);
85 greg 1.1 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 greg 1.3 const int skip_thresh = 8192;
93 greg 1.1 const size_t elsiz = asize*ncomp;
94     const int width = scanlen(&res);
95 greg 1.2 const long skip_len = (width-ncols)*elsiz;
96     char *buf;
97 greg 1.1 int y;
98 greg 1.2 /* check if fseek() useful */
99     if (skip_len > skip_thresh &&
100 greg 1.15 fseek(fp, ((long)rmin*width + cmin)*elsiz, SEEK_CUR) == 0) {
101 greg 1.17 int fd;
102 greg 1.13 off_t curpos;
103 greg 1.2 buf = (char *)malloc(ncols*elsiz);
104     if (!buf)
105     goto memerr;
106 greg 1.13 #ifdef NON_POSIX
107 greg 1.2 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 greg 1.13 #else
119 greg 1.17 fd = fileno(fp);
120 greg 1.13 curpos = ftello(fp);
121     for (y = nrows; y-- > 0; curpos += width*elsiz) {
122 greg 1.17 if (pread(fd, buf, ncols*elsiz,
123 greg 1.13 curpos) != ncols*elsiz)
124     goto readerr;
125     if (putbinary(buf, elsiz, ncols, stdout) != ncols)
126     goto writerr;
127     }
128     #endif
129 greg 1.12 free(buf);
130     if (fflush(stdout) == EOF)
131     goto writerr;
132     return(1); /* success! */
133 greg 1.2 } /* else need to read it all... */
134     buf = (char *)malloc(width*elsiz);
135     if (!buf)
136     goto memerr;
137 greg 1.1 /* skip rows as requested */
138 greg 1.2 if (skip_len > skip_thresh ||
139 greg 1.15 (rmin && fseek(fp, (long)rmin*width*elsiz, SEEK_CUR) < 0))
140 greg 1.1 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 greg 1.2 memerr:
161     fputs(progname, stderr);
162     fputs(": out of memory!\n", stderr);
163     return(0);
164 greg 1.1 }
165    
166     /* Read (and copy) specified number of white-space-separated words */
167     static int
168 greg 1.15 readwords(FILE *finp, long nwords, FILE *fout)
169 greg 1.1 {
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 greg 1.15 if (readwords(fp, (long)rmin*width*ncomp, NULL) < 0)
198 greg 1.1 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 greg 1.10 /* 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 greg 1.11
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 greg 1.10 }
253    
254    
255 greg 1.1 /* 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 greg 1.16 if ((rmin < 0) | (cmin < 0))
275 greg 1.1 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 greg 1.7 #ifdef getc_unlocked /* avoid stupid semaphores */
291     flockfile(fp);
292     flockfile(stdout);
293     #endif
294 greg 1.1 /* 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 greg 1.16 if (nrows <= 0 )
307     nrows += numscans(&res) - rmin;
308     if (ncols <= 0)
309     ncols += scanlen(&res) - cmin;
310 greg 1.1 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 greg 1.10 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 greg 1.1 }
323 greg 1.10 if (gotdims) /* dimensions + format */
324 greg 1.1 printf("NROWS=%d\nNCOLS=%d\n", nrows, ncols);
325     if (ncomp)
326 greg 1.14 fputncomp(ncomp, stdout);
327 greg 1.1 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 greg 1.5 } 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 greg 1.1 } else if (globmatch(PICFMT, fmt)) {
353     asiz = -1;
354     if (!ncomp) ncomp = 3;
355 greg 1.4 else ncomp *= (ncomp == 3);
356 greg 1.14 } else if (!strcmp(fmt, SPECFMT)) {
357     asiz = ncomp+1;
358     ncomp = 1; /* XXX assumes uncompressed */
359 greg 1.1 } 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 greg 1.10 asiz ? binary_copyf(fp, asiz) : ascii_copyf(fp)))
373 greg 1.1 return(1);
374 greg 1.6 /* 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 greg 1.1 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     }