1 /*****************************************************************************
2    Major portions of this software are copyrighted by the Medical College
3    of Wisconsin, 1994-2000, and are released under the Gnu General Public
4    License, Version 2.  See the file README.Copyright for details.
5 ******************************************************************************/
6 
7 #include "mrilib.h"
8 
9 #define XYNUM    0
10 #define YXNUM    1
11 #define XDOTYNUM 2
12 #define YDOTXNUM 3
prog_usage(int detail)13 void prog_usage(int detail)
14 {
15          printf(
16  "Usage: 2dcat [options] fname1 fname2 etc.\n"
17  "Puts a set images into an image matrix (IM) \n"
18  " montage of NX by NY images.\n"
19  " The minimum set of input is N images (N >= 1).\n"
20  " If need be, the default is to reuse images until the desired\n"
21  " NX by NY size is achieved. \n"
22  " See options -zero_wrap and -image_wrap for more detail.\n"
23  " \n"
24  "OPTIONS:\n"
25  " ++ Options for editing, coloring input images:\n"
26  "  -scale_image SCALE_IMG: Multiply each image IM(i,j) in output\n"
27  "                          image matrix IM by the color or intensity\n"
28  "                          of the pixel (i,j) in SCALE_IMG.\n"
29  "  -scale_pixels SCALE_PIX: Multiply each pixel (i,j) in output image\n"
30  "                          by the color or intensity\n"
31  "                          of the pixel (i,j) in SCALE_IMG.\n"
32  "                          SCALE_IMG is automatically resized to the\n"
33  "                          resolution of the output image.\n"
34  "  -scale_intensity: Instead of multiplying by the color of \n"
35  "                          pixel (i,j), use its intensity \n"
36  "                          (average color)\n"
37  "  -gscale FAC: Apply FAC in addition to scaling of -scale_* options\n"
38  "  -rgb_out: Force output to be in rgb, even if input is bytes.\n"
39  "            This option is turned on automatically in certain cases.\n"
40  "  -res_in RX RY: Set resolution of all input images to RX by RY pixels.\n"
41  "                 Default is to make all input have the same\n"
42  "                 resolution as the first image.\n"
43  "  -respad_in RPX RPY: Like -res_in, but resample to the max while respecting\n"
44  "                      the aspect ratio, and then pad to achieve desired \n"
45  "                      pixel count.\n"
46  "  -pad_val VAL: Set the padding value, should it be needed by -respad_in\n"
47  "                to VAL. VAL is typecast to byte, default is 0, max is 255.\n"
48  "  -crop L R T B: Crop images by L (Left), R (Right), T (Top), B (Bottom)\n"
49  "                 pixels. Cutting is performed after any resolution change, \n"
50  "                 if any, is to be done.\n"
51  "  -autocrop_ctol CTOL: A line is eliminated if none of its R G B values \n"
52  "                       differ by more than CTOL%% from those of the corner\n"
53  "                       pixel.\n"
54  "  -autocrop_atol ATOL: A line is eliminated if none of its R G B values \n"
55  "                       differ by more than ATOL%% from those of line\n"
56  "                       average.\n"
57  "  -autocrop: This option is the same as using both of -autocrop_atol 20 \n"
58  "             and -autocrop_ctol 20\n"
59  "  NOTE: Do not mix -autocrop* options with -crop\n"
60  "        Cropping is determined from the 1st input image and applied to \n"
61  "        to all remaining ones.\n"
62  " ++ Options for output:\n"
63  "  -zero_wrap: If number of images is not enough to fill matrix\n"
64  "              solid black images are used.\n"
65  "  -white_wrap: If number of images is not enough to fill matrix\n"
66  "              solid white images are used.\n"
67  "  -gray_wrap GRAY: If number of images is not enough to fill matrix\n"
68  "              solid gray images are used. GRAY must be between 0 and 1.0\n"
69  "  -image_wrap: If number of images is not enough to fill matrix\n"
70  "               images on command line are reused (default)\n"
71  "  -rand_wrap: When reusing images to fill matrix, randomize the order\n"
72  "              in refill section only.\n"
73  "  -prefix ppp = Prefix the output files with string 'ppp'\n"
74  "          Note: If the prefix ends with .1D, then a 1D file containing\n"
75  "                the average of RGB values. You can view the output with\n"
76  "                1dgrayplot.\n"
77  "  -matrix NX NY: Specify number of images in each row and column \n"
78  "                 of IM at the same time. \n"
79  "  -nx NX: Number of images in each row (3 for example below)\n"
80  "  -ny NY: Number of images in each column (4 for example below)\n"
81  "      Example: If 12 images appearing on the command line\n"
82  "               are to be assembled into a 3x4 IM matrix they\n"
83  "               would appear in this order:\n"
84  "                 0  1  2\n"
85  "                 3  4  5\n"
86  "                 6  7  8\n"
87  "                 9  10 11\n"
88  "    NOTE: The program will try to guess if neither NX nor NY \n"
89  "          are specified.\n"
90  "  -matrix_from_scale: Set NX and NY to be the same as the \n"
91  "                      SCALE_IMG's dimensions. (needs -scale_image)\n"
92  "  -gap G: Put a line G pixels wide between images.\n"
93  "  -gap_col R G B: Set color of line to R G B values.\n"
94  "                  Values range between 0 and 255.\n"
95  "\n"
96  "Example 0 (assuming afni is in ~/abin directory):\n"
97  "   Resizing an image:\n"
98  "   2dcat -prefix big -res_in 1024 1024 \\\n"
99  "         ~/abin/funstuff/face_zzzsunbrain.jpg \n"
100  "   2dcat -prefix small -res_in 64 64 \\\n"
101  "         ~/abin/funstuff/face_zzzsunbrain.jpg \n"
102  "   aiv small.ppm big.ppm \n"
103  "\n"
104  "Example 1:\n"
105  "   Stitching together images:\n"
106  "    (Can be used to make very high resolution SUMA images.\n"
107  "     Read about 'Ctrl+r' in SUMA's GUI help.)\n"
108  "   2dcat -prefix cat -matrix 14 12 \\\n"
109  "         ~/abin/funstuff/face_*.jpg\n"
110  "   aiv cat.ppm\n"
111  "\n"
112  "Example 2:\n"
113  "   Stitching together 3 images getting rid of annoying white boundary:\n"
114  "\n"
115  "   2dcat -prefix surfview_pry3b.jpg -ny 1 -autocrop surfview.000[789].jpg\n"
116  "\n"
117  "Example 20 (assuming afni is in ~/abin directory):\n"
118  "   2dcat -prefix bigcat.jpg -scale_image ~/abin/afnigui_logo.jpg \\\n"
119  "         -matrix_from_scale -rand_wrap -rgb_out -respad_in 128 128 \\\n"
120  "         -pad_val 128 ~/abin/funstuff/face_*.jpg \n"
121  "   aiv   bigcat.jpg bigcat.jpg \n"
122  "   Crop/Zoom in to see what was done. In practice, you want to use\n"
123  "   a faster image viewer to examine the result. Zooming on such\n"
124  "   a large image is not fast in aiv.\n"
125  "   Be careful with this toy. Images get real big, real quick.\n"
126  "\n"
127  "You can look at the output image file with\n"
128  "  afni -im ppp.ppm  [then open the Sagittal image window]\n"
129  "\n"
130  "Deprecation warning: The imcat program will be replaced by 2dcat in the future."
131  "\n"
132             ) ;
133    return;
134 }
135 
136 #define ABS(a) ( (a) < 0 ? (-(a)):(a) )
main(int argc,char * argv[])137 int main( int argc , char * argv[] )
138 {
139    MRI_IMARR * imar, *inimar;
140    MRI_IMAGE * im ;
141    char prefix[240] = "cat" , fnam[256] ;
142    char suffix[50] = "\0";
143    char *scale_image = NULL, *scale_pixels = NULL;
144    int iarg , ii,jj , nx,ny , nxim,nyim ;
145    int nmode = XYNUM, nxin, nyin, nbad = 0;
146    int cutL=0, cutR=0, cutT=0, cutB=0, cutlev=0, cutlevu=0;
147    int gap = 0, ScaleInt=0, force_rgb_out = 0, matrix_size_from_scale = 0;
148    byte  gap_col[3] = {255, 20, 128}, pval = 0 ;
149    MRI_IMAGE *imscl=NULL;
150    int kkk, nscl=-1, resix=-1, resiy=-1, force_rgb_at_input=0,
151        N_byte = 0, N_rgb = 0, ks = 1, wrapmode = 1;
152    float *scl=NULL, fac=1.0, ff=0;
153    byte *scl3=NULL, *rgb=NULL, *b1, *b2, *b3;
154    char name[100];
155    void *ggg=NULL;
156 
157 
158    mainENTRY("2dcat main"); machdep() ;
159 
160     wrapmode = 1;
161     ScaleInt = 0;
162     resix=-1;
163     resiy=-1;
164     ks = 1;
165     cutL=0;
166     cutB=0;
167     cutT=0;
168     cutR=0;
169     cutlev =-2;
170     cutlevu=-2;
171     fac = 1.0;
172     force_rgb_out = 0;
173     iarg = 1 ;
174     pval = 0 ;
175     nx = -1; ny = -1;
176     while( iarg < argc && argv[iarg][0] == '-' ){
177        if( strcmp(argv[iarg],"-help") == 0 ||
178            strcmp(argv[iarg],"-h") == 0 ) {
179          prog_usage(strlen(argv[iarg])>2 ? 2:1);
180          exit(0);  /* do not continue   18 Sep 2018 [rickr] */
181        }
182 
183        if( strcmp(argv[iarg],"-rand_wrap") == 0  ) {
184          wrapmode = 2;
185          iarg++ ; continue ;
186        }
187 
188        if( strcmp(argv[iarg],"-matrix") == 0 ){
189          if (iarg+2 >= argc) {
190             fprintf(stderr,"*** ERROR: Need two integers after -matrix\n");
191             exit(1);
192          }
193          nx = (int) strtod( argv[++iarg] , NULL ) ;
194          ny = (int) strtod( argv[++iarg] , NULL ) ;
195           iarg++ ; continue ;
196        }
197 
198        if( strcmp(argv[iarg],"-crop") == 0 ){
199          if (iarg+4 >= argc) {
200             fprintf(stderr,
201                      "*** ERROR: Need four positive integers after -crop\n");
202             exit(1);
203          }
204          cutL = (int) strtod( argv[++iarg] , NULL ) ;
205          cutR = (int) strtod( argv[++iarg] , NULL ) ;
206          cutT = (int) strtod( argv[++iarg] , NULL ) ;
207          cutB = (int) strtod( argv[++iarg] , NULL ) ;
208           iarg++ ; continue ;
209        }
210 
211        if( strcmp(argv[iarg],"-autocrop") == 0 ){
212          cutlev = -1; cutlevu = -1;
213          iarg++ ; continue ;
214        }
215 
216        if ( strcmp(argv[iarg],"-autocrop_ctol") == 0 ){
217          if (iarg+2 >= argc) {
218             fprintf(stderr,
219              "*** ERROR: Need one integer between 0 and 100 after"
220              " -autocrop_ctol\n");
221             exit(1);
222          }
223          cutlev  = ((int)strtod( argv[++iarg] , NULL ) );
224          if (cutlev < 0 || cutlev > 100) {
225             fprintf(stderr,
226          "*** ERROR: Need one integer between 0 and 100 after -autocrop_ctol\n"
227                "Got %d\n", cutlevu);
228             exit(1);
229          }
230 
231          iarg++ ; continue ;
232        }
233 
234        if ( strcmp(argv[iarg],"-autocrop_atol") == 0 ){
235          if (iarg+2 >= argc) {
236             fprintf(stderr,
237              "*** ERROR: Need one integer between 0 and 100 after"
238              " -autocrop_atol\n");
239             exit(1);
240          }
241          cutlevu  = ((int)strtod( argv[++iarg] , NULL ) );
242          if (cutlevu < 0 || cutlevu > 100) {
243             fprintf(stderr,
244          "*** ERROR: Need one integer between 0 and 100 after -autocrop_atol\n"
245                "Got %d\n", cutlevu);
246             exit(1);
247          }
248 
249          iarg++ ; continue ;
250        }
251 
252 
253        if( strcmp(argv[iarg],"-res_in") == 0 ){
254          if (iarg+2 >= argc) {
255             fprintf(stderr,"*** ERROR: Need two integers after -res_in\n");
256             exit(1);
257          }
258          resix = (int) strtod( argv[++iarg] , NULL ) ;
259          resiy = (int) strtod( argv[++iarg] , NULL ) ;
260           iarg++ ; continue ;
261        }
262 
263        if( strcmp(argv[iarg],"-gscale") == 0 ){
264          if (iarg+1 >= argc) {
265             fprintf(stderr,"*** ERROR: Need one float after -gscale\n");
266             exit(1);
267          }
268          fac = (float) strtod( argv[++iarg] , NULL ) ;
269           iarg++ ; continue ;
270        }
271 
272 
273        if( strcmp(argv[iarg],"-respad_in") == 0 ){
274          if (iarg+2 >= argc) {
275             fprintf(stderr,"*** ERROR: Need two integers after -respad_in\n");
276             exit(1);
277          }
278          resix = (int) strtod( argv[++iarg] , NULL ) ;
279          resiy = (int) strtod( argv[++iarg] , NULL ) ;
280          ks = -1;
281           iarg++ ; continue ;
282        }
283 
284        if( strcmp(argv[iarg],"-pad_val") == 0 ){
285          if (iarg+1 >= argc) {
286             fprintf(stderr,"*** ERROR: Need one byte after -pad_val\n");
287             exit(1);
288          }
289          pval = (byte) strtod( argv[++iarg] , NULL ) ;
290           iarg++ ; continue ;
291        }
292 
293        if( strcmp(argv[iarg],"-nx") == 0 ){
294          if (iarg+1 >= argc) {
295             fprintf(stderr,"*** ERROR: Need an integer after -nx\n");
296             exit(1);
297          }
298          nx = (int) strtod( argv[++iarg] , NULL ) ;
299           iarg++ ; continue ;
300        }
301 
302        if( strcmp(argv[iarg],"-ny") == 0 ){
303          if (iarg+1 >= argc) {
304             fprintf(stderr,"*** ERROR: Need an integer after -ny\n");
305             exit(1);
306          }
307          ny = (int) strtod( argv[++iarg] , NULL ) ;
308           iarg++ ; continue ;
309        }
310 
311        if( strcmp(argv[iarg],"-gap") == 0 ){
312          if (iarg+1 >= argc) {
313             fprintf(stderr,"*** ERROR: Need an integer after -gap\n");
314             exit(1);
315          }
316          gap = (int) strtod( argv[++iarg] , NULL ) ;
317           iarg++ ; continue ;
318        }
319        if( strcmp(argv[iarg],"-gap_col") == 0 ){
320          if (iarg+2 >= argc) {
321             fprintf(stderr,
322          "*** ERROR: Need three integers between 0 and 255 after -gap_col\n");
323             exit(1);
324          }
325          gap_col[0] = (byte) strtod( argv[++iarg] , NULL ) ;
326          gap_col[1] = (byte) strtod( argv[++iarg] , NULL ) ;
327          gap_col[2] = (byte) strtod( argv[++iarg] , NULL ) ;
328           iarg++ ; continue ;
329        }
330 
331        if( strcmp(argv[iarg],"-scale_image") == 0 ){
332           if (iarg+1 >= argc) {
333             fprintf(stderr,"*** ERROR: Need an image after -scale_image\n");
334             exit(1);
335          }
336           scale_image = argv[++iarg];
337           iarg++ ; continue ;
338        }
339 
340        if( strcmp(argv[iarg],"-scale_pixels") == 0 ){
341           if (iarg+1 >= argc) {
342             fprintf(stderr,"*** ERROR: Need an image after -scale_pixels\n");
343             exit(1);
344           }
345           scale_pixels = argv[++iarg];
346           if (!THD_is_ondisk(scale_pixels)) {
347             fprintf(stderr,"*** ERROR: Image %s not found\n", scale_pixels);
348             exit(1);
349           }
350           iarg++ ; continue ;
351        }
352 
353        if( strcmp(argv[iarg],"-scale_intensity") == 0) {
354          ScaleInt = 1;
355          iarg++ ; continue ;
356        }
357 
358        if( strcmp(argv[iarg],"-rgb_out") == 0) {
359          force_rgb_out = 1;
360          iarg++ ; continue ;
361        }
362 
363        if( strcmp(argv[iarg],"-zero_wrap") == 0) {
364          mri_Set_OK_WrapZero(1);
365          iarg++ ; continue ;
366        }
367        if( strcmp(argv[iarg],"-white_wrap") == 0) {
368          mri_Set_OK_WrapZero(255);
369          iarg++ ; continue ;
370        }
371 
372        if( strcmp(argv[iarg],"-gray_wrap") == 0) {
373          byte bb;
374          if (iarg+1 >= argc) {
375             fprintf(stderr,
376                     "*** ERROR: Need a number between 0 and 1 for -gray_wrap\n");
377             exit(1);
378          }
379          ++iarg;
380          bb = (byte)(atof(argv[iarg])*255);
381          if (bb < 1) bb = 1;
382          mri_Set_OK_WrapZero(bb);
383          iarg++ ; continue ;
384        }
385        if( strcmp(argv[iarg],"-image_wrap") == 0) {
386          mri_Set_KO_WrapZero();
387          iarg++ ; continue ;
388        }
389        if( strcmp(argv[iarg],"-matrix_from_scale") == 0) {
390          matrix_size_from_scale = 1;
391          iarg++ ; continue ;
392        }
393 
394        if( strcmp(argv[iarg],"-prefix") == 0 ){
395           MCW_strncpy( prefix , argv[++iarg] , 240 ) ;
396           iarg++ ; continue ;
397        }
398 
399        fprintf(stderr,"*** ERROR: illegal option %s\n",argv[iarg]) ;
400        suggest_best_prog_option(argv[0], argv[iarg]);
401        exit(1) ;
402     }
403 
404     if( argc < 4 ){
405       ERROR_message("Too few options");
406       prog_usage(0);
407       exit(1) ;
408     }
409 
410     if (cutlevu == -1 && cutlev == -1) {
411       /* No params set, but autocrop desired*/
412       cutlev = 20;
413       cutlevu = 20;
414     }
415 
416     if (scale_image) {
417       if (!(imscl = mri_read_just_one(scale_image))) {
418          fprintf(stderr,"*** Failed to read scale image.\n");
419          exit(1);
420       }else {
421          fprintf(stderr,"++Scale image prep\n");
422          rgb= MRI_BYTE_PTR(imscl);
423          nscl = imscl->nx*imscl->ny;
424          scl = (float *)malloc(sizeof(float)*nscl);
425          scl3 = (byte *)malloc(sizeof(byte)*nscl*3);
426          if (imscl->kind == MRI_rgb) {
427             for (kkk=0; kkk<nscl; ++kkk) {
428                scl[kkk] = ( (float)rgb[3*kkk  ] +
429                             (float)rgb[3*kkk+1] +
430                             (float)rgb[3*kkk+2] ) / 3.0 * fac;
431                if ((ff = rgb[3*kkk  ]* fac) > 255) ff = 255;
432                scl3[3*kkk  ] = ff;
433                if ((ff = rgb[3*kkk+1]* fac) > 255) ff = 255;
434                scl3[3*kkk+1] = ff;
435                if ((ff = rgb[3*kkk+2]* fac) > 255) ff = 255;
436                scl3[3*kkk+2] = ff;
437             }
438         } else if (imscl->kind == MRI_byte) {
439             for (kkk=0; kkk<nscl; ++kkk) {
440                scl[kkk] = ((float)rgb[kkk  ]* fac);
441                if ((ff=scl[kkk])>255) ff = 255;
442                scl3[3*kkk  ] = scl3[3*kkk+1] = scl3[3*kkk+2] = ff;
443             }
444         } else {
445          fprintf(stderr,"*** Scale image must be RGB or byte type.\n");
446             exit(1);
447         }
448       }
449    }
450 
451    if (matrix_size_from_scale) {
452       if (imscl) {
453          fprintf(stderr,"+++ Matrix size of %dx%d, based on scale image\n",
454                          imscl->nx, imscl->ny);
455          nx = imscl->nx; ny = imscl->ny;
456       } else {
457          fprintf(stderr,
458             "*** Want matrix size from scale image but no scale image found.\n");
459          exit(1);
460       }
461    }
462    /* allow from catwrapping */
463    if (wrapmode == 2) mri_Set_OK_catrandwrap();
464    else mri_Set_OK_catwrap();
465 
466    /* read all images */
467    inimar = mri_read_resamp_many_files( argc-iarg , argv+iarg,
468                                         resix, ks*resiy, pval) ;
469    if( inimar == NULL ){
470       fprintf(stderr,"*** no input images read!\a\n") ;
471       exit(1) ;
472    } else if( inimar->num < 1 ){
473       fprintf(stderr,"*** less than 1 input image read!\a\n") ;
474       exit(1) ;
475    }
476 
477    /* Figure out cropping based on one image, written as loop in
478    case I change my mind */
479    if (cutlev >= 0 || cutlevu >= 0) {
480       MRI_IMAGE *imin;
481       byte *colav=NULL, *rowav=NULL;
482       int mis=0, kx=0, ky=0, e0, e1, e2;
483       double d0, d1, d2;
484       if (cutlev  > 0) cutlev   = (int)(cutlev *2.55);
485       if (cutlevu > 0) cutlevu  = (int)(cutlevu*2.55);
486       cutL = 0;
487       for (kkk=0; kkk<1; ++kkk) {
488          imin = IMAGE_IN_IMARR(inimar,kkk);
489          rgb= MRI_BYTE_PTR(imin);
490          if (imin->kind == MRI_rgb) {
491             e0 = (imin->nx*imin->ny-1)*3;
492             e1 = e0+1;
493             e2 = e0+2;
494             kkk = 0;
495             /* fprintf(stderr,"RGB image nx=%d, ny=%d, cut lev %d, avg lev %d\n",
496                     imin->nx, imin->ny, cutlev, cutlevu); */
497 
498             /* Compute column and row averages */
499             if (cutlevu >= 0) {
500                colav = (byte *)calloc(3*imin->nx, sizeof(byte));
501                for (kx=0; kx<imin->nx; ++kx) {
502                   d0 = d1 = d2 = 0.0;
503                   for (ky=0; ky<imin->ny; ++ky) {
504                      kkk = kx+imin->nx*ky;
505                      d0 += rgb[3*kkk  ];
506                      d1 += rgb[3*kkk+1];
507                      d2 += rgb[3*kkk+2];
508                   }
509                   colav[3*kx  ] = (byte)(d0/imin->ny);
510                   colav[3*kx+1] = (byte)(d1/imin->ny);
511                   colav[3*kx+2] = (byte)(d2/imin->ny);
512                }
513                rowav = (byte *)calloc(3*imin->ny, sizeof(byte));
514                for (ky=0; ky<imin->ny; ++ky) {
515                   d0 = d1 = d2 = 0.0;
516                   for (kx=0; kx<imin->nx; ++kx) {
517                      kkk = kx+imin->nx*ky;
518                      d0 += rgb[3*kkk  ];
519                      d1 += rgb[3*kkk+1];
520                      d2 += rgb[3*kkk+2];
521                   }
522                   rowav[3*ky  ] = (byte)(d0/imin->nx);
523                   rowav[3*ky+1] = (byte)(d1/imin->nx);
524                   rowav[3*ky+2] = (byte)(d2/imin->nx);
525                }
526             }
527 
528             /* Left */
529             cutL = 0;
530             mis = 0;
531                for (kx=0; kx<imin->nx && !mis; ++kx) {
532             for (ky=0; ky<imin->ny && !mis; ++ky) {
533                   kkk = kx+imin->nx*ky;
534                   if (cutlev >= 0) {
535                      /* break if color changes from corner */
536                      if (ABS(rgb[3*kkk  ] - rgb[0]) > cutlev ||
537                          ABS(rgb[3*kkk+1] - rgb[1]) > cutlev ||
538                          ABS(rgb[3*kkk+2] - rgb[2]) > cutlev ) {
539                         /* fprintf(stderr,
540                              "Break from [%d %d %d] at %d %d with [%d %d %d]\n",
541                                 rgb[0], rgb[1], rgb[2], kx, ky,
542                                 rgb[3*kkk  ], rgb[3*kkk+1], rgb[3*kkk+2]); */
543                         mis = 1;
544                      }
545                   }
546                   /* break if color changes from average of column */
547                   if (cutlevu >= 0) {
548                      if (ABS(rgb[3*kkk  ] - colav[3*kx  ]) > cutlevu ||
549                          ABS(rgb[3*kkk+1] - colav[3*kx+1]) > cutlevu ||
550                          ABS(rgb[3*kkk+2] - colav[3*kx+2]) > cutlevu ) {
551                         /* fprintf(stderr,
552                      "Break from colav [%d %d %d] at %d %d with [%d %d %d]\n",
553                           colav[3*kx  ], colav[3*kx+1], colav[3*kx+2], kx, ky,
554                           rgb[3*kkk  ], rgb[3*kkk+1], rgb[3*kkk+2]); */
555                         mis = 1;
556                      }
557                   }
558                }
559                if (!mis) {
560                   ++cutL;
561                   /* fprintf(stderr,"Line at x=%d is cst\n", kx); */
562                }
563             }
564             /* Right */
565             cutR = 0;
566             mis = 0;
567                for (kx=imin->nx-1; kx>=0 && !mis; --kx) {
568             for (ky=0; ky<imin->ny && !mis; ++ky) {
569                   kkk = kx+imin->nx*ky;
570                   if (cutlev >= 0) {
571                      if (ABS(rgb[3*kkk  ] - rgb[e0]) > cutlev ||
572                          ABS(rgb[3*kkk+1] - rgb[e1]) > cutlev ||
573                          ABS(rgb[3*kkk+2] - rgb[e2]) > cutlev ) {
574                         /* fprintf(stderr,
575                              "Break from [%d %d %d] at %d %d with [%d %d %d]\n",
576                                 rgb[0], rgb[1], rgb[2], kx, ky,
577                                 rgb[3*kkk  ], rgb[3*kkk+1], rgb[3*kkk+2]); */
578                         mis = 1;
579                      }
580                   }
581                   /* break if color changes from average of column */
582                   if (cutlevu >= 0) {
583                      if (ABS(rgb[3*kkk  ] - colav[3*kx  ]) > cutlevu ||
584                          ABS(rgb[3*kkk+1] - colav[3*kx+1]) > cutlevu ||
585                          ABS(rgb[3*kkk+2] - colav[3*kx+2]) > cutlevu ) {
586                         /* fprintf(stderr,
587                      "Break from colav [%d %d %d] at %d %d with [%d %d %d]\n",
588                           colav[3*kx  ], colav[3*kx+1], colav[3*kx+2], kx, ky,
589                           rgb[3*kkk  ], rgb[3*kkk+1], rgb[3*kkk+2]); */
590                         mis = 1;
591                      }
592                   }
593                }
594                if (!mis) {
595                   ++cutR;
596                   /* fprintf(stderr,"Line at x=%d is cst\n", kx); */
597                }
598             }
599             /* Bottom */
600             cutB = 0;
601             mis = 0;
602             for (ky=imin->ny-1; ky>=0 && !mis; --ky) {
603                for (kx=imin->nx-1; kx>=0 && !mis; --kx) {
604                   kkk = kx+imin->nx*ky;
605                   if (cutlev >= 0) {
606                      if (ABS(rgb[3*kkk  ] - rgb[e0]) > cutlev ||
607                          ABS(rgb[3*kkk+1] - rgb[e1]) > cutlev ||
608                          ABS(rgb[3*kkk+2] - rgb[e2]) > cutlev ) {
609                         /* fprintf(stderr,
610                              "Break from [%d %d %d] at %d %d with [%d %d %d]\n",
611                                 rgb[0], rgb[1], rgb[2], kx, ky,
612                                 rgb[3*kkk  ], rgb[3*kkk+1], rgb[3*kkk+2]); */
613                         mis = 1;
614                      }
615                   }
616                   /* break if color changes from average of column */
617                   if (cutlevu >= 0) {
618                      if (ABS(rgb[3*kkk  ] - rowav[3*ky  ]) > cutlevu ||
619                          ABS(rgb[3*kkk+1] - rowav[3*ky+1]) > cutlevu ||
620                          ABS(rgb[3*kkk+2] - rowav[3*ky+2]) > cutlevu ) {
621                         /* fprintf(stderr,
622                      "Break from colav [%d %d %d] at %d %d with [%d %d %d]\n",
623                           rowav[3*ky  ], rowav[3*ky+1], rowav[3*ky+2], kx, ky,
624                           rgb[3*kkk  ], rgb[3*kkk+1], rgb[3*kkk+2]); */
625                         mis = 1;
626                      }
627                   }
628                }
629                if (!mis) {
630                   ++cutB;
631                   /* fprintf(stderr,"Line at y=%d is cst\n", ky); */
632                }
633             }
634             /* Top */
635             cutT = 0;
636             mis = 0;
637             for (ky=0; ky<imin->ny && !mis; ++ky) {
638                for (kx=imin->nx-1; kx>=0 && !mis; --kx) {
639                   kkk = kx+imin->nx*ky;
640                   if (cutlev >= 0) {
641                      if (ABS(rgb[3*kkk  ] - rgb[e0]) > cutlev ||
642                          ABS(rgb[3*kkk+1] - rgb[e1]) > cutlev ||
643                          ABS(rgb[3*kkk+2] - rgb[e2]) > cutlev ) {
644                         /* fprintf(stderr,
645                              "Break from [%d %d %d] at %d %d with [%d %d %d]\n",
646                                 rgb[0], rgb[1], rgb[2], kx, ky,
647                                 rgb[3*kkk  ], rgb[3*kkk+1], rgb[3*kkk+2]); */
648                         mis = 1;
649                      }
650                   }
651                   /* break if color changes from average of column */
652                   if (cutlevu >= 0) {
653                      if (ABS(rgb[3*kkk  ] - rowav[3*ky  ]) > cutlevu ||
654                          ABS(rgb[3*kkk+1] - rowav[3*ky+1]) > cutlevu ||
655                          ABS(rgb[3*kkk+2] - rowav[3*ky+2]) > cutlevu ) {
656                         /* fprintf(stderr,
657                      "Break from colav [%d %d %d] at %d %d with [%d %d %d]\n",
658                           rowav[3*ky  ], rowav[3*ky+1], rowav[3*ky+2], kx, ky,
659                           rgb[3*kkk  ], rgb[3*kkk+1], rgb[3*kkk+2]); */
660                         mis = 1;
661                      }
662                   }
663                }
664                if (!mis) {
665                   ++cutT;
666                   /* fprintf(stderr,"Line at y=%d is cst\n", ky); */
667                }
668             }
669             if (colav) free(colav); colav=NULL;
670             if (rowav) free(rowav); rowav=NULL;
671         } else if (imin->kind == MRI_byte) {
672             e0 = (imin->nx*imin->ny-1);
673             kkk = 0;
674             /* fprintf(stderr,"Byte image nx=%d, ny=%d, cut level %d, %d\n",
675                     imin->nx, imin->ny, cutlev, cutlevu); */
676             /* Compute column and row averages */
677             if (cutlevu >= 0) {
678                colav = (byte *)calloc(imin->nx, sizeof(byte));
679                for (kx=0; kx<imin->nx; ++kx) {
680                   d0 = 0.0;
681                   for (ky=0; ky<imin->ny; ++ky) {
682                      kkk = kx+imin->nx*ky;
683                      d0 += rgb[kkk  ];
684                   }
685                   colav[kx  ] = (byte)(d0/imin->ny);
686                }
687                rowav = (byte *)calloc(imin->ny, sizeof(byte));
688                for (ky=0; ky<imin->ny; ++ky) {
689                   d0 = 0.0;
690                   for (kx=0; kx<imin->nx; ++kx) {
691                      kkk = kx+imin->nx*ky;
692                      d0 += rgb[kkk  ];
693                   }
694                   rowav[ky  ] = (byte)(d0/imin->nx);
695                }
696             }
697             /* Left */
698             cutL = 0;
699             mis = 0;
700             for (kx=0; kx<imin->nx && !mis; ++kx) {
701                for (ky=0; ky<imin->ny && !mis; ++ky) {
702                   kkk = kx+imin->nx*ky;
703                   if (cutlev >= 0) {
704                      if (ABS(rgb[kkk] - rgb[0]) > cutlev) {
705                         /* fprintf(stderr,
706                                 "Break from [%d] at %d %d with [%d]\n",
707                                 rgb[0], kx, ky, rgb[kkk]); */
708                         mis = 1;
709                      }
710                   }
711                   /* break if color changes from average of column */
712                   if (cutlevu >= 0) {
713                      if (ABS(rgb[kkk  ] - colav[kx  ]) > cutlevu) {
714                         /* fprintf(stderr,
715                      "Break from colav [%d] at %d %d with [%d]\n",
716                           colav[kx  ], kx, ky,
717                           rgb[kkk  ]); */
718                         mis = 1;
719                      }
720                   }
721                }
722                if (!mis) {
723                   ++cutL;
724                   /* fprintf(stderr,"Line at x=%d is cst\n", kx); */
725                }
726             }
727             /* Right */
728             cutR = 0;
729             mis = 0;
730             for (kx=imin->nx-1; kx>=0 && !mis; --kx) {
731                for (ky=0; ky<imin->ny && !mis; ++ky) {
732                   kkk = kx+imin->nx*ky;
733                   if (cutlev >= 0) {
734                      if (ABS(rgb[kkk] - rgb[e0]) > cutlev ) {
735                         /* fprintf(stderr,
736                                 "Break from [%d] at %d %d with [%d]\n",
737                                 rgb[0], kx, ky, rgb[kkk]); */
738                         mis = 1;
739                      }
740                   }
741                   /* break if color changes from average of column */
742                   if (cutlevu >= 0) {
743                      if (ABS(rgb[kkk  ] - colav[kx  ]) > cutlevu) {
744                         /* fprintf(stderr,
745                      "Break from colav [%d] at %d %d with [%d]\n",
746                           colav[kx  ], kx, ky,
747                           rgb[kkk  ]); */
748                         mis = 1;
749                      }
750                   }
751                }
752                if (!mis) {
753                   ++cutR;
754                   /* fprintf(stderr,"Line at x=%d is cst\n", kx); */
755                }
756             }
757             /* Bottom */
758             cutB = 0;
759             mis = 0;
760             for (ky=imin->ny-1; ky>=0 && !mis; --ky) {
761                for (kx=imin->nx-1; kx>=0 && !mis; --kx) {
762                   kkk = kx+imin->nx*ky;
763                   if (cutlev >= 0) {
764                      if (ABS(rgb[kkk] - rgb[e0]) > cutlev ) {
765                         /* fprintf(stderr,
766                                 "Break from [%d] at %d %d with [%d]\n",
767                                 rgb[0], kx, ky, rgb[kkk]); */
768                         mis = 1;
769                      }
770                   }
771                   /* break if color changes from average of column */
772                   if (cutlevu >= 0) {
773                      if (ABS(rgb[kkk  ] - rowav[ky  ]) > cutlevu) {
774                         /* fprintf(stderr,
775                      "Break from rowav [%d] at %d %d with [%d]\n",
776                           rowav[ky  ], kx, ky,
777                           rgb[kkk  ]); */
778                         mis = 1;
779                      }
780                   }
781                }
782                if (!mis) {
783                   ++cutB;
784                   /* fprintf(stderr,"Line at y=%d is cst\n", ky); */
785                }
786             }
787             /* Top */
788             cutT = 0;
789             mis = 0;
790             for (ky=0; ky<imin->ny && !mis; ++ky) {
791                for (kx=imin->nx-1; kx>=0 && !mis; --kx) {
792                   kkk = kx+imin->nx*ky;
793                   if (cutlev >= 0) {
794                      if (ABS(rgb[kkk  ] - rgb[e0]) > cutlev) {
795                         /* fprintf(stderr,
796                                 "Break from [%d] at %d %d with [%d]\n",
797                                 rgb[0], kx, ky, rgb[kkk]); */
798                         mis = 1;
799                      }
800                   }
801                   /* break if color changes from average of column */
802                   if (cutlevu >= 0) {
803                      if (ABS(rgb[kkk  ] - rowav[ky  ]) > cutlevu) {
804                         /* fprintf(stderr,
805                      "Break from rowav [%d] at %d %d with [%d]\n",
806                           rowav[ky  ], kx, ky,
807                           rgb[kkk  ]); */
808                         mis = 1;
809                      }
810                   }
811                }
812                if (!mis) {
813                   ++cutT;
814                   /* fprintf(stderr,"Line at y=%d is cst\n", ky); */
815                }
816             }
817             if (colav) free(colav); colav=NULL;
818             if (rowav) free(rowav); rowav=NULL;
819         } else {
820             fprintf(stderr,"*** For autocrop image must be RGB or byte type.\n");
821             exit(1);
822         }
823 
824         fprintf(stdout,"+++ Autocrop set to L%d R%d T%d B%d\n",
825                        cutL, cutR, cutT, cutB);
826       }
827    }
828 
829    /* crop all images if needed */
830    if (cutL || cutR || cutT || cutB) {
831       /* original image size */
832       nxin = IMAGE_IN_IMARR(inimar,0)->nx;
833       nyin = IMAGE_IN_IMARR(inimar,0)->ny;
834 
835       nbad = mri_cut_many_2D(inimar, cutL, nxin-1-cutR, cutT, nyin-1-cutB);
836       if (nbad) {
837          fprintf(stderr,"*** failed (%d) in cropping operation!\a\n", nbad) ;
838          exit(1) ;
839       }
840    }
841 
842    /* figure out the count */
843    if (nx < 0 && ny < 0) {
844       nx = ny = (int)sqrt((double)inimar->num+0.00001);
845       if (nx*ny != inimar->num) {
846          fprintf(stderr,"*** Can't guess at matrix layout for %d images.\n"
847                         "    Use -nx, -ny or -matrix\n", inimar->num);
848          exit(1);
849       }
850    } else if (nx < 0) {
851       if (inimar->num % ny) {
852          fprintf(stderr,"--- Have %d images, not divisible by %d\n"
853                         "    will pad to fill matrix.\n"
854                         , inimar->num, ny);
855          nx = inimar->num / ny + 1;
856       } else {
857          nx = inimar->num / ny;
858       }
859    } else if (ny < 0) {
860       if (inimar->num % nx) {
861          fprintf(stderr,"--- Have %d images, not divisible by %d!\n"
862                         "    will pad to fill matrix.\n"
863                         , inimar->num, nx);
864          ny = inimar->num / nx + 1;
865       } else {
866          ny = inimar->num / nx;
867       }
868    }
869 
870    if( nx < 1 || ny < 1 ){
871     fprintf(stderr,"*** ERROR: illegal values nx=%d ny=%d\n",nx,ny);
872     exit(1) ;
873    }
874    if (nx*ny > inimar->num) {
875       fprintf(stderr,"+++ Have %d images. Will wrap to fill %dx%d matrix\n",
876                inimar->num, nx, ny);
877    } else if (nx*ny < inimar->num) {
878       fprintf(stderr,"+++ Have more images than needed to fill matrix.\n"
879                      "    Will ignore the last %d images.\n",
880                      inimar->num- nx*ny);
881    }
882 
883    nxin = IMAGE_IN_IMARR(inimar,0)->nx;
884    nyin = IMAGE_IN_IMARR(inimar,0)->ny;
885 
886    fprintf(stdout, "+++ Arranging %d images (each %dx%d) into a %dx%d matrix.\n",                    inimar->num, nxin, nyin, nx, ny);
887 
888    force_rgb_at_input = 0;
889    N_byte = 0; N_rgb = 0;
890    if (gap) force_rgb_at_input = 1; /* must go rgb */
891    else {
892       /* if have multiple types, must also go rgb */
893       for (kkk=0; kkk<inimar->num; ++kkk) {
894          if (IMAGE_IN_IMARR(inimar,kkk)->kind != MRI_byte &&
895              IMAGE_IN_IMARR(inimar,kkk)->kind != MRI_rgb) {
896             fprintf(stderr,"*** Unexpected image kind on input.\n"
897                            "    Only byte and rgb (3byte) images allowed.\n");
898             exit(1);
899          } else if (IMAGE_IN_IMARR(inimar,kkk)->kind == MRI_byte) {
900             ++N_byte;
901          } else if (IMAGE_IN_IMARR(inimar,kkk)->kind == MRI_rgb) {
902             ++N_rgb;
903          }
904          if (N_byte && N_rgb) { force_rgb_at_input = 1; continue; }
905       }
906    }
907 
908    if (force_rgb_at_input) { /* make sure all images are rgb type */
909       MRI_IMAGE *imin, *newim;
910       int kkk, nmin;
911       if (nx*ny < inimar->num) nmin = nx*ny;
912       else nmin = inimar->num;
913       /* must transform input to rgb here to allow for gap option */
914       fprintf(stderr,"+++ Transforming all input to rgb for a good reason \n");
915       for (kkk=0; kkk<nmin; ++kkk) {
916          imin = IMAGE_IN_IMARR(inimar,kkk%inimar->num);
917          if(imin->kind == MRI_byte) {
918             newim = mri_3to_rgb( imin, imin, imin ) ;
919             MRI_COPY_AUX(newim,imin) ; mri_free(imin);
920             IMAGE_IN_IMARR(inimar,kkk%inimar->num) = newim;
921          } else if (imin->kind != MRI_rgb) {
922             fprintf(stderr,"*** Unexpected image kind.\n");
923             exit(1);
924          }
925       }
926    }
927 
928 
929    ggg = (void *)gap_col;
930 
931    if (!(im = mri_cat2D( nx , ny , gap , ggg , inimar ))) {
932       fprintf(stderr,"*** ERROR: Failed to create image!\n");
933       exit(1) ;
934    }
935    FREE_IMARR(inimar) ; inimar = NULL;
936 
937    if (force_rgb_out && im->kind == MRI_byte) {
938       MRI_IMAGE *newim=NULL;
939       fprintf(stderr,"+++ Forcing output to RGB\n");
940       newim = mri_3to_rgb( im, im, im ) ;
941       MRI_COPY_AUX(newim,im) ; mri_free(im);
942       im = newim;
943    }
944 
945    /* image scaling needed, not very efficient in implementation but
946       mostly for fun */
947    if (scale_image && ( im->kind == MRI_rgb || im->kind == MRI_byte) ) {
948       MRI_IMARR *imtriple ;
949       MRI_IMAGE *rim, *gim, *bim, *tim, *imin, *newim;
950       fprintf(stderr,"+++ Scaling by image\n");
951       if (!imscl) {
952          fprintf(stderr,"*** No scale image!!!.\n");
953          exit(1);
954       }else {
955          rgb= MRI_BYTE_PTR(imscl);
956          nscl = imscl->nx*imscl->ny;
957          scl = (float *)malloc(sizeof(float)*nscl);
958          scl3 = (byte *)malloc(sizeof(byte)*nscl*3);
959          if (imscl->kind == MRI_rgb) {
960             for (kkk=0; kkk<nscl; ++kkk) {
961                scl[kkk] = ((float)rgb[3*kkk  ] +
962                           (float)rgb[3*kkk+1] +
963                           (float)rgb[3*kkk+2] ) / 3.0 * fac ;
964 
965                if ((ff = rgb[3*kkk  ]* fac) > 255)  ff=255 ;
966                scl3[3*kkk  ] = ff;
967                if ((ff = rgb[3*kkk+1]* fac) > 255)  ff=255;
968                scl3[3*kkk+1] = ff;
969                if ((ff = rgb[3*kkk+2]* fac) > 255)  ff=255;
970                scl3[3*kkk+2] = ff;
971             }
972         } else if (imscl->kind == MRI_byte) {
973             for (kkk=0; kkk<nscl; ++kkk) {
974                scl[kkk] = ((float)rgb[kkk  ]* fac) ;
975                if ((ff = rgb[kkk]* fac) > 255) ff = 255;
976                scl3[3*kkk  ] = scl3[3*kkk+1] = scl3[3*kkk+2] = ff;
977             }
978         } else {
979          fprintf(stderr,"*** Scale image must be RGB or byte type.\n");
980             exit(1);
981         }
982       }
983 
984       /* Now break the image again */
985       if (!(inimar = mri_uncat2D(  nxin ,  nyin ,im ))) {
986          fprintf(stderr,"*** Failed to cut up image\n");
987          exit(1);
988       }
989       mri_free(im); im = NULL;
990 
991       for (kkk=0; kkk<inimar->num; ++kkk) {
992          imin = IMAGE_IN_IMARR(inimar,kkk);
993          /*  sprintf(name,"prescaled.%d.ppm", kkk);
994            mri_write(name,imin); */
995          if(imin->kind == MRI_rgb) {
996             imtriple = mri_rgb_to_3byte( imin ) ;
997             if( imtriple == NULL ){
998              fprintf(stderr,"*** mri_rgb_to_3byte fails!\n"); break;
999             }
1000            rim = IMAGE_IN_IMARR(imtriple,0) ;
1001            gim = IMAGE_IN_IMARR(imtriple,1) ;
1002            bim = IMAGE_IN_IMARR(imtriple,2) ; FREE_IMARR(imtriple) ;
1003            /* scale image */
1004            if (ScaleInt) {
1005               /* fprintf(stderr,"Scaling image %d by %f\n",
1006                                  kkk, scl[kkk%nscl]); */
1007               tim = mri_to_byte_scl(0.0, scl[kkk%nscl], rim );
1008                                                    mri_free(rim); rim = tim;
1009               tim = mri_to_byte_scl(0.0, scl[kkk%nscl], gim );
1010                                                    mri_free(gim); gim = tim;
1011               tim = mri_to_byte_scl(0.0, scl[kkk%nscl], bim );
1012                                                    mri_free(bim); bim = tim;
1013            } else {
1014               /* fprintf(stderr,"Scaling image %d by [%.2f %.2f %.2f]\n",
1015                               kkk,  (float)scl3[3*(kkk%nscl)  ],
1016                                     (float)scl3[3*(kkk%nscl)+1],
1017                                     (float)scl3[3*(kkk%nscl)+2]); */
1018               tim = mri_to_byte_scl(0.0, (float)scl3[3*(kkk%nscl)  ], rim );
1019                                                     mri_free(rim); rim = tim;
1020               tim = mri_to_byte_scl(0.0, (float)scl3[3*(kkk%nscl)+1], gim );
1021                                                     mri_free(gim); gim = tim;
1022               tim = mri_to_byte_scl(0.0, (float)scl3[3*(kkk%nscl)+2], bim );
1023                                                     mri_free(bim); bim = tim;
1024            }
1025            newim = mri_3to_rgb( rim, gim, bim ) ;
1026            mri_free(rim) ; mri_free(gim) ; mri_free(bim) ;
1027            MRI_COPY_AUX(newim,imin) ; mri_free(imin);
1028            IMAGE_IN_IMARR(inimar,kkk) = newim;
1029          } else if(imin->kind == MRI_byte) {
1030            /* scale image */
1031            /* fprintf(stderr,"Scaling byte image %d by %f\n",
1032                               kkk, scl[kkk%nscl]); */
1033            newim = mri_to_byte_scl(0.0, (float)scl[kkk%nscl], imin );
1034            MRI_COPY_AUX(newim,imin) ; mri_free(imin);
1035            /* sprintf(name,"postscaled.%d.ppm", kkk);
1036            mri_write(name,newim); */
1037            IMAGE_IN_IMARR(inimar,kkk) = newim;
1038          } else {
1039             fprintf(stderr,
1040                "*** image %d is not rgb or byte. No scaling for you!\n",
1041                kkk%inimar->num);
1042          }
1043       }
1044       if (scl) free(scl); scl = NULL;
1045       if (scl3) free(scl3); scl3 = NULL;
1046       /* Now put it back together */
1047       /* fprintf(stderr,"Going to cat2D, again\n"); */
1048       if (!(im = mri_cat2D( nx , ny , gap , ggg , inimar ))) {
1049          fprintf(stderr,"*** ERROR: Failed to create image!\n");
1050          exit(1) ;
1051       }
1052       FREE_IMARR(inimar) ; inimar = NULL;
1053 
1054    }
1055 
1056    if (scale_pixels) {
1057       MRI_IMARR *imtriple ;
1058       MRI_IMAGE *rim, *gim, *bim, *tim, *newim;
1059       if (im->kind != MRI_rgb && im->kind != MRI_byte) {
1060          fprintf(stderr,"*** Output not MRI_rgb or MRI_byte. Cannot scale.\n");
1061          exit(1);
1062       }
1063       fprintf(stderr,"*** Pixel scaling ...\n");
1064       if (!(imar = mri_read_resamp_many_files( 1 , &scale_pixels,
1065                                                  im->nx, ks*im->ny, pval )) ||
1066            imar->num != 1) {
1067          fprintf(stderr,"*** Failed to read 1 image from %s\n", scale_pixels);
1068          exit(1) ;
1069       }
1070 
1071       if (imscl) mri_free(imscl); imscl=NULL;
1072       if (scl) free(scl); scl=NULL;
1073       if (scl3) free(scl3); scl3 = NULL;
1074 
1075       imscl = IMAGE_IN_IMARR(imar,0);
1076       rgb= MRI_BYTE_PTR(imscl);
1077       nscl = imscl->nx*imscl->ny;
1078       scl = (float *)malloc(sizeof(float)*nscl);
1079       scl3 = (byte *)malloc(sizeof(byte)*nscl*3);
1080       if (imscl->kind == MRI_rgb) {
1081          for (kkk=0; kkk<nscl; ++kkk) {
1082             scl[kkk] = (   (float)rgb[3*kkk  ] +
1083                            (float)rgb[3*kkk+1] +
1084                            (float)rgb[3*kkk+2] ) / 3.0;
1085             scl3[3*kkk  ] = rgb[3*kkk  ];
1086             scl3[3*kkk+1] = rgb[3*kkk+1];
1087             scl3[3*kkk+2] = rgb[3*kkk+2];
1088          }
1089       } else if (imscl->kind == MRI_byte) {
1090          for (kkk=0; kkk<nscl; ++kkk) {
1091             scl[kkk] = ((float)rgb[kkk  ]);
1092             scl3[3*kkk  ] = rgb[kkk];  /* inefficient, but makes life easy */
1093             scl3[3*kkk+1] = rgb[kkk];
1094             scl3[3*kkk+2] = rgb[kkk];
1095          }
1096       } else {
1097          fprintf(stderr,"*** Scale image must be RGB or byte type.\n");
1098          exit(1);
1099       }
1100       /* Now scale */
1101       if(im->kind == MRI_rgb) {
1102          imtriple = mri_rgb_to_3byte( im ) ;
1103          if( imtriple == NULL ){
1104             fprintf(stderr,"*** mri_rgb_to_3byte fails!\n"); exit(1);
1105          }
1106          rim = IMAGE_IN_IMARR(imtriple,0) ; b1 = MRI_BYTE_PTR(rim) ;
1107          gim = IMAGE_IN_IMARR(imtriple,1) ; b2 = MRI_BYTE_PTR(gim) ;
1108          bim = IMAGE_IN_IMARR(imtriple,2) ; b3 = MRI_BYTE_PTR(bim) ;
1109          FREE_IMARR(imtriple) ;
1110          /* scale image */
1111          if (ScaleInt) {
1112             for (kkk=0; kkk<im->nvox; ++kkk) {
1113                b1[kkk] = BYTEIZE((b1[kkk]*(float)scl[kkk])/255.0);
1114                b2[kkk] = BYTEIZE((b2[kkk]*(float)scl[kkk])/255.0);
1115                b3[kkk] = BYTEIZE((b3[kkk]*(float)scl[kkk])/255.0);
1116             }
1117          } else {
1118             /* fprintf(stderr,"Scaling image %d by [%.2f %.2f %.2f]\n",
1119                            kkk,  (float)scl3[3*(kkk%nscl)  ],
1120                                  (float)scl3[3*(kkk%nscl)+1],
1121                                  (float)scl3[3*(kkk%nscl)+2]); */
1122             for (kkk=0; kkk<im->nvox; ++kkk) {
1123                b1[kkk] = BYTEIZE((b1[kkk]*(float)scl3[3*kkk  ])/255.0);
1124                b2[kkk] = BYTEIZE((b2[kkk]*(float)scl3[3*kkk+1])/255.0);
1125                b3[kkk] = BYTEIZE((b3[kkk]*(float)scl3[3*kkk+2])/255.0);
1126             }
1127          }
1128          newim = mri_3to_rgb( rim, gim, bim ) ;
1129          mri_free(rim) ; mri_free(gim) ; mri_free(bim) ;
1130          MRI_COPY_AUX(newim,im) ; mri_free(im);
1131          im = newim; newim = NULL;
1132       } else if(im->kind == MRI_byte) {
1133          /* scale image */
1134          b1 = MRI_BYTE_PTR(im) ;
1135          for (kkk=0; kkk<im->nvox; ++kkk) {
1136             b1[kkk] = BYTEIZE((b1[kkk]*(float)scl[kkk])/255.0);
1137          }
1138       } else {
1139             fprintf(stderr,
1140                "*** image is not rgb or byte. No scaling for you!\n");
1141       }
1142       if (scl) free(scl); scl = NULL;
1143       if (scl3) free(scl3); scl3 = NULL;
1144    }
1145 
1146    if (!(STRING_HAS_SUFFIX_CASE(prefix,".1D"))) {
1147       if (!(STRING_HAS_SUFFIX_CASE(prefix,".jpg")) &&
1148           !(STRING_HAS_SUFFIX_CASE(prefix,".ppm")) ) {
1149          sprintf(fnam,"%s.ppm",prefix);
1150       } else {
1151          sprintf(fnam,"%s",prefix);
1152       }
1153       fprintf(stderr,"+++ Writing image to %s\n", fnam);
1154       mri_write(fnam,im) ;
1155       fprintf(stdout, "You can view image %s with:\n aiv %s \n", fnam, fnam);
1156    } else { /* write a 1D out */
1157       FILE *fout=fopen(prefix,"w");
1158       float *fff=NULL;
1159       MRI_IMAGE *tim;
1160       if (!fout) {
1161          fprintf(stderr,"*** ERROR: Failed to open %s for output!\n", prefix);
1162          exit(1) ;
1163       }
1164       if (!(tim = mri_to_float(im))) {
1165          fprintf(stderr,"*** ERROR: Failed to convert output image.\n");
1166          exit(1) ;
1167       }
1168       fff= MRI_FLOAT_PTR(tim);
1169       for (jj=0; jj<tim->ny; ++jj)  {
1170          for (ii=0; ii<tim->nx; ++ii) {
1171             fprintf(fout,"%.4f ", fff[jj*tim->nx+ii]);
1172          }
1173          fprintf(fout,"\n");
1174       }
1175       fclose(fout);
1176       mri_free(tim); tim = NULL;
1177       fprintf(stdout, "You can view image %s with:\n 1dgrayplot %s \n",
1178                         fnam, prefix);
1179    }
1180 
1181    mri_free(im); im = NULL;
1182     exit(0) ;
1183 }
1184