1 | /****************************************************************************** |
---|
2 | * SAGE - Scalable Adaptive Graphics Environment |
---|
3 | * |
---|
4 | * Copyright (C) 2004 Electronic Visualization Laboratory, |
---|
5 | * University of Illinois at Chicago |
---|
6 | * |
---|
7 | * All rights reserved. |
---|
8 | * |
---|
9 | * Redistribution and use in source and binary forms, with or without |
---|
10 | * modification, are permitted provided that the following conditions are met: |
---|
11 | * |
---|
12 | * * Redistributions of source code must retain the above copyright |
---|
13 | * notice, this list of conditions and the following disclaimer. |
---|
14 | * * Redistributions in binary form must reproduce the above |
---|
15 | * copyright notice, this list of conditions and the following disclaimer |
---|
16 | * in the documentation and/or other materials provided with the distribution. |
---|
17 | * * Neither the name of the University of Illinois at Chicago nor |
---|
18 | * the names of its contributors may be used to endorse or promote |
---|
19 | * products derived from this software without specific prior written permission. |
---|
20 | * |
---|
21 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
---|
22 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
---|
23 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
---|
24 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR |
---|
25 | * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
---|
26 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
---|
27 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
---|
28 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF |
---|
29 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING |
---|
30 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
---|
31 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
---|
32 | * |
---|
33 | * Direct questions, comments etc about SAGE to http://www.evl.uic.edu/cavern/forum/ |
---|
34 | * |
---|
35 | *****************************************************************************/ |
---|
36 | |
---|
37 | #ifndef lint |
---|
38 | static char sccsid[] = "@(#)sgigt.c 1.8 4/25/89"; |
---|
39 | #endif |
---|
40 | |
---|
41 | #include <stdio.h> |
---|
42 | #include <gl.h> |
---|
43 | #include <gl/device.h> |
---|
44 | #include "tiffio.h" |
---|
45 | #include "imginfo.h" |
---|
46 | |
---|
47 | static u_long *raster; /* displayable image */ |
---|
48 | static u_short bitspersample; |
---|
49 | static u_short samplesperpixel; |
---|
50 | static u_short photometric; |
---|
51 | static u_short orientation; |
---|
52 | static u_short *redcmap, *greencmap, *bluecmap;/* colormap for palette images */ |
---|
53 | |
---|
54 | #define rgba(r, g, b, a) ((a)<<24 | (b)<<16 | (g)<<8 | (r)) |
---|
55 | #define rgbi(r, g, b) (0xFF000000 | (b)<<16 | (g)<<8 | (r)) |
---|
56 | |
---|
57 | IMG * |
---|
58 | TIFFmakedisp(fname) |
---|
59 | char *fname; |
---|
60 | { |
---|
61 | TIFF *tif; |
---|
62 | short width, height; |
---|
63 | register IMG *im; |
---|
64 | |
---|
65 | tif = TIFFOpen(fname, "r"); |
---|
66 | if(tif == NULL) |
---|
67 | return NULL; |
---|
68 | |
---|
69 | TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &width); |
---|
70 | TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &height); |
---|
71 | im = (IMG *)malloc(sizeof(IMG)); |
---|
72 | im->type = IT_LONG; |
---|
73 | im->rowbytes = sizeof(long) * width; |
---|
74 | im->xsize = width; |
---|
75 | im->ysize = height; |
---|
76 | im->data = (unsigned char *)malloc(im->rowbytes * height); |
---|
77 | if(im->data == NULL) { |
---|
78 | fprintf(stderr, "Can't malloc %d bytes of memory for image\n", |
---|
79 | im->rowbytes * height); |
---|
80 | exit(2); |
---|
81 | } |
---|
82 | if(tiffgt(tif, width, height, (u_long *)im->data) == 0) { |
---|
83 | free(im->data); |
---|
84 | free(im); |
---|
85 | im = NULL; |
---|
86 | } |
---|
87 | TIFFClose(tif); |
---|
88 | return im; |
---|
89 | } |
---|
90 | |
---|
91 | RGBvalue **BWmap; |
---|
92 | |
---|
93 | static |
---|
94 | tiffgt(tif, w, h, raster) |
---|
95 | TIFF *tif; |
---|
96 | int w, h; |
---|
97 | u_long *raster; |
---|
98 | { |
---|
99 | u_short minsamplevalue, maxsamplevalue, planarconfig; |
---|
100 | RGBvalue *Map; |
---|
101 | int e; |
---|
102 | |
---|
103 | if (!TIFFGetField(tif, TIFFTAG_PHOTOMETRIC, &photometric)) { |
---|
104 | switch (samplesperpixel) { |
---|
105 | case 1: |
---|
106 | photometric = PHOTOMETRIC_MINISBLACK; |
---|
107 | break; |
---|
108 | case 3: case 4: |
---|
109 | photometric = PHOTOMETRIC_RGB; |
---|
110 | break; |
---|
111 | default: |
---|
112 | fprintf(stderr, "Missing needed \"%s\" tag.\n", |
---|
113 | "PhotometricInterpretation"); |
---|
114 | return (0); |
---|
115 | } |
---|
116 | printf("No \"PhotometricInterpretation\" tag, assuming %s.\n", |
---|
117 | photometric == PHOTOMETRIC_RGB ? "RGB" : "min-is-black"); |
---|
118 | } |
---|
119 | if (!TIFFGetField(tif, TIFFTAG_SAMPLESPERPIXEL, &samplesperpixel)) |
---|
120 | samplesperpixel = 1; |
---|
121 | if (!TIFFGetField(tif, TIFFTAG_BITSPERSAMPLE, &bitspersample)) |
---|
122 | bitspersample = 8; |
---|
123 | if (!TIFFGetField(tif, TIFFTAG_MINSAMPLEVALUE, &minsamplevalue)) |
---|
124 | minsamplevalue = 0; |
---|
125 | if (!TIFFGetField(tif, TIFFTAG_MAXSAMPLEVALUE, &maxsamplevalue)) |
---|
126 | maxsamplevalue = (1<<bitspersample)-1; |
---|
127 | Map = NULL; |
---|
128 | switch (photometric) { |
---|
129 | case PHOTOMETRIC_RGB: |
---|
130 | case PHOTOMETRIC_MINISBLACK: |
---|
131 | if (minsamplevalue == 0 && maxsamplevalue == 255) |
---|
132 | break; |
---|
133 | /* fall thru... */ |
---|
134 | case PHOTOMETRIC_MINISWHITE: { |
---|
135 | register int x, range; |
---|
136 | |
---|
137 | range = maxsamplevalue - minsamplevalue + 1; |
---|
138 | Map = (RGBvalue *)malloc(range * sizeof (RGBvalue)); |
---|
139 | if (Map == NULL) { |
---|
140 | fprintf(stderr, |
---|
141 | "No space for photometric conversion table.\n"); |
---|
142 | return (0); |
---|
143 | } |
---|
144 | if (photometric == PHOTOMETRIC_MINISWHITE) { |
---|
145 | for (x = 0; x < range; x++) |
---|
146 | Map[x] = ((range - x) * 255) / range; |
---|
147 | } else { |
---|
148 | for (x = 0; x < range; x++) |
---|
149 | Map[x] = (x * 255) / range; |
---|
150 | } |
---|
151 | if (bitspersample < 8 && photometric != PHOTOMETRIC_RGB) { |
---|
152 | if (!makebwmap(Map)) |
---|
153 | return (0); |
---|
154 | /* no longer need Map, free it */ |
---|
155 | free((char *)Map); |
---|
156 | Map = NULL; |
---|
157 | } |
---|
158 | break; |
---|
159 | } |
---|
160 | case PHOTOMETRIC_PALETTE: |
---|
161 | if (!TIFFGetField(tif, TIFFTAG_COLORMAP, |
---|
162 | &redcmap, &greencmap, &bluecmap)) { |
---|
163 | fprintf(stderr, "Missing required \"Colormap\" tag.\n"); |
---|
164 | return (0); |
---|
165 | } |
---|
166 | break; |
---|
167 | } |
---|
168 | TIFFGetField(tif, TIFFTAG_PLANARCONFIG, &planarconfig); |
---|
169 | if (planarconfig == PLANARCONFIG_SEPARATE) |
---|
170 | e = gtseparate(tif, raster, Map, h, w); |
---|
171 | else |
---|
172 | e = gtcontig(tif, raster, Map, h, w); |
---|
173 | if (Map) |
---|
174 | free((char *)Map); |
---|
175 | return (e); |
---|
176 | } |
---|
177 | |
---|
178 | setorientation(tif, h) |
---|
179 | TIFF *tif; |
---|
180 | int h; |
---|
181 | { |
---|
182 | int y; |
---|
183 | |
---|
184 | if (!TIFFGetField(tif, TIFFTAG_ORIENTATION, &orientation)) |
---|
185 | orientation = ORIENTATION_TOPLEFT; |
---|
186 | switch (orientation) { |
---|
187 | case ORIENTATION_BOTRIGHT: |
---|
188 | case ORIENTATION_RIGHTBOT: /* XXX */ |
---|
189 | case ORIENTATION_LEFTBOT: /* XXX */ |
---|
190 | printf("Warning, using bottom-left orientation.\n"); |
---|
191 | orientation = ORIENTATION_BOTLEFT; |
---|
192 | /* fall thru... */ |
---|
193 | case ORIENTATION_BOTLEFT: |
---|
194 | y = 0; |
---|
195 | break; |
---|
196 | case ORIENTATION_TOPRIGHT: |
---|
197 | case ORIENTATION_RIGHTTOP: /* XXX */ |
---|
198 | case ORIENTATION_LEFTTOP: /* XXX */ |
---|
199 | printf("Warning, using top-left orientation.\n"); |
---|
200 | orientation = ORIENTATION_TOPLEFT; |
---|
201 | /* fall thru... */ |
---|
202 | case ORIENTATION_TOPLEFT: |
---|
203 | y = h-1; |
---|
204 | break; |
---|
205 | } |
---|
206 | return (y); |
---|
207 | } |
---|
208 | |
---|
209 | gtcontig(tif, raster, Map, h, w) |
---|
210 | TIFF *tif; |
---|
211 | u_long *raster; |
---|
212 | register RGBvalue *Map; |
---|
213 | int h, w; |
---|
214 | { |
---|
215 | register u_char *pp; |
---|
216 | register u_long *cp; |
---|
217 | register int x; |
---|
218 | int scanline, row, y; |
---|
219 | u_char *buf; |
---|
220 | |
---|
221 | buf = (u_char *)malloc(TIFFScanlineSize(tif)); |
---|
222 | if (buf == 0) { |
---|
223 | fprintf(stderr, "No space for scanline buffer\n"); |
---|
224 | return (0); |
---|
225 | } |
---|
226 | y = setorientation(tif, h); |
---|
227 | for (row = 0; row < h; row++) { |
---|
228 | if (TIFFReadScanline(tif, buf, row, 0) < 0) |
---|
229 | break; |
---|
230 | pp = buf; |
---|
231 | cp = raster + y*w; |
---|
232 | switch (photometric) { |
---|
233 | case PHOTOMETRIC_RGB: |
---|
234 | rgb: |
---|
235 | switch (bitspersample) { |
---|
236 | case 8: |
---|
237 | if (Map) { |
---|
238 | for (x = w; x-- > 0;) { |
---|
239 | pp[0] = Map[pp[0]]; |
---|
240 | pp[1] = Map[pp[1]]; |
---|
241 | pp[2] = Map[pp[2]]; |
---|
242 | pp += samplesperpixel; |
---|
243 | } |
---|
244 | pp = buf; |
---|
245 | } |
---|
246 | if(samplesperpixel == 4) { |
---|
247 | for(x = w; --x >= 0; pp += 4) |
---|
248 | *cp++ = rgba(pp[0], pp[1], pp[2],pp[3]); |
---|
249 | } else { |
---|
250 | for (x = w; x-- > 0; pp += samplesperpixel) |
---|
251 | *cp++ = rgbi(pp[0], pp[1], pp[2]); |
---|
252 | } |
---|
253 | break; |
---|
254 | case 16: { |
---|
255 | register u_short *wp; |
---|
256 | |
---|
257 | if (Map) { |
---|
258 | wp = (u_short *)pp; |
---|
259 | for (x = w; x-- > 0;) { |
---|
260 | wp[0] = Map[wp[0]]; |
---|
261 | wp[1] = Map[wp[1]]; |
---|
262 | wp[2] = Map[wp[2]]; |
---|
263 | wp += samplesperpixel; |
---|
264 | } |
---|
265 | } |
---|
266 | wp = (u_short *)pp; |
---|
267 | for (x = w; x-- > 0;) { |
---|
268 | *cp++ = rgbi(wp[0], wp[1], wp[2]); |
---|
269 | wp += samplesperpixel; |
---|
270 | } |
---|
271 | break; |
---|
272 | } |
---|
273 | } |
---|
274 | break; |
---|
275 | case PHOTOMETRIC_PALETTE: |
---|
276 | for (x = w; x-- > 0;) { |
---|
277 | RGBvalue c = *pp++; |
---|
278 | *cp++ = rgbi(redcmap[c], |
---|
279 | greencmap[c], bluecmap[c]); |
---|
280 | } |
---|
281 | break; |
---|
282 | case PHOTOMETRIC_MINISWHITE: |
---|
283 | case PHOTOMETRIC_MINISBLACK: |
---|
284 | if(samplesperpixel > 1) |
---|
285 | goto rgb; |
---|
286 | |
---|
287 | if (bitspersample == 8) { |
---|
288 | register RGBvalue c; |
---|
289 | |
---|
290 | for (x = w; x-- > 0;) { |
---|
291 | c = Map[*pp++]; |
---|
292 | *cp++ = rgbi(c, c, c); |
---|
293 | } |
---|
294 | } else |
---|
295 | gtbw(bitspersample, w, cp, pp); |
---|
296 | break; |
---|
297 | } |
---|
298 | y += (orientation == ORIENTATION_TOPLEFT ? -1 : 1); |
---|
299 | } |
---|
300 | return (1); |
---|
301 | } |
---|
302 | |
---|
303 | gtseparate(tif, raster, Map, h, w) |
---|
304 | TIFF *tif; |
---|
305 | u_long *raster; |
---|
306 | register RGBvalue *Map; |
---|
307 | int h, w; |
---|
308 | { |
---|
309 | register u_long *cp; |
---|
310 | register int x; |
---|
311 | u_char *red; |
---|
312 | int scanline, row, y; |
---|
313 | |
---|
314 | scanline = TIFFScanlineSize(tif); |
---|
315 | switch (samplesperpixel) { |
---|
316 | case 1: |
---|
317 | red = (u_char *)malloc(scanline); |
---|
318 | break; |
---|
319 | case 3: case 4: |
---|
320 | red = (u_char *)malloc(4*scanline); |
---|
321 | break; |
---|
322 | } |
---|
323 | y = setorientation(tif, h); |
---|
324 | for (row = 0; row < h; row++) { |
---|
325 | cp = raster + y*w; |
---|
326 | if (TIFFReadScanline(tif, red, row, 0) < 0) |
---|
327 | break; |
---|
328 | switch (photometric) { |
---|
329 | case PHOTOMETRIC_RGB: { |
---|
330 | register u_char *r, *g, *b, *a; |
---|
331 | |
---|
332 | r = red; |
---|
333 | if (TIFFReadScanline(tif, g = r + scanline, row, 1) < 0) |
---|
334 | break; |
---|
335 | if (TIFFReadScanline(tif, b = g + scanline, row, 2) < 0) |
---|
336 | break; |
---|
337 | if(samplesperpixel == 4) { |
---|
338 | a = b + scanline; |
---|
339 | if(TIFFReadScanline(tif, a, row, 3) < 0) |
---|
340 | break; |
---|
341 | } |
---|
342 | switch (bitspersample) { |
---|
343 | case 8: |
---|
344 | if(samplesperpixel == 4) { |
---|
345 | for(x = w; --x >= 0; ) |
---|
346 | *cp++ = rgba(*r++, *g++, *b++, *a++); |
---|
347 | } else { |
---|
348 | for (x = w; x-- > 0;) |
---|
349 | *cp++ = rgbi(*r++, *g++, *b++); |
---|
350 | } |
---|
351 | break; |
---|
352 | case 16: |
---|
353 | #define wp(x) ((u_short *)(x)) |
---|
354 | for (x = 0; x < w; x++) |
---|
355 | *cp++ = rgbi( |
---|
356 | Map[wp(r)[x]], |
---|
357 | Map[wp(g)[x]], |
---|
358 | Map[wp(b)[x]]); |
---|
359 | break; |
---|
360 | #undef wp |
---|
361 | } |
---|
362 | break; |
---|
363 | } |
---|
364 | case PHOTOMETRIC_PALETTE: { |
---|
365 | register u_char *pp = red; |
---|
366 | for (x = w; x-- > 0;) { |
---|
367 | RGBvalue c = *pp++; |
---|
368 | *cp++ = rgbi(redcmap[c], |
---|
369 | greencmap[c], bluecmap[c]); |
---|
370 | } |
---|
371 | break; |
---|
372 | } |
---|
373 | case PHOTOMETRIC_MINISWHITE: |
---|
374 | case PHOTOMETRIC_MINISBLACK: |
---|
375 | if (bitspersample == 8) { |
---|
376 | register u_short *pp = (u_short *)red; |
---|
377 | register RGBvalue c; |
---|
378 | |
---|
379 | for (x = w; x-- > 0;) { |
---|
380 | c = Map[*pp++]; |
---|
381 | *cp++ = rgbi(c, c, c); |
---|
382 | } |
---|
383 | } else |
---|
384 | gtbw(bitspersample, w, Map, cp, red); |
---|
385 | break; |
---|
386 | } |
---|
387 | y += (orientation == ORIENTATION_TOPLEFT ? -1 : 1); |
---|
388 | } |
---|
389 | if (red) |
---|
390 | free(red); |
---|
391 | return (1); |
---|
392 | } |
---|
393 | |
---|
394 | /* |
---|
395 | * Greyscale images with less than 8 bits/sample are handled |
---|
396 | * with a table to avoid lots of shits and masks. The table |
---|
397 | * is setup so that gtbw (below) can retrieve 8/bitspersample |
---|
398 | * pixel values simply by indexing into the table with one |
---|
399 | * number. |
---|
400 | */ |
---|
401 | makebwmap(Map) |
---|
402 | RGBvalue *Map; |
---|
403 | { |
---|
404 | register int i; |
---|
405 | int nsamples = 8 / bitspersample; |
---|
406 | register RGBvalue *p; |
---|
407 | |
---|
408 | BWmap = (RGBvalue **)malloc( |
---|
409 | 256*sizeof (RGBvalue *)+(256*nsamples*sizeof(RGBvalue))); |
---|
410 | if (BWmap == NULL) { |
---|
411 | fprintf(stderr, "No space for B&W mapping table.\n"); |
---|
412 | return (0); |
---|
413 | } |
---|
414 | p = (RGBvalue *)(BWmap + 256); |
---|
415 | for (i = 0; i < 256; i++) { |
---|
416 | BWmap[i] = p; |
---|
417 | switch (bitspersample) { |
---|
418 | case 1: |
---|
419 | *p++ = Map[i>>7]; |
---|
420 | *p++ = Map[(i>>6)&1]; |
---|
421 | *p++ = Map[(i>>5)&1]; |
---|
422 | *p++ = Map[(i>>4)&1]; |
---|
423 | *p++ = Map[(i>>3)&1]; |
---|
424 | *p++ = Map[(i>>2)&1]; |
---|
425 | *p++ = Map[(i>>1)&1]; |
---|
426 | *p++ = Map[i&1]; |
---|
427 | break; |
---|
428 | case 2: |
---|
429 | *p++ = Map[i>>6]; |
---|
430 | *p++ = Map[(i>>4)&3]; |
---|
431 | *p++ = Map[(i>>2)&3]; |
---|
432 | *p++ = Map[i&3]; |
---|
433 | break; |
---|
434 | case 4: |
---|
435 | *p++ = Map[i>>4]; |
---|
436 | *p++ = Map[i&0xf]; |
---|
437 | break; |
---|
438 | } |
---|
439 | } |
---|
440 | return (1); |
---|
441 | } |
---|
442 | |
---|
443 | #define REPEAT8(op) REPEAT4(op); REPEAT4(op) |
---|
444 | #define REPEAT4(op) REPEAT2(op); REPEAT2(op) |
---|
445 | #define REPEAT2(op) op; op |
---|
446 | |
---|
447 | gtbw(bitspersample, w, cp, pp) |
---|
448 | int bitspersample, w; |
---|
449 | register u_long *cp; |
---|
450 | register u_char *pp; |
---|
451 | { |
---|
452 | register RGBvalue c, *bw; |
---|
453 | register int x; |
---|
454 | |
---|
455 | switch (bitspersample) { |
---|
456 | case 1: |
---|
457 | for (x = w; x > 0; x -= 8) { |
---|
458 | bw = BWmap[*pp++]; |
---|
459 | REPEAT8(c = *bw++; *cp++ = rgbi(c, c, c)); |
---|
460 | } |
---|
461 | break; |
---|
462 | case 2: |
---|
463 | for (x = w; x > 0; x -= 4) { |
---|
464 | bw = BWmap[*pp++]; |
---|
465 | REPEAT4(c = *bw++; *cp++ = rgbi(c, c, c)); |
---|
466 | } |
---|
467 | break; |
---|
468 | case 4: |
---|
469 | for (x = w; x > 0; x -= 2) { |
---|
470 | bw = BWmap[*pp++]; |
---|
471 | REPEAT2(c = *bw++; *cp++ = rgbi(c, c, c)); |
---|
472 | } |
---|
473 | break; |
---|
474 | } |
---|
475 | } |
---|