ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/util/rcrop.c
Revision: 1.13
Committed: Thu Apr 7 16:58:30 2022 UTC (5 months, 3 weeks ago) by greg
Content type: text/plain
Branch: MAIN
CVS Tags: HEAD
Changes since 1.12: +13 -1 lines
Log Message:
perf(rcrop): Improved i/o performance for binary data under Unix with pread(2)

File Contents

# Content
1 #ifndef lint
2 static const char RCSid[] = "$Id: rcrop.c,v 1.12 2022/03/21 20:19:19 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 (!strncmp(s, "NCOMP=", 6)) {
31 ncomp = atoi(s+6);
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, (rmin*width + cmin)*elsiz, SEEK_CUR) == 0) {
101 off_t curpos;
102 buf = (char *)malloc(ncols*elsiz);
103 if (!buf)
104 goto memerr;
105 #ifdef NON_POSIX
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 #else
118 curpos = ftello(fp);
119 for (y = nrows; y-- > 0; curpos += width*elsiz) {
120 if (pread(fileno(fp), buf, ncols*elsiz,
121 curpos) != ncols*elsiz)
122 goto readerr;
123 if (putbinary(buf, elsiz, ncols, stdout) != ncols)
124 goto writerr;
125 }
126 #endif
127 free(buf);
128 if (fflush(stdout) == EOF)
129 goto writerr;
130 return(1); /* success! */
131 } /* else need to read it all... */
132 buf = (char *)malloc(width*elsiz);
133 if (!buf)
134 goto memerr;
135 /* skip rows as requested */
136 if (skip_len > skip_thresh ||
137 (rmin && fseek(fp, rmin*width*elsiz, SEEK_CUR) < 0))
138 for (y = 0; y < rmin; y++)
139 if (getbinary(buf, elsiz, width, fp) != width)
140 goto readerr;
141 for (y = 0; y < nrows; y++) { /* copy portion */
142 if (getbinary(buf, elsiz, width, fp) != width)
143 goto readerr;
144 if (putbinary(buf+cmin*elsiz, elsiz, ncols, stdout) != ncols)
145 goto writerr;
146 }
147 free(buf); /* we're done */
148 if (fflush(stdout) == 0)
149 return(1);
150 writerr:
151 fputs(progname, stderr);
152 fputs(": error writing binary data\n", stderr);
153 return(0);
154 readerr:
155 fputs(progname, stderr);
156 fputs(": error reading binary data\n", stderr);
157 return(0);
158 memerr:
159 fputs(progname, stderr);
160 fputs(": out of memory!\n", stderr);
161 return(0);
162 }
163
164 /* Read (and copy) specified number of white-space-separated words */
165 static int
166 readwords(FILE *finp, int nwords, FILE *fout)
167 {
168 while (nwords-- > 0) {
169 int c;
170 do {
171 c = getc(finp);
172 } while (isspace(c));
173 if (c == EOF)
174 return(-1);
175 if (fout && fputc(' ', fout) == EOF)
176 return(-1);
177 do {
178 if (fout)
179 putc(c, fout);
180 } while ((c = getc(finp)) != EOF && !isspace(c));
181 }
182 return(0);
183 }
184
185 /* Copy routine for ascii data */
186 static int
187 ascii_copyf(FILE *fp)
188 {
189 const int width = scanlen(&res);
190 int x, y;
191
192 SET_FILE_TEXT(fp); /* started as binary */
193 SET_FILE_TEXT(stdout);
194 /* skip rows as requested */
195 if (readwords(fp, rmin*width*ncomp, NULL) < 0)
196 goto io_err;
197 for (y = 0; y < nrows; y++) { /* copy part */
198 if (readwords(fp, cmin*ncomp, NULL) < 0)
199 goto io_err;
200 if (readwords(fp, ncols*ncomp, stdout) < 0)
201 goto io_err;
202 fputc('\n', stdout); /* newline per row */
203 if (readwords(fp, (width-ncols-cmin)*ncomp, NULL) < 0)
204 goto io_err;
205 }
206 if (fflush(stdout) == 0)
207 return(1);
208 io_err:
209 fputs(progname, stderr);
210 fputs(": error copying ascii data\n", stderr);
211 return(0);
212 }
213
214 /* Adjust (crop) our view */
215 static int
216 adjust_view(void)
217 {
218 double p0[2], p1[2];
219 const char *err;
220
221 if (res.rt & YMAJOR) {
222 p0[0] = cmin/(double)res.xr;
223 p0[1] = rmin/(double)res.yr;
224 p1[0] = (cmin+ncols)/(double)res.xr;
225 p1[1] = (rmin+nrows)/(double)res.yr;
226 } else {
227 p0[0] = rmin/(double)res.xr;
228 p0[1] = cmin/(double)res.yr;
229 p1[0] = (rmin+nrows)/(double)res.xr;
230 p1[1] = (cmin+ncols)/(double)res.yr;
231 }
232 if (res.rt & XDECR) {
233 p0[0] = 1. - p0[0];
234 p1[0] = 1. - p1[0];
235 }
236 if (res.rt & YDECR) {
237 p0[1] = 1. - p0[1];
238 p1[1] = 1. - p1[1];
239 }
240 err = cropview(&vw, p0[0], p0[1], p1[0], p1[1]);
241
242 if (!err)
243 return(1); /* success! */
244
245 fputs(progname, stderr);
246 fputs(": view error - ", stderr);
247 fputs(err, stderr);
248 fputc('\n', stderr);
249 return(0); /* something went wrong */
250 }
251
252
253 /* Main routine -- load header and call processor */
254 int
255 main(int argc, char *argv[])
256 {
257 FILE *fp = stdin;
258 int asiz = 0;
259 int gotdims;
260
261 progname = argv[0];
262 /* get input and output */
263 if ((argc < 5) | (argc > 7))
264 goto usage;
265 if (!isint(argv[1]) | !isint(argv[2]) |
266 !isint(argv[3]) | !isint(argv[4]))
267 goto usage;
268 rmin = atoi(argv[1]);
269 cmin = atoi(argv[2]);
270 nrows = atoi(argv[3]);
271 ncols = atoi(argv[4]);
272 if ((rmin < 0) | (cmin < 0) | (nrows < 0) | (ncols < 0))
273 goto usage;
274 if (argc <= 5)
275 SET_FILE_BINARY(fp);
276 else if (!(fp = fopen(argv[5], "rb"))) {
277 fputs(argv[5], stderr);
278 fputs(": cannot open for reading\n", stderr);
279 return(1);
280 }
281 if (argc <= 6)
282 SET_FILE_BINARY(stdout);
283 else if (!freopen(argv[6], "wb", stdout)) {
284 fputs(argv[6], stderr);
285 fputs(": cannot open for writing\n", stderr);
286 return(1);
287 }
288 #ifdef getc_unlocked /* avoid stupid semaphores */
289 flockfile(fp);
290 flockfile(stdout);
291 #endif
292 /* process information header */
293 if (getheader(fp, headline, NULL) < 0) {
294 fputs(progname, stderr);
295 fputs(": bad input header\n", stderr);
296 return(1);
297 }
298 gotdims = (res.rt == PIXSTANDARD) & (res.xr > 0) & (res.yr > 0);
299 if (!gotdims && !fgetsresolu(&res, fp)) {
300 fputs(progname, stderr);
301 fputs(": missing input dimensions\n", stderr);
302 return(1);
303 }
304 if (!nrows)
305 nrows = numscans(&res) - rmin;
306 if (!ncols)
307 ncols = scanlen(&res) - cmin;
308 if ((nrows <= 0) | (ncols <= 0) |
309 (rmin+nrows > numscans(&res)) |
310 (cmin+ncols > scanlen(&res))) {
311 fputs(progname, stderr);
312 fputs(": illegal crop\n", stderr);
313 return(1);
314 }
315 printargs(5, argv, stdout); /* add to header */
316 if (gotvw && adjust_view()) {
317 fputs(VIEWSTR, stdout); /* write adjusted view */
318 fprintview(&vw, stdout);
319 fputc('\n', stdout);
320 }
321 if (gotdims) /* dimensions + format */
322 printf("NROWS=%d\nNCOLS=%d\n", nrows, ncols);
323 if (ncomp)
324 printf("NCOMP=%d\n", ncomp);
325 fputformat(fmt, stdout); /* will align bytes if it can */
326 fputc('\n', stdout); /* end of new header */
327 if (!gotdims) { /* add resolution string? */
328 RESOLU newres;
329 if (res.rt & YMAJOR) {
330 newres.xr = ncols;
331 newres.yr = nrows;
332 } else {
333 newres.xr = nrows;
334 newres.yr = ncols;
335 }
336 newres.rt = res.rt;
337 fputsresolu(&newres, stdout);
338 }
339 /* call appropriate processor */
340 if (!strcmp(fmt, "float")) {
341 asiz = sizeof(float);
342 } else if (!strcmp(fmt, "double")) {
343 asiz = sizeof(double);
344 } else if (!strcmp(fmt, "32-bit_encoded_normal")) {
345 asiz = 4;
346 ncomp = 1;
347 } else if (!strcmp(fmt, "16-bit_encoded_depth")) {
348 asiz = 2;
349 ncomp = 1;
350 } else if (globmatch(PICFMT, fmt)) {
351 asiz = -1;
352 if (!ncomp) ncomp = 3;
353 else ncomp *= (ncomp == 3);
354 } else if (strcasecmp(fmt, "ascii")) {
355 fputs(progname, stderr);
356 fputs(": unsupported format - ", stderr);
357 fputs(fmt, stderr);
358 fputc('\n', stderr);
359 return(1);
360 }
361 if (ncomp <= 0) {
362 fputs(progname, stderr);
363 fputs(": illegal number of components\n", stderr);
364 return(1);
365 }
366 if (!(asiz < 0 ? colr_copyf(fp) :
367 asiz ? binary_copyf(fp, asiz) : ascii_copyf(fp)))
368 return(1);
369 /* need to consume the rest? */
370 if (fp == stdin && rmin+nrows < numscans(&res) &&
371 fseek(fp, 0L, SEEK_END) < 0)
372 while (getc(fp) != EOF)
373 ;
374 return(0);
375 usage:
376 fputs("Usage: ", stderr);
377 fputs(progname, stderr);
378 fputs(" row0 col0 nrows ncols [input [output]]\n", stderr);
379 return(1);
380 }