ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/px/psketch.c
Revision: 2.4
Committed: Thu Aug 2 18:33:46 2018 UTC (5 years, 8 months ago) by greg
Content type: text/plain
Branch: MAIN
CVS Tags: rad5R4, rad5R2, rad5R3, HEAD
Changes since 2.3: +2 -2 lines
Log Message:
Created MAXFMTLEN to guard against buffer overrun attacks in header input

File Contents

# Content
1 #ifndef lint
2 static const char RCSid[] = "$Id: psketch.c,v 2.3 2017/08/29 16:31:32 greg Exp $";
3 #endif
4 /*
5 * psketch.c - modify picture to sketch objects with named modifiers
6 *
7 * 9/23/2017
8 */
9
10 #include "copyright.h"
11
12 #include <string.h>
13
14 #include "standard.h"
15 #include "platform.h"
16 #include "paths.h"
17 #include "resolu.h"
18 #include "color.h"
19
20 #define MAXMOD 2048 /* maximum number of modifiers */
21 #define USESORT 12 /* switch to sorted search */
22
23 double smoothing = 0.8; /* weight for moving average filter */
24 double mixfact = 0.3; /* amount to mix above/below */
25
26 char *modlist[MAXMOD]; /* (sorted) modifier list */
27 int nmods = 0; /* number of modifiers */
28
29 unsigned char *hasmod; /* scanline bitmap */
30 unsigned char *hasmod1;
31 COLOR *scan[2]; /* i/o scanlines */
32 RESOLU pres; /* input resolution */
33 int bmwidth; /* bytes per bitmap */
34
35 #undef tstbit /* conflicting def's in param.h */
36 #undef setbit
37 #undef clrbit
38 #undef tglbit
39
40 #define bitop(bm,x,op) ((bm)[(x)>>3] op (1<<((x)&7)))
41 #define tstbit(bm,x) bitop(bm,x,&)
42 #define setbit(bm,x) bitop(bm,x,|=)
43 #define clrbit(bm,x) bitop(bm,x,&=~)
44 #define tglbit(bm,x) bitop(bm,x,^=)
45
46 const char *octree, *infname; /* input octree and picture names */
47 FILE *infp; /* picture input stream */
48 FILE *mafp; /* pipe from rtrace with modifiers */
49 int linesread = 0; /* scanlines read so far */
50
51 static int
52 find_mod(const char *s)
53 {
54 int ilower, iupper;
55 int c, i;
56
57 if (nmods < USESORT) { /* linear search */
58 for (i = nmods; i-- > 0; )
59 if (!strcmp(s, modlist[i]))
60 return(i);
61 return(-1);
62 }
63 ilower = 0; iupper = nmods;
64 c = iupper; /* binary search */
65 while ((i = (iupper + ilower) >> 1) != c) {
66 c = strcmp(s, modlist[i]);
67 if (c > 0)
68 ilower = i;
69 else if (c < 0)
70 iupper = i;
71 else
72 return(i);
73 c = i;
74 }
75 return(-1);
76 }
77
78 static int
79 read_scan(void)
80 {
81 const int spread = (int)(smoothing*10);
82 int x, width = scanlen(&pres);
83 unsigned char *tbmp;
84 COLOR *tscn;
85 char modbuf[516];
86 /* advance buffer */
87 tscn = scan[0];
88 scan[0] = scan[1];
89 scan[1] = tscn;
90 /* check if we are at the end */
91 if (linesread >= numscans(&pres))
92 return(0);
93 /* set scanline bitmap */
94 if (linesread) {
95 /* load & check materials */
96 memset(hasmod1, 0, bmwidth);
97 for (x = 0; x < width; x++) {
98 int len;
99 if (fgets(modbuf, sizeof(modbuf), mafp) == NULL) {
100 fprintf(stderr, "Error reading from rtrace!\n");
101 return(-1);
102 }
103 len = strlen(modbuf);
104 if (len < 3 || (modbuf[len-1] != '\n') |
105 (modbuf[len-2] != '\t')) {
106 fprintf(stderr, "Garbled rtrace output: %s", modbuf);
107 return(-1);
108 }
109 modbuf[len-2] = '\0';
110 if (find_mod(modbuf) >= 0)
111 setbit(hasmod1, x);
112 }
113 /* smear to cover around object */
114 memset(hasmod, 0, bmwidth);
115 for (x = spread; x < width-spread; x++) {
116 int ox;
117 if (!tstbit(hasmod1,x)) continue;
118 for (ox = -spread; ox <= spread; ox++)
119 setbit(hasmod,x+ox);
120 }
121 }
122 /* read next picture scanline */
123 if (freadscan(scan[1], width, infp) < 0) {
124 fprintf(stderr, "%s: error reading scanline %d\n",
125 infname, linesread);
126 return(-1);
127 }
128 return(++linesread);
129 }
130
131 static int
132 spcmp(const void *p1, const void *p2)
133 {
134 return strcmp(*(const char **)p1, *(const char **)p2);
135 }
136
137 static int
138 get_started(void)
139 {
140 char combuf[1024];
141
142 if (nmods >= USESORT) /* need to sort for search? */
143 qsort(modlist, nmods, sizeof(char *), &spcmp);
144 /* open pipe from rtrace */
145 sprintf(combuf, "vwrays -fd %s | rtrace -h -fda -om %s",
146 infname, octree);
147 mafp = popen(combuf, "r");
148 if (mafp == NULL) {
149 perror("popen");
150 return(0);
151 }
152 /* allocate bitmaps & buffers */
153 bmwidth = (scanlen(&pres)+7) >> 3;
154 hasmod = (unsigned char *)malloc(bmwidth);
155 hasmod1 = (unsigned char *)malloc(bmwidth);
156 scan[0] = (COLOR *)malloc(scanlen(&pres)*sizeof(COLOR));
157 scan[1] = (COLOR *)malloc(scanlen(&pres)*sizeof(COLOR));
158 if (!hasmod | !hasmod1 | !scan[0] | !scan[1]) {
159 perror("malloc");
160 return(0);
161 }
162 if (!read_scan()) /* read first scanline */
163 return(0);
164 return(1);
165 }
166
167 static int
168 advance_scanline(void)
169 {
170 static int alldone = 0;
171 int width = scanlen(&pres);
172 int height = numscans(&pres);
173 int x, xstart = 0, xstop = width, xstep = 1;
174 COLOR cmavg;
175
176 if (alldone) /* finished last scanline? */
177 return(0);
178 alldone = (linesread >= height);
179 /* advance scanline */
180 if (read_scan() < !alldone)
181 return(-1);
182 if (linesread & 1) { /* process in horizontal zig-zag */
183 xstart = width-1;
184 xstop = -1;
185 xstep = -1;
186 }
187 setcolor(cmavg, .0f, .0f, .0f); /* process this scanline */
188 for (x = xstart; x != xstop; x += xstep) {
189 COLOR cmix;
190 if (!tstbit(hasmod,x)) continue;
191 /* apply moving average */
192 scalecolor(scan[0][x], 1.-smoothing);
193 scalecolor(cmavg, smoothing);
194 addcolor(cmavg, scan[0][x]);
195 copycolor(scan[0][x], cmavg);
196 /* mix pixel into next scanline */
197 copycolor(cmix, scan[0][x]);
198 scalecolor(cmix, mixfact);
199 scalecolor(scan[1][x], 1.-mixfact);
200 addcolor(scan[1][x], cmix);
201 }
202 /* write out result */
203 if (fwritescan(scan[0], width, stdout) < 0) {
204 perror("write error");
205 return(-1);
206 }
207 return(1);
208 }
209
210 static int
211 clean_up(void)
212 {
213 char linebuf[128];
214 /* read unused materials */
215 while (fgets(linebuf, sizeof(linebuf), mafp) != NULL)
216 ;
217 if (pclose(mafp) != 0) {
218 fprintf(stderr, "Error running rtrace!\n");
219 return(0);
220 }
221 fclose(infp);
222 free(hasmod);
223 free(hasmod1);
224 free(scan[0]);
225 free(scan[1]);
226 return(1);
227 }
228
229 int
230 main(int argc, char *argv[])
231 {
232 int i, rval;
233 char pfmt[MAXFMTLEN];
234 /* process options */
235 for (i = 1; i < argc && argv[i][0] == '-'; i++)
236 switch (argv[i][1]) {
237 case 'm': /* new modifier name */
238 if (nmods >= MAXMOD) {
239 fprintf(stderr, "%s: too many modifiers\n", argv[0]);
240 return(1);
241 }
242 modlist[nmods++] = argv[++i];
243 break;
244 case 'M': /* modifier file */
245 rval = wordfile(modlist, MAXMOD-nmods, argv[++i]);
246 if (rval < 0) {
247 fprintf(stderr, "%s: cannot open modifier file '%s'\n",
248 argv[0], argv[i]);
249 return(1);
250 }
251 nmods += rval;
252 break;
253 case 's': /* filter smoothing amount */
254 smoothing = atof(argv[++i]);
255 if ((smoothing <= FTINY) | (smoothing >= 1.-FTINY)) {
256 fprintf(stderr, "%s: smoothing factor must be in (0,1) range\n",
257 argv[0]);
258 return(1);
259 }
260 break;
261 default:
262 fprintf(stderr, "%s: unknown option '%s'\n",
263 argv[0], argv[i]);
264 return(1);
265 }
266 if ((argc-i < 2) | (argc-i > 3)) {
267 fprintf(stderr, "Usage: %s [-m modname][-M modfile][-s smoothing] octree input.hdr [output.hdr]\n",
268 argv[0]);
269 return(1);
270 }
271 if (!nmods) {
272 fprintf(stderr, "%s: at least one '-m' or '-M' option needed\n",
273 argv[0]);
274 return(1);
275 }
276 octree = argv[i];
277 infname = argv[i+1]; /* open input picture */
278 infp = fopen(infname, "rb");
279 if (infp == NULL) {
280 fprintf(stderr, "%s: cannot open input '%s' for reading\n",
281 argv[0], argv[i+1]);
282 return(1);
283 }
284 if (i+2 < argc && /* open output picture */
285 freopen(argv[i+2], "w", stdout) == NULL) {
286 fprintf(stderr, "%s: cannot open output '%s' for writing\n",
287 argv[0], argv[i+2]);
288 return(1);
289 }
290 SET_FILE_BINARY(stdout);
291 strcpy(pfmt, PICFMT); /* copy format/resolution */
292 if (checkheader(infp, pfmt, stdout) < 0 || !fgetsresolu(&pres, infp)) {
293 fprintf(stderr, "%s: bad format for input picture\n",
294 argv[0]);
295 return(1);
296 }
297 printargs(argc, argv, stdout); /* complete header */
298 fputformat(pfmt, stdout);
299 fputc('\n', stdout);
300 fputsresolu(&pres, stdout); /* resolution does not change */
301 if (!get_started())
302 return(1);
303 while ((rval = advance_scanline()))
304 if (rval < 0)
305 return(1);
306 if (!clean_up())
307 return(1);
308 return(0);
309 }