1 /*
2  * This software is copyrighted as noted below.  It may be freely copied,
3  * modified, and redistributed, provided that the copyright notice is
4  * preserved on all copies.
5  *
6  * There is no warranty or other guarantee of fitness for this software,
7  * it is provided solely "as is".  Bug reports or fixes may be sent
8  * to the author, who may or may not act on them as he desires.
9  *
10  * You may not include this software in a program or other software product
11  * without supplying the source, or without informing the end-user that the
12  * source is available for no extra charge.
13  *
14  * If you modify this software, you should include a notice giving the
15  * name of the person performing the modification, the date of modification,
16  * and the reason for such modification.
17  */
18 /*
19  * vcrtorle.c - Convert from VICAR to RLE.
20  *
21  * Author:	Spencer W. Thomas
22  * 		Information Technology and Networking
23  * 		University of Michigan Medical Center
24  * Date:	Mon Feb 17 1992
25  * Copyright (c) 1992, University of Michigan
26  *
27  * From: vcr2wff.c
28  * Author: K.R. Sloan
29  */
30 
31 /*
32  * The VICAR file starts with a bunch of labels in ASCII of the form
33  * "keyword=value", separated by spaces.  The entire label string is
34  * terminated by a 0 byte.  The very first label is always LBLSIZE,
35  * which tells you the size in bytes of the space that has been set
36  * aside for the label.  The actual size of the label (to the 0
37  * terminator byte) may be shorter than the space allocated for it.
38  * So, the first characters of the file are always "LBLSIZE=" followed
39  * by an integer in ASCII format.  The other items in the label you
40  * need to look for are NL (number of lines) and NS (number of
41  * samples).  The keywords are always upper case.
42  *
43  *  The image data itself starts immediately after the space allocated
44  * for the label.  So, skip LBLSIZE bytes at the beginning of the file
45  * to find the start of the image.  The image is stored in binary (not
46  * ASCII), one byte per pixel (gray scale), with 0 being black and 255
47  * being white.  It is stored in a simple matrix of NS samples (X
48  * dimension) by NL lines (Y dimension), with X varying the fastest.
49  * So, the first NS bytes contain the entire first line of the image,
50  * the second NS bytes contain the entire second line, etc.  The order
51  * goes left-to-right, top-to-bottom.
52  *
53  *  The full VICAR format can be more complex than this, but this
54  * description will hold for most files.  If you want to do a sanity
55  * check, then the following have to be true for this description to
56  * work: FORMAT='BYTE' ORG='BSQ' NB=1 NBB=0 NLB=0.
57  *
58  * For example, here's the beginning of the file from an actual image,
59  * dumped in ASCII format (the newlines are artificial for this
60  * message, and are not in the file):
61  *
62  * LBLSIZE=1024        FORMAT='BYTE'  TYPE='IMAGE'  BUFSIZ=20480  DIM=3  EOL=0
63  * RECSIZE=1024  ORG='BSQ'  NL=1024  NS=1024  NB=1  N1=1024  N2=1024  N3=1
64  * N4=0 NBB=0  NLB=0  HOST='VAX-VMS'  INTFMT='LOW'  REALFMT='VAX'  TASK= ...
65  *
66  * This says the image is 1024 samples (NS, X dimension) by 1024 lines
67  * (NL, Y dimension).  The space allocated for the label is 1024
68  * bytes.  So, the image data starts at byte number 1024 (0-based) in
69  * the file.  That first byte is the upper left pixel of the image.
70  * The first 1024 bytes in the image are the first horizontal line of
71  * the image.  The next 1024 bytes are the second line, and so on.
72  * There is no data compression.
73  *
74  *  Note that items in the label do not have to be in the same order
75  * (except LBLSIZE is always first), so don't count on that.  Also,
76  * LBLSIZE does not have to equal NS, although it does have to be an
77  * integer multiple of NS.  NL and NS do not have to be equal, i.e.
78  * the image does not have to be square.
79  *
80  *  Ron Baalke                           baalke@mars.jpl.nasa.gov
81  *  Jet Propulsion Lab
82  *
83  */
84 #ifndef lint
85 static char rcs_id[] = "$Header:$";
86 #endif
87 #if 0
88 vcrtorle()			/* Tag. */
89 #endif
90 
91 #include <assert.h>
92 #include <stdio.h>
93 #include "rle.h"
94 
95 
96 static int VERBOSE = 0;
97 
FatalError(s)98 static void FatalError(s)
99  char *s;
100  {
101   fprintf(stderr,"%s\n",s); exit(1);
102  }
103 
104 /* VICAR stuff */
105  /* tags, and guesses as to meaning... */
106 static int  LBLSIZE;       /* size of header, must be int mult of NS */
107 static char FORMAT[80];    /* 'BYTE' is OK */
108 static char TYPE[80];      /* 'IMAGE' is OK */
109 static char ORG[80];       /* `BSQ` is OK */
110 static int  NL;            /* height */
111 static int  NS;            /* width */
112 static int  NB;            /* samples per pixel? */
113 static char HOST[80];      /* machine type? */
114 static char INTFMT[80];    /* integer format? */
115 static char REALFMT[80];   /* real format? */
116 static char TASK[80];      /* processing applied? */
117 static char USER[80];      /* who was responsible? */
118 static char DAT_TIM[80];   /* when? */
119 static char COMMENT[80];   /* comment! */
120 
ParseVICARHeader(fd)121 static void ParseVICARHeader(fd)
122 FILE *fd;
123 {
124     char Name[81],Value[1024];
125     int n;
126 
127     for ( n = 0; ; n++ )
128     {
129 	Value[n] = fgetc( fd );
130 	if ( Value[n] == ' ' )
131 	    break;
132     }
133     Value[n++] = 0;
134 
135     sscanf(Value,"%80[^=]=%d",Name,&LBLSIZE);
136     if (VERBOSE) fprintf(stderr,"[%s = %d]\n",Name,LBLSIZE);
137     if (0 != strcmp("LBLSIZE",Name)) FatalError("This is not a VICAR file");
138 
139     /* There must be a better way to read the header.  This is gross. */
140     while(n < LBLSIZE)
141     {
142 	register char *cp;
143 	register char c = ' ';
144 	int done;
145 
146 	/* Skip spaces. */
147 	while ( c == ' ' && n < LBLSIZE )
148 	{
149 	    c = fgetc( fd );
150 	    n++;
151 	}
152 
153 	/* Get Name. */
154 	cp = &Name[0];
155 	while ( c != '=' && c != '\0' && n < LBLSIZE )
156 	{
157 	    *cp++ = c;
158 	    c = fgetc( fd );
159 	    n++;
160 	}
161 	*cp = 0;
162 
163 	if ( n >= LBLSIZE )
164 	    break;
165 
166 	if ('\0' == Name[0] || c == '\0')
167 	    break;
168 
169 	/* At this point, c is '='.  Get the next character. */
170 	Value[0] = fgetc( fd );
171 	n++;
172 
173 	cp = &Value[1];
174 	if ('\'' == Value[0])
175 	    for(;n < LBLSIZE;cp++)
176 	    {
177 		*cp = fgetc( fd );
178 		n++;
179 		if ('\'' == *cp)
180 		{
181 		    *++cp = '\0';
182 		    break;
183 		}
184 	    }
185 	else
186 	    for(;n < LBLSIZE;cp++)
187 	    {
188 		*cp = fgetc(fd);
189 		n++;
190 		if (' ' == *cp)
191 		{
192 		    *cp = '\0';
193 		    done =  0;
194 		    break;
195 		}
196 		if ('\0' == *cp)
197 		{
198 		    done = -1;
199 		    break;
200 		}
201 	    }
202 
203 	if (VERBOSE) fprintf(stderr,"[%s = %s]\n",Name,Value);
204 	Value[80] = '\0';	/* for our own protection... */
205 
206 	if (0 == strcmp("FORMAT" ,Name)) {strcpy(FORMAT ,Value); continue;}
207 	if (0 == strcmp("TYPE"   ,Name)) {strcpy(TYPE   ,Value); continue;}
208 	if (0 == strcmp("BUFSIZ" ,Name)) { (void) atoi(Value); continue;}
209 	if (0 == strcmp("DIM"    ,Name)) { (void) atoi(Value); continue;}
210 	if (0 == strcmp("EOL"    ,Name)) { (void) atoi(Value); continue;}
211 	if (0 == strcmp("RECSIZE",Name)) { (void) atoi(Value); continue;}
212 	if (0 == strcmp("ORG"    ,Name)) {strcpy(ORG    ,Value); continue;}
213 	if (0 == strcmp("NL"     ,Name)) {NL      = atoi(Value); continue;}
214 	if (0 == strcmp("NS"     ,Name)) {NS      = atoi(Value); continue;}
215 	if (0 == strcmp("NB"     ,Name)) {NB      = atoi(Value); continue;}
216 	if (0 == strcmp("N1"     ,Name)) { (void) atoi(Value); continue;}
217 	if (0 == strcmp("N2"     ,Name)) { (void) atoi(Value); continue;}
218 	if (0 == strcmp("N3"     ,Name)) { (void) atoi(Value); continue;}
219 	if (0 == strcmp("N4"     ,Name)) { (void) atoi(Value); continue;}
220 	if (0 == strcmp("NBB"    ,Name)) { (void) atoi(Value); continue;}
221 	if (0 == strcmp("NLB"    ,Name)) { (void) atoi(Value); continue;}
222 	if (0 == strcmp("HOST"   ,Name)) {strcpy(HOST   ,Value); continue;}
223 	if (0 == strcmp("INTFMT" ,Name)) {strcpy(INTFMT ,Value); continue;}
224 	if (0 == strcmp("REALFMT",Name)) {strcpy(REALFMT,Value); continue;}
225 	if (0 == strcmp("TASK"   ,Name)) {strcpy(TASK   ,Value); continue;}
226 	if (0 == strcmp("USER"   ,Name)) {strcpy(USER   ,Value); continue;}
227 	if (0 == strcmp("DAT_TIM",Name)) {strcpy(DAT_TIM,Value); continue;}
228 	if (0 == strcmp("COMMENT",Name)) {strcpy(COMMENT,Value); continue;}
229 	if (done) break;
230     }
231 
232     /* Skip the rest of the label. */
233     while ( n < LBLSIZE )
234     {
235 	(void)fgetc( fd );
236 	n++;
237     }
238 
239 }
240 
241 /* RLE stuff */
242 void
addVICARcomment(the_hdr,label,value)243 addVICARcomment( the_hdr, label, value )
244 rle_hdr *the_hdr;
245 char *label, *value;
246 {
247     char *comment;
248 
249     if ( *value == 0 )
250 	return;
251     /* 8 = length of "VICAR" + "=" + nul byte. */
252     comment = (char *)malloc( 8 + strlen( label ) + strlen( value ) );
253     sprintf( comment, "VICAR-%s=%s", label, value );
254     rle_putcom( comment, the_hdr );
255 }
256 
SetUpRLEFile(the_hdr,xsize,ysize,zsize)257 void SetUpRLEFile(the_hdr, xsize, ysize, zsize)
258 rle_hdr *the_hdr;
259 int xsize, ysize, zsize;
260 {
261 
262     the_hdr->xmin = 0;
263     the_hdr->xmax = xsize - 1;
264     the_hdr->ymin = 0;
265     the_hdr->ymax = ysize - 1;
266 
267     /* 1=B&W, 3=RGB? */
268     the_hdr->ncolors = zsize;
269 
270     /* Carry over info from VICAR file as comments. */
271     addVICARcomment( the_hdr, "USER", USER );
272     addVICARcomment( the_hdr, "DAT_TIM", DAT_TIM );
273     addVICARcomment( the_hdr, "TASK", TASK );
274     addVICARcomment( the_hdr, "COMMENT", COMMENT );
275 }
276 
main(argc,argv)277 int main(argc,argv)
278 int argc;
279 char *argv[];
280 {
281     char *VICARFileName = NULL;
282     FILE *fd;
283     unsigned char *VICARImage;
284     char *outfname = NULL;
285     int oflag = 0;
286     int y;
287     long int nread;
288     rle_hdr the_hdr;
289     rle_pixel **rows;
290 
291     the_hdr = *rle_hdr_init( (rle_hdr *)NULL );
292     if ( scanargs( argc, argv, "% v%- o%-outfile!s infile%s\n(\
293 \tConvert VICAR format image to URT.\n\
294 \t-v\tVerbose -- print out VICAR header information.)",
295 		   &VERBOSE, &oflag, &outfname, &VICARFileName ) == 0 )
296 	exit( 1 );
297     rle_names( &the_hdr, cmd_name( argv ), outfname );
298     rle_addhist( argv, NULL, &the_hdr );
299 
300     fd = rle_open_f(the_hdr.cmd,VICARFileName,"r");
301 
302     ParseVICARHeader(fd);
303 
304     /* Check for what we know how to handle. */
305     if ( NB != 1 )
306     {
307 	fprintf( stderr, "%s: Can't handle NB (%d) != 1 in %s.\n",
308 		 the_hdr.cmd, NB, the_hdr.file_name );
309 	exit( 1 );
310     }
311     if ( strcmp( FORMAT, "'BYTE'" ) != 0 )
312     {
313 	fprintf( stderr, "%s: Can't handle FORMAT (%s) != 'BYTE' in %s.\n",
314 		 the_hdr.cmd, FORMAT, the_hdr.file_name );
315 	exit( 1 );
316     }
317 
318     /* !!! Will have to be modified when we handle NB>1. !!! */
319     VICARImage = (unsigned char *)malloc( NS * NL );
320     RLE_CHECK_ALLOC(the_hdr.cmd, VICARImage, "image");
321 
322     the_hdr.rle_file = rle_open_f( the_hdr.cmd, outfname, "w" );
323 
324     SetUpRLEFile(&the_hdr, NS, NL, NB);
325     rle_put_setup( &the_hdr );
326 
327     rows = (rle_pixel **)malloc( NB * sizeof(rle_pixel *) );
328 
329     /* !!! Will have to be modified when we handle NB>1. !!! */
330     nread = fread( VICARImage, 1, NS*NL, fd );
331     if ( nread < NS*NL )
332 	fprintf( stderr, "%s: Short read from %s (%d bytes missing)\n",
333 		 the_hdr.cmd, the_hdr.file_name, NS*NL - nread );
334     for(y=(NL-1);y>=0;y--)	/* flip in y */
335     {
336 	/* !!! Loop somehow if NB > 1. !!! */
337 	rows[0] = VICARImage + NS * y;
338 
339 	rle_putrow( rows, NS, &the_hdr );
340     }
341     rle_puteof( &the_hdr );
342     exit(0);
343 }
344