e51d7889bc73e4fe8a8b255b6657407bcc2d3a6c
[ctsim.git] / src / sdf2img.c
1 /*****************************************************************************
2 **  This is part of the CTSim program
3 **  Copyright (C) 1983-2000 Kevin Rosenberg
4 **
5 **  $Id: sdf2img.c,v 1.4 2000/05/24 22:50:04 kevin Exp $
6 **  $Log: sdf2img.c,v $
7 **  Revision 1.4  2000/05/24 22:50:04  kevin
8 **  Added support for new SGP library
9 **
10 **  Revision 1.3  2000/05/16 04:33:59  kevin
11 **  Improved option processing
12 **
13 **  Revision 1.2  2000/05/08 20:02:32  kevin
14 **  ANSI C changes
15 **
16 **  Revision 1.1.1.1  2000/04/28 13:02:44  kevin
17 **  Initial CVS import for first public release
18 **
19 **
20 **
21 **  This program is free software; you can redistribute it and/or modify
22 **  it under the terms of the GNU General Public License (version 2) as
23 **  published by the Free Software Foundation.
24 **
25 **  This program is distributed in the hope that it will be useful,
26 **  but WITHOUT ANY WARRANTY; without even the implied warranty of
27 **  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
28 **  GNU General Public License for more details.
29 **
30 **  You should have received a copy of the GNU General Public License
31 **  along with this program; if not, write to the Free Software
32 **  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
33 ******************************************************************************/
34
35 /* FILE
36  *   sdf2img.c          Convert an SDF file to a viewable format image
37  */
38
39 #include "ct.h"
40
41 #if HAVE_PNG
42 void sdf2d_to_png (IMAGE *im, char *outfile, int nxcell, int nycell, double densmin, double densmax);
43 #endif
44 #if HAVE_GIF
45 void sdf2d_to_gif (IMAGE *im, char *outfile, int nxcell, int nycell, double densmin, double densmax);
46 #endif
47 void sdf2d_to_pgm (IMAGE *im, char *outfile, int nxcell, int nycell, double densmin, double densmax);
48 void sdf2d_to_pgmasc (IMAGE *im, char *outfile, int nxcell, int nycell, double densmin, double densmax);
49
50 enum { O_SCALE, O_MIN, O_MAX, O_AUTO, O_CENTER, O_STATS, O_FORMAT, O_LABELS, 
51        O_HELP, O_VERBOSE, O_VERSION, O_DEBUG };
52
53 static struct option my_options[] =
54 {
55   {"scale", 1, 0, O_SCALE},
56   {"min", 1, 0, O_MIN},
57   {"max", 1, 0, O_MAX},
58   {"auto", 1, 0, O_AUTO},
59   {"center", 1, 0, O_CENTER},
60   {"format", 1, 0, O_FORMAT},
61   {"labels", 0, 0, O_LABELS},
62   {"stats", 0, 0, O_STATS},
63   {"verbose", 0, 0, O_VERBOSE},
64   {"debug", 0, 0, O_DEBUG},
65   {"help", 0, 0, O_HELP},
66   {"version", 0, 0, O_VERSION},
67   {0, 0, 0, 0}
68 };
69
70 enum { O_AUTO_FULL, O_AUTO_STD0_1, O_AUTO_STD0_5, O_AUTO_STD1, O_AUTO_STD2, O_AUTO_STD3 };
71 #define O_AUTO_FULL_STR  "full"
72 #define O_AUTO_STD0_1_STR  "std0.1"
73 #define O_AUTO_STD0_5_STR  "std0.5"
74 #define O_AUTO_STD1_STR  "std1"
75 #define O_AUTO_STD2_STR  "std2"
76 #define O_AUTO_STD3_STR  "std3"
77
78 enum { O_CENTER_MEAN, O_CENTER_MODE };
79 #define O_CENTER_MEAN_STR  "mean"
80 #define O_CENTER_MODE_STR  "mode"
81
82 enum { O_FORMAT_GIF, O_FORMAT_PNG, O_FORMAT_PGM, O_FORMAT_PGMASC, O_FORMAT_DISP };
83 #define O_FORMAT_GIF_STR   "gif"
84 #define O_FORMAT_PNG_STR   "png" 
85 #define O_FORMAT_PGM_STR   "pgm"
86 #define O_FORMAT_PGMASC_STR "pgmasc"
87 #define O_FORMAT_DISP_STR    "disp"
88
89 void 
90 sdf2img_usage (const char *program)
91 {
92   fprintf(stdout, "sdf2img_usage: %s sdfname outfile [OPTIONS]\n", kbasename(program));
93   fprintf(stdout, "Convert SDF2D file to an image file\n");
94   fprintf(stdout, "\n");
95   fprintf(stdout, "     sdfname    Name of input SDF file\n");
96   fprintf(stdout, "     outfile    Name of output file\n");
97   fprintf(stdout, "     --format   Output format\n");
98   fprintf(stdout, "         pgm    PGM (portable graymap) format (default)\n");
99   fprintf(stdout, "         pgmasc PGM (portable graymap) ASCII format\n");
100 #ifdef HAVE_PNG
101   fprintf(stdout, "         png    PNG format\n");
102 #endif
103 #ifdef HAVE_GIF
104   fprintf(stdout, "         gif    GIF format\n");
105 #endif
106   fprintf(stdout, "         disp   Display on screen\n");
107   fprintf(stdout, "     --center   Center of window\n");
108   fprintf(stdout, "         mode   Mode is center of window (default)\n");
109   fprintf(stdout, "         mean   Mean is center of window\n");
110   fprintf(stdout, "     --auto     Set auto window\n");
111   fprintf(stdout, "         full   Use full window (default)\n");
112   fprintf(stdout, "         std0.1 Use 0.1 standard deviation about center\n");
113   fprintf(stdout, "         std0.5 Use 0.5 standard deviation about center\n");
114   fprintf(stdout, "         std1   Use one standard deviation about center\n");
115   fprintf(stdout, "         std2   Use two standard deviations about center\n");
116   fprintf(stdout, "         std3   Use three standard deviations about center\n");
117   fprintf(stdout, "     --scale    Scaling factor for output size\n");
118   fprintf(stdout, "     --min      Set minimum intensity\n");
119   fprintf(stdout, "     --max      Set maximum intensity\n");
120   fprintf(stdout, "     --stats    Print image statistics\n");
121   fprintf(stdout, "     --labels   Print image labels\n");
122   fprintf(stdout, "     --debug    Set debug mode\n");
123   fprintf(stdout, "     --verbose  Set verbose mode\n");
124   fprintf(stdout, "     --version  Print version\n");
125   fprintf(stdout, "     --help     Print this help message\n");
126 }
127
128
129 int 
130 sdf2img_main (int argc, char *const argv[])
131 {
132   IMAGE *im;
133   double densmin = HUGE_VAL, densmax = -HUGE_VAL;
134   char *in_file, *out_file;
135   int opt_verbose = 0;
136   int opt_scale = 1;
137   int opt_auto = O_AUTO_FULL;
138   int opt_set_max = 0;
139   int opt_set_min = 0;
140   int opt_stats = 0;
141   int opt_debug = 0;
142   int opt_center = O_CENTER_MODE;
143   int opt_format = O_FORMAT_PGM;
144   int opt_labels = 0;
145
146   while (1)
147     {
148       int c = getopt_long (argc, argv, "", my_options, NULL);
149       char *endptr = NULL;
150       char *endstr;
151       
152       if (c == -1)
153         break;
154       
155       switch (c)
156         {
157         case O_MIN:
158           opt_set_min = 1;
159           densmin = strtod(optarg, &endptr);
160           endstr = optarg + strlen(optarg);
161           if (endptr != endstr)
162             {
163               fprintf(stderr, "Error setting --min to %s\n", optarg);
164               sdf2img_usage(argv[0]);
165               return (1);
166             }
167           break;
168         case O_MAX:
169           opt_set_max = 1;
170           densmax = strtod(optarg, &endptr);
171           endstr = optarg + strlen(optarg);
172           if (endptr != endstr)
173             {
174               fprintf(stderr, "Error setting --max to %s\n", optarg);
175               sdf2img_usage(argv[0]);
176               return (1);
177             }
178           break;
179         case O_SCALE:
180           opt_scale = strtol(optarg, &endptr, 10);
181           endstr = optarg + strlen(optarg);
182           if (endptr != endstr)
183             {
184               fprintf(stderr,"Error setting --scale to %s\n", optarg);
185               sdf2img_usage(argv[0]);
186               return (1);
187             }
188           break;
189         case O_AUTO:
190           if (strcmp(optarg, O_AUTO_FULL_STR) == 0)
191             opt_auto = O_AUTO_FULL;
192           else if (strcmp(optarg, O_AUTO_STD1_STR) == 0)
193             opt_auto = O_AUTO_STD1;
194           else if (strcmp(optarg, O_AUTO_STD0_5_STR) == 0)
195             opt_auto = O_AUTO_STD0_5;
196           else if (strcmp(optarg, O_AUTO_STD0_1_STR) == 0)
197             opt_auto = O_AUTO_STD0_1;
198           else if (strcmp(optarg, O_AUTO_STD2_STR) == 0)
199             opt_auto = O_AUTO_STD2;
200           else if (strcmp(optarg, O_AUTO_STD3_STR) == 0)
201             opt_auto = O_AUTO_STD3;
202           else
203             {
204               fprintf(stderr, "Invalid auto mode %s\n", optarg);
205               sdf2img_usage(argv[0]);
206               return (1);
207             }
208                 break;
209         case O_CENTER:
210           if (strcmp(optarg, O_CENTER_MEAN_STR) == 0)
211             opt_center = O_CENTER_MEAN;
212           else if (strcmp(optarg, O_CENTER_MODE_STR) == 0)
213             opt_center = O_CENTER_MODE;
214           else
215             {
216               fprintf(stderr, "Invalid center mode %s\n", optarg);
217               sdf2img_usage(argv[0]);
218               return (1);
219             }
220                 break;
221         case O_FORMAT:
222           if (strcmp(optarg, O_FORMAT_PGM_STR) == 0)
223             opt_format = O_FORMAT_PGM;
224           else if (strcmp(optarg, O_FORMAT_PGMASC_STR) == 0)
225             opt_format = O_FORMAT_PGMASC;
226 #if HAVE_PNG
227           else if (strcmp(optarg, O_FORMAT_PNG_STR) == 0)
228             opt_format = O_FORMAT_PNG;
229 #endif
230 #if HAVE_GIF
231           else if (strcmp(optarg, O_FORMAT_GIF_STR) == 0)
232             opt_format = O_FORMAT_GIF;
233 #endif
234           else if (strcmp(optarg, O_FORMAT_DISP_STR) == 0)
235             opt_format = O_FORMAT_DISP;
236           else {
237               fprintf(stderr, "Invalid format mode %s\n", optarg);
238               sdf2img_usage(argv[0]);
239               return (1);
240             }
241           break;
242         case O_LABELS:
243           opt_labels = 1;
244           break;
245         case O_VERBOSE:
246           opt_verbose = 1;
247           break;
248         case O_DEBUG:
249           opt_debug = 1;
250           break;
251         case O_STATS:
252           opt_stats = 1;
253           break;
254         case O_VERSION:
255 #ifdef VERSION
256           fprintf(stdout, "Version %s\n", VERSION);
257 #else
258           fprintf(stderr, "Unknown version number");
259 #endif
260           exit(0);
261         case O_HELP:
262         case '?':
263           sdf2img_usage(argv[0]);
264           return (0);
265         default:
266           sdf2img_usage(argv[0]);
267           return (1);
268         }
269     }
270
271   if ((opt_format == O_FORMAT_DISP && optind + 1 != argc) 
272       || (opt_format != O_FORMAT_DISP && optind + 2 != argc))
273     {
274         sdf2img_usage(argv[0]);
275         return (1);
276     }
277   
278   in_file = argv[optind];
279
280   if (opt_format != O_FORMAT_DISP)
281       out_file = argv[optind+1];
282   else out_file = NULL;
283
284   if ((im = image_load (in_file)) == NULL)
285     {
286       fprintf(stderr, "File %s does not exist\n", in_file);
287       return (1);
288     }
289
290   if (opt_labels) 
291     {
292       int nlabels = im->dfp_2d->dfp->num_label;
293       int i;
294
295       for (i = 0; i < nlabels; i++)
296         {
297           SDF_BLK blk;
298           if (sdf_read_label(&blk.lab, i, im->dfp_2d->dfp) != SDF_OK)
299             break;
300           if (blk.lab.label_type == LT_HISTORY) {
301             fprintf(stdout, "History: %s\n", blk.lab.label_str);
302             fprintf(stdout, "  calc time = %.2f secs\n", blk.lab.calc_time);
303             fprintf(stdout, "  Timestamp = %s\n", td_str_tmdt(&blk.lab.timedate));
304           } else if (blk.lab.label_type == LT_TITLE) {
305             fprintf(stdout, "Title: %s\n", blk.lab.label_str);
306             fprintf(stdout, "  Timestamp = %s\n", td_str_tmdt(&blk.lab.timedate));
307           } else if (blk.lab.label_type == LT_NOTE) {
308             fprintf(stdout, "Note: %s\n", blk.lab.label_str);
309             fprintf(stdout, "  Timestamp = %s\n", td_str_tmdt(&blk.lab.timedate));
310           }
311         }
312     }
313
314   if (opt_stats || (! (opt_set_max && opt_set_min)))
315     {
316       double minfound = HUGE_VAL, maxfound = -HUGE_VAL;
317       double mode = 0, mean = 0, stddev = 0, window = 0;
318       double spread;
319       int hist[256];
320       int ibin, nbin = 256;
321       int max_bin, max_binindex; 
322       double maxbin;
323       int ix, iy;
324
325       maxbin = nbin - 1;
326       for (ix = 0; ix < im->nx; ix++)
327         {
328           for (iy = 0; iy < im->ny; iy++)
329             {
330               if (im->v[ix][iy] > maxfound)
331                 maxfound = im->v[ix][iy];
332               if (im->v[ix][iy] < minfound)
333                 minfound = im->v[ix][iy];
334               mean += im->v[ix][iy];
335             }
336         }
337       spread = maxfound - minfound;
338       if (spread == 0)
339         mode = minfound;
340       else
341         {
342           for (ibin = 0; ibin < nbin; ibin++)
343             hist[ibin] = 0;
344           for (ix = 0; ix < im->nx; ix++)
345             {
346               for (iy = 0; iy < im->ny; iy++)
347                 {
348                   int b = (int) ((((im->v[ix][iy] - minfound) / spread) * (double) maxbin) + 0.5);
349                   hist[b]++;
350                 }
351             }
352           max_binindex = 0;
353           max_bin = -1;
354           for (ibin = 0; ibin < nbin; ibin++)
355             {
356               if (hist[ibin] > max_bin)
357                 {
358                   max_bin = hist[ibin];
359                   max_binindex = ibin;
360                 }
361             }
362           mode = (((double) max_binindex) * spread / ((double) maxbin)) + minfound;
363         }
364
365       if (opt_auto == O_AUTO_FULL)
366         {
367           if (! opt_set_max)
368             densmax = maxfound;
369           if (! opt_set_min)
370             densmin = minfound;
371         }
372       if (opt_stats || opt_auto != O_AUTO_FULL)
373         {
374           mean /= im->nx * im->ny;
375           for (ix = 0; ix < im->nx; ix++)
376             {
377               for (iy = 0; iy < im->ny; iy++)
378                 {
379                   double diff = (im->v[ix][iy] - mean);
380                   stddev += diff * diff;
381                 }
382             }
383           stddev = sqrt(stddev / (im->nx * im->ny));
384           if (opt_auto == O_AUTO_FULL)
385             ;
386           else if (opt_auto == O_AUTO_STD1)
387             window = stddev;
388           else if (opt_auto == O_AUTO_STD0_1)
389             window = stddev * 0.1;
390           else if (opt_auto == O_AUTO_STD0_5)
391             window = stddev * 0.5;
392           else if (opt_auto == O_AUTO_STD2)
393             window = stddev * 2;
394           else if (opt_auto == O_AUTO_STD3)
395             window = stddev * 3;
396           else
397             {
398               fprintf(stderr, "Internal Error: Invalid auto mode %d\n", opt_auto);
399               return (1);
400             }
401         }
402       if (opt_stats)
403         {
404           fprintf(stdout,"nx=%d\n", im->nx);
405           fprintf(stdout,"ny=%d\n", im->ny);
406           fprintf(stdout,"min=%f\n", minfound);
407           fprintf(stdout,"max=%f\n", maxfound);
408           fprintf(stdout,"mean=%f\n", mean);
409           fprintf(stdout,"mode=%f\n", mode);
410           fprintf(stdout,"stddev=%f\n", stddev);
411         }
412       if (opt_auto != O_AUTO_FULL)
413         {
414           double center;
415
416           if (opt_center == O_CENTER_MODE)
417             center = mode;
418           else if (opt_center == O_CENTER_MEAN)
419             center = mean;
420           else
421             {
422               fprintf(stderr, "Internal Error: Invalid center mode %d\n", opt_center);
423               return (1);
424             }
425           if (! opt_set_max)
426             densmax = center + window;
427           if (! opt_set_min)
428             densmin = center - window;
429         }
430     }
431
432   if (opt_stats)
433     {
434       fprintf(stdout,"min_disp=%f\n", densmin);
435       fprintf(stdout,"max_disp=%f\n", densmax);
436     }
437   
438   if (opt_format == O_FORMAT_PGM)
439     sdf2d_to_pgm (im, out_file, opt_scale, opt_scale, densmin, densmax);
440   else if (opt_format == O_FORMAT_PGMASC)
441     sdf2d_to_pgmasc (im, out_file, opt_scale, opt_scale, densmin, densmax);
442 #if HAVE_PNG
443   else if (opt_format == O_FORMAT_PNG)
444     sdf2d_to_png (im, out_file, opt_scale, opt_scale, densmin, densmax);
445 #endif
446 #if HAVE_GIF
447   else if (opt_format == O_FORMAT_GIF) 
448     sdf2d_to_gif (im, out_file, opt_scale, opt_scale, densmin, densmax);
449 #endif
450   else if (opt_format == O_FORMAT_DISP) {
451       int gid = image_display_scale (im, opt_scale, densmin, densmax);
452       cio_kb_getc();
453       g2_close(gid);
454   }
455   else
456     {
457       fprintf(stderr, "Internal Error: Invalid format mode %d\n", opt_format);
458       return (1);
459     }
460   return (0);
461 }
462
463
464 void 
465 sdf2d_to_pgm (IMAGE *im, char *outfile, int nxcell, int nycell, double densmin, double densmax)
466 {
467   FILE *fp;
468   int irow;
469   unsigned char *rowp;
470
471   rowp = (unsigned char *) sys_alloc(im->nx * nxcell,"sdf2d_to_img");
472   if (rowp == NULL)
473     return;
474
475   if ((fp = fopen (outfile, "wb")) == NULL)
476      return;
477
478   fprintf(fp, "P5\n");
479   fprintf(fp, "%d %d\n", im->nx, im->ny);
480   fprintf(fp, "255\n");
481
482   for (irow = im->ny - 1; irow >= 0; irow--)
483     {
484       int icol, ir;
485
486       for (icol = 0; icol < im->nx; icol++)
487         {
488           double dens;
489           int p;
490           int pos = icol * nxcell;
491           dens = (im->v[icol][irow] - densmin) / (densmax - densmin);
492           if (dens < 0)
493             dens = 0;
494           else if (dens > 1)
495             dens = 1;
496           for (p = pos; p < pos + nxcell; p++)
497             {
498               rowp[p] = (unsigned int) (dens * 255.);
499             }
500         }
501       for (ir = 0; ir < nycell; ir++)
502         {
503           int ic;
504           for (ic = 0; ic < im->nx * nxcell; ic++) 
505             fprintf(fp, "%c ", rowp[ic]);
506         }
507     }
508   sys_free(rowp, "sdf2img");
509
510   fclose(fp);
511 }
512
513 void 
514 sdf2d_to_pgmasc (IMAGE *im, char *outfile, int nxcell, int nycell, double densmin, double densmax)
515 {
516   FILE *fp;
517   int irow;
518   unsigned char *rowp;
519
520   rowp = (unsigned char *) sys_alloc(im->nx * nxcell,"sdf2d_to_img");
521   if (rowp == NULL)
522     return;
523
524   if ((fp = fopen (outfile, "wb")) == NULL)
525      return;
526
527   fprintf(fp, "P2\n");
528   fprintf(fp, "%d %d\n", im->nx, im->ny);
529   fprintf(fp, "255\n");
530
531   for (irow = im->ny - 1; irow >= 0; irow--)
532     {
533       int icol, ir;
534
535       for (icol = 0; icol < im->nx; icol++)
536         {
537           double dens;
538           int p;
539           int pos = icol * nxcell;
540           dens = (im->v[icol][irow] - densmin) / (densmax - densmin);
541           if (dens < 0)
542             dens = 0;
543           else if (dens > 1)
544             dens = 1;
545           for (p = pos; p < pos + nxcell; p++)
546             {
547               rowp[p] = (unsigned int) (dens * 255.);
548             }
549         }
550       for (ir = 0; ir < nycell; ir++)
551         {
552           int ic;
553           for (ic = 0; ic < im->nx * nxcell; ic++) 
554             fprintf(fp, "%d ", rowp[ic]);
555           fprintf(fp, "\n");
556         }
557     }
558   sys_free(rowp, "sdf2img");
559
560   fclose(fp);
561 }
562
563
564 #ifdef HAVE_PNG
565 void 
566 sdf2d_to_png (IMAGE *im, char *outfile, int nxcell, int nycell, double densmin, double densmax)
567 {
568   FILE *fp;
569   png_structp png_ptr;
570   png_infop info_ptr;
571   int irow;
572   unsigned char *rowp;
573
574   rowp = (unsigned char *) sys_alloc(im->nx * nxcell,"sdf2d_to_img");
575   if (rowp == NULL)
576     return;
577
578   if ((fp = fopen (outfile, "wb")) == NULL)
579      return;
580
581   png_ptr = png_create_write_struct (PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
582   if (! png_ptr)
583     return;
584
585   info_ptr = png_create_info_struct(png_ptr);
586   if (! info_ptr)
587     {
588       png_destroy_write_struct(&png_ptr, (png_infopp) NULL);
589       fclose(fp);
590       return;
591     }
592
593   if (setjmp(png_ptr->jmpbuf))
594     {
595       png_destroy_write_struct(&png_ptr, &info_ptr);
596       fclose(fp);
597       return;
598     }
599
600   png_init_io(png_ptr, fp);
601
602   png_set_IHDR(png_ptr, info_ptr, im->nx * nxcell, im->ny * nycell, 8, PNG_COLOR_TYPE_GRAY, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_DEFAULT);
603
604   png_write_info(png_ptr, info_ptr);
605   for (irow = im->ny - 1; irow >= 0; irow--)
606     {
607       png_bytep row_pointer;
608       int icol, ir;
609
610       for (icol = 0; icol < im->nx; icol++)
611         {
612           double dens;
613           int p;
614           int pos = icol * nxcell;
615           dens = (im->v[icol][irow] - densmin) / (densmax - densmin);
616           if (dens < 0)
617             dens = 0;
618           else if (dens > 1)
619             dens = 1;
620           for (p = pos; p < pos + nxcell; p++)
621             {
622               rowp[p] = (unsigned int) (dens * 255.);
623             }
624         }
625       row_pointer = rowp;
626       for (ir = 0; ir < nycell; ir++)
627         {
628           png_write_rows (png_ptr, &row_pointer, 1);
629         }
630     }
631   sys_free(rowp, "sdf2img");
632
633   png_write_end(png_ptr, info_ptr);
634   png_destroy_write_struct(&png_ptr, &info_ptr);
635
636   fclose(fp);
637 }
638 #endif
639
640 #ifdef HAVE_GD
641 #include "gd.h"
642 #define N_GRAYSCALE 256
643 #endif
644
645 void
646 sdf2d_to_gif (IMAGE *im, char *outfile, int nxcell, int nycell, double densmin, double densmax)
647 {
648 #ifdef HAVE_GD
649   gdImagePtr gif;
650   FILE *out;
651   int gs_indices[N_GRAYSCALE];
652   int i;
653   int irow;
654   int lastrow;
655   unsigned char *rowp;
656
657   rowp = (unsigned char *) sys_alloc(im->nx * nxcell,"sdf2d_to_img");
658   if (rowp == NULL)
659     return;
660
661   gif = gdImageCreate(im->nx * nxcell, im->ny * nycell);
662   for (i = 0; i < N_GRAYSCALE; i++)
663     gs_indices[i] = gdImageColorAllocate(gif, i, i, i);
664
665   lastrow = im->ny * nycell - 1;
666   for (irow = 0; irow < im->ny; irow++)
667     {
668       int icol, ir;
669       int rpos = irow * nycell;
670       for (ir = rpos; ir < rpos + nycell; ir++)
671         {
672           for (icol = 0; icol < im->nx; icol++)
673             {
674               double dens;
675               int ic;
676               int cpos = icol * nxcell;
677               dens = (im->v[icol][irow] - densmin) / (densmax - densmin);
678               if (dens < 0)
679                 dens = 0;
680               else if (dens > 1)
681                 dens = 1;
682               for (ic = cpos; ic < cpos + nxcell; ic++)
683                 {
684                   rowp[ic] = (unsigned int) (dens * (double) (N_GRAYSCALE - 1));
685                   gdImageSetPixel(gif, ic, lastrow - ir, gs_indices[rowp[ic]]);
686                 }
687             }
688         }
689     }
690   sys_free(rowp, "sdf2img");
691
692   if ((out = fopen(outfile,"w")) == NULL)
693     {
694       fprintf(stderr,"Error opening output file %s for writing\n", outfile);
695       exit(1);
696     }
697   gdImageGif(gif,out);
698   fclose(out);
699   gdImageDestroy(gif);
700 #else
701   fprintf(stderr, "This version does not support GIF");
702 #endif
703 }
704
705 #ifndef NO_MAIN
706 int 
707 main (int argc, char *const argv[])
708 {
709   return (sdf2img_main(argc, argv));
710 }
711 #endif