1 /*------------------------------------------------------------------------*/
2 /*--- AFNI Image Viewer - quicky adaptation from afni_plugin.c stuff. ----*/
3 /*------------------------------------------------------------------------*/
4
5 #include "mrilib.h"
6 #include "imseq.h"
7
8 /*------------------------------------------------------------------------*/
9
10 typedef struct {
11 MCW_imseq *seq ;
12 MRI_IMARR *imar ;
13 int rgb_count ;
14 generic_func *kill_func ;
15 void *kill_data ;
16 } AIVVVV_imseq ;
17
18 static AIVVVV_imseq *psq_global ;
19 static XtAppContext AIVVV_appcontext ;
20
21 static NI_stream AIVVV_stream = (NI_stream)NULL ;
22 static char AIVVV_strnam[64] ;
23 static int AIVVV_have_dummy = 0 ;
24
25 static void * AIVVV_imseq_popup( MRI_IMARR *, generic_func *, void * ) ;
26 static void AIVVV_imseq_retitle( void * , char * ) ;
27 static XtPointer AIVVV_imseq_getim( int , int , XtPointer ) ;
28 static void AIVVV_imseq_send_CB( MCW_imseq * , XtPointer , ISQ_cbs * ) ;
29 static void AIVVV_imseq_addto( MRI_IMAGE *im ) ; /* 25 Jul 2005 */
30 static RwcBoolean AIVVV_workproc( XtPointer ) ; /* 25 Jul 2005 */
31 static void AIVVV_niml_quitter( char *, NI_stream , NI_element * ) ;
32
33 /*------------------------------------------------------------------------*/
34
35 static char *FALLback[] =
36 { "AFNI*fontList: 9x15bold=charset1" ,
37 "AFNI*pbar*fontList: 6x10=charset1" ,
38 "AFNI*imseq*fontList: 7x13=charset1" ,
39 "AFNI*background: gray20" ,
40 "AFNI*menu*background: gray10" ,
41 "AFNI*borderColor: gray20" ,
42 "AFNI*foreground: yellow" ,
43 "AFNI*borderWidth: 0" ,
44 "AFNI*troughColor: blue" ,
45 "AFNI*XmLabel.translations: #override<Btn2Down>:" , /* Motif 2.0 bug */
46 "AFNI*help*background: black" ,
47 "AFNI*help*foreground: yellow" ,
48 "AFNI*help*helpborder: False" ,
49 "AFNI*help*waitPeriod: 1066" ,
50 "AFNI*help*fontList: 9x15bold=charset1" ,
51 "AFNI*cluefont: 9x15bold" ,
52 "AFNI*help*cancelWaitPeriod: 50" ,
53 "AFNI*XmList.translations: #override" /* 24 Feb 2007 */
54 "<Btn4Down>: ListPrevItem()\\n"
55 "<Btn5Down>: ListNextItem()" ,
56 "AFNI*XmText.translations: #override"
57 "<Btn4Down>: previous-line()\\n"
58 "<Btn5Down>: next-line()" ,
59 "AFNI*XmScrollBar.translations: #override"
60 "<Btn4Down>: IncrementUpOrLeft(0) IncrementUpOrLeft(1)\\n"
61 "<Btn5Down>: IncrementDownOrRight(1) IncrementDownOrRight(0)" ,
62 NULL } ;
63
64 static MCW_DC *MAIN_dc ;
65 static XtAppContext MAIN_app ;
66 static MRI_IMARR *MAIN_imar ;
67
68 #define DEFAULT_NCOLOVR 20
69
70 static char *INIT_colovr[DEFAULT_NCOLOVR] = {
71 "#ffff00" , "#ffcc00" , "#ff9900" , "#ff6900" , "#ff4400" , "#ff0000" ,
72 "#0000ff" , "#0044ff" , "#0069ff" , "#0099ff" , "#00ccff" , "#00ffff" ,
73 "green" , "limegreen" , "violet" , "hotpink" ,
74 "white" , "#dddddd" , "#bbbbbb" , "black"
75 } ;
76
77 static char *INIT_labovr[DEFAULT_NCOLOVR] = {
78 "yellow" , "yell-oran" , "oran-yell" , "orange" , "oran-red" , "red" ,
79 "dk-blue", "blue" , "lt-blue1" , "lt-blue2" , "blue-cyan", "cyan" ,
80 "green" , "limegreen" , "violet" , "hotpink" ,
81 "white" , "gry-dd" , "gry-bb" , "black"
82 } ;
83
84 static char wintit[256] = { "Images" } ;
85 /*------------------------------------------------------------------------*/
86
killer(void * pt)87 static void killer( void *pt ){ exit(0); }
AFNI_handler(char * msg)88 static void AFNI_handler(char *msg){ return ; } /* hide X11 warnings */
89
90 /*------------------------------------------------------------------------*/
91 /*! Called to start up display, after X11 has had time to get going. */
92
timeout_CB(XtPointer client_data,XtIntervalId * id)93 static void timeout_CB( XtPointer client_data , XtIntervalId *id )
94 {
95 ENTRY("timeout_CB") ;
96 (void) AIVVV_imseq_popup( MAIN_imar , killer , NULL ) ;
97 if( AIVVV_stream != (NI_stream)NULL ){
98 XtAppAddWorkProc( AIVVV_appcontext, AIVVV_workproc, NULL ) ;
99 NI_register_doer( "QUIT" , AIVVV_niml_quitter ) ;
100 NI_register_doer( "EXIT" , AIVVV_niml_quitter ) ;
101 }
102 EXRETURN ;
103 }
104
105 /*------------------------------------------------------------------------*/
106
main(int argc,char * argv[])107 int main( int argc , char *argv[] )
108 {
109 int ii , quiet=0, verb=0 , iarg=1 , jj , dopad=0 , xpad=0,ypad=0 ;
110 MRI_IMAGE *im ; /* 1 input image */
111 MRI_IMARR *qar ; /* all input images */
112 Widget shell ;
113 int gnim ; char **gname=NULL ; /* 23 Dec 2002: glob filenames */
114
115 if( argc < 2 || strcmp(argv[1],"-help") == 0 ){
116 printf(
117 "Usage: aiv [-v] [-q] [-title] [-p xxxx ] image ...\n"
118 "\n"
119 "AFNI Image Viewer program.\n"
120 "\n"
121 "Shows the 2D images on the command line in an AFNI-like image viewer.\n"
122 "\n"
123 "Can also read images in NIML '<MRI_IMAGE...>' format from a TCP/IP socket.\n"
124 "\n"
125 "Image file formats are those supported by to3d:\n"
126 " * various MRI formats (e.g., DICOM, GEMS I.xxx)\n"
127 " * raw PPM or PGM\n"
128 " * JPEG (if djpeg is in the path)\n"
129 " * GIF, TIFF, BMP, and PNG (if netpbm is in the path)\n"
130 "\n"
131 "The '-v' option will make aiv print out the image filenames\n"
132 " as it reads them - this can be a useful progress meter if\n"
133 " the program starts up slowly.\n"
134 "\n"
135 "The '-q' option tells the program to be very quiet.\n"
136 "\n"
137 "The '-pad' option tells the program to pad all input images\n"
138 " (from the command line) to be the same size.\n"
139 " Images that are much smaller than the largest image will\n"
140 " also be inflated somewhat so as not to look tiny.\n"
141 "In the form '-pad X Y', where 'X' and 'Y' are integers >= 64,\n"
142 " then all images will be resized to fit inside those dimensions.\n"
143 "\n"
144 "The '-title WORD' option titles the window WORD. \n"
145 "The default is the name of the image file if only one is \n"
146 "specified on the command line. If many images are read in\n"
147 "the default window title is 'Images'.\n"
148 "\n"
149 "The '-p xxxx' option will make aiv listen to TCP/IP port 'xxxx'\n"
150 "for incoming images in the NIML '<MRI_IMAGE...>' format. The\n"
151 "port number must be between 1024 and 65535, inclusive. For\n"
152 "conversion to NIML '<MRI_IMAGE...>' format, see program im2niml.\n"
153 "\n"
154 "Normally, at least one image must be given on the command line.\n"
155 "If the '-p xxxx' option is used, then you don't have to input\n"
156 "any images this way; however, since the program requires at least\n"
157 "one image to start up, a crude 'X' will be displayed. When the\n"
158 "first image arrives via the socket, the 'X' image will be replaced.\n"
159 "Subsequent images arriving by socket will be added to the sequence.\n"
160 "\n-----------------------------------------------------------------\n"
161 "Sample program fragment, for sending images from one program\n"
162 "into a copy of aiv (which that program also starts up):\n"
163 "\n"
164 "#include \"mrilib.h\"\n"
165 "NI_stream ns; MRI_IMAGE *im; float *far; int nx,ny;\n"
166 "system(\"aiv -p 4444 &\"); /* start aiv */\n"
167 "ns = NI_stream_open( \"tcp:localhost:4444\" , \"w\" ); /* connect to it */\n"
168 "while(1){\n"
169 " /** ......... create 2D nx X ny data into the far array .........**/\n"
170 " im = mri_new_vol_empty( nx , ny , 1 , MRI_float ); /* fake image */\n"
171 " mri_fix_data_pointer( far , im ); /* attach data */\n"
172 " NI_element nel = mri_to_niml(im); /* convert to NIML element */\n"
173 " NI_write_element( ns , nel , NI_BINARY_MODE ); /* send to aiv */\n"
174 " NI_free_element(nel); mri_clear_data_pointer(im); mri_free(im);\n"
175 "}\n"
176 "NI_stream_writestring( ns , \"<ni_do ni_verb='QUIT'>\" ) ;\n"
177 "NI_stream_close( ns ) ; /* do this, or the above, if done with aiv */\n"
178 "\n"
179 "-- Authors: RW Cox and DR Glen\n"
180 ) ;
181 PRINT_COMPILE_DATE ; exit(0) ;
182 }
183
184 mainENTRY("aiv main") ; machdep() ;
185
186 /* options? */
187
188 while( iarg < argc && argv[iarg][0] == '-' ){
189 /*-- title --*/
190 if( strncmp(argv[iarg],"-title",6) == 0 ){
191 if (iarg+1 > argc) {
192 ERROR_message("Need a string after -title");
193 /* ignore option */
194 } else {
195 snprintf(wintit,128*sizeof(char),"%s", argv[++iarg]);
196 }
197 iarg++; continue;
198 }
199 /*-- verbosity --*/
200
201 if( strncmp(argv[iarg],"-v",2) == 0 ){ verb=1; iarg++; continue; }
202 if( strncmp(argv[iarg],"-q",2) == 0 ){ quiet=1; iarg++; continue; }
203
204 if( strcmp(argv[iarg],"-pad") == 0 ){ /* 02 Nov 2017 */
205 dopad++ ;
206 if( iarg+2 < argc && isdigit(argv[iarg+1][0]) && isdigit(argv[iarg+2][0]) ){
207 xpad = (int)strtod(argv[++iarg],NULL) ; if( xpad < 64 || xpad > 6666 ) xpad = 0 ;
208 ypad = (int)strtod(argv[++iarg],NULL) ; if( ypad < 64 || ypad > 6666 ) ypad = 0 ;
209 }
210 iarg++ ; continue ;
211 }
212
213 /*-- port or sherry? --*/
214
215 if( strncmp(argv[iarg],"-p",2) == 0 ){
216 int port = (int)strtol(argv[++iarg],NULL,10) ;
217 if( AIVVV_stream != NULL ){
218 ERROR_message("Can't use multiple '-p' options!") ;
219 iarg++ ; continue ; /* skip to next option */
220 }
221 if( port <= 1023 ){
222 ERROR_message("Illegal value after -p; not listening.") ;
223 } else {
224 sprintf(AIVVV_strnam,"tcp:x:%d",port) ;
225 AIVVV_stream = NI_stream_open( AIVVV_strnam , "r" ) ;
226 if( AIVVV_stream == (NI_stream)NULL ){
227 ERROR_message("Can't listen to port %d!",port) ;
228 } else {
229 int nn ;
230 nn = NI_stream_goodcheck(AIVVV_stream,66) ;
231 if( verb ){
232 if( nn > 0 ) INFO_message("Connected to port %d",port) ;
233 else INFO_message("Listening to port %d",port) ;
234 }
235 }
236 }
237 iarg++ ; continue ;
238 }
239
240 /*-- WTF? --*/
241
242 ERROR_exit("Unknown option: %s",argv[iarg]) ;
243 }
244 if (!quiet) { PRINT_VERSION("aiv") ; }
245
246 /* glob filenames, read images */
247
248 MCW_file_expand( argc-iarg , argv+iarg , &gnim , &gname ) ;
249 if( gnim == 0 && AIVVV_stream==(NI_stream)NULL )
250 ERROR_exit("No filenames on command line (after wildcard expansion)?!") ;
251
252 INIT_IMARR(MAIN_imar) ;
253
254 for( ii=0 ; ii < gnim ; ii++ ){
255 if( !THD_filename_ok(gname[ii]) ) continue ; /* 23 Apr 2003 */
256 if (!strcmp(wintit,"Images") && gnim == 1) { /* give window a useful name */
257 snprintf(wintit,128*sizeof(char),"%s", gname[ii]);
258 }
259 if( verb ) fprintf(stderr,"+") ;
260 qar = mri_read_file( gname[ii] ) ; /* may have more than 1 2D image */
261 if( qar == NULL || IMARR_COUNT(qar) < 1 ){
262 if( verb )
263 fprintf(stderr,"\n** Can't read file %s - skipping!",gname[ii]) ;
264 else
265 fprintf(stderr,"** AIV ERROR: Can't read file %s - skipping!\n",gname[ii]) ;
266 continue ;
267 } else if( verb ){
268 fprintf(stderr,"%s",gname[ii]) ;
269 }
270
271 if( IMARR_COUNT(qar) == 1 ){ /* possibly a 3D dataset from AFNI */
272 im = IMARR_SUBIM(qar,0) ;
273 if( im != NULL && im->nz > 1 ){ /* break 3D array into 2D images */
274 MRI_IMARR *zar = mri_to_imarr(im) ;
275 if( zar != NULL ){ DESTROY_IMARR(qar) ; qar = zar ; }
276 }
277 }
278
279 for( jj=0 ; jj < IMARR_COUNT(qar) ; jj++ ){
280 im = IMARR_SUBIM(qar,jj) ;
281 if( im != NULL && im->nx > 1 && im->ny > 1 ){
282 if( im->nx > 6666 || im->ny > 6666 ){ /* no big images [03 Nov 2017] */
283 float sx,sy ; MRI_IMAGE *qim ;
284 sx = (im->nx > 6000) ? im->nx/6000.0f : 1.0f ;
285 sy = (im->ny > 6000) ? im->ny/6000.0f : 1.0f ;
286 sx = MIN(sx,sy) ;
287 qim = mri_resize( im , (int)(sx*im->nx) , (int)(sx*im->ny) ) ;
288 if( qim != NULL ){ mri_free(im) ; im = qim ; }
289 }
290 ADDTO_IMARR(MAIN_imar,im);
291 }
292 }
293 FREE_IMARR(qar) ; /* just FREE, not DESTROY */
294 }
295
296 /* print a message about the images? */
297
298 if( IMARR_COUNT(MAIN_imar) == 0 && AIVVV_stream==(NI_stream)NULL )
299 ERROR_exit("No images found on command line!?") ;
300
301 if( !quiet && IMARR_COUNT(MAIN_imar) > 0 ){
302 fprintf(stderr, (verb) ? " = " : "++ " ) ;
303 if( IMARR_COUNT(MAIN_imar) == 1 )fprintf(stderr,"1 image\n") ;
304 else fprintf(stderr,"%d images\n",IMARR_COUNT(MAIN_imar)) ;
305 }
306
307 if( gnim > 0 ) MCW_free_expand( gnim , gname ) ;
308
309 /*----- padding? [02 Nov 2017] -----*/
310
311 if( dopad && IMARR_COUNT(MAIN_imar) > 1 ){
312 int nxtop=0,nytop=0, nx,ny, bx,tx,by,ty, fx,fy ; MRI_IMAGE *qim ;
313 float sx,sy ; char mark='\0'; int xfin,yfin ;
314
315 if( !quiet ) fprintf(stderr,"++ padding ") ;
316 for( ii=0 ; ii < IMARR_COUNT(MAIN_imar) ; ii++ ){
317 im = IMARR_SUBIM(MAIN_imar,ii) ;
318 if( im != NULL ){ nxtop = MAX(nxtop,im->nx); nytop = MAX(nytop,im->ny); }
319 }
320 if( xpad > 0 && ypad > 0 ){ xfin = xpad ; yfin = ypad ; }
321 else { xfin = nxtop; yfin = nytop; }
322 for( ii=0 ; ii < IMARR_COUNT(MAIN_imar) ; ii++ ){
323 im = IMARR_SUBIM(MAIN_imar,ii) ;
324 nx = im->nx ; ny = im->ny ; mark = '\0' ;
325 if( xpad > 0 && ypad > 0 ){
326 if( nx == xpad && ny == ypad ) continue ;
327 sx = (float)(xpad) / (float)(nx) ;
328 sy = (float)(ypad) / (float)(ny) ; sx = MIN(sx,sy) ;
329 qim = mri_resize( im , (int)(sx*nx) , (int)(sx*ny) ) ;
330 if( qim != NULL ){ mri_free(im) ; im = qim ; }
331 nx = im->nx ; ny = im->ny ;
332 mark = '*' ;
333 } else {
334 if( nx >= nxtop && ny >= nytop ) continue ;
335 if( nx <= 2 || ny <= 2 ) continue ;
336 sx = (float)(nxtop) / (float)(nx) ;
337 sy = (float)(nytop) / (float)(ny) ; sx = MIN(sx,sy) ;
338 fx = (int)sx; fy = (int)sy; fx = MIN(fx,fy) ;
339 if( fx > 2 && dopad == 1 ){
340 qim = mri_dup2D(fx,im) ;
341 if( qim != NULL ){ mri_free(im) ; im = qim ; }
342 nx = im->nx ; ny = im->ny ;
343 mark = '+' ;
344 } else if( sx > 1.1f ){
345 qim = mri_resize( im , (int)(sx*nx) , (int)(sx*ny) ) ;
346 if( qim != NULL ){ mri_free(im) ; im = qim ; }
347 nx = im->nx ; ny = im->ny ;
348 mark = '*' ;
349 }
350 }
351 if( nx < xfin ){ bx = (xfin-nx)/2 ; tx = xfin-nx-bx ; }
352 else { bx = tx = 0 ; }
353 if( ny < yfin ){ by = (yfin-ny)/2 ; ty = yfin-ny-by ; }
354 else { by = ty = 0 ; }
355 if( bx > 0 || tx > 0 || by > 0 || ty > 0 ){
356 qim = mri_zeropad_2D( bx,tx , by,ty , im ) ;
357 if( qim != NULL ){ mri_free(im) ; im = qim ; }
358 if( mark == '\0' ) mark = '.' ;
359 }
360 IMARR_SUBIM(MAIN_imar,ii) = im ;
361 if( !quiet ) fprintf(stderr,"%c",mark) ;
362 }
363 if( !quiet ) fprintf(stderr,"!\n") ;
364
365 } /*----- end of padding ----*/
366
367 /* connect to X11 */
368
369 shell = XtVaAppInitialize( &MAIN_app , "AFNI" , NULL , 0 ,
370 &argc , argv , FALLback , NULL ) ;
371
372 if( shell == NULL )
373 ERROR_exit("Can't initialize X11") ;
374
375 AIVVV_appcontext = XtWidgetToApplicationContext(shell) ;
376
377 (void) XtAppSetWarningHandler(MAIN_app,AFNI_handler) ;
378
379 MAIN_dc = MCW_new_DC( shell, 128,
380 DEFAULT_NCOLOVR, INIT_colovr, INIT_labovr, 1.0, 0 ) ;
381
382 srand48((long)time(NULL)+(long)getpid()) ;
383
384 /* wait a little bit, then popup the image viewer window */
385
386 (void) XtAppAddTimeOut( MAIN_app, 234, timeout_CB, NULL ) ;
387 XtAppMainLoop(MAIN_app) ; /* will never return */
388 exit(0) ;
389 }
390
391 /*-------------------------------------------------------------------------*/
392 /*! Open the image viewer. */
393
AIVVV_imseq_popup(MRI_IMARR * imar,generic_func * kfunc,void * kdata)394 static void * AIVVV_imseq_popup( MRI_IMARR *imar, generic_func *kfunc, void *kdata )
395 {
396 int ntot , ii ;
397 MRI_IMAGE *im , *cim ;
398 AIVVVV_imseq *psq ;
399
400 ENTRY("AIVVV_imseq_popup") ;
401
402 if( imar == NULL ) RETURN(NULL) ;
403
404 ntot = IMARR_COUNT(imar) ;
405 if( ntot == 0 ){ /** dummy 'X' image **/
406 #define QQ_NXYZ 16
407 static byte xxx[QQ_NXYZ*QQ_NXYZ] = {
408 0,0,21,131,135,135,135,8,0,0,3,100,135,135,135,128,
409 0,0,0,108,255,255,255,86,0,0,115,255,255,255,255,121,
410 0,0,0,21,216,255,255,213,0,19,223,255,255,255,187,5,
411 0,0,0,0,92,244,255,255,114,114,255,255,255,234,58,0,
412 0,0,0,0,0,174,255,255,252,230,255,255,255,130,0,0,
413 0,0,0,0,0,58,244,255,255,255,255,255,228,29,0,0,
414 0,0,0,0,0,0,118,255,255,255,255,255,74,0,0,0,
415 0,0,0,0,0,0,55,248,255,255,255,199,3,0,0,0,
416 0,0,0,0,0,5,170,255,255,255,255,227,32,0,0,0,
417 0,0,0,0,0,104,255,255,255,255,255,255,140,5,0,0,
418 0,0,0,0,13,217,255,255,252,215,255,255,255,67,0,0,
419 0,0,0,0,159,255,255,255,212,23,233,255,255,187,7,0,
420 0,0,0,81,241,255,255,255,85,0,72,255,255,255,66,0,
421 0,0,16,206,255,255,255,212,0,0,8,193,255,255,237,12,
422 0,0,94,255,255,255,255,86,0,0,0,73,255,255,255,121,
423 0,14,129,134,134,134,85,1,0,0,0,3,106,134,134,127 } ;
424 byte *ar ; MRI_IMAGE *xim ;
425
426 ar = (byte *)malloc(sizeof(byte)*QQ_NXYZ*QQ_NXYZ) ;
427 memcpy(ar,xxx,sizeof(byte)*QQ_NXYZ*QQ_NXYZ) ;
428 xim = mri_new_vol_empty( QQ_NXYZ,QQ_NXYZ,1 , MRI_byte ) ;
429 mri_fix_data_pointer( ar , xim ) ;
430 xim->dx = xim->dy = 16.0 ;
431 ADDTO_IMARR(imar,xim) ; ntot = 1 ; AIVVV_have_dummy = 1 ;
432 }
433
434 /* psq holds all the data needed for viewing */
435
436 psq = psq_global = (AIVVVV_imseq *)calloc(1,sizeof(AIVVVV_imseq)) ;
437 if( psq == NULL ) RETURN(NULL) ; /* should never happen */
438
439 psq->imar = imar ;
440
441 psq->kill_func = kfunc ;
442 psq->kill_data = kdata ;
443 psq->rgb_count = 0 ;
444
445 /* actually create the viewer */
446
447 psq->seq = open_MCW_imseq( MAIN_dc , AIVVV_imseq_getim , psq ) ;
448
449 drive_MCW_imseq( psq->seq , isqDR_clearstat , NULL ) ;
450
451 { ISQ_options opt ; /* change some options from the defaults */
452
453 ISQ_DEFAULT_OPT(opt) ;
454 opt.save_one = False ; /* change to Save:bkg */
455 opt.save_pnm = False ;
456 drive_MCW_imseq( psq->seq , isqDR_options , (XtPointer) &opt ) ;
457 drive_MCW_imseq( psq->seq , isqDR_periodicmont , (XtPointer) 0 ) ;
458 drive_MCW_imseq( psq->seq , isqDR_penbbox , (XtPointer) 0 ) ;
459 }
460
461 /* make it popup */
462
463 drive_MCW_imseq( psq->seq , isqDR_realize, NULL ) ;
464 drive_MCW_imseq( psq->seq , isqDR_title, wintit ) ;
465
466 if( ntot == 1 )
467 drive_MCW_imseq( psq->seq , isqDR_onoffwid , (XtPointer) isqDR_offwid );
468 else
469 drive_MCW_imseq( psq->seq , isqDR_onoffwid , (XtPointer) isqDR_onwid );
470
471 /* show the first image */
472
473 drive_MCW_imseq( psq->seq , isqDR_display, (XtPointer)0 ) ;
474
475 drive_MCW_imseq( psq->seq , isqDR_imhelptext ,
476 (XtPointer)
477 "Keyboard Shortcuts:\n\n"
478 "q = close window a = fix aspect ratio\n"
479 "p = toggle panning mode c = crop image mode\n"
480 "s = sharpen image m = toggle Min-to-Max\n"
481 "D = open Disp panel M = open Montage panel\n"
482 "S = Save image l = left-right mirror\n"
483 "> = Page Up = forward 1 image\n"
484 "< = Page Down = backward 1 image\n"
485 "v/V = Video image sequence up/down\n"
486 "r/R = Ricochet image sequence up/down\n"
487 "i/I = image fraction down/up\n"
488 "e = toggle edge detection in image\n"
489 ) ;
490
491 RETURN( (void *)psq ) ;
492 }
493
494 /*-----------------------------------------------------------------------*/
495
AIVVV_imseq_retitle(void * handle,char * title)496 static void AIVVV_imseq_retitle( void *handle , char *title )
497 {
498 AIVVVV_imseq *psq = (AIVVVV_imseq *) handle ;
499
500 if( psq == NULL || psq->seq == NULL || title == NULL ) return ;
501 drive_MCW_imseq( psq->seq , isqDR_title, title ) ;
502 return ;
503 }
504
505 /*------------------------------------------------------------------
506 Routine to provide data to the imseq.
507 Just returns the control information, or the selected image.
508 --------------------------------------------------------------------*/
509
AIVVV_imseq_getim(int n,int type,XtPointer handle)510 static XtPointer AIVVV_imseq_getim( int n, int type, XtPointer handle )
511 {
512 AIVVVV_imseq *psq = (AIVVVV_imseq *) handle ;
513 int ntot = 0 ;
514
515 ENTRY("AIVVV_imseq_getim") ;
516
517 if( psq->imar != NULL ) ntot = IMARR_COUNT(psq->imar) ;
518 if( ntot < 1 ) ntot = 1 ;
519
520 /*--- send control info ---*/
521
522 if( type == isqCR_getstatus ){
523 MCW_imseq_status *stat = myXtNew( MCW_imseq_status ) ; /* will be freed */
524 /* when imseq is */
525 /* destroyed */
526 stat->num_total = ntot ;
527 stat->num_series = ntot ;
528 stat->send_CB = AIVVV_imseq_send_CB ;
529 stat->parent = NULL ;
530 stat->aux = NULL ;
531
532 stat->transforms0D = NULL ;
533 stat->transforms2D = NULL ;
534 stat->slice_proj = NULL ;
535
536 RETURN( (XtPointer)stat ) ;
537 }
538
539 /*--- return a copy of an image
540 (since the imseq will delete it when it is done) ---*/
541
542 if( type == isqCR_getimage || type == isqCR_getqimage ){
543 MRI_IMAGE *im = NULL , *rim ;
544
545 if( psq->imar != NULL ){
546 if( n < 0 ) n = 0 ; else if( n >= ntot ) n = ntot-1 ;
547 rim = IMARR_SUBIMAGE(psq->imar,n) ;
548 if( psq->rgb_count > 0 )
549 im = mri_to_rgb( rim ) ;
550 else
551 im = mri_copy( rim ) ;
552 }
553 RETURN( (XtPointer)im ) ;
554 }
555
556 RETURN(NULL) ; /* any other request gets nothing */
557 }
558
559 /*---------------------------------------------------------------------------
560 Routine called when the imseq wants to send a message.
561 In this case, all we need to handle is the destroy message,
562 so that we can free some memory.
563 -----------------------------------------------------------------------------*/
564
AIVVV_imseq_send_CB(MCW_imseq * seq,XtPointer handle,ISQ_cbs * cbs)565 static void AIVVV_imseq_send_CB( MCW_imseq *seq, XtPointer handle, ISQ_cbs *cbs )
566 {
567 AIVVVV_imseq *psq = (AIVVVV_imseq *) handle ;
568
569 ENTRY("AIVVV_imseq_send_CB") ;
570
571 switch( cbs->reason ){
572 case isqCR_destroy:{
573 myXtFree(psq->seq) ;
574 DESTROY_IMARR( psq->imar ) ;
575
576 if( psq->kill_func != NULL )
577 psq->kill_func( psq->kill_data ) ;
578 free(psq) ;
579 }
580 break ;
581
582 case isqCR_newimage:{
583 drive_MCW_imseq( psq->seq, isqDR_display, (XtPointer)ITOP(cbs->nim) );
584 }
585 break ;
586 }
587 EXRETURN ;
588 }
589
590 /*---------------------------------------------------------------------------*/
591 /* Add an image to the display sequence. */
592
AIVVV_imseq_addto(MRI_IMAGE * im)593 static void AIVVV_imseq_addto( MRI_IMAGE *im )
594 {
595 int ntot , num ;
596 AIVVVV_imseq *psq = psq_global ;
597
598 ENTRY("AIVVV_imseq_addto") ;
599
600 if( im == NULL ) EXRETURN ;
601
602 if( im->nx < 4 || im->ny < 4 ) EXRETURN ;
603
604 /** if more than 1 slice, carve up the volume
605 into multiple 2D slices and recursively add each one **/
606
607 num = im->nz * im->nt * im->nu * im->nv * im->nw ;
608 if( num > 1 ){
609 MRI_IMAGE *qim ; int kk,nb ; char *iar=(char *)mri_data_pointer(im) ;
610 nb = im->nx * im->ny * im->pixel_size ;
611 for( kk=0 ; kk < num ; kk++ ){
612 qim = mri_new_vol_empty( im->nx , im->ny , 1, im->kind ) ;
613 qim->dx = im->dx ; qim->dy = im->dy ;
614 mri_fix_data_pointer( iar + kk*nb , qim ) ;
615 AIVVV_imseq_addto( qim ) ;
616 }
617 EXRETURN ;
618 }
619
620 if( AIVVV_have_dummy ){ /* replace the dummy 'X' */
621 IMARR_SUBIM(psq->imar,0) = im ;
622 AIVVV_have_dummy = 0 ;
623 } else {
624 ADDTO_IMARR(psq->imar,im) ; /* add to sequence */
625 }
626 if( im->kind == MRI_rgb ) psq->rgb_count++ ;
627
628 drive_MCW_imseq( psq->seq , isqDR_newseq , psq ) ;
629
630 ntot = IMARR_COUNT(psq->imar) ;
631 if( ntot == 2 )
632 drive_MCW_imseq( psq->seq , isqDR_onoffwid , (XtPointer) isqDR_onwid ) ;
633
634 drive_MCW_imseq( psq->seq , isqDR_reimage , (XtPointer)ITOP(ntot-1) ) ;
635 EXRETURN ;
636 }
637
638 /*---------------------------------------------------------------------------*/
639 /* Listen to the socket and see if any new <MRI_IMAGE ...> NIML elements
640 appear.
641 -----------------------------------------------------------------------------*/
642
AIVVV_workproc(XtPointer fred)643 static RwcBoolean AIVVV_workproc( XtPointer fred )
644 {
645 int nn ;
646 NI_element *nel ;
647 MRI_IMAGE *im ;
648
649 nn = NI_stream_goodcheck(AIVVV_stream,3) ;
650 if( nn < 0 ){ /* dead? reopen it */
651 NI_stream_closenow(AIVVV_stream) ;
652 NI_sleep(9) ;
653 AIVVV_stream = NI_stream_open( AIVVV_strnam , "r" ) ;
654 return False ;
655 }
656
657 nn = NI_stream_hasinput(AIVVV_stream,9) ; /* anything? */
658 if( nn <= 0 ) return False ; /* no data */
659
660 /* read data, add image */
661
662 nel = (NI_element *)NI_read_element(AIVVV_stream,99) ;
663 if( NI_element_type(nel) != NI_ELEMENT_TYPE ){ /* bad read */
664 NI_free_element(nel) ; return False ;
665 }
666
667 /* the only type of element we deal with is MRI_IMAGE */
668
669 im = niml_to_mri( nel ) ; /* convert element to image */
670 NI_free_element( nel ) ;
671 AIVVV_imseq_addto( im ) ; /* add image to the display sequence */
672 return False ;
673 }
674
675 /*---------------------------------------------------------------------------*/
676
AIVVV_niml_quitter(char * obj,NI_stream ns,NI_element * nel)677 static void AIVVV_niml_quitter( char *obj, NI_stream ns, NI_element *nel )
678 {
679 INFO_message("Received remote command to exit") ;
680 NI_stream_closenow(AIVVV_stream) ;
681 NI_sleep(333) ;
682 exit(0) ;
683 }
684