1 /*
2 * xvpds.c - load routine for astronomical PDS/VICAR format pictures
3 * version of 6-4-93
4 *
5 * Anthony A. Datri
6 * Siemens Corporate Research
7 * 755 College Road East
8 * Princeton NJ 08540
9 * aad@scr.siemens.com
10 *
11 * Alexandra Aarhus-Dusenberg
12 * alexd@world.std.com
13 *
14 * 5-3-93 added leading spaces back into sscanf's -- some huffmanized
15 files have them.
16 * 5-2-93 slapped in Peter G. Ford <pgf@space.mit.edu>'s patches for
17 xv 3.00:
18 Adds code to Makefile to compile under SunOS 4.0.3 (as if anybody cares).
19 Improves PDS/VICAR file recognition.
20 Writes current directory name in Doggie's window title.
21 Handles (most) PDS and VICAR images correctly.
22 Choice of algorithm for 16->8 bit conversion--linear or histogram stretch.
23 (adds CONV24_HIST item in "24/8 bit" pull-down menu.)
24 Uses any "palette.tab" file in cwd to color PDS/VICAR image.
25
26 * 9-2-91 began integration. Much of this code is lifted from vicar.c,
27 which I wrote for xloadimage. This is a little simpler, though.
28
29 * 10-17-91 pdsuncomp is called with system(), which typically feeds the
30 commandline to sh. Make sure that your .profile adds wherever
31 you have pdsuncomp to the PATH, like
32
33 PATH=$PATH:/usr/local/bin
34
35 * 11-15-91 substituted vdcomp from Viking CD's for pdsuncomp. I added
36 recognition of - and shut off various messages
37
38 * 1-5-92 merged into xv rel 2
39
40 * 3-11-92 cleaned up some comments
41
42 * 3-24-92 Got some new CD's from NASA of mosics and other processed Viking
43 stuff. There are actually records terminated with CRNLCR in
44 these images, as well as ones that identify the spacecraft name
45 as {VIKING_ORBITER_1, VIKING_ORBITER_2}. I hacked up the code
46 yet further to deal with these. There's a Sun 4 XView binary for
47 an image display program on these discs, but it's nowhere near as
48 neat as the good Mr. Bradley's XV.
49
50
51 * Sources of these CD's:
52 *
53 * National Space Science Data Center
54 * Goddard Space Flight Center
55 * Code 933.4
56 * Greenbelt, Maryland
57 * (301) 286-6695
58 * or call
59 * (301) 286-9000 (300,1200,2400 bps)
60 * or telnet
61 * nssdca.gsfc.nasa.gov (128.183.10.4) and log in as 'NODIS' (no password).
62 *
63 * Randy Davis
64 * LASP
65 * University of Colorado
66 * Boulder CO 80309-0392
67 * (303) 492-6867
68 *
69 * These CD's are reasonably priced. Encourage the continue production
70 * of them by buying a set.
71 *
72 * There are three types of files that we deal with here. I'll call them
73 * PDS-labeled, PDS-labeled Huffman-encoded, and VICAR. Each consists of data
74 * prefixed with a set of ASCII headers. PDS-labeled and VICAR files are raw
75 * grayscale data, the dimensions of which can be found from the headers.
76 * PDS-labeled, Huffman-encoded files have the image information adaptively
77 * Huffman-encoded, and the encoding histogram follows the ASCII headers.
78 * To decode these, we use a slightly modified version of "vdcomp.c" from the
79 * NASA Viking CD-ROMS. For xv to work, you need to have vdcomp compiled
80 * and in your search path. vdcomp.c should be included with this distribution.
81 *
82 * I've heard that newer discs have FITS images on them. If they do, support
83 * for them will be added when I get one. Until then, you can use fitstopgm.
84 *
85 * LoadPDS(fname, numcols) - coerces a PDS/VICAR image
86 * WriteVICAR(fp, pic, w, h, r,g,b, numcols, style)
87 */
88
89 /*
90 * Copyright 1989, 1990 by Anthony A. Datri
91 *
92 * Permission to use, copy, and distribute for non-commercial purposes,
93 * is hereby granted without fee, providing that the above copyright
94 * notice appear in all copies, that both the copyright notice and this
95 * permission notice appear in supporting documentation.
96 *
97 * In exception to the above, permission to John Bradley is hereby granted to
98 * distribute this code as he sees fit within the context of his "xv" image
99 * viewer.
100 *
101 * This software is provided "as is" without any express or implied warranty.
102 */
103
104 #define NEEDSDIR /* for S_IRUSR|S_IWUSR */
105 #include "xv.h"
106
107 #ifdef HAVE_PDS
108
109
110 #define PDSFIXED (1)
111 #define PDSVARIABLE (2)
112 #define PDSTRASH (-1)
113 #define VICAR (3)
114 #define VIKINGFIXED (4) /* Viking discs have a unique variant */
115 #define VIKINGVARIABLE (5)
116
117
118 #ifndef TRUE
119 #define TRUE (1)
120 #define FALSE (0)
121 #endif
122
123 #define MAX_SIZE 20480 /* a guess -- even magellan images aren't
124 bigger than 2k x 2k */
125 #define RTBUFFSIZE 62 /* small buffer for magic */
126 #define FNAMESIZE 1024 /* too hard to generalize really getting it */
127 #define PDSUNCOMP "vdcomp" /* filter to un-Huffmanize */
128
129 /* This is arbitrary. Everything I've seen so far fits in 50 chars */
130 #define COMMENTSIZE 50
131 #define INOTESIZE 1000
132
133
134 static int lastwasinote = FALSE;
135 static char scanbuff [MAX_SIZE+1],
136 rtbuff [RTBUFFSIZE+1],
137 inote [INOTESIZE+1],
138 infobuff [COMMENTSIZE+1],
139 spacecraft [COMMENTSIZE+1],
140 target [COMMENTSIZE+1],
141 filtname [COMMENTSIZE+1],
142 gainmode [COMMENTSIZE+1],
143 editmode [COMMENTSIZE+1],
144 scanmode [COMMENTSIZE+1],
145 exposure [COMMENTSIZE+1],
146 shuttermode [COMMENTSIZE+1],
147 mphase [COMMENTSIZE+1],
148 iname [COMMENTSIZE+1],
149 itime [COMMENTSIZE+1],
150 garbage [1024],
151 *tmptmp,
152 pdsuncompfname[FNAMESIZE];
153
154 #define SSTR(l) "%" #l "s"
155 #define S(l) SSTR(l)
156
157 byte *image;
158 static int elaphe;
159
160
161
162 /* local function declarations */
163 static int getpdsrec PARM((FILE *, char *));
164 static int Convert16BitImage PARM((char *, PICINFO *, int));
165 static int LoadPDSPalette PARM((char *, PICINFO *));
166
167
168
169 /* Get a NULL-, CR-, or CRLF-terminated record from a PDS file */
170 /* The method of termination is unpredictable. A pox on VMS. */
171 /* Sometimes we even get mixtures of CR's and LF's. Sigh. */
172
getpdsrec(f,buff)173 static int getpdsrec(f,buff)
174 FILE *f;
175 char *buff;
176 {
177 static char *bp;
178 static int count;
179 int c;
180
181 /* read any leading CR's or LF's (sigh) */
182 *buff='\0';
183 bp=buff;
184 count = 0;
185 while (count==0) {
186 c=fgetc(f);
187 switch (c) {
188 case EOF: return(0);
189 case '\r':
190 case '\n': continue;
191 default: ungetc(c,f);
192 count = -1;
193 }
194 }
195
196 count=0;
197 bp=buff;
198 while (1) {
199 c=fgetc(f);
200 switch (c) {
201
202 case '\r': *bp='\0';
203 switch (c=fgetc(f)) {
204 case EOF:
205 case '\n': break;
206 default: ungetc(c,f);
207 }
208 return(count);
209
210 case EOF: *bp='\0'; return(count);
211
212 case '\0': return(count);
213
214 default: count++; *bp++ = c;
215 }
216 }
217 }
218
219
220 /* A VICAR image seems to begin with a one-line header describing all sorts
221 * of things, almost all of which don't mean much to Joe User, who just
222 * wants to see what Venus looks like. The first thing in this label is a
223 * string defining the size of the label, like "LBLSIZE=2048". Then there's
224 * other crud of variable usefulness. Important to us are the NL and NS
225 * fields, which seem to tell us the number of columns and rows, respectively.
226 * Among these other fields seem to be the local map coordinates of the region.
227 * These files are easy -- you can even convert one to usefulness by grabbing
228 * the dimensions and lblsize and feeding to rawtopgm. Example, if lblsize,
229 * nl, and ns are 2048, 1536, and 2048, respectively, use "rawtopgm -headerskip
230 * 2048 2048 1536 <foo.img >foo.pgm. All of the samples I've seen are 8 bits
231 * deep, so we assume that. Yeah, yeah, that's nasty and evil, and I'm
232 * terribly ashamed of it, but I'm not going to bother with bit fiddling
233 * until I see an image that needs it. I once had a 16-bit Galileo image of
234 * Venus, but it got lost (sigh).
235 *
236 * These images are typically fairly big, so it makes sense to verify the
237 * format before we try to read it all in.
238 *
239 * PDS images are prefixed like this:
240 *
241 * od -a c2061139.imq | head -a
242 * 0000000 - nul N J P L 1 I 0 0 P D S 1 0 0
243 *
244 * so we'll read off the first two chars, which seem to be a length field
245 * of some kind, then look for NJPL.. Images on the Sampler
246 * disc seem to leave off the first two bytes. Sigh. This may sometimes be
247 * a distinction between the fixed and variable-record files.
248 */
249
250 /*******************************************/
LoadPDS(fname,pinfo)251 int LoadPDS(fname, pinfo)
252 char *fname;
253 PICINFO *pinfo;
254 {
255 /* returns '1' on success, '0' on failure */
256
257 int tempnum, bytewidth, bufsize;
258 #ifndef USE_MKSTEMP
259 int tmpfd;
260 #endif
261 FILE *zf;
262 static int isfixed,teco,i,j,itype,vaxbyte,
263 recsize,hrecsize,irecsize,isimage,labelrecs,labelsofar,
264 w,h,lpsize,lssize,samplesize,returnp,labelsize,yy;
265 char *tmp;
266 const char *ftypstr;
267 unsigned long filesize;
268 char sampletype[64];
269
270 pinfo->type = PIC8;
271 isfixed = TRUE;
272 returnp = isimage = FALSE;
273 itype = PDSTRASH;
274
275 teco = i = j = recsize = hrecsize = irecsize = labelrecs = w = h = 0;
276 lpsize = lssize = samplesize = labelsize = labelsofar = 0;
277
278 (*pdsuncompfname) = (*iname) = (*target) = (*filtname) = (*garbage) = '\0';
279 (*itime) = (*spacecraft) = (*scanbuff) = (*mphase) = (*rtbuff) = '\0';
280 (*sampletype) = (*inote) = (*infobuff) = (*gainmode) = (*editmode) = '\0';
281 (*scanmode) = (*exposure) = (*shuttermode) = '\0';
282
283 /* there may be some wisdom in statically mallocing space for an 800x800
284 image, since that's what the Voyager cd's have, or even a 2kx2k, since
285 some of the Magellan images from Ames are that size */
286
287 zf = xv_fopen(fname,"r");
288 if (!zf) {
289 SetISTR(ISTR_WARNING,"LoadPDS: can't open %s\n",fname);
290 return 0;
291 }
292
293 /* figure out the file size (for Informational Purposes Only) */
294 fseek(zf, 0L, 2);
295 filesize = ftell(zf);
296 fseek(zf, 0L, 0);
297
298 /* read the magic. If it's got two bytes of crud in front of it, it's
299 a screwy "variable-length-record" file. We have to jump through
300 bloody VAX hoops to find out how long the record is. Sigh. Have
301 people never heard of newlines? */
302
303 if ((teco=fread(rtbuff,(size_t) 13, (size_t) 1,zf)) != 1) {
304 SetISTR(ISTR_WARNING,"LoadPDS: couldn't read magic #: %d,%s",teco,fname);
305 fclose(zf);
306 return 0;
307 }
308
309 /* this makes sscanf so much happier */
310 rtbuff[RTBUFFSIZE-1] = '\0';
311
312 if (strncmp(rtbuff, "NJPL1I00PDS", (size_t) 11) == 0) {
313 itype=PDSFIXED;
314 } else if (strncmp(rtbuff+2,"NJPL1I00PDS", (size_t) 11) == 0) {
315 itype=PDSVARIABLE;
316 } else if (strncmp(rtbuff,"CCSD3Z", (size_t) 6) == 0) {
317 itype=VIKINGFIXED; /* unique variant of PDS on Viking discs (browse) */
318 } else if (strncmp(rtbuff+2,"CCSD3Z", (size_t) 6) == 0) {
319 itype=VIKINGVARIABLE;
320 } else if (sscanf(rtbuff,"LBLSIZE = %d%n",&labelsize,&labelsofar) == 1) {
321 itype=VICAR;
322 } else {
323 SetISTR(ISTR_WARNING,"LoadPDS: can't handle this file, for some reason\n");
324 fclose(zf);
325 return 0;
326 }
327
328 switch (itype) {
329 case PDSFIXED:
330 case VICAR:
331 case VIKINGFIXED: isfixed=TRUE;
332 sprintf(pinfo->fullInfo,
333 "PDS/VICAR, 8 bits per pixel. (%ld bytes)",
334 filesize);
335 break;
336 case PDSVARIABLE:
337 case VIKINGVARIABLE: isfixed=FALSE;
338 sprintf(pinfo->fullInfo,
339 "Huffman-encoded PDS, 8 bits per pixel. (%ld bytes)",
340 filesize);
341 }
342
343 if ((itype == PDSFIXED) || (itype == PDSVARIABLE) ||
344 (itype == VIKINGFIXED) || (itype == VIKINGVARIABLE)) {
345
346 if (isfixed == FALSE) {
347 teco = ((*rtbuff) + ((*(rtbuff+1)) << 8));
348 fread(rtbuff, (size_t) ((teco%2 ? teco+1 : teco) - 11),(size_t) 1, zf);
349 }
350
351 /* We know that we've got a PDS file of some sort. We have to
352 search through the labels looking for things because usage doesn't seem
353 to be consistent, or even predictable. */
354
355 for (;;) {
356 if (isfixed) {
357 if (getpdsrec(zf,scanbuff) == 0) {
358 SetISTR(ISTR_WARNING,"corrupt or incomplete PDS labels (low fread)");
359 break;
360 }
361 } else {
362 /* AAAARGGGGH! We've got a bloody variable-length file where
363 * the headers are preceded by a byte count, as a VAX 16-bit
364 * integer of all things.
365 *
366 * "A compressed image file is composed of variable-length records
367 * defined according to the ISO standard. Each variable length
368 * record starts with a record length indicator, stored as a 16-bit
369 * integer, followed by the number of bytes indicated in the record
370 * length indicator. If the length indicator is odd, then a pad byte
371 * is appended to the end of the record so that all records contain
372 * an even number of bytes." */
373
374 i=getc(zf);
375 j=getc(zf);
376 if (j == EOF) {
377 SetISTR(ISTR_WARNING,"LoadPDS: j is EOF\n");
378 fclose(zf);
379 return 0;
380 }
381
382 teco = i + (j << 8);
383 if (teco % 2) teco++;
384
385 if (fread(scanbuff, (size_t) teco, (size_t) 1, zf) != 1) {
386 SetISTR(ISTR_WARNING,"LoadPDS: bad fread reading labels\n");
387 fclose(zf);
388 return 0;
389 }
390
391 scanbuff[teco]='\0';
392 }
393
394 /* otay, we've managed to wrestle a header of some sort from the
395 file -- now we grep through until we hit the END, at which point
396 we break out of the loop and see what we've got. In the future,
397 we'll check for informational headers and write them out if the
398 fool user wants them. There seems to be disagreement about what
399 the headers are called, since we might find, for example, either
400 TARGET_BODY or TARGET_NAME. Bloody 'ell. I think the problem
401 is that there isn't an actual *standard* for these formats, or
402 the standard isn't widely available, so
403 people kinda make it up as they go along. */
404
405 if (strcmp(scanbuff,"END") == 0) {
406 break;
407 } else if (sscanf(scanbuff, " RECORD_TYPE = " S(RTBUFFSIZE), rtbuff) == 1) {
408 if (strncmp(rtbuff,"VARIABLE_LENGTH", (size_t) 15) == 0) {
409 /* itype=PDSVARIABLE; */
410 } else if (strncmp(rtbuff,"FIXED_LENGTH", (size_t) 12) == 0) {
411 /* itype=PDSFIXED;*/
412 } else {
413 rtbuff[RTBUFFSIZE-1]='\0'; /* juuuust in case */
414 SetISTR(ISTR_WARNING,
415 "LoadPDS: unsupported record type \"%s\"\n",rtbuff);
416 fclose(zf);
417 return 0;
418 }
419 lastwasinote=FALSE;
420 } else if (sscanf(scanbuff," RECORD_BYTES = %d",&recsize) == 1) {
421 /* these default to RECORD_BYTES unless explicitly set */
422 if (hrecsize == 0) hrecsize=recsize;
423 if (irecsize == 0) irecsize=recsize;
424 lastwasinote=FALSE;
425 continue;
426 } else if (sscanf(scanbuff, " FILE_TYPE = " S(RTBUFFSIZE), rtbuff) != 0) {
427 lastwasinote=FALSE;
428 if (strncmp(rtbuff,"IMAGE", (size_t) 5) == 0) {
429 isimage=TRUE;
430 continue;
431 } else {
432 isimage=FALSE;
433 break;
434 }
435 } else if ((sscanf(scanbuff," HEADER_RECORDS = %d",&labelrecs) == 1) ||
436 (sscanf(scanbuff," LABEL_RECORDS = %d", &labelrecs) == 1)) {
437 lastwasinote=FALSE;
438 continue;
439 } else if (sscanf(scanbuff," IMAGE_LINES = %d",&h) == 1) {
440 isimage=TRUE; lastwasinote=FALSE; continue;
441 } else if (sscanf(scanbuff," LINE_SAMPLES = %d",&w) == 1) {
442 lastwasinote=FALSE; continue;
443 } else if (sscanf(scanbuff," LINES = %d",&h) == 1) {
444 isimage=TRUE; lastwasinote=FALSE; continue;
445 } else if (sscanf(scanbuff," HEADER_RECORD_BYTES = %d",&hrecsize)==1) {
446 lastwasinote=FALSE; continue;
447 } else if (sscanf(scanbuff," IMAGE_RECORD_BYTES = %d",&irecsize)==1) {
448 lastwasinote=FALSE; continue;
449 } else if (sscanf(scanbuff," LINE_PREFIX_BYTES = %d",&lpsize)==1) {
450 lastwasinote=FALSE; continue;
451 } else if (sscanf(scanbuff," LINE_SUFFIX_BYTES = %d",&lssize)==1) {
452 lastwasinote=FALSE; continue;
453 } else if (sscanf(scanbuff," SAMPLE_BITS = %d", &samplesize) == 1) {
454 lastwasinote=FALSE; continue;
455 } else if (sscanf(scanbuff, " SAMPLE_TYPE = " S(64), sampletype) == 1) {
456 lastwasinote=FALSE; continue;
457 } else if (sscanf(scanbuff," SPACECRAFT_NAME = " S(COMMENTSIZE) " " S(1023),
458 spacecraft,garbage) == 2 ) {
459 const char *tmp = xv_strstr(scanbuff, spacecraft) + strlen(spacecraft);
460 strncat(spacecraft, tmp, COMMENTSIZE - strlen(spacecraft));
461 lastwasinote=FALSE; continue;
462 } else if (sscanf(scanbuff, " SPACECRAFT_NAME = " S(COMMENTSIZE), spacecraft) == 1) {
463 lastwasinote=FALSE; continue;
464
465 } else if (sscanf(scanbuff, " TARGET_NAME = " S(COMMENTSIZE), target) == 1) {
466 lastwasinote=FALSE; continue;
467 } else if (sscanf(scanbuff, " TARGET_BODY = " S(COMMENTSIZE), target) == 1) {
468 lastwasinote=FALSE; continue;
469
470 } else if (sscanf(scanbuff, " MISSION_PHASE_NAME = " S(COMMENTSIZE), mphase) == 1) {
471 lastwasinote=FALSE; continue;
472 } else if (sscanf(scanbuff, " MISSION_PHASE = " S(COMMENTSIZE), mphase) == 1) {
473 lastwasinote=FALSE; continue;
474
475 } else if (sscanf(scanbuff, " INSTRUMENT_NAME = " S(COMMENTSIZE), iname) == 1) {
476 lastwasinote=FALSE; continue;
477
478 } else if (sscanf(scanbuff, " GAIN_MODE_ID = " S(COMMENTSIZE), gainmode) == 1) {
479 lastwasinote=FALSE; continue;
480
481 } else if (sscanf(scanbuff, " INSTRUMENT_GAIN_STATE = " S(COMMENTSIZE), gainmode) ==1 ) {
482 lastwasinote=FALSE; continue;
483
484 } else if (sscanf(scanbuff, " EDIT_MODE_ID = " S(COMMENTSIZE), editmode) == 1) {
485 lastwasinote=FALSE; continue;
486
487 } else if (sscanf(scanbuff, " INSTRUMENT_EDIT_MODE = " S(COMMENTSIZE), editmode) == 1) {
488 lastwasinote=FALSE; continue;
489
490 } else if (sscanf(scanbuff, " SCAN_MODE_ID = " S(COMMENTSIZE), scanmode) == 1) {
491 lastwasinote=FALSE; continue;
492
493 } else if (sscanf(scanbuff, " INSTRUMENT_SCAN_RATE = " S(COMMENTSIZE), scanmode) == 1) {
494 lastwasinote=FALSE; continue;
495
496 } else if (sscanf(scanbuff, " SHUTTER_MODE_ID = " S(COMMENTSIZE), shuttermode) == 1) {
497 lastwasinote=FALSE; continue;
498
499 } else if (sscanf(scanbuff, " INSTRUMENT_SHUTTER_MODE = " S(COMMENTSIZE), shuttermode) == 1) {
500 lastwasinote=FALSE; continue;
501
502 } else if (sscanf(scanbuff, " SCAN_MODE_ID = " S(COMMENTSIZE), scanmode) == 1) {
503 lastwasinote=FALSE; continue;
504
505 } else if (sscanf(scanbuff, " INSTRUMENT_SCAN_RATE = " S(COMMENTSIZE), scanmode) == 1) {
506 lastwasinote=FALSE; continue;
507
508 } else if (sscanf(scanbuff, " SPACECRAFT_EVENT_TIME = " S(COMMENTSIZE), itime) == 1) {
509 lastwasinote=FALSE; continue;
510
511 } else if (sscanf(scanbuff, " IMAGE_TIME = " S(COMMENTSIZE), itime) == 1) {
512 lastwasinote=FALSE; continue;
513
514 } else if (sscanf(scanbuff, " FILTER_NAME = " S(COMMENTSIZE), filtname) == 1) {
515 lastwasinote=FALSE; continue;
516
517 } else if (sscanf(scanbuff, " INSTRUMENT_FILTER_NAME = " S(COMMENTSIZE), filtname) == 1) {
518 lastwasinote=FALSE; continue;
519
520 } else if ((sscanf(scanbuff, " EXPOSURE_DURATION = " S(COMMENTSIZE), exposure) == 1)
521 || (sscanf(scanbuff, " INSTRUMENT_EXPOSURE_DURATION = " S(COMMENTSIZE),
522 exposure)) == 1) {
523 tmptmp = (char *) index(scanbuff,'=');
524 tmptmp++;
525 while((*tmptmp) == ' ')
526 tmptmp++;
527 strcpy(exposure,tmptmp);
528 lastwasinote=FALSE; continue;
529
530 } else if (sscanf(scanbuff, "NOTE = " S(INOTESIZE), inote) == 1) {
531 tmptmp = (char *) index(scanbuff,'='); tmptmp++;
532 while (((*tmptmp) == ' ') || ((*tmptmp) == '"')) tmptmp++;
533 strncpy(inote, tmptmp, INOTESIZE - 1);
534 strcat(inote," ");
535
536 /* evil and somewhat risky: A "note" (really, any textual
537 * field) can span records until " is reached. If I ever
538 * get my hands on the clown who designed this format...
539 * What we basically assume here
540 * is that a NOTE record that doesn't end with a " is
541 * followed by some number of continuations, one of which
542 * will have a " in it. If this turns out to not be true,
543 * well, we'll segmentation fault real soon. We use
544 * lastwasinote as a semaphore to indicate that the previous
545 * record was an unfinished NOTE record. We clear the
546 * flag in each of the above record types for potential
547 * error recovery, although it really breaks up the beauty
548 * of the cascading sscanfs. Dykstra'd love me for this one */
549
550 if (inote[strlen(inote)-1] != '"')
551 lastwasinote=TRUE;
552 else lastwasinote=FALSE;
553 continue;
554
555 } else if (lastwasinote) {
556 tmptmp=scanbuff;
557 while (((*tmptmp) == ' ') || ((*tmptmp) == '"')) tmptmp++;
558 strncat(inote, tmptmp, INOTESIZE - strlen(inote) - 1);
559 strcat(inote," ");
560 if (index(tmptmp,'"') != NULL)
561 lastwasinote=FALSE;
562 continue;
563 }
564 }
565
566 elaphe=strlen(inote)-1;
567 while ( (inote[elaphe] == ' ') || (inote[elaphe] == '"')) {
568 inote[elaphe--]='\0';
569 }
570 if ((isimage == TRUE) && (labelsize=(labelrecs * hrecsize))) {
571 ;
572 } else {
573 SetISTR(ISTR_WARNING,
574 "This looks like a PDS/VICAR image, but not enough.\n");
575 fclose(zf);
576 return 0;
577 }
578
579 vaxbyte = strncmp(sampletype, "VAX_", (size_t) 4) == 0 ||
580 strncmp(sampletype, "LSB_", (size_t) 4) == 0;
581
582 } else if (itype == VICAR) {
583 /* we've got a VICAR file. Let's find out how big the puppy is */
584 ungetc(' ', zf);
585 --labelsofar;
586
587 if (fread(scanbuff, (size_t) (labelsize-labelsofar),(size_t) 1,zf) == 1) {
588 if ((tmp = (char *) xv_strstr(scanbuff," NL=")) == NULL) {
589 SetISTR(ISTR_WARNING,"LoadPDS: bad NL in VICAR\n");
590 returnp=TRUE;
591 }
592
593 if (sscanf(tmp," NL = %d",&h) != 1) {
594 SetISTR(ISTR_WARNING,"LoadPDS: bad scan NL in VICAR\n");
595 returnp=TRUE;
596 }
597
598 if ((tmp = (char *) xv_strstr(scanbuff, " NS=")) == NULL) {
599 SetISTR(ISTR_WARNING,"LoadPDS: bad NS in VICAR\n");
600 returnp=TRUE;
601 }
602
603 if (sscanf(tmp, " NS = %d",&w) != 1) {
604 SetISTR(ISTR_WARNING,"LoadPDS: bad scan NS in VICAR\n");
605 returnp=TRUE;
606 }
607
608 if ( (tmp=(char *) xv_strstr(scanbuff, " NBB=")))
609 if (sscanf(tmp, " NBB = %d",&lpsize) != 1) {
610 SetISTR(ISTR_WARNING,"LoadPDS: bad scan NBB in VICAR\n");
611 returnp=TRUE;
612 }
613
614 vaxbyte = (xv_strstr(scanbuff, " INTFMT='HIGH'") == NULL);
615
616 if (xv_strstr(scanbuff, " FORMAT='BYTE'"))
617 samplesize = 8;
618 else if (xv_strstr(scanbuff, " FORMAT='HALF'"))
619 samplesize = 16;
620 else if (xv_strstr(scanbuff, " FORMAT=")) {
621 SetISTR(ISTR_WARNING,"LoadPDS: unsupported FORMAT in VICAR\n");
622 returnp=TRUE;
623 } else {
624 SetISTR(ISTR_WARNING,"LoadPDS: bad FORMAT in VICAR\n");
625 returnp=TRUE;
626 }
627
628 }
629
630 } else {
631 SetISTR(ISTR_WARNING,"LoadPDS: Unable to parse data.\n");
632 returnp=TRUE;
633 }
634
635 /* samplesize can be arbitrarily large (up to int limit) in non-VICAR files */
636 if (samplesize != 8 && samplesize != 16) {
637 SetISTR(ISTR_WARNING,"LoadPDS: %d bits per pixel not supported",
638 samplesize);
639 returnp=TRUE;
640 }
641
642 if (returnp) {
643 fclose(zf);
644 return 0;
645 }
646
647 /* PDS files tend to have lots of information like this in them. The
648 * following are a few of the more interesting headers. We'd do more, but
649 * there's only so much space in the info box. I tried to pick a
650 * reasonable subset of these to display; if you want others, it's easy
651 * to change the set. XV 3.00 has a comment window where we write this
652 * stuff in glorious detail. Now, if I only had a clue as to what these
653 * fields actually *mean* ... */
654
655 *infobuff='\0';
656 if (*spacecraft) {
657 strncat(infobuff, spacecraft, sizeof(infobuff) - 1);
658 }
659
660 if (*target) {
661 strncat(infobuff, ", ", sizeof(infobuff) - strlen(infobuff) - 1);
662 strncat(infobuff, target, sizeof(infobuff) - strlen(infobuff) - 1);
663 }
664
665 if (*filtname) {
666 strncat(infobuff, ", ", sizeof(infobuff) - strlen(infobuff) - 1);
667 strncat(infobuff, filtname, sizeof(infobuff) - strlen(infobuff) - 1);
668 }
669
670 if (*itime) {
671 strncat(infobuff, ", ", sizeof(infobuff) - strlen(infobuff) - 1);
672 strncat(infobuff, itime, sizeof(infobuff) - strlen(infobuff) - 1);
673 }
674
675 SetISTR(ISTR_WARNING, "%s", infobuff);
676
677 strncpy(pdsuncompfname,fname,sizeof(pdsuncompfname) - 1);
678 ftypstr = "";
679
680 switch (itype) {
681 case VICAR:
682 sprintf(pinfo->fullInfo,"VICAR, %d bits per pixel. (%ld bytes)",
683 samplesize, filesize);
684 ftypstr = "VICAR";
685 rewind(zf);
686 break;
687
688 case PDSFIXED:
689 case VIKINGFIXED:
690 sprintf(pinfo->fullInfo,"PDS, %d bits per pixel. (%ld bytes)",
691 samplesize, filesize);
692 ftypstr = "PDS";
693 rewind(zf);
694 break;
695
696 case PDSVARIABLE:
697 case VIKINGVARIABLE:
698 sprintf(pinfo->fullInfo,
699 "PDS, %d bits per pixel, Huffman-encoded. (%ld bytes)",
700 samplesize, filesize);
701 ftypstr = "PDS (Huffman)";
702 fclose(zf);
703
704 #ifndef VMS
705 snprintf(pdsuncompfname, sizeof(pdsuncompfname) - 1, "%s/xvhuffXXXXXX", tmpdir);
706 #else
707 strcpy(pdsuncompfname,"sys$disk:[]xvhuffXXXXXX");
708 #endif
709
710 #ifdef USE_MKSTEMP
711 close(mkstemp(pdsuncompfname));
712 #else
713 mktemp(pdsuncompfname);
714 tmpfd = open(pdsuncompfname,O_WRONLY|O_CREAT|O_EXCL,S_IRWUSR);
715 if (tmpfd < 0) {
716 SetISTR(ISTR_WARNING,"Unable to create temporary file.");
717 return 0;
718 }
719 close(tmpfd);
720 #endif
721
722 #ifndef VMS
723 sprintf(scanbuff,"%s '%s' - 4 > %s", PDSUNCOMP, fname, pdsuncompfname);
724 #else
725 sprintf(scanbuff,"%s %s %s 4",PDSUNCOMP,fname,pdsuncompfname);
726 #endif
727
728 SetISTR(ISTR_INFO,"De-Huffmanizing '%s'...",fname);
729
730 /* pdsuncomp filters to a raw file */
731 #ifndef VMS
732 if ( (tempnum=system(scanbuff)) ) {
733 SetISTR(ISTR_WARNING,"Unable to de-Huffmanize '%s'.",fname);
734 return 0;
735 }
736 #else
737 if ( (tempnum = !system(scanbuff)) ) {
738 SetISTR(ISTR_WARNING,"Unable to de-Huffmanize '%s'.",fname);
739 return 0;
740 }
741 #endif
742
743
744 zf = xv_fopen(pdsuncompfname,"r");
745 if (!zf) {
746 SetISTR(ISTR_WARNING,"LoadPDS: can't open uncompressed file %s\n",
747 pdsuncompfname);
748 return 0;
749 }
750 }
751
752 /* skip headers */
753
754 if ( isfixed == TRUE ) {
755 fread(scanbuff, (size_t) labelsize, (size_t) 1, zf);
756 }
757
758 /* samplesize is bits per pixel; guaranteed at this point to be 8 or 16 */
759 bytewidth = w * (samplesize/8);
760 bufsize = bytewidth * h;
761 if (w <= 0 || h <= 0 || bytewidth/w != (samplesize/8) ||
762 bufsize/bytewidth != h)
763 {
764 SetISTR(ISTR_WARNING,"LoadPDS: image dimensions out of range (%dx%dx%d)",
765 w, h, samplesize/8);
766 fclose(zf);
767 return 0;
768 }
769
770 image = (byte *) malloc((size_t) bufsize);
771 if (image == NULL) {
772 fclose(zf);
773 if (isfixed == FALSE)
774 unlink(pdsuncompfname);
775 FatalError("LoadPDS: can't malloc image buffer");
776 }
777
778 if ((lssize || lpsize) &&
779 ((itype == PDSFIXED) || (itype == VIKINGFIXED) || (itype == VICAR)) ) {
780 /* ARrrrgh. Some of these images have crud intermixed with the image, */
781 /* preventing us from freading in one fell swoop */
782 /* (whatever a fell swoop is) */
783
784 for (yy=0; yy<h; yy++) {
785 if (lpsize &&
786 (teco=fread(scanbuff,(size_t) lpsize,(size_t) 1,zf)) != 1) {
787 SetISTR(ISTR_WARNING, "LoadPDS: unexpected EOF reading prefix");
788 fclose(zf);
789 return 0;
790 }
791
792 teco = fread(image+(yy*bytewidth), (size_t) bytewidth, (size_t) 1,zf);
793 if (teco != 1) {
794 SetISTR(ISTR_WARNING, "LoadPDS: unexpected EOF reading line %d",yy);
795 fclose(zf);
796 return 0;
797 }
798
799 if (lssize &&
800 (teco=fread(scanbuff,(size_t) lssize,(size_t) 1,zf)) != 1) {
801 SetISTR(ISTR_WARNING, "LoadPDS: unexpected EOF reading suffix");
802 fclose(zf);
803 return 0;
804 }
805 }
806
807 } else if ((yy=fread(image, (size_t) bytewidth*h, (size_t) 1, zf)) != 1) {
808 SetISTR(ISTR_WARNING,"LoadPDS: error reading image data");
809 fclose(zf);
810 if (itype==PDSVARIABLE || itype==VIKINGVARIABLE)
811 unlink(pdsuncompfname);
812 return 0;
813 }
814
815 fclose(zf);
816
817
818 if (isfixed == FALSE)
819 unlink(pdsuncompfname);
820
821 pinfo->pic = image;
822 pinfo->w = w; /* true pixel-width now (no longer bytewidth!) */
823 pinfo->h = h;
824
825 if (samplesize == 16)
826 if (Convert16BitImage(fname, pinfo,
827 vaxbyte ^ (*(char *)&samplesize == 16)) == 0)
828 return 0;
829
830 pinfo->frmType = -1; /* can't save as PDS */
831 pinfo->colType = F_GREYSCALE;
832 sprintf(pinfo->shrtInfo, "%dx%d %s. ", pinfo->w, pinfo->h, ftypstr);
833
834 pinfo->comment = (char *) malloc((size_t) 2000);
835 if (pinfo->comment) {
836 char tmp[256];
837 *(pinfo->comment) = '\0';
838
839 sprintf(tmp, "Spacecraft: %-28.28sTarget: %-32.32s\n", spacecraft, target);
840 strncat(pinfo->comment, tmp, 2000 - strlen(pinfo->comment) - 1);
841
842 sprintf(tmp, "Filter: %-32.32sMission phase: %-24.24s\n", filtname, mphase);
843 strncat(pinfo->comment, tmp, 2000 - strlen(pinfo->comment) - 1);
844
845 sprintf(tmp, "Image time: %-28.28sGain mode: %-29.29s\n", itime, gainmode);
846 strncat(pinfo->comment, tmp, 2000 - strlen(pinfo->comment) - 1);
847
848 sprintf(tmp, "Edit mode: %-29.29sScan mode: %-29.29s\n", editmode, scanmode);
849 strncat(pinfo->comment, tmp, 2000 - strlen(pinfo->comment) - 1);
850
851 sprintf(tmp, "Exposure: %-30.30sShutter mode: %-25.25s\n", exposure,shuttermode);
852 strncat(pinfo->comment, tmp, 2000 - strlen(pinfo->comment) - 1);
853
854 sprintf(tmp, "Instrument: %-28.28sImage time: %-28.28s\n", iname, itime);
855 strncat(pinfo->comment, tmp, 2000 - strlen(pinfo->comment) - 1);
856
857 sprintf(tmp, "Image Note: %-28.28s", inote);
858 strncat(pinfo->comment, tmp, 2000 - strlen(pinfo->comment) - 1);
859 }
860
861 if (LoadPDSPalette(fname, pinfo)) return 1;
862
863 /* these are grayscale, so cobble up a ramped colormap */
864 /* Viking images on the CD's seem to be inverted. Sigh */
865
866 switch (itype) {
867 case PDSVARIABLE:
868 case PDSFIXED:
869 case VICAR:
870 for (yy=0; yy<=255; yy++) {
871 pinfo->r[yy] = pinfo->g[yy] = pinfo->b[yy] = yy;
872 }
873 break;
874
875 case VIKINGFIXED:
876 case VIKINGVARIABLE:
877 for (yy=0; yy<=255; yy++) {
878 pinfo->r[yy] = pinfo->g[yy] = pinfo->b[yy] = (255-yy);
879 }
880 }
881
882 pinfo->normw = pinfo->w; pinfo->normh = pinfo->h;
883 return 1;
884 }
885
886
887
888 /*
889 * 16-bit to 8-bit conversion
890 */
891
892 /*******************************************/
Convert16BitImage(fname,pinfo,swab)893 static int Convert16BitImage(fname, pinfo, swab)
894 char *fname;
895 PICINFO *pinfo;
896 int swab;
897 {
898 unsigned short *pShort;
899 long i, j, k, l, n, *hist, nTot;
900 size_t m;
901 byte *lut, *pPix8;
902 FILE *fp;
903 char name[1024], *c;
904
905 m = 65536 * sizeof(byte);
906 lut = (byte *) malloc(m);
907 if (lut == NULL) {
908 FatalError("LoadPDS: can't malloc LUT buffer");
909 }
910
911 /* allocate histogram table */
912 m = 65536 * sizeof(long);
913 hist = (long *) malloc(m);
914 if (hist == NULL) {
915 free(lut);
916 FatalError("LoadPDS: can't malloc histogram buffer");
917 }
918
919 /* check whether histogram file exists */
920 #ifdef VMS
921 c = (char *) rindex(strcpy(name,
922 (c = (char *) rindex(fname, ':')) ? c+1 : fname),
923 ']');
924 #else
925 c = (char *) rindex(strcpy(name, fname), '/');
926 #endif /* VMS */
927 (void)strcpy(c ? c+1 : name, "hist.tab");
928
929 /* read the histogram file which is always LSB_INTEGER */
930 if ((fp = xv_fopen(name, "r")) != NULL) {
931 for (n = k = nTot = 0; n < 65536 && k != EOF; n++, nTot += j) {
932 for (i = j = 0; i < 4 && (k = getc(fp)) != EOF; i++)
933 j = ((j >> 8) & 0xffffff) | ((k & 255) << 24);
934 hist[swab ? ((n & 255) << 8) | ((n >> 8) & 255) : n] = j;
935 }
936 fclose(fp);
937 if (k == EOF)
938 fp = NULL;
939 }
940
941 /* if no external histogram, make one */
942 if (fp == NULL) {
943 for (n = 0; n < 65536; n++)
944 hist[n] = 0;
945 nTot = n = pinfo->h * pinfo->w;
946 pShort = (unsigned short *)pinfo->pic;
947 while (--n >= 0) {
948 hist[*pShort++]++;
949 }
950 }
951
952 /* use either histogram equalization or linear stretch */
953 if (0) { /* was: (conv24MB.flags[CONV24_HIST]) */
954
955 /* construct lookup table to invert the histogram */
956 m = l = hist[0];
957 i = (nTot - m) >> 8;
958 for (n = j = 1; n < 65536; n++) {
959 k = swab ? ((n & 255) << 8) | ((n >> 8) & 255) : n;
960 if ((l += hist[k]) > m && j < 255)
961 j++, m += i;
962 lut[k] = j;
963 }
964
965 } else {
966
967 /* find min and max of histogram */
968 n = nTot/10000;
969 for (m = 0, j = 1; j < 65536; j++)
970 if ((m += hist[swab ? ((j & 255) << 8) | ((j >> 8) & 255) : j]) > n)
971 break;
972 for (m = 0, k = 65535; --k > 1; )
973 if ((m += hist[swab ? ((k & 255) << 8) | ((k >> 8) & 255) : k]) > n)
974 break;
975
976 /* construct stretch table */
977 for (n = 0; n < 65536; n++) {
978 i = swab ? (((n & 255) << 8) | ((n >> 8) & 255)) : n;
979 m = 1 + (254 * (n - j)) / (k - j);
980 lut[i] = n < j ? 0 : (n > k ? 255 : m);
981 }
982 }
983
984 free(hist);
985
986 /* allocate new 8-bit image */
987 n = pinfo->w * pinfo->h;
988 if (pinfo->w <= 0 || pinfo->h <= 0 || n/pinfo->w != pinfo->h) {
989 SetISTR(ISTR_WARNING,"LoadPDS: image dimensions out of range (%dx%d)",
990 pinfo->w, pinfo->h);
991 free(lut);
992 return 0;
993 }
994 pPix8 = (byte *)malloc(n*sizeof(byte));
995 if (pPix8 == NULL) {
996 free(lut);
997 FatalError("LoadPDS: can't malloc 16-to-8-bit conversion buffer");
998 }
999
1000 /* convert the 16-bit image to 8-bit */
1001 lut[0] = 0;
1002 free(pShort = (unsigned short *)pinfo->pic);
1003 pinfo->pic = pPix8;
1004 while(--n >= 0)
1005 *pPix8++ = lut[*pShort++];
1006 free(lut);
1007 return 1;
1008 }
1009
1010 /*
1011 * If there is a PALETTE.TAB file in the same directory, use it
1012 */
1013
1014 /*******************************************/
LoadPDSPalette(fname,pinfo)1015 static int LoadPDSPalette(fname, pinfo)
1016 char *fname;
1017 PICINFO *pinfo;
1018 {
1019 FILE *fp;
1020 char name[1024], buf[256], *c;
1021 int i, n, r, g, b;
1022
1023 #ifdef VMS
1024 c = (char *) rindex(strcpy(name,
1025 (c = (char *) rindex(fname, ':')) ? c+1 : fname),
1026 ']');
1027 #else
1028 c = (char *) rindex(strcpy(name, fname), '/');
1029 #endif /* VMS */
1030 (void)strcpy(c ? c+1 : name, "palette.tab");
1031
1032 if ((fp = xv_fopen(name, "r")) == NULL)
1033 return 0;
1034 for (i = 0; i < 256; i++) {
1035 if (fgets(c = buf, (int) (sizeof(buf)-1), fp) == NULL)
1036 break;
1037 while (*c && isspace(*c))
1038 c++;
1039 if (*c == '\0' || *c == '#')
1040 continue;
1041 if (sscanf(buf, "%d %d %d %d", &n, &r, &g, &b) != 4)
1042 continue;
1043 if (n < 0 || n > 255)
1044 continue;
1045 pinfo->r[n] = r;
1046 pinfo->g[n] = g;
1047 pinfo->b[n] = b;
1048 if (r != g && r != b)
1049 pinfo->colType = F_FULLCOLOR;
1050 }
1051 (void)fclose(fp);
1052 return 1;
1053 }
1054
1055
1056 #endif /* HAVE_PDS */
1057